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