iw_cxgb_resource.c revision 183292
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 183292 2008-09-23 03:16:54Z 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_NOWAIT);
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(*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_NOWAIT);
153	if (rdev_p->rscp->qpid_fifo == NULL)
154		return (-ENOMEM);
155
156	for (i = 16; i < T3_MAX_NUM_QP; i++)
157		if (!(i & rdev_p->qpmask))
158			buf_ring_enqueue(rdev_p->rscp->qpid_fifo, (void *) (uintptr_t)i);
159	return 0;
160}
161
162#ifdef needed
163int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
164{
165	return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
166				       0);
167}
168
169void cxio_hal_destroy_rhdl_resource(void)
170{
171	buf_ring_free(rhdl_fifo);
172}
173#endif
174
175/* nr_* must be power of 2 */
176int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
177			   u32 nr_tpt, u32 nr_pbl,
178			   u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
179{
180	int err = 0;
181	struct cxio_hal_resource *rscp;
182
183	rscp = malloc(sizeof(*rscp), M_DEVBUF, M_NOWAIT|M_ZERO);
184	if (!rscp)
185		return (-ENOMEM);
186	rdev_p->rscp = rscp;
187	err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
188				      &rscp->tpt_fifo_lock,
189				      nr_tpt, 1, 0);
190	if (err)
191		goto tpt_err;
192	err = cxio_init_qpid_fifo(rdev_p);
193	if (err)
194		goto qpid_err;
195	err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
196				      nr_cqid, 1, 0);
197	if (err)
198		goto cqid_err;
199	err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
200				      nr_pdid, 1, 0);
201	if (err)
202		goto pdid_err;
203	return 0;
204pdid_err:
205	buf_ring_free(rscp->cqid_fifo);
206cqid_err:
207	buf_ring_free(rscp->qpid_fifo);
208qpid_err:
209	buf_ring_free(rscp->tpt_fifo);
210tpt_err:
211	return (-ENOMEM);
212}
213
214/*
215 * returns 0 if no resource available
216 */
217static u32 cxio_hal_get_resource(struct buf_ring *fifo, struct mtx *lock)
218{
219	u32 entry;
220
221	mtx_lock(lock);
222	entry = (u32)(uintptr_t)buf_ring_dequeue(fifo);
223	mtx_unlock(lock);
224	return entry;
225}
226
227static void cxio_hal_put_resource(struct buf_ring *fifo, u32 entry, struct mtx *lock)
228{
229	mtx_lock(lock);
230	buf_ring_enqueue(fifo, (void *) (uintptr_t)entry);
231	mtx_unlock(lock);
232}
233
234u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
235{
236	return cxio_hal_get_resource(rscp->tpt_fifo, &rscp->tpt_fifo_lock);
237}
238
239void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
240{
241	cxio_hal_put_resource(rscp->tpt_fifo, stag, &rscp->tpt_fifo_lock);
242}
243
244u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
245{
246	u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo, &rscp->qpid_fifo_lock);
247	CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
248	return qpid;
249}
250
251void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
252{
253	CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
254	cxio_hal_put_resource(rscp->qpid_fifo, qpid, &rscp->qpid_fifo_lock);
255}
256
257u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
258{
259	return cxio_hal_get_resource(rscp->cqid_fifo, &rscp->cqid_fifo_lock);
260}
261
262void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
263{
264	cxio_hal_put_resource(rscp->cqid_fifo, cqid, &rscp->cqid_fifo_lock);
265}
266
267u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
268{
269	return cxio_hal_get_resource(rscp->pdid_fifo, &rscp->pdid_fifo_lock);
270}
271
272void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
273{
274	cxio_hal_put_resource(rscp->pdid_fifo, pdid, &rscp->pdid_fifo_lock);
275}
276
277void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
278{
279	buf_ring_free(rscp->tpt_fifo);
280	buf_ring_free(rscp->cqid_fifo);
281	buf_ring_free(rscp->qpid_fifo);
282	buf_ring_free(rscp->pdid_fifo);
283	free(rscp, M_DEVBUF);
284}
285
286/*
287 * PBL Memory Manager.  Uses Linux generic allocator.
288 */
289
290#define MIN_PBL_SHIFT 8			/* 256B == min PBL size (32 entries) */
291#define PBL_CHUNK 2*1024*1024
292
293u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
294{
295	unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
296	CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size);
297	return (u32)addr;
298}
299
300void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
301{
302	CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size);
303	gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
304}
305
306int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
307{
308
309	rdev_p->pbl_pool = gen_pool_create(rdev_p->rnic_info.pbl_base, MIN_PBL_SHIFT,
310	    rdev_p->rnic_info.pbl_top - rdev_p->rnic_info.pbl_base);
311#if 0
312	if (rdev_p->pbl_pool) {
313
314		unsigned long i;
315		for (i = rdev_p->rnic_info.pbl_base;
316		     i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
317		     i += PBL_CHUNK)
318			gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
319	}
320#endif
321	return rdev_p->pbl_pool ? 0 : (-ENOMEM);
322}
323
324void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
325{
326	gen_pool_destroy(rdev_p->pbl_pool);
327}
328
329/*
330 * RQT Memory Manager.  Uses Linux generic allocator.
331 */
332
333#define MIN_RQT_SHIFT 10	/* 1KB == mini RQT size (16 entries) */
334#define RQT_CHUNK 2*1024*1024
335
336u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size)
337{
338	unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
339	CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size << 6);
340	return (u32)addr;
341}
342
343void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
344{
345	CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size << 6);
346	gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
347}
348
349int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p)
350{
351
352	rdev_p->rqt_pool = gen_pool_create(rdev_p->rnic_info.rqt_base,
353	    MIN_RQT_SHIFT, rdev_p->rnic_info.rqt_top - rdev_p->rnic_info.rqt_base);
354#if 0
355	if (rdev_p->rqt_pool) {
356		unsigned long i;
357
358		for (i = rdev_p->rnic_info.rqt_base;
359		     i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
360		     i += RQT_CHUNK)
361			gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
362	}
363#endif
364	return rdev_p->rqt_pool ? 0 : (-ENOMEM);
365}
366
367void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
368{
369	gen_pool_destroy(rdev_p->rqt_pool);
370}
371