]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_resource.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / cxgb / ulp / iw_cxgb / iw_cxgb_resource.c
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$");
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
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
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
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
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
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
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 */
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  */
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
372 void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
373 {
374         gen_pool_destroy(rdev_p->rqt_pool);
375 }
376 #endif