diff options
Diffstat (limited to 'drivers/infiniband/hw/cxgb3/cxio_resource.c')
-rw-r--r-- | drivers/infiniband/hw/cxgb3/cxio_resource.c | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/drivers/infiniband/hw/cxgb3/cxio_resource.c b/drivers/infiniband/hw/cxgb3/cxio_resource.c new file mode 100644 index 000000000000..997aa32cbf07 --- /dev/null +++ b/drivers/infiniband/hw/cxgb3/cxio_resource.c | |||
@@ -0,0 +1,331 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Chelsio, Inc. All rights reserved. | ||
3 | * Copyright (c) 2006 Open Grid Computing, 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 | /* Crude resource management */ | ||
34 | #include <linux/kernel.h> | ||
35 | #include <linux/random.h> | ||
36 | #include <linux/slab.h> | ||
37 | #include <linux/kfifo.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/errno.h> | ||
40 | #include "cxio_resource.h" | ||
41 | #include "cxio_hal.h" | ||
42 | |||
43 | static struct kfifo *rhdl_fifo; | ||
44 | static spinlock_t rhdl_fifo_lock; | ||
45 | |||
46 | #define RANDOM_SIZE 16 | ||
47 | |||
48 | static int __cxio_init_resource_fifo(struct kfifo **fifo, | ||
49 | spinlock_t *fifo_lock, | ||
50 | u32 nr, u32 skip_low, | ||
51 | u32 skip_high, | ||
52 | int random) | ||
53 | { | ||
54 | u32 i, j, entry = 0, idx; | ||
55 | u32 random_bytes; | ||
56 | u32 rarray[16]; | ||
57 | spin_lock_init(fifo_lock); | ||
58 | |||
59 | *fifo = kfifo_alloc(nr * sizeof(u32), GFP_KERNEL, fifo_lock); | ||
60 | if (IS_ERR(*fifo)) | ||
61 | return -ENOMEM; | ||
62 | |||
63 | for (i = 0; i < skip_low + skip_high; i++) | ||
64 | __kfifo_put(*fifo, (unsigned char *) &entry, sizeof(u32)); | ||
65 | if (random) { | ||
66 | j = 0; | ||
67 | random_bytes = random32(); | ||
68 | for (i = 0; i < RANDOM_SIZE; i++) | ||
69 | rarray[i] = i + skip_low; | ||
70 | for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) { | ||
71 | if (j >= RANDOM_SIZE) { | ||
72 | j = 0; | ||
73 | random_bytes = random32(); | ||
74 | } | ||
75 | idx = (random_bytes >> (j * 2)) & 0xF; | ||
76 | __kfifo_put(*fifo, | ||
77 | (unsigned char *) &rarray[idx], | ||
78 | sizeof(u32)); | ||
79 | rarray[idx] = i; | ||
80 | j++; | ||
81 | } | ||
82 | for (i = 0; i < RANDOM_SIZE; i++) | ||
83 | __kfifo_put(*fifo, | ||
84 | (unsigned char *) &rarray[i], | ||
85 | sizeof(u32)); | ||
86 | } else | ||
87 | for (i = skip_low; i < nr - skip_high; i++) | ||
88 | __kfifo_put(*fifo, (unsigned char *) &i, sizeof(u32)); | ||
89 | |||
90 | for (i = 0; i < skip_low + skip_high; i++) | ||
91 | kfifo_get(*fifo, (unsigned char *) &entry, sizeof(u32)); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static int cxio_init_resource_fifo(struct kfifo **fifo, spinlock_t * fifo_lock, | ||
96 | u32 nr, u32 skip_low, u32 skip_high) | ||
97 | { | ||
98 | return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low, | ||
99 | skip_high, 0)); | ||
100 | } | ||
101 | |||
102 | static int cxio_init_resource_fifo_random(struct kfifo **fifo, | ||
103 | spinlock_t * fifo_lock, | ||
104 | u32 nr, u32 skip_low, u32 skip_high) | ||
105 | { | ||
106 | |||
107 | return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low, | ||
108 | skip_high, 1)); | ||
109 | } | ||
110 | |||
111 | static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p) | ||
112 | { | ||
113 | u32 i; | ||
114 | |||
115 | spin_lock_init(&rdev_p->rscp->qpid_fifo_lock); | ||
116 | |||
117 | rdev_p->rscp->qpid_fifo = kfifo_alloc(T3_MAX_NUM_QP * sizeof(u32), | ||
118 | GFP_KERNEL, | ||
119 | &rdev_p->rscp->qpid_fifo_lock); | ||
120 | if (IS_ERR(rdev_p->rscp->qpid_fifo)) | ||
121 | return -ENOMEM; | ||
122 | |||
123 | for (i = 16; i < T3_MAX_NUM_QP; i++) | ||
124 | if (!(i & rdev_p->qpmask)) | ||
125 | __kfifo_put(rdev_p->rscp->qpid_fifo, | ||
126 | (unsigned char *) &i, sizeof(u32)); | ||
127 | return 0; | ||
128 | } | ||
129 | |||
130 | int cxio_hal_init_rhdl_resource(u32 nr_rhdl) | ||
131 | { | ||
132 | return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1, | ||
133 | 0); | ||
134 | } | ||
135 | |||
136 | void cxio_hal_destroy_rhdl_resource(void) | ||
137 | { | ||
138 | kfifo_free(rhdl_fifo); | ||
139 | } | ||
140 | |||
141 | /* nr_* must be power of 2 */ | ||
142 | int cxio_hal_init_resource(struct cxio_rdev *rdev_p, | ||
143 | u32 nr_tpt, u32 nr_pbl, | ||
144 | u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid) | ||
145 | { | ||
146 | int err = 0; | ||
147 | struct cxio_hal_resource *rscp; | ||
148 | |||
149 | rscp = kmalloc(sizeof(*rscp), GFP_KERNEL); | ||
150 | if (!rscp) | ||
151 | return -ENOMEM; | ||
152 | rdev_p->rscp = rscp; | ||
153 | err = cxio_init_resource_fifo_random(&rscp->tpt_fifo, | ||
154 | &rscp->tpt_fifo_lock, | ||
155 | nr_tpt, 1, 0); | ||
156 | if (err) | ||
157 | goto tpt_err; | ||
158 | err = cxio_init_qpid_fifo(rdev_p); | ||
159 | if (err) | ||
160 | goto qpid_err; | ||
161 | err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, | ||
162 | nr_cqid, 1, 0); | ||
163 | if (err) | ||
164 | goto cqid_err; | ||
165 | err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, | ||
166 | nr_pdid, 1, 0); | ||
167 | if (err) | ||
168 | goto pdid_err; | ||
169 | return 0; | ||
170 | pdid_err: | ||
171 | kfifo_free(rscp->cqid_fifo); | ||
172 | cqid_err: | ||
173 | kfifo_free(rscp->qpid_fifo); | ||
174 | qpid_err: | ||
175 | kfifo_free(rscp->tpt_fifo); | ||
176 | tpt_err: | ||
177 | return -ENOMEM; | ||
178 | } | ||
179 | |||
180 | /* | ||
181 | * returns 0 if no resource available | ||
182 | */ | ||
183 | static inline u32 cxio_hal_get_resource(struct kfifo *fifo) | ||
184 | { | ||
185 | u32 entry; | ||
186 | if (kfifo_get(fifo, (unsigned char *) &entry, sizeof(u32))) | ||
187 | return entry; | ||
188 | else | ||
189 | return 0; /* fifo emptry */ | ||
190 | } | ||
191 | |||
192 | static inline void cxio_hal_put_resource(struct kfifo *fifo, u32 entry) | ||
193 | { | ||
194 | BUG_ON(kfifo_put(fifo, (unsigned char *) &entry, sizeof(u32)) == 0); | ||
195 | } | ||
196 | |||
197 | u32 cxio_hal_get_rhdl(void) | ||
198 | { | ||
199 | return cxio_hal_get_resource(rhdl_fifo); | ||
200 | } | ||
201 | |||
202 | void cxio_hal_put_rhdl(u32 rhdl) | ||
203 | { | ||
204 | cxio_hal_put_resource(rhdl_fifo, rhdl); | ||
205 | } | ||
206 | |||
207 | u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp) | ||
208 | { | ||
209 | return cxio_hal_get_resource(rscp->tpt_fifo); | ||
210 | } | ||
211 | |||
212 | void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag) | ||
213 | { | ||
214 | cxio_hal_put_resource(rscp->tpt_fifo, stag); | ||
215 | } | ||
216 | |||
217 | u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp) | ||
218 | { | ||
219 | u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo); | ||
220 | PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); | ||
221 | return qpid; | ||
222 | } | ||
223 | |||
224 | void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid) | ||
225 | { | ||
226 | PDBG("%s qpid 0x%x\n", __FUNCTION__, qpid); | ||
227 | cxio_hal_put_resource(rscp->qpid_fifo, qpid); | ||
228 | } | ||
229 | |||
230 | u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp) | ||
231 | { | ||
232 | return cxio_hal_get_resource(rscp->cqid_fifo); | ||
233 | } | ||
234 | |||
235 | void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid) | ||
236 | { | ||
237 | cxio_hal_put_resource(rscp->cqid_fifo, cqid); | ||
238 | } | ||
239 | |||
240 | u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp) | ||
241 | { | ||
242 | return cxio_hal_get_resource(rscp->pdid_fifo); | ||
243 | } | ||
244 | |||
245 | void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid) | ||
246 | { | ||
247 | cxio_hal_put_resource(rscp->pdid_fifo, pdid); | ||
248 | } | ||
249 | |||
250 | void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp) | ||
251 | { | ||
252 | kfifo_free(rscp->tpt_fifo); | ||
253 | kfifo_free(rscp->cqid_fifo); | ||
254 | kfifo_free(rscp->qpid_fifo); | ||
255 | kfifo_free(rscp->pdid_fifo); | ||
256 | kfree(rscp); | ||
257 | } | ||
258 | |||
259 | /* | ||
260 | * PBL Memory Manager. Uses Linux generic allocator. | ||
261 | */ | ||
262 | |||
263 | #define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */ | ||
264 | #define PBL_CHUNK 2*1024*1024 | ||
265 | |||
266 | u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size) | ||
267 | { | ||
268 | unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size); | ||
269 | PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size); | ||
270 | return (u32)addr; | ||
271 | } | ||
272 | |||
273 | void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size) | ||
274 | { | ||
275 | PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size); | ||
276 | gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size); | ||
277 | } | ||
278 | |||
279 | int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p) | ||
280 | { | ||
281 | unsigned long i; | ||
282 | rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1); | ||
283 | if (rdev_p->pbl_pool) | ||
284 | for (i = rdev_p->rnic_info.pbl_base; | ||
285 | i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1; | ||
286 | i += PBL_CHUNK) | ||
287 | gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1); | ||
288 | return rdev_p->pbl_pool ? 0 : -ENOMEM; | ||
289 | } | ||
290 | |||
291 | void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p) | ||
292 | { | ||
293 | gen_pool_destroy(rdev_p->pbl_pool); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * RQT Memory Manager. Uses Linux generic allocator. | ||
298 | */ | ||
299 | |||
300 | #define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */ | ||
301 | #define RQT_CHUNK 2*1024*1024 | ||
302 | |||
303 | u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size) | ||
304 | { | ||
305 | unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6); | ||
306 | PDBG("%s addr 0x%x size %d\n", __FUNCTION__, (u32)addr, size << 6); | ||
307 | return (u32)addr; | ||
308 | } | ||
309 | |||
310 | void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size) | ||
311 | { | ||
312 | PDBG("%s addr 0x%x size %d\n", __FUNCTION__, addr, size << 6); | ||
313 | gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6); | ||
314 | } | ||
315 | |||
316 | int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p) | ||
317 | { | ||
318 | unsigned long i; | ||
319 | rdev_p->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1); | ||
320 | if (rdev_p->rqt_pool) | ||
321 | for (i = rdev_p->rnic_info.rqt_base; | ||
322 | i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1; | ||
323 | i += RQT_CHUNK) | ||
324 | gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1); | ||
325 | return rdev_p->rqt_pool ? 0 : -ENOMEM; | ||
326 | } | ||
327 | |||
328 | void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p) | ||
329 | { | ||
330 | gen_pool_destroy(rdev_p->rqt_pool); | ||
331 | } | ||