]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/cxgb/ulp/iw_cxgb/iw_cxgb_resource.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.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 <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
67 #ifdef CONFIG_DEFINED
68 #include <cxgb_include.h>
69 #include <ulp/iw_cxgb/iw_cxgb_wr.h>
70 #include <ulp/iw_cxgb/iw_cxgb_hal.h>
71 #include <ulp/iw_cxgb/iw_cxgb_provider.h>
72 #include <ulp/iw_cxgb/iw_cxgb_cm.h>
73 #include <ulp/iw_cxgb/iw_cxgb.h>
74 #include <ulp/iw_cxgb/iw_cxgb_resource.h>
75 #include <ulp/iw_cxgb/iw_cxgb_user.h>
76 #else
77 #include <dev/cxgb/cxgb_include.h>
78 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_wr.h>
79 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_hal.h>
80 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_provider.h>
81 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_cm.h>
82 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb.h>
83 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_resource.h>
84 #include <dev/cxgb/ulp/iw_cxgb/iw_cxgb_user.h>
85 #endif
86
87 #ifdef needed
88 static struct buf_ring *rhdl_fifo;
89 static struct mtx rhdl_fifo_lock;
90 #endif
91
92 #define RANDOM_SIZE 16
93
94 static int __cxio_init_resource_fifo(struct buf_ring **fifo,
95                                    struct mtx *fifo_lock,
96                                    u32 nr, u32 skip_low,
97                                    u32 skip_high,
98                                    int randomize)
99 {
100         u32 i, j, idx;
101         u32 random_bytes;
102         u32 rarray[16];
103         mtx_init(fifo_lock, "cxio fifo", NULL, MTX_DEF|MTX_DUPOK);
104
105         *fifo = buf_ring_alloc(nr, M_NOWAIT);
106         if (*fifo == NULL)
107                 return (-ENOMEM);
108 #if 0
109         for (i = 0; i < skip_low + skip_high; i++) {
110                 u32 entry = 0;
111                 
112                 buf_ring_enqueue(*fifo, (uintptr_t) entry);
113         }
114 #endif  
115         if (randomize) {
116                 j = 0;
117                 random_bytes = random();
118                 for (i = 0; i < RANDOM_SIZE; i++)
119                         rarray[i] = i + skip_low;
120                 for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
121                         if (j >= RANDOM_SIZE) {
122                                 j = 0;
123                                 random_bytes = random();
124                         }
125                         idx = (random_bytes >> (j * 2)) & 0xF;
126                         buf_ring_enqueue(*fifo, (void *)(uintptr_t)rarray[idx]);
127                         rarray[idx] = i;
128                         j++;
129                 }
130                 for (i = 0; i < RANDOM_SIZE; i++)
131                         buf_ring_enqueue(*fifo, (void *) (uintptr_t)rarray[i]);
132         } else
133                 for (i = skip_low; i < nr - skip_high; i++)
134                         buf_ring_enqueue(*fifo, (void *) (uintptr_t)i);
135 #if 0
136         for (i = 0; i < skip_low + skip_high; i++)
137                 buf_ring_dequeue(*fifo);
138 #endif  
139         return 0;
140 }
141
142 static int cxio_init_resource_fifo(struct buf_ring **fifo, struct mtx * fifo_lock,
143                                    u32 nr, u32 skip_low, u32 skip_high)
144 {
145         return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
146                                           skip_high, 0));
147 }
148
149 static int cxio_init_resource_fifo_random(struct buf_ring **fifo,
150                                   struct mtx * fifo_lock,
151                                    u32 nr, u32 skip_low, u32 skip_high)
152 {
153
154         return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
155                                           skip_high, 1));
156 }
157
158 static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
159 {
160         u32 i;
161
162         mtx_init(&rdev_p->rscp->qpid_fifo_lock, "qpid fifo", NULL, MTX_DEF);
163
164         rdev_p->rscp->qpid_fifo = buf_ring_alloc(T3_MAX_NUM_QP, M_NOWAIT);
165         if (rdev_p->rscp->qpid_fifo == NULL)
166                 return (-ENOMEM);
167
168         for (i = 16; i < T3_MAX_NUM_QP; i++)
169                 if (!(i & rdev_p->qpmask))
170                         buf_ring_enqueue(rdev_p->rscp->qpid_fifo, (void *) (uintptr_t)i);
171         return 0;
172 }
173
174 #ifdef needed
175 int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
176 {
177         return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
178                                        0);
179 }
180
181 void cxio_hal_destroy_rhdl_resource(void)
182 {
183         buf_ring_free(rhdl_fifo);
184 }
185 #endif
186
187 /* nr_* must be power of 2 */
188 int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
189                            u32 nr_tpt, u32 nr_pbl,
190                            u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
191 {
192         int err = 0;
193         struct cxio_hal_resource *rscp;
194
195         rscp = malloc(sizeof(*rscp), M_DEVBUF, M_NOWAIT|M_ZERO);
196         if (!rscp)
197                 return (-ENOMEM);
198         rdev_p->rscp = rscp;
199         err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
200                                       &rscp->tpt_fifo_lock,
201                                       nr_tpt, 1, 0);
202         if (err)
203                 goto tpt_err;
204         err = cxio_init_qpid_fifo(rdev_p);
205         if (err)
206                 goto qpid_err;
207         err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
208                                       nr_cqid, 1, 0);
209         if (err)
210                 goto cqid_err;
211         err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
212                                       nr_pdid, 1, 0);
213         if (err)
214                 goto pdid_err;
215         return 0;
216 pdid_err:
217         buf_ring_free(rscp->cqid_fifo);
218 cqid_err:
219         buf_ring_free(rscp->qpid_fifo);
220 qpid_err:
221         buf_ring_free(rscp->tpt_fifo);
222 tpt_err:
223         return (-ENOMEM);
224 }
225
226 /*
227  * returns 0 if no resource available
228  */
229 static u32 cxio_hal_get_resource(struct buf_ring *fifo, struct mtx *lock)
230 {
231         u32 entry;
232         
233         mtx_lock(lock);
234         entry = (u32)(uintptr_t)buf_ring_dequeue(fifo);
235         mtx_unlock(lock);
236         return entry;
237 }
238
239 static void cxio_hal_put_resource(struct buf_ring *fifo, u32 entry, struct mtx *lock)
240 {
241         mtx_lock(lock);
242         buf_ring_enqueue(fifo, (void *) (uintptr_t)entry);
243         mtx_unlock(lock);
244 }
245
246 u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
247 {
248         return cxio_hal_get_resource(rscp->tpt_fifo, &rscp->tpt_fifo_lock);
249 }
250
251 void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
252 {
253         cxio_hal_put_resource(rscp->tpt_fifo, stag, &rscp->tpt_fifo_lock);
254 }
255
256 u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
257 {
258         u32 qpid = cxio_hal_get_resource(rscp->qpid_fifo, &rscp->qpid_fifo_lock);
259         CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
260         return qpid;
261 }
262
263 void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
264 {
265         CTR2(KTR_IW_CXGB, "%s qpid 0x%x", __FUNCTION__, qpid);
266         cxio_hal_put_resource(rscp->qpid_fifo, qpid, &rscp->qpid_fifo_lock);
267 }
268
269 u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
270 {
271         return cxio_hal_get_resource(rscp->cqid_fifo, &rscp->cqid_fifo_lock);
272 }
273
274 void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
275 {
276         cxio_hal_put_resource(rscp->cqid_fifo, cqid, &rscp->cqid_fifo_lock);
277 }
278
279 u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
280 {
281         return cxio_hal_get_resource(rscp->pdid_fifo, &rscp->pdid_fifo_lock);
282 }
283
284 void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
285 {
286         cxio_hal_put_resource(rscp->pdid_fifo, pdid, &rscp->pdid_fifo_lock);
287 }
288
289 void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
290 {
291         buf_ring_free(rscp->tpt_fifo);
292         buf_ring_free(rscp->cqid_fifo);
293         buf_ring_free(rscp->qpid_fifo);
294         buf_ring_free(rscp->pdid_fifo);
295         free(rscp, M_DEVBUF);
296 }
297
298 /*
299  * PBL Memory Manager.  Uses Linux generic allocator.
300  */
301
302 #define MIN_PBL_SHIFT 8                 /* 256B == min PBL size (32 entries) */
303 #define PBL_CHUNK 2*1024*1024
304
305 u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
306 {
307         unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
308         CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size);
309         return (u32)addr;
310 }
311
312 void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
313 {
314         CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size);
315         gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
316 }
317
318 int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
319 {
320
321         rdev_p->pbl_pool = gen_pool_create(rdev_p->rnic_info.pbl_base, MIN_PBL_SHIFT,
322             rdev_p->rnic_info.pbl_top - rdev_p->rnic_info.pbl_base);
323 #if 0   
324         if (rdev_p->pbl_pool) {
325                 
326                 unsigned long i;
327                 for (i = rdev_p->rnic_info.pbl_base;
328                      i <= rdev_p->rnic_info.pbl_top - PBL_CHUNK + 1;
329                      i += PBL_CHUNK)
330                         gen_pool_add(rdev_p->pbl_pool, i, PBL_CHUNK, -1);
331         }
332 #endif  
333         return rdev_p->pbl_pool ? 0 : (-ENOMEM);
334 }
335
336 void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
337 {
338         gen_pool_destroy(rdev_p->pbl_pool);
339 }
340
341 /*
342  * RQT Memory Manager.  Uses Linux generic allocator.
343  */
344
345 #define MIN_RQT_SHIFT 10        /* 1KB == mini RQT size (16 entries) */
346 #define RQT_CHUNK 2*1024*1024
347
348 u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size)
349 {
350         unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
351         CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, (u32)addr, size << 6);
352         return (u32)addr;
353 }
354
355 void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
356 {
357         CTR3(KTR_IW_CXGB, "%s addr 0x%x size %d", __FUNCTION__, addr, size << 6);
358         gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
359 }
360
361 int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p)
362 {
363         
364         rdev_p->rqt_pool = gen_pool_create(rdev_p->rnic_info.rqt_base,
365             MIN_RQT_SHIFT, rdev_p->rnic_info.rqt_top - rdev_p->rnic_info.rqt_base);
366 #if 0
367         if (rdev_p->rqt_pool) {
368                 unsigned long i;
369
370                 for (i = rdev_p->rnic_info.rqt_base;
371                      i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
372                      i += RQT_CHUNK)
373                         gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
374         }
375 #endif  
376         return rdev_p->rqt_pool ? 0 : (-ENOMEM);
377 }
378
379 void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
380 {
381         gen_pool_destroy(rdev_p->rqt_pool);
382 }