ipath_keys.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. /*
  2. * Copyright (c) 2005, 2006 PathScale, Inc. All rights reserved.
  3. *
  4. * This software is available to you under a choice of one of two
  5. * licenses. You may choose to be licensed under the terms of the GNU
  6. * General Public License (GPL) Version 2, available from the file
  7. * COPYING in the main directory of this source tree, or the
  8. * OpenIB.org BSD license below:
  9. *
  10. * Redistribution and use in source and binary forms, with or
  11. * without modification, are permitted provided that the following
  12. * conditions are met:
  13. *
  14. * - Redistributions of source code must retain the above
  15. * copyright notice, this list of conditions and the following
  16. * disclaimer.
  17. *
  18. * - Redistributions in binary form must reproduce the above
  19. * copyright notice, this list of conditions and the following
  20. * disclaimer in the documentation and/or other materials
  21. * provided with the distribution.
  22. *
  23. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30. * SOFTWARE.
  31. */
  32. #include <asm/io.h>
  33. #include "ipath_verbs.h"
  34. /**
  35. * ipath_alloc_lkey - allocate an lkey
  36. * @rkt: lkey table in which to allocate the lkey
  37. * @mr: memory region that this lkey protects
  38. *
  39. * Returns 1 if successful, otherwise returns 0.
  40. */
  41. int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr)
  42. {
  43. unsigned long flags;
  44. u32 r;
  45. u32 n;
  46. int ret;
  47. spin_lock_irqsave(&rkt->lock, flags);
  48. /* Find the next available LKEY */
  49. r = n = rkt->next;
  50. for (;;) {
  51. if (rkt->table[r] == NULL)
  52. break;
  53. r = (r + 1) & (rkt->max - 1);
  54. if (r == n) {
  55. spin_unlock_irqrestore(&rkt->lock, flags);
  56. _VERBS_INFO("LKEY table full\n");
  57. ret = 0;
  58. goto bail;
  59. }
  60. }
  61. rkt->next = (r + 1) & (rkt->max - 1);
  62. /*
  63. * Make sure lkey is never zero which is reserved to indicate an
  64. * unrestricted LKEY.
  65. */
  66. rkt->gen++;
  67. mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) |
  68. ((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen)
  69. << 8);
  70. if (mr->lkey == 0) {
  71. mr->lkey |= 1 << 8;
  72. rkt->gen++;
  73. }
  74. rkt->table[r] = mr;
  75. spin_unlock_irqrestore(&rkt->lock, flags);
  76. ret = 1;
  77. bail:
  78. return ret;
  79. }
  80. /**
  81. * ipath_free_lkey - free an lkey
  82. * @rkt: table from which to free the lkey
  83. * @lkey: lkey id to free
  84. */
  85. void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey)
  86. {
  87. unsigned long flags;
  88. u32 r;
  89. if (lkey == 0)
  90. return;
  91. r = lkey >> (32 - ib_ipath_lkey_table_size);
  92. spin_lock_irqsave(&rkt->lock, flags);
  93. rkt->table[r] = NULL;
  94. spin_unlock_irqrestore(&rkt->lock, flags);
  95. }
  96. /**
  97. * ipath_lkey_ok - check IB SGE for validity and initialize
  98. * @rkt: table containing lkey to check SGE against
  99. * @isge: outgoing internal SGE
  100. * @sge: SGE to check
  101. * @acc: access flags
  102. *
  103. * Return 1 if valid and successful, otherwise returns 0.
  104. *
  105. * Check the IB SGE for validity and initialize our internal version
  106. * of it.
  107. */
  108. int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge,
  109. struct ib_sge *sge, int acc)
  110. {
  111. struct ipath_mregion *mr;
  112. size_t off;
  113. int ret;
  114. /*
  115. * We use LKEY == zero to mean a physical kmalloc() address.
  116. * This is a bit of a hack since we rely on dma_map_single()
  117. * being reversible by calling bus_to_virt().
  118. */
  119. if (sge->lkey == 0) {
  120. isge->mr = NULL;
  121. isge->vaddr = bus_to_virt(sge->addr);
  122. isge->length = sge->length;
  123. isge->sge_length = sge->length;
  124. ret = 1;
  125. goto bail;
  126. }
  127. spin_lock(&rkt->lock);
  128. mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
  129. spin_unlock(&rkt->lock);
  130. if (unlikely(mr == NULL || mr->lkey != sge->lkey)) {
  131. ret = 0;
  132. goto bail;
  133. }
  134. off = sge->addr - mr->user_base;
  135. if (unlikely(sge->addr < mr->user_base ||
  136. off + sge->length > mr->length ||
  137. (mr->access_flags & acc) != acc)) {
  138. ret = 0;
  139. goto bail;
  140. }
  141. off += mr->offset;
  142. isge->mr = mr;
  143. isge->m = 0;
  144. isge->n = 0;
  145. while (off >= mr->map[isge->m]->segs[isge->n].length) {
  146. off -= mr->map[isge->m]->segs[isge->n].length;
  147. isge->n++;
  148. if (isge->n >= IPATH_SEGSZ) {
  149. isge->m++;
  150. isge->n = 0;
  151. }
  152. }
  153. isge->vaddr = mr->map[isge->m]->segs[isge->n].vaddr + off;
  154. isge->length = mr->map[isge->m]->segs[isge->n].length - off;
  155. isge->sge_length = sge->length;
  156. ret = 1;
  157. bail:
  158. return ret;
  159. }
  160. /**
  161. * ipath_rkey_ok - check the IB virtual address, length, and RKEY
  162. * @dev: infiniband device
  163. * @ss: SGE state
  164. * @len: length of data
  165. * @vaddr: virtual address to place data
  166. * @rkey: rkey to check
  167. * @acc: access flags
  168. *
  169. * Return 1 if successful, otherwise 0.
  170. *
  171. * The QP r_rq.lock should be held.
  172. */
  173. int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss,
  174. u32 len, u64 vaddr, u32 rkey, int acc)
  175. {
  176. struct ipath_lkey_table *rkt = &dev->lk_table;
  177. struct ipath_sge *sge = &ss->sge;
  178. struct ipath_mregion *mr;
  179. size_t off;
  180. int ret;
  181. spin_lock(&rkt->lock);
  182. mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
  183. spin_unlock(&rkt->lock);
  184. if (unlikely(mr == NULL || mr->lkey != rkey)) {
  185. ret = 0;
  186. goto bail;
  187. }
  188. off = vaddr - mr->iova;
  189. if (unlikely(vaddr < mr->iova || off + len > mr->length ||
  190. (mr->access_flags & acc) == 0)) {
  191. ret = 0;
  192. goto bail;
  193. }
  194. off += mr->offset;
  195. sge->mr = mr;
  196. sge->m = 0;
  197. sge->n = 0;
  198. while (off >= mr->map[sge->m]->segs[sge->n].length) {
  199. off -= mr->map[sge->m]->segs[sge->n].length;
  200. sge->n++;
  201. if (sge->n >= IPATH_SEGSZ) {
  202. sge->m++;
  203. sge->n = 0;
  204. }
  205. }
  206. sge->vaddr = mr->map[sge->m]->segs[sge->n].vaddr + off;
  207. sge->length = mr->map[sge->m]->segs[sge->n].length - off;
  208. sge->sge_length = len;
  209. ss->sg_list = NULL;
  210. ss->num_sge = 1;
  211. ret = 1;
  212. bail:
  213. return ret;
  214. }