Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/infiniband/hw/ipath/ipath_keys.c
15112 views
1
/*
2
* Copyright (c) 2006, 2007 QLogic Corporation. All rights reserved.
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"
37
#include "ipath_kernel.h"
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);
64
ipath_dbg("LKEY table full\n");
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
*/
121
int ipath_lkey_ok(struct ipath_qp *qp, struct ipath_sge *isge,
122
struct ib_sge *sge, int acc)
123
{
124
struct ipath_lkey_table *rkt = &to_idev(qp->ibqp.device)->lk_table;
125
struct ipath_mregion *mr;
126
unsigned n, m;
127
size_t off;
128
int ret;
129
130
/*
131
* We use LKEY == zero for kernel virtual addresses
132
* (see ipath_get_dma_mr and ipath_dma.c).
133
*/
134
if (sge->lkey == 0) {
135
/* always a kernel port, no locking needed */
136
struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
137
138
if (pd->user) {
139
ret = 0;
140
goto bail;
141
}
142
isge->mr = NULL;
143
isge->vaddr = (void *) sge->addr;
144
isge->length = sge->length;
145
isge->sge_length = sge->length;
146
ret = 1;
147
goto bail;
148
}
149
mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))];
150
if (unlikely(mr == NULL || mr->lkey != sge->lkey ||
151
qp->ibqp.pd != mr->pd)) {
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;
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;
173
}
174
}
175
isge->mr = mr;
176
isge->vaddr = mr->map[m]->segs[n].vaddr + off;
177
isge->length = mr->map[m]->segs[n].length - off;
178
isge->sge_length = sge->length;
179
isge->m = m;
180
isge->n = n;
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.
198
*/
199
int ipath_rkey_ok(struct ipath_qp *qp, struct ipath_sge_state *ss,
200
u32 len, u64 vaddr, u32 rkey, int acc)
201
{
202
struct ipath_ibdev *dev = to_idev(qp->ibqp.device);
203
struct ipath_lkey_table *rkt = &dev->lk_table;
204
struct ipath_sge *sge = &ss->sge;
205
struct ipath_mregion *mr;
206
unsigned n, m;
207
size_t off;
208
int ret;
209
210
/*
211
* We use RKEY == zero for kernel virtual addresses
212
* (see ipath_get_dma_mr and ipath_dma.c).
213
*/
214
if (rkey == 0) {
215
/* always a kernel port, no locking needed */
216
struct ipath_pd *pd = to_ipd(qp->ibqp.pd);
217
218
if (pd->user) {
219
ret = 0;
220
goto bail;
221
}
222
sge->mr = NULL;
223
sge->vaddr = (void *) vaddr;
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
232
mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))];
233
if (unlikely(mr == NULL || mr->lkey != rkey ||
234
qp->ibqp.pd != mr->pd)) {
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;
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;
255
}
256
}
257
sge->mr = mr;
258
sge->vaddr = mr->map[m]->segs[n].vaddr + off;
259
sge->length = mr->map[m]->segs[n].length - off;
260
sge->sge_length = len;
261
sge->m = m;
262
sge->n = n;
263
ss->sg_list = NULL;
264
ss->num_sge = 1;
265
266
ret = 1;
267
268
bail:
269
return ret;
270
}
271
272