diff options
author | Bryan O'Sullivan <bos@pathscale.com> | 2006-03-29 18:23:36 -0500 |
---|---|---|
committer | Roland Dreier <rolandd@cisco.com> | 2006-03-31 16:14:20 -0500 |
commit | cef1cce5c87d84f76e44f0e7b4de72ab3818ac3a (patch) | |
tree | c9cb13413cae9dd636a699e3ec7d41882fd8e514 /drivers/infiniband/hw/ipath/ipath_keys.c | |
parent | 97f9efbc47f0b1bc88abac8724b505f0794a48d0 (diff) |
IB/ipath: misc infiniband code, part 1
Completion queues, local and remote memory keys, and memory region
support.
Signed-off-by: Bryan O'Sullivan <bos@pathscale.com>
Signed-off-by: Roland Dreier <rolandd@cisco.com>
Diffstat (limited to 'drivers/infiniband/hw/ipath/ipath_keys.c')
-rw-r--r-- | drivers/infiniband/hw/ipath/ipath_keys.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/ipath/ipath_keys.c b/drivers/infiniband/hw/ipath/ipath_keys.c new file mode 100644 index 000000000000..aa33b0e9f2f6 --- /dev/null +++ b/drivers/infiniband/hw/ipath/ipath_keys.c | |||
@@ -0,0 +1,236 @@ | |||
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 | |||
33 | #include <asm/io.h> | ||
34 | |||
35 | #include "ipath_verbs.h" | ||
36 | |||
37 | /** | ||
38 | * ipath_alloc_lkey - allocate an lkey | ||
39 | * @rkt: lkey table in which to allocate the lkey | ||
40 | * @mr: memory region that this lkey protects | ||
41 | * | ||
42 | * Returns 1 if successful, otherwise returns 0. | ||
43 | */ | ||
44 | |||
45 | int ipath_alloc_lkey(struct ipath_lkey_table *rkt, struct ipath_mregion *mr) | ||
46 | { | ||
47 | unsigned long flags; | ||
48 | u32 r; | ||
49 | u32 n; | ||
50 | int ret; | ||
51 | |||
52 | spin_lock_irqsave(&rkt->lock, flags); | ||
53 | |||
54 | /* Find the next available LKEY */ | ||
55 | r = n = rkt->next; | ||
56 | for (;;) { | ||
57 | if (rkt->table[r] == NULL) | ||
58 | break; | ||
59 | r = (r + 1) & (rkt->max - 1); | ||
60 | if (r == n) { | ||
61 | spin_unlock_irqrestore(&rkt->lock, flags); | ||
62 | _VERBS_INFO("LKEY table full\n"); | ||
63 | ret = 0; | ||
64 | goto bail; | ||
65 | } | ||
66 | } | ||
67 | rkt->next = (r + 1) & (rkt->max - 1); | ||
68 | /* | ||
69 | * Make sure lkey is never zero which is reserved to indicate an | ||
70 | * unrestricted LKEY. | ||
71 | */ | ||
72 | rkt->gen++; | ||
73 | mr->lkey = (r << (32 - ib_ipath_lkey_table_size)) | | ||
74 | ((((1 << (24 - ib_ipath_lkey_table_size)) - 1) & rkt->gen) | ||
75 | << 8); | ||
76 | if (mr->lkey == 0) { | ||
77 | mr->lkey |= 1 << 8; | ||
78 | rkt->gen++; | ||
79 | } | ||
80 | rkt->table[r] = mr; | ||
81 | spin_unlock_irqrestore(&rkt->lock, flags); | ||
82 | |||
83 | ret = 1; | ||
84 | |||
85 | bail: | ||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | /** | ||
90 | * ipath_free_lkey - free an lkey | ||
91 | * @rkt: table from which to free the lkey | ||
92 | * @lkey: lkey id to free | ||
93 | */ | ||
94 | void ipath_free_lkey(struct ipath_lkey_table *rkt, u32 lkey) | ||
95 | { | ||
96 | unsigned long flags; | ||
97 | u32 r; | ||
98 | |||
99 | if (lkey == 0) | ||
100 | return; | ||
101 | r = lkey >> (32 - ib_ipath_lkey_table_size); | ||
102 | spin_lock_irqsave(&rkt->lock, flags); | ||
103 | rkt->table[r] = NULL; | ||
104 | spin_unlock_irqrestore(&rkt->lock, flags); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * ipath_lkey_ok - check IB SGE for validity and initialize | ||
109 | * @rkt: table containing lkey to check SGE against | ||
110 | * @isge: outgoing internal SGE | ||
111 | * @sge: SGE to check | ||
112 | * @acc: access flags | ||
113 | * | ||
114 | * Return 1 if valid and successful, otherwise returns 0. | ||
115 | * | ||
116 | * Check the IB SGE for validity and initialize our internal version | ||
117 | * of it. | ||
118 | */ | ||
119 | int ipath_lkey_ok(struct ipath_lkey_table *rkt, struct ipath_sge *isge, | ||
120 | struct ib_sge *sge, int acc) | ||
121 | { | ||
122 | struct ipath_mregion *mr; | ||
123 | size_t off; | ||
124 | int ret; | ||
125 | |||
126 | /* | ||
127 | * We use LKEY == zero to mean a physical kmalloc() address. | ||
128 | * This is a bit of a hack since we rely on dma_map_single() | ||
129 | * being reversible by calling bus_to_virt(). | ||
130 | */ | ||
131 | if (sge->lkey == 0) { | ||
132 | isge->mr = NULL; | ||
133 | isge->vaddr = bus_to_virt(sge->addr); | ||
134 | isge->length = sge->length; | ||
135 | isge->sge_length = sge->length; | ||
136 | ret = 1; | ||
137 | goto bail; | ||
138 | } | ||
139 | spin_lock(&rkt->lock); | ||
140 | mr = rkt->table[(sge->lkey >> (32 - ib_ipath_lkey_table_size))]; | ||
141 | spin_unlock(&rkt->lock); | ||
142 | if (unlikely(mr == NULL || mr->lkey != sge->lkey)) { | ||
143 | ret = 0; | ||
144 | goto bail; | ||
145 | } | ||
146 | |||
147 | off = sge->addr - mr->user_base; | ||
148 | if (unlikely(sge->addr < mr->user_base || | ||
149 | off + sge->length > mr->length || | ||
150 | (mr->access_flags & acc) != acc)) { | ||
151 | ret = 0; | ||
152 | goto bail; | ||
153 | } | ||
154 | |||
155 | off += mr->offset; | ||
156 | isge->mr = mr; | ||
157 | isge->m = 0; | ||
158 | isge->n = 0; | ||
159 | while (off >= mr->map[isge->m]->segs[isge->n].length) { | ||
160 | off -= mr->map[isge->m]->segs[isge->n].length; | ||
161 | isge->n++; | ||
162 | if (isge->n >= IPATH_SEGSZ) { | ||
163 | isge->m++; | ||
164 | isge->n = 0; | ||
165 | } | ||
166 | } | ||
167 | isge->vaddr = mr->map[isge->m]->segs[isge->n].vaddr + off; | ||
168 | isge->length = mr->map[isge->m]->segs[isge->n].length - off; | ||
169 | isge->sge_length = sge->length; | ||
170 | |||
171 | ret = 1; | ||
172 | |||
173 | bail: | ||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * ipath_rkey_ok - check the IB virtual address, length, and RKEY | ||
179 | * @dev: infiniband device | ||
180 | * @ss: SGE state | ||
181 | * @len: length of data | ||
182 | * @vaddr: virtual address to place data | ||
183 | * @rkey: rkey to check | ||
184 | * @acc: access flags | ||
185 | * | ||
186 | * Return 1 if successful, otherwise 0. | ||
187 | * | ||
188 | * The QP r_rq.lock should be held. | ||
189 | */ | ||
190 | int ipath_rkey_ok(struct ipath_ibdev *dev, struct ipath_sge_state *ss, | ||
191 | u32 len, u64 vaddr, u32 rkey, int acc) | ||
192 | { | ||
193 | struct ipath_lkey_table *rkt = &dev->lk_table; | ||
194 | struct ipath_sge *sge = &ss->sge; | ||
195 | struct ipath_mregion *mr; | ||
196 | size_t off; | ||
197 | int ret; | ||
198 | |||
199 | spin_lock(&rkt->lock); | ||
200 | mr = rkt->table[(rkey >> (32 - ib_ipath_lkey_table_size))]; | ||
201 | spin_unlock(&rkt->lock); | ||
202 | if (unlikely(mr == NULL || mr->lkey != rkey)) { | ||
203 | ret = 0; | ||
204 | goto bail; | ||
205 | } | ||
206 | |||
207 | off = vaddr - mr->iova; | ||
208 | if (unlikely(vaddr < mr->iova || off + len > mr->length || | ||
209 | (mr->access_flags & acc) == 0)) { | ||
210 | ret = 0; | ||
211 | goto bail; | ||
212 | } | ||
213 | |||
214 | off += mr->offset; | ||
215 | sge->mr = mr; | ||
216 | sge->m = 0; | ||
217 | sge->n = 0; | ||
218 | while (off >= mr->map[sge->m]->segs[sge->n].length) { | ||
219 | off -= mr->map[sge->m]->segs[sge->n].length; | ||
220 | sge->n++; | ||
221 | if (sge->n >= IPATH_SEGSZ) { | ||
222 | sge->m++; | ||
223 | sge->n = 0; | ||
224 | } | ||
225 | } | ||
226 | sge->vaddr = mr->map[sge->m]->segs[sge->n].vaddr + off; | ||
227 | sge->length = mr->map[sge->m]->segs[sge->n].length - off; | ||
228 | sge->sge_length = len; | ||
229 | ss->sg_list = NULL; | ||
230 | ss->num_sge = 1; | ||
231 | |||
232 | ret = 1; | ||
233 | |||
234 | bail: | ||
235 | return ret; | ||
236 | } | ||