cxio_resource.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  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. static struct kfifo rhdl_fifo;
  42. static spinlock_t rhdl_fifo_lock;
  43. #define RANDOM_SIZE 16
  44. static int __cxio_init_resource_fifo(struct kfifo *fifo,
  45. spinlock_t *fifo_lock,
  46. u32 nr, u32 skip_low,
  47. u32 skip_high,
  48. int random)
  49. {
  50. u32 i, j, entry = 0, idx;
  51. u32 random_bytes;
  52. u32 rarray[16];
  53. spin_lock_init(fifo_lock);
  54. if (kfifo_alloc(fifo, nr * sizeof(u32), GFP_KERNEL))
  55. return -ENOMEM;
  56. for (i = 0; i < skip_low + skip_high; i++)
  57. kfifo_in(fifo, (unsigned char *) &entry, sizeof(u32));
  58. if (random) {
  59. j = 0;
  60. random_bytes = random32();
  61. for (i = 0; i < RANDOM_SIZE; i++)
  62. rarray[i] = i + skip_low;
  63. for (i = skip_low + RANDOM_SIZE; i < nr - skip_high; i++) {
  64. if (j >= RANDOM_SIZE) {
  65. j = 0;
  66. random_bytes = random32();
  67. }
  68. idx = (random_bytes >> (j * 2)) & 0xF;
  69. kfifo_in(fifo,
  70. (unsigned char *) &rarray[idx],
  71. sizeof(u32));
  72. rarray[idx] = i;
  73. j++;
  74. }
  75. for (i = 0; i < RANDOM_SIZE; i++)
  76. kfifo_in(fifo,
  77. (unsigned char *) &rarray[i],
  78. sizeof(u32));
  79. } else
  80. for (i = skip_low; i < nr - skip_high; i++)
  81. kfifo_in(fifo, (unsigned char *) &i, sizeof(u32));
  82. for (i = 0; i < skip_low + skip_high; i++)
  83. if (kfifo_out_locked(fifo, (unsigned char *) &entry,
  84. sizeof(u32), fifo_lock) != sizeof(u32))
  85. break;
  86. return 0;
  87. }
  88. static int cxio_init_resource_fifo(struct kfifo *fifo, spinlock_t * fifo_lock,
  89. u32 nr, u32 skip_low, u32 skip_high)
  90. {
  91. return (__cxio_init_resource_fifo(fifo, fifo_lock, nr, skip_low,
  92. skip_high, 0));
  93. }
  94. static int cxio_init_resource_fifo_random(struct kfifo *fifo,
  95. 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, 1));
  100. }
  101. static int cxio_init_qpid_fifo(struct cxio_rdev *rdev_p)
  102. {
  103. u32 i;
  104. spin_lock_init(&rdev_p->rscp->qpid_fifo_lock);
  105. if (kfifo_alloc(&rdev_p->rscp->qpid_fifo, T3_MAX_NUM_QP * sizeof(u32),
  106. GFP_KERNEL))
  107. return -ENOMEM;
  108. for (i = 16; i < T3_MAX_NUM_QP; i++)
  109. if (!(i & rdev_p->qpmask))
  110. kfifo_in(&rdev_p->rscp->qpid_fifo,
  111. (unsigned char *) &i, sizeof(u32));
  112. return 0;
  113. }
  114. int cxio_hal_init_rhdl_resource(u32 nr_rhdl)
  115. {
  116. return cxio_init_resource_fifo(&rhdl_fifo, &rhdl_fifo_lock, nr_rhdl, 1,
  117. 0);
  118. }
  119. void cxio_hal_destroy_rhdl_resource(void)
  120. {
  121. kfifo_free(&rhdl_fifo);
  122. }
  123. /* nr_* must be power of 2 */
  124. int cxio_hal_init_resource(struct cxio_rdev *rdev_p,
  125. u32 nr_tpt, u32 nr_pbl,
  126. u32 nr_rqt, u32 nr_qpid, u32 nr_cqid, u32 nr_pdid)
  127. {
  128. int err = 0;
  129. struct cxio_hal_resource *rscp;
  130. rscp = kmalloc(sizeof(*rscp), GFP_KERNEL);
  131. if (!rscp)
  132. return -ENOMEM;
  133. rdev_p->rscp = rscp;
  134. err = cxio_init_resource_fifo_random(&rscp->tpt_fifo,
  135. &rscp->tpt_fifo_lock,
  136. nr_tpt, 1, 0);
  137. if (err)
  138. goto tpt_err;
  139. err = cxio_init_qpid_fifo(rdev_p);
  140. if (err)
  141. goto qpid_err;
  142. err = cxio_init_resource_fifo(&rscp->cqid_fifo, &rscp->cqid_fifo_lock,
  143. nr_cqid, 1, 0);
  144. if (err)
  145. goto cqid_err;
  146. err = cxio_init_resource_fifo(&rscp->pdid_fifo, &rscp->pdid_fifo_lock,
  147. nr_pdid, 1, 0);
  148. if (err)
  149. goto pdid_err;
  150. return 0;
  151. pdid_err:
  152. kfifo_free(&rscp->cqid_fifo);
  153. cqid_err:
  154. kfifo_free(&rscp->qpid_fifo);
  155. qpid_err:
  156. kfifo_free(&rscp->tpt_fifo);
  157. tpt_err:
  158. return -ENOMEM;
  159. }
  160. /*
  161. * returns 0 if no resource available
  162. */
  163. static u32 cxio_hal_get_resource(struct kfifo *fifo, spinlock_t * lock)
  164. {
  165. u32 entry;
  166. if (kfifo_out_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock))
  167. return entry;
  168. else
  169. return 0; /* fifo emptry */
  170. }
  171. static void cxio_hal_put_resource(struct kfifo *fifo, spinlock_t * lock,
  172. u32 entry)
  173. {
  174. BUG_ON(
  175. kfifo_in_locked(fifo, (unsigned char *) &entry, sizeof(u32), lock)
  176. == 0);
  177. }
  178. u32 cxio_hal_get_stag(struct cxio_hal_resource *rscp)
  179. {
  180. return cxio_hal_get_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock);
  181. }
  182. void cxio_hal_put_stag(struct cxio_hal_resource *rscp, u32 stag)
  183. {
  184. cxio_hal_put_resource(&rscp->tpt_fifo, &rscp->tpt_fifo_lock, stag);
  185. }
  186. u32 cxio_hal_get_qpid(struct cxio_hal_resource *rscp)
  187. {
  188. u32 qpid = cxio_hal_get_resource(&rscp->qpid_fifo,
  189. &rscp->qpid_fifo_lock);
  190. PDBG("%s qpid 0x%x\n", __func__, qpid);
  191. return qpid;
  192. }
  193. void cxio_hal_put_qpid(struct cxio_hal_resource *rscp, u32 qpid)
  194. {
  195. PDBG("%s qpid 0x%x\n", __func__, qpid);
  196. cxio_hal_put_resource(&rscp->qpid_fifo, &rscp->qpid_fifo_lock, qpid);
  197. }
  198. u32 cxio_hal_get_cqid(struct cxio_hal_resource *rscp)
  199. {
  200. return cxio_hal_get_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock);
  201. }
  202. void cxio_hal_put_cqid(struct cxio_hal_resource *rscp, u32 cqid)
  203. {
  204. cxio_hal_put_resource(&rscp->cqid_fifo, &rscp->cqid_fifo_lock, cqid);
  205. }
  206. u32 cxio_hal_get_pdid(struct cxio_hal_resource *rscp)
  207. {
  208. return cxio_hal_get_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock);
  209. }
  210. void cxio_hal_put_pdid(struct cxio_hal_resource *rscp, u32 pdid)
  211. {
  212. cxio_hal_put_resource(&rscp->pdid_fifo, &rscp->pdid_fifo_lock, pdid);
  213. }
  214. void cxio_hal_destroy_resource(struct cxio_hal_resource *rscp)
  215. {
  216. kfifo_free(&rscp->tpt_fifo);
  217. kfifo_free(&rscp->cqid_fifo);
  218. kfifo_free(&rscp->qpid_fifo);
  219. kfifo_free(&rscp->pdid_fifo);
  220. kfree(rscp);
  221. }
  222. /*
  223. * PBL Memory Manager. Uses Linux generic allocator.
  224. */
  225. #define MIN_PBL_SHIFT 8 /* 256B == min PBL size (32 entries) */
  226. u32 cxio_hal_pblpool_alloc(struct cxio_rdev *rdev_p, int size)
  227. {
  228. unsigned long addr = gen_pool_alloc(rdev_p->pbl_pool, size);
  229. PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size);
  230. return (u32)addr;
  231. }
  232. void cxio_hal_pblpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
  233. {
  234. PDBG("%s addr 0x%x size %d\n", __func__, addr, size);
  235. gen_pool_free(rdev_p->pbl_pool, (unsigned long)addr, size);
  236. }
  237. int cxio_hal_pblpool_create(struct cxio_rdev *rdev_p)
  238. {
  239. unsigned pbl_start, pbl_chunk;
  240. rdev_p->pbl_pool = gen_pool_create(MIN_PBL_SHIFT, -1);
  241. if (!rdev_p->pbl_pool)
  242. return -ENOMEM;
  243. pbl_start = rdev_p->rnic_info.pbl_base;
  244. pbl_chunk = rdev_p->rnic_info.pbl_top - pbl_start + 1;
  245. while (pbl_start < rdev_p->rnic_info.pbl_top) {
  246. pbl_chunk = min(rdev_p->rnic_info.pbl_top - pbl_start + 1,
  247. pbl_chunk);
  248. if (gen_pool_add(rdev_p->pbl_pool, pbl_start, pbl_chunk, -1)) {
  249. PDBG("%s failed to add PBL chunk (%x/%x)\n",
  250. __func__, pbl_start, pbl_chunk);
  251. if (pbl_chunk <= 1024 << MIN_PBL_SHIFT) {
  252. printk(KERN_WARNING MOD "%s: Failed to add all PBL chunks (%x/%x)\n",
  253. __func__, pbl_start, rdev_p->rnic_info.pbl_top - pbl_start);
  254. return 0;
  255. }
  256. pbl_chunk >>= 1;
  257. } else {
  258. PDBG("%s added PBL chunk (%x/%x)\n",
  259. __func__, pbl_start, pbl_chunk);
  260. pbl_start += pbl_chunk;
  261. }
  262. }
  263. return 0;
  264. }
  265. void cxio_hal_pblpool_destroy(struct cxio_rdev *rdev_p)
  266. {
  267. gen_pool_destroy(rdev_p->pbl_pool);
  268. }
  269. /*
  270. * RQT Memory Manager. Uses Linux generic allocator.
  271. */
  272. #define MIN_RQT_SHIFT 10 /* 1KB == mini RQT size (16 entries) */
  273. #define RQT_CHUNK 2*1024*1024
  274. u32 cxio_hal_rqtpool_alloc(struct cxio_rdev *rdev_p, int size)
  275. {
  276. unsigned long addr = gen_pool_alloc(rdev_p->rqt_pool, size << 6);
  277. PDBG("%s addr 0x%x size %d\n", __func__, (u32)addr, size << 6);
  278. return (u32)addr;
  279. }
  280. void cxio_hal_rqtpool_free(struct cxio_rdev *rdev_p, u32 addr, int size)
  281. {
  282. PDBG("%s addr 0x%x size %d\n", __func__, addr, size << 6);
  283. gen_pool_free(rdev_p->rqt_pool, (unsigned long)addr, size << 6);
  284. }
  285. int cxio_hal_rqtpool_create(struct cxio_rdev *rdev_p)
  286. {
  287. unsigned long i;
  288. rdev_p->rqt_pool = gen_pool_create(MIN_RQT_SHIFT, -1);
  289. if (rdev_p->rqt_pool)
  290. for (i = rdev_p->rnic_info.rqt_base;
  291. i <= rdev_p->rnic_info.rqt_top - RQT_CHUNK + 1;
  292. i += RQT_CHUNK)
  293. gen_pool_add(rdev_p->rqt_pool, i, RQT_CHUNK, -1);
  294. return rdev_p->rqt_pool ? 0 : -ENOMEM;
  295. }
  296. void cxio_hal_rqtpool_destroy(struct cxio_rdev *rdev_p)
  297. {
  298. gen_pool_destroy(rdev_p->rqt_pool);
  299. }