iw_cxgb_resource.c revision 237263
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 237263 2012-06-19 07:34:13Z 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
80static struct buf_ring *rhdl_fifo;
81static struct mtx rhdl_fifo_lock;
82#endif
83
84#define RANDOM_SIZE 16
85
86static 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
134static 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
141static 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
150static 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
168int 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
174void 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 */
181int 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;
209pdid_err:
210	buf_ring_free(rscp->cqid_fifo, M_DEVBUF);
211cqid_err:
212	buf_ring_free(rscp->qpid_fifo, M_DEVBUF);
213qpid_err:
214	buf_ring_free(rscp->tpt_fifo, M_DEVBUF);
215tpt_err:
216	return (-ENOMEM);
217}
218
219/*
220 * returns 0 if no resource available
221 */
222static 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
232static 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
239u32 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
244void 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
249u32 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
256void 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
262u32 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
267void 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
272u32 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
277void 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
282void 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
298u32 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
305void 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
311int 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
329void 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
341u32 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
348void 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
354int 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
372void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
373{
374	gen_pool_destroy(rdev_p->rqt_pool);
375}
376#endif
377