1 /**************************************************************************
2
3 Copyright (c) 2007, Chelsio Inc.
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8
9 1. Redistributions of source code must retain the above copyright notice,
10 this list of conditions and the following disclaimer.
11
12 2. Neither the name of the Chelsio Corporation nor the names of its
13 contributors may be used to endorse or promote products derived from
14 this software without specific prior written permission.
15
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 POSSIBILITY OF SUCH DAMAGE.
27
28 ***************************************************************************/
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD: stable/9/sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_resource.c 237920 2012-07-01 12:00:36Z np $");
31
32 #include "opt_inet.h"
33
34 #ifdef TCP_OFFLOAD
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/bus.h>
39 #include <sys/pciio.h>
40 #include <sys/conf.h>
41 #include <machine/bus.h>
42 #include <machine/resource.h>
43 #include <sys/bus_dma.h>
44 #include <sys/rman.h>
45 #include <sys/ioccom.h>
46 #include <sys/mbuf.h>
47 #include <sys/mutex.h>
48 #include <sys/rwlock.h>
49 #include <sys/linker.h>
50 #include <sys/firmware.h>
51 #include <sys/socket.h>
52 #include <sys/sockio.h>
53 #include <sys/smp.h>
54 #include <sys/sysctl.h>
55 #include <sys/syslog.h>
56 #include <sys/queue.h>
57 #include <sys/taskqueue.h>
58 #include <sys/proc.h>
59 #include <sys/queue.h>
60 #include <sys/libkern.h>
61
62 #include <netinet/in.h>
63
64 #include <rdma/ib_verbs.h>
65 #include <rdma/ib_umem.h>
66 #include <rdma/ib_user_verbs.h>
67 #include <linux/idr.h>
68 #include <ulp/iw_cxgb/iw_cxgb_ib_intfc.h>
69
70 #include <cxgb_include.h>
71 #include <ulp/iw_cxgb/iw_cxgb_wr.h>
72 #include <ulp/iw_cxgb/iw_cxgb_hal.h>
73 #include <ulp/iw_cxgb/iw_cxgb_provider.h>
74 #include <ulp/iw_cxgb/iw_cxgb_cm.h>
75 #include <ulp/iw_cxgb/iw_cxgb.h>
76 #include <ulp/iw_cxgb/iw_cxgb_resource.h>
77 #include <ulp/iw_cxgb/iw_cxgb_user.h>
78
79 #ifdef needed
80 static struct buf_ring *rhdl_fifo;
81 static struct mtx rhdl_fifo_lock;
82 #endif
83
84 #define RANDOM_SIZE 16
85
__cxio_init_resource_fifo(struct buf_ring ** fifo,struct mtx * fifo_lock,u32 nr,u32 skip_low,u32 skip_high,int randomize)86 static int __cxio_init_resource_fifo(struct buf_ring **fifo,
87 struct mtx *fifo_lock,
88 u32 nr, u32 skip_low,
89 u32 skip_high,
90 int randomize)
91 {
92 u32 i, j, idx;
93 u32 random_bytes;
94 u32 rarray[16];
95 mtx_init(fifo_lock, "cxio fifo", NULL, MTX_DEF|MTX_DUPOK);
96
97 *fifo = buf_ring_alloc(nr, M_DEVBUF, M_NOWAIT, fifo_lock);
98 if (*fifo == NULL)
99 return (-ENOMEM);
100 #if 0
101 for (i = 0; i < skip_low + skip_high; i++) {
102 u32 entry = 0;
103
104 buf_ring_enqueue(*fifo, (uintptr_t) entry);
105 }
106 #endif
107 if (randomize) {
108 j = 0;
109 random_bytes = random();
110 for (i = 0; i < RANDOM_SIZE; i++)
111 rarray[i] = i + skip_low;
112 for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
113 if (j >= RANDOM_SIZE) {
114 j = 0;
115 random_bytes = random();
116 }
117 idx = (random_bytes >> (j * 2)) & 0xF;
118 buf_ring_enqueue(*fifo, (void *)(uintptr_t)rarray[idx]);
119 rarray[idx] = i;
120 j++;
121 }
122 for (i = 0; i < RANDOM_SIZE; i++)
123 buf_ring_enqueue(*fifo, (void *) (uintptr_t)rarray[i]);
124 } else
125 for (i = skip_low; i < nr - skip_high; i++)
126 buf_ring_enqueue(*fifo, (void *) (uintptr_t)i);
127 #if 0
128 for (i = 0; i < skip_low + skip_high; i++)
129 buf_ring_dequeue_sc(*fifo);
130 #endif
131 return 0;
132 }
133
cxio_init_resource_fifo(struct buf_ring ** fifo,struct mtx * fifo_lock,u32 nr,u32 skip_low,u32 skip_high)134 static int cxio_init_resource_fifo(struct buf_ring **fifo, struct mtx * fifo_lock,
135 u32 nr, u32 skip_low, u32 skip_high)
136 {
137 return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
138 skip_high, 0));
139 }
140
cxio_init_resource_fifo_random(struct buf_ring ** fifo,struct mtx * fifo_lock,u32 nr,u32 skip_low,u32 skip_high)141 static int cxio_init_resource_fifo_random(struct buf_ring **fifo,
142 struct mtx * fifo_lock,
143 u32 nr, u32 skip_low, u32 skip_high)
144 {
145
146 return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
147 skip_high, 1));
148 }
149
cxio_init_qpid_fifo(struct cxio_rdev * rdev_p)150 static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
151 {
152 u32 i;
153
154 mtx_init(&rdev_p->rscp->qpid_fifo_lock, "qpid fifo", NULL, MTX_DEF);
155
156 rdev_p->rscp->qpid_fifo = buf_ring_alloc(T3_MAX_NUM_QP, M_DEVBUF,
157 M_NOWAIT, &rdev_p->rscp->qpid_fifo_lock);
158 if (rdev_p->rscp->qpid_fifo == NULL)
159 return (-ENOMEM);
160
161 for (i = 16; i < T3_MAX_NUM_QP; i++)
162 if (!(i & rdev_p->qpmask))
163 buf_ring_enqueue(rdev_p->rscp->qpid_fifo, (void *) (uintptr_t)i);
164 return 0;
165 }
166
167 #ifdef needed
cxio_hal_init_rhdl_resource(u32 nr_rhdl)168 int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
169 {
170 return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
171 0);
172 }
173
cxio_hal_destroy_rhdl_resource(void)174 void cxio_hal_destroy_rhdl_resource(void)
175 {
176 buf_ring_free(rhdl_fifo, M_DEVBUF);
177 }
178 #endif
179
180 /* nr_* must be power of 2 */
cxio_hal_init_resource(struct cxio_rdev * rdev_p,u32 nr_tpt,u32 nr_pbl,u32 nr_rqt,u32 nr_qpid,u32 nr_cqid,u32 nr_pdid)181 int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
182 u32 nr_tpt, u32 nr_pbl,
183 u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
184 {
185 int err = 0;
186 struct cxio_hal_resource *rscp;
187
188 rscp = malloc(sizeof(*rscp), M_DEVBUF, M_NOWAIT|M_ZERO);
189 if (!rscp)
190 return (-ENOMEM);
191 rdev_p->rscp = rscp;
192 err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
193 &rscp->tpt_fifo_lock,
194 nr_tpt, 1, 0);
195 if (err)
196 goto tpt_err;
197 err = cxio_init_qpid_fifo(rdev_p);
198 if (err)
199 goto qpid_err;
200 err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
201 nr_cqid, 1, 0);
202 if (err)
203 goto cqid_err;
204 err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
205 nr_pdid, 1, 0);
206 if (err)
207 goto pdid_err;
208 return 0;
209 pdid_err:
210 buf_ring_free(rscp->cqid_fifo, M_DEVBUF);
211 cqid_err:
212 buf_ring_free(rscp->qpid_fifo, M_DEVBUF);
213 qpid_err:
214 buf_ring_free(rscp->tpt_fifo, M_DEVBUF);
215 tpt_err:
216 return (-ENOMEM);
217 }
218
219 /*
220 * returns 0 if no resource available
221 */
cxio_hal_get_resource(struct buf_ring * fifo,struct mtx * lock)222 static u32 cxio_hal_get_resource(struct buf_ring *fifo, struct mtx *lock)
223 {
224 u32 entry;
225
226 mtx_lock(lock);
227 entry = (u32)(uintptr_t)buf_ring_dequeue_sc(fifo);
228 mtx_unlock(lock);
229 return entry;
230 }
231
cxio_hal_put_resource(struct buf_ring * fifo,u32 entry,struct mtx * lock)232 static void cxio_hal_put_resource(struct buf_ring *fifo, u32 entry, struct mtx *lock)
233 {
234 mtx_lock(lock);
235 buf_ring_enqueue(fifo, (void *) (uintptr_t)entry);
236 mtx_unlock(lock);
237 }
238
cxio_hal_get_stag(struct cxio_hal_resource * rscp)239 u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
240 {
241 return cxio_hal_get_resource(rscp->tpt_fifo, &rscp->tpt_fifo_lock);
242 }
243
cxio_hal_put_stag(struct cxio_hal_resource * rscp,u32 stag)244 void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
245 {
246 cxio_hal_put_resource(rscp->tpt_fifo, stag, &rscp->tpt_fifo_lock);
247 }
248
cxio_hal_get_qpid(struct cxio_hal_resource * rscp)249 u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
250 {
251 u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo, &rscp->qpid_fifo_lock);
252 CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
253 return qpid;
254 }
255
cxio_hal_put_qpid(struct cxio_hal_resource * rscp,u32 qpid)256 void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
257 {
258 CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
259 cxio_hal_put_resource(rscp->qpid_fifo, qpid, &rscp->qpid_fifo_lock);
260 }
261
cxio_hal_get_cqid(struct cxio_hal_resource * rscp)262 u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
263 {
264 return cxio_hal_get_resource(rscp->cqid_fifo, &rscp->cqid_fifo_lock);
265 }
266
cxio_hal_put_cqid(struct cxio_hal_resource * rscp,u32 cqid)267 void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
268 {
269 cxio_hal_put_resource(rscp->cqid_fifo, cqid, &rscp->cqid_fifo_lock);
270 }
271
cxio_hal_get_pdid(struct cxio_hal_resource * rscp)272 u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
273 {
274 return cxio_hal_get_resource(rscp->pdid_fifo, &rscp->pdid_fifo_lock);
275 }
276
cxio_hal_put_pdid(struct cxio_hal_resource * rscp,u32 pdid)277 void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
278 {
279 cxio_hal_put_resource(rscp->pdid_fifo, pdid, &rscp->pdid_fifo_lock);
280 }
281
cxio_hal_destroy_resource(struct cxio_hal_resource * rscp)282 void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
283 {
284 buf_ring_free(rscp->tpt_fifo, M_DEVBUF);
285 buf_ring_free(rscp->cqid_fifo, M_DEVBUF);
286 buf_ring_free(rscp->qpid_fifo, M_DEVBUF);
287 buf_ring_free(rscp->pdid_fifo, M_DEVBUF);
288 free(rscp, M_DEVBUF);
289 }
290
291 /*
292 * PBL Memory Manager. Uses Linux generic allocator.
293 */
294
295 #define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
296 #define PBL_CHUNK 2*1024*1024
297
cxio_hal_pblpool_alloc(struct cxio_rdev * rdev_p,int size)298 u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
299 {
300 unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
301 CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size);
302 return (u32)addr;
303 }
304
cxio_hal_pblpool_free(struct cxio_rdev * rdev_p,u32 addr,int size)305 void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
306 {
307 CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size);
308 gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
309 }
310
cxio_hal_pblpool_create(struct cxio_rdev * rdev_p)311 int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
312 {
313
314 rdev_p->pbl_pool = gen_pool_create(rdev_p->rnic_info.pbl_base, MIN_PBL_SHIFT,
315 rdev_p->rnic_info.pbl_top - rdev_p->rnic_info.pbl_base);
316 #if 0
317 if (rdev_p->pbl_pool) {
318
319 unsigned long i;
320 for (i = rdev_p->rnic_info.pbl_base;
321 i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
322 i += PBL_CHUNK)
323 gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
324 }
325 #endif
326 return rdev_p->pbl_pool ? 0 : (-ENOMEM);
327 }
328
cxio_hal_pblpool_destroy(struct cxio_rdev * rdev_p)329 void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
330 {
331 gen_pool_destroy(rdev_p->pbl_pool);
332 }
333
334 /*
335 * RQT Memory Manager. Uses Linux generic allocator.
336 */
337
338 #define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */
339 #define RQT_CHUNK 2*1024*1024
340
cxio_hal_rqtpool_alloc(struct cxio_rdev * rdev_p,int size)341 u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size)
342 {
343 unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
344 CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size << 6);
345 return (u32)addr;
346 }
347
cxio_hal_rqtpool_free(struct cxio_rdev * rdev_p,u32 addr,int size)348 void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
349 {
350 CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size << 6);
351 gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
352 }
353
cxio_hal_rqtpool_create(struct cxio_rdev * rdev_p)354 int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p)
355 {
356
357 rdev_p->rqt_pool = gen_pool_create(rdev_p->rnic_info.rqt_base,
358 MIN_RQT_SHIFT, rdev_p->rnic_info.rqt_top - rdev_p->rnic_info.rqt_base);
359 #if 0
360 if (rdev_p->rqt_pool) {
361 unsigned long i;
362
363 for (i = rdev_p->rnic_info.rqt_base;
364 i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
365 i += RQT_CHUNK)
366 gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
367 }
368 #endif
369 return rdev_p->rqt_pool ? 0 : (-ENOMEM);
370 }
371
cxio_hal_rqtpool_destroy(struct cxio_rdev * rdev_p)372 void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
373 {
374 gen_pool_destroy(rdev_p->rqt_pool);
375 }
376 #endif
377