wbuff.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. /*
  2. * Copyright (c) 2018 The Linux Foundation. All rights reserved.
  3. *
  4. * Permission to use, copy, modify, and/or distribute this software for
  5. * any purpose with or without fee is hereby granted, provided that the
  6. * above copyright notice and this permission notice appear in all
  7. * copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
  10. * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
  11. * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
  12. * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  13. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  14. * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  15. * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  16. * PERFORMANCE OF THIS SOFTWARE.
  17. */
  18. /**
  19. * DOC: wbuff.c
  20. * wbuff buffer management APIs
  21. */
  22. #include <wbuff.h>
  23. #include "i_wbuff.h"
  24. /**
  25. * Allocation holder array for all wbuff registered modules
  26. */
  27. struct wbuff_holder wbuff;
  28. /**
  29. * wbuff_get_pool_slot_from_len() - get pool_slot from length
  30. * @len: length of the buffer
  31. *
  32. * Return: pool slot
  33. */
  34. static uint8_t wbuff_get_pool_slot_from_len(uint16_t len)
  35. {
  36. if ((len > 0) && (len <= WBUFF_LEN_POOL0))
  37. return WBUFF_POOL_0;
  38. else if ((len > WBUFF_LEN_POOL0) && (len <= WBUFF_LEN_POOL1))
  39. return WBUFF_POOL_1;
  40. else if ((len > WBUFF_LEN_POOL1) && (len <= WBUFF_LEN_POOL2))
  41. return WBUFF_POOL_2;
  42. else
  43. return WBUFF_POOL_3;
  44. }
  45. /**
  46. * wbuff_get_len_from_pool_slot() - get len from pool slot
  47. * @pool_slot: wbuff pool_slot
  48. *
  49. * Return: nbuf length from pool slot
  50. */
  51. static uint32_t wbuff_get_len_from_pool_slot(uint16_t pool_slot)
  52. {
  53. uint32_t len = 0;
  54. switch (pool_slot) {
  55. case 0:
  56. len = WBUFF_LEN_POOL0;
  57. break;
  58. case 1:
  59. len = WBUFF_LEN_POOL1;
  60. break;
  61. case 2:
  62. len = WBUFF_LEN_POOL2;
  63. break;
  64. case 3:
  65. len = WBUFF_LEN_POOL3;
  66. break;
  67. default:
  68. len = 0;
  69. }
  70. return len;
  71. }
  72. /**
  73. * wbuff_get_free_mod_slot() - get free module slot
  74. *
  75. * Return: module slot
  76. */
  77. static uint8_t wbuff_get_free_mod_slot(void)
  78. {
  79. uint8_t mslot = 0;
  80. for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
  81. qdf_spin_lock_bh(&wbuff.mod[mslot].lock);
  82. if (!wbuff.mod[mslot].registered) {
  83. wbuff.mod[mslot].registered = true;
  84. qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
  85. break;
  86. }
  87. qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
  88. }
  89. return mslot;
  90. }
  91. /**
  92. * wbuff_is_valid_alloc_req() - validate alloc request
  93. * @req: allocation request from registered module
  94. * @num: number of pools required
  95. *
  96. * Return: true if valid wbuff_alloc_request
  97. * false if invalid wbuff_alloc_request
  98. */
  99. static bool wbuff_is_valid_alloc_req(struct wbuff_alloc_request *req,
  100. uint8_t num)
  101. {
  102. uint16_t psize = 0;
  103. uint8_t alloc = 0, pslot = 0;
  104. for (alloc = 0; alloc < num; alloc++) {
  105. pslot = req[alloc].slot;
  106. psize = req[alloc].size;
  107. if ((pslot > WBUFF_MAX_POOLS - 1) ||
  108. (psize > wbuff_alloc_max[pslot]))
  109. return false;
  110. }
  111. return true;
  112. }
  113. /**
  114. * wbuff_prepare_nbuf() - allocate nbuf
  115. * @mslot: module slot
  116. * @pslot: pool slot
  117. * @len: length of the buffer
  118. * @reserve: nbuf headroom to start with
  119. * @align: alignment for the nbuf
  120. *
  121. * Return: nbuf if success
  122. * NULL if failure
  123. */
  124. static qdf_nbuf_t wbuff_prepare_nbuf(uint8_t mslot, uint8_t pslot,
  125. uint32_t len, int reserve, int align)
  126. {
  127. qdf_nbuf_t buf;
  128. unsigned long dev_scratch = 0;
  129. buf = qdf_nbuf_alloc(NULL, roundup(len + reserve, align), reserve,
  130. align, false);
  131. if (!buf)
  132. return NULL;
  133. dev_scratch = mslot;
  134. dev_scratch <<= WBUFF_MSLOT_SHIFT;
  135. dev_scratch |= ((pslot << WBUFF_PSLOT_SHIFT) | 1);
  136. qdf_nbuf_set_dev_scratch(buf, dev_scratch);
  137. return buf;
  138. }
  139. /**
  140. * wbuff_is_valid_handle() - validate wbuff handle
  141. * @handle: wbuff handle passed by module
  142. *
  143. * Return: true - valid wbuff_handle
  144. * false - invalid wbuff_handle
  145. */
  146. static bool wbuff_is_valid_handle(struct wbuff_handle *handle)
  147. {
  148. if ((handle) && (handle->id < WBUFF_MAX_MODULES) &&
  149. (wbuff.mod[handle->id].registered))
  150. return true;
  151. return false;
  152. }
  153. QDF_STATUS wbuff_module_init(void)
  154. {
  155. struct wbuff_module *mod = NULL;
  156. uint8_t mslot = 0, pslot = 0;
  157. if (!qdf_nbuf_is_dev_scratch_supported()) {
  158. wbuff.initialized = false;
  159. return QDF_STATUS_E_NOSUPPORT;
  160. }
  161. for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
  162. mod = &wbuff.mod[mslot];
  163. qdf_spinlock_create(&mod->lock);
  164. for (pslot = 0; pslot < WBUFF_MAX_POOLS; pslot++)
  165. mod->pool[pslot] = NULL;
  166. mod->registered = false;
  167. }
  168. wbuff.initialized = true;
  169. return QDF_STATUS_SUCCESS;
  170. }
  171. QDF_STATUS wbuff_module_deinit(void)
  172. {
  173. struct wbuff_module *mod = NULL;
  174. uint8_t mslot = 0;
  175. if (!wbuff.initialized)
  176. return QDF_STATUS_E_INVAL;
  177. wbuff.initialized = false;
  178. for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
  179. mod = &wbuff.mod[mslot];
  180. if (mod->registered)
  181. wbuff_module_deregister((struct wbuff_mod_handle *)
  182. &mod->handle);
  183. qdf_spinlock_destroy(&mod->lock);
  184. }
  185. return QDF_STATUS_SUCCESS;
  186. }
  187. struct wbuff_mod_handle *
  188. wbuff_module_register(struct wbuff_alloc_request *req, uint8_t num,
  189. int reserve, int align)
  190. {
  191. struct wbuff_module *mod = NULL;
  192. qdf_nbuf_t buf = NULL;
  193. uint32_t len = 0;
  194. uint16_t idx = 0, psize = 0;
  195. uint8_t alloc = 0, mslot = 0, pslot = 0;
  196. if (!wbuff.initialized)
  197. return NULL;
  198. if ((num == 0) || (num > WBUFF_MAX_POOLS))
  199. return NULL;
  200. if (!wbuff_is_valid_alloc_req(req, num))
  201. return NULL;
  202. mslot = wbuff_get_free_mod_slot();
  203. if (mslot == WBUFF_MAX_MODULES)
  204. return NULL;
  205. mod = &wbuff.mod[mslot];
  206. mod->handle.id = mslot;
  207. for (alloc = 0; alloc < num; alloc++) {
  208. pslot = req[alloc].slot;
  209. psize = req[alloc].size;
  210. len = wbuff_get_len_from_pool_slot(pslot);
  211. /**
  212. * Allocate pool_cnt number of buffers for
  213. * the pool given by pslot
  214. */
  215. for (idx = 0; idx < psize; idx++) {
  216. buf = wbuff_prepare_nbuf(mslot, pslot, len, reserve,
  217. align);
  218. if (!buf)
  219. continue;
  220. if (!mod->pool[pslot]) {
  221. qdf_nbuf_set_next(buf, NULL);
  222. mod->pool[pslot] = buf;
  223. } else {
  224. qdf_nbuf_set_next(buf, mod->pool[pslot]);
  225. mod->pool[pslot] = buf;
  226. }
  227. }
  228. }
  229. mod->reserve = reserve;
  230. mod->align = align;
  231. return (struct wbuff_mod_handle *)&mod->handle;
  232. }
  233. QDF_STATUS wbuff_module_deregister(struct wbuff_mod_handle *hdl)
  234. {
  235. struct wbuff_handle *handle;
  236. struct wbuff_module *mod = NULL;
  237. uint8_t mslot = 0, pslot = 0;
  238. qdf_nbuf_t first = NULL, buf = NULL;
  239. handle = (struct wbuff_handle *)hdl;
  240. if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)))
  241. return QDF_STATUS_E_INVAL;
  242. mslot = handle->id;
  243. mod = &wbuff.mod[mslot];
  244. qdf_spin_lock_bh(&mod->lock);
  245. for (pslot = 0; pslot < WBUFF_MAX_POOLS; pslot++) {
  246. first = mod->pool[pslot];
  247. while (first) {
  248. buf = first;
  249. first = qdf_nbuf_next(buf);
  250. qdf_nbuf_free(buf);
  251. }
  252. }
  253. mod->registered = false;
  254. qdf_spin_unlock_bh(&mod->lock);
  255. return QDF_STATUS_SUCCESS;
  256. }
  257. qdf_nbuf_t wbuff_buff_get(struct wbuff_mod_handle *hdl, uint32_t len)
  258. {
  259. struct wbuff_handle *handle;
  260. struct wbuff_module *mod = NULL;
  261. uint8_t mslot = 0;
  262. uint8_t pslot = 0;
  263. qdf_nbuf_t buf = NULL;
  264. handle = (struct wbuff_handle *)hdl;
  265. if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)) || !len ||
  266. (len > WBUFF_MAX_BUFFER_SIZE))
  267. return NULL;
  268. mslot = handle->id;
  269. pslot = wbuff_get_pool_slot_from_len(len);
  270. mod = &wbuff.mod[mslot];
  271. qdf_spin_lock_bh(&mod->lock);
  272. if (mod->pool[pslot]) {
  273. buf = mod->pool[pslot];
  274. mod->pool[pslot] = qdf_nbuf_next(buf);
  275. mod->pending_returns++;
  276. }
  277. qdf_spin_unlock_bh(&mod->lock);
  278. if (buf)
  279. qdf_nbuf_set_next(buf, NULL);
  280. return buf;
  281. }
  282. qdf_nbuf_t wbuff_buff_put(qdf_nbuf_t buf)
  283. {
  284. qdf_nbuf_t buffer = buf;
  285. unsigned long slot_info = 0;
  286. uint8_t mslot = 0, pslot = 0;
  287. if (!wbuff.initialized)
  288. return buffer;
  289. slot_info = qdf_nbuf_get_dev_scratch(buf);
  290. if (!slot_info)
  291. return buffer;
  292. mslot = (slot_info & WBUFF_MSLOT_BITMASK) >> WBUFF_MSLOT_SHIFT;
  293. pslot = (slot_info & WBUFF_PSLOT_BITMASK) >> WBUFF_PSLOT_SHIFT;
  294. qdf_nbuf_reset(buffer, wbuff.mod[mslot].reserve, wbuff.mod[mslot].
  295. align);
  296. qdf_spin_lock_bh(&wbuff.mod[mslot].lock);
  297. if (wbuff.mod[mslot].registered) {
  298. qdf_nbuf_set_next(buffer, wbuff.mod[mslot].pool[pslot]);
  299. wbuff.mod[mslot].pool[pslot] = buffer;
  300. wbuff.mod[mslot].pending_returns--;
  301. buffer = NULL;
  302. }
  303. qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
  304. return buffer;
  305. }