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