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