Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
cxio_resource.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2006 Chelsio, Inc. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses. You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  * Redistribution and use in source and binary forms, with or
11  * without modification, are permitted provided that the following
12  * conditions are met:
13  *
14  * - Redistributions of source code must retain the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above
19  * copyright notice, this list of conditions and the following
20  * disclaimer in the documentation and/or other materials
21  * provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32 /* Crude resource management */
33 #include <linux/kernel.h>
34 #include <linux/random.h>
35 #include <linux/slab.h>
36 #include <linux/kfifo.h>
37 #include <linux/spinlock.h>
38 #include <linux/errno.h>
39 #include "cxio_resource.h"
40 #include "cxio_hal.h"
41 
42 static struct kfifo rhdl_fifo;
43 static spinlock_t rhdl_fifo_lock;
44 
45 #define RANDOM_SIZE 16
46 
47 static int __cxio_init_resource_fifo(struct kfifo *fifo,
48  spinlock_t *fifo_lock,
49  u32 nr, u32 skip_low,
50  u32 skip_high,
51  int random)
52 {
53  u32 i, j, entry = 0, idx;
54  u32 random_bytes;
55  u32 rarray[16];
56  spin_lock_init(fifo_lock);
57 
58  if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
59  return -ENOMEM;
60 
61  for (i = 0; i < skip_low + skip_high; i++)
62  kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
63  if (random) {
64  j = 0;
65  random_bytes = random32();
66  for (i = 0; i < RANDOM_SIZE; i++)
67  rarray[i] = i + skip_low;
68  for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
69  if (j >= RANDOM_SIZE) {
70  j = 0;
71  random_bytes = random32();
72  }
73  idx = (random_bytes >> (j * 2)) & 0xF;
74  kfifo_in(fifo,
75  (unsigned char *) &rarray[idx],
76  sizeof(u32));
77  rarray[idx] = i;
78  j++;
79  }
80  for (i = 0; i < RANDOM_SIZE; i++)
81  kfifo_in(fifo,
82  (unsigned char *) &rarray[i],
83  sizeof(u32));
84  } else
85  for (i = skip_low; i < nr - skip_high; i++)
86  kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
87 
88  for (i = 0; i < skip_low + skip_high; i++)
89  if (kfifo_out_locked(fifo, (unsigned char *) &entry,
90  sizeof(u32), fifo_lock) != sizeof(u32))
91  break;
92  return 0;
93 }
94 
95 static int cxio_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
96  u32 nr, u32 skip_low, u32 skip_high)
97 {
98  return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
99  skip_high, 0));
100 }
101 
102 static int cxio_init_resource_fifo_random(struct kfifo *fifo,
103  spinlock_t * fifo_lock,
104  u32 nr, u32 skip_low, u32 skip_high)
105 {
106 
107  return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
108  skip_high, 1));
109 }
110 
111 static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
112 {
113  u32 i;
114 
115  spin_lock_init(&rdev_p->rscp->qpid_fifo_lock);
116 
117  if (kfifo_alloc(&rdev_p->rscp->qpid_fifo, T3_MAX_NUM_QP * sizeof(u32),
118  GFP_KERNEL))
119  return -ENOMEM;
120 
121  for (i = 16; i < T3_MAX_NUM_QP; i++)
122  if (!(i & rdev_p->qpmask))
123  kfifo_in(&rdev_p->rscp->qpid_fifo,
124  (unsigned char *) &i, sizeof(u32));
125  return 0;
126 }
127 
129 {
130  return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
131  0);
132 }
133 
135 {
136  kfifo_free(&rhdl_fifo);
137 }
138 
139 /* nr_* must be power of 2 */
141  u32 nr_tpt, u32 nr_pbl,
142  u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
143 {
144  int err = 0;
145  struct cxio_hal_resource *rscp;
146 
147  rscp = kmalloc(sizeof(*rscp), GFP_KERNEL);
148  if (!rscp)
149  return -ENOMEM;
150  rdev_p->rscp = rscp;
151  err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
152  &rscp->tpt_fifo_lock,
153  nr_tpt, 1, 0);
154  if (err)
155  goto tpt_err;
156  err = cxio_init_qpid_fifo(rdev_p);
157  if (err)
158  goto qpid_err;
159  err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
160  nr_cqid, 1, 0);
161  if (err)
162  goto cqid_err;
163  err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
164  nr_pdid, 1, 0);
165  if (err)
166  goto pdid_err;
167  return 0;
168 pdid_err:
169  kfifo_free(&rscp->cqid_fifo);
170 cqid_err:
171  kfifo_free(&rscp->qpid_fifo);
172 qpid_err:
173  kfifo_free(&rscp->tpt_fifo);
174 tpt_err:
175  return -ENOMEM;
176 }
177 
178 /*
179  * returns 0 if no resource available
180  */
181 static u32 cxio_hal_get_resource(struct kfifo *fifo, spinlock_t * lock)
182 {
183  u32 entry;
184  if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
185  return entry;
186  else
187  return 0; /* fifo emptry */
188 }
189 
190 static void cxio_hal_put_resource(struct kfifo *fifo, spinlock_t * lock,
191  u32 entry)
192 {
193  BUG_ON(
194  kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock)
195  == 0);
196 }
197 
199 {
200  return cxio_hal_get_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock);
201 }
202 
204 {
205  cxio_hal_put_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock, stag);
206 }
207 
209 {
210  u32 qpid = cxio_hal_get_resource(&rscp->qpid_fifo,
211  &rscp->qpid_fifo_lock);
212  PDBG("%s qpid 0x%x\n", __func__, qpid);
213  return qpid;
214 }
215 
216 void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
217 {
218  PDBG("%s qpid 0x%x\n", __func__, qpid);
219  cxio_hal_put_resource(&rscp->qpid_fifo, &rscp->qpid_fifo_lock, qpid);
220 }
221 
223 {
224  return cxio_hal_get_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock);
225 }
226 
227 void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
228 {
229  cxio_hal_put_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, cqid);
230 }
231 
233 {
234  return cxio_hal_get_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock);
235 }
236 
237 void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
238 {
239  cxio_hal_put_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, pdid);
240 }
241 
243 {
244  kfifo_free(&rscp->tpt_fifo);
245  kfifo_free(&rscp->cqid_fifo);
246  kfifo_free(&rscp->qpid_fifo);
247  kfifo_free(&rscp->pdid_fifo);
248  kfree(rscp);
249 }
250 
251 /*
252  * PBL Memory Manager. Uses Linux generic allocator.
253  */
254 
255 #define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
256 
258 {
259  unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
260  PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
261  return (u32)addr;
262 }
263 
264 void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
265 {
266  PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
267  gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
268 }
269 
271 {
272  unsigned pbl_start, pbl_chunk;
273 
274  rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
275  if (!rdev_p->pbl_pool)
276  return -ENOMEM;
277 
278  pbl_start = rdev_p->rnic_info.pbl_base;
279  pbl_chunk = rdev_p->rnic_info.pbl_top - pbl_start + 1;
280 
281  while (pbl_start < rdev_p->rnic_info.pbl_top) {
282  pbl_chunk = min(rdev_p->rnic_info.pbl_top - pbl_start + 1,
283  pbl_chunk);
284  if (gen_pool_add(rdev_p->pbl_pool, pbl_start, pbl_chunk, -1)) {
285  PDBG("%s failed to add PBL chunk (%x/%x)\n",
286  __func__, pbl_start, pbl_chunk);
287  if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
288  printk(KERN_WARNING MOD "%s: Failed to add all PBL chunks (%x/%x)\n",
289  __func__, pbl_start, rdev_p->rnic_info.pbl_top - pbl_start);
290  return 0;
291  }
292  pbl_chunk >>= 1;
293  } else {
294  PDBG("%s added PBL chunk (%x/%x)\n",
295  __func__, pbl_start, pbl_chunk);
296  pbl_start += pbl_chunk;
297  }
298  }
299 
300  return 0;
301 }
302 
304 {
305  gen_pool_destroy(rdev_p->pbl_pool);
306 }
307 
308 /*
309  * RQT Memory Manager. Uses Linux generic allocator.
310  */
311 
312 #define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */
313 #define RQT_CHUNK 2*1024*1024
314 
316 {
317  unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
318  PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
319  return (u32)addr;
320 }
321 
322 void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
323 {
324  PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6);
325  gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
326 }
327 
329 {
330  unsigned long i;
331  rdev_p->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
332  if (rdev_p->rqt_pool)
333  for (i = rdev_p->rnic_info.rqt_base;
334  i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
335  i += RQT_CHUNK)
336  gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
337  return rdev_p->rqt_pool ? 0 : -ENOMEM;
338 }
339 
341 {
342  gen_pool_destroy(rdev_p->rqt_pool);
343 }