123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- /*
- * Copyright (c) 2018 The Linux Foundation. All rights reserved.
- *
- * Permission to use, copy, modify, and/or distribute this software for
- * any purpose with or without fee is hereby granted, provided that the
- * above copyright notice and this permission notice appear in all
- * copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
- * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
- * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- * PERFORMANCE OF THIS SOFTWARE.
- */
- /**
- * DOC: wbuff.c
- * wbuff buffer management APIs
- */
- #include <wbuff.h>
- #include "i_wbuff.h"
- /**
- * Allocation holder array for all wbuff registered modules
- */
- struct wbuff_holder wbuff;
- /**
- * wbuff_get_pool_slot_from_len() - get pool_slot from length
- * @len: length of the buffer
- *
- * Return: pool slot
- */
- static uint8_t wbuff_get_pool_slot_from_len(uint16_t len)
- {
- if ((len > 0) && (len <= WBUFF_LEN_POOL0))
- return WBUFF_POOL_0;
- else if ((len > WBUFF_LEN_POOL0) && (len <= WBUFF_LEN_POOL1))
- return WBUFF_POOL_1;
- else if ((len > WBUFF_LEN_POOL1) && (len <= WBUFF_LEN_POOL2))
- return WBUFF_POOL_2;
- else
- return WBUFF_POOL_3;
- }
- /**
- * wbuff_get_len_from_pool_slot() - get len from pool slot
- * @pool_slot: wbuff pool_slot
- *
- * Return: nbuf length from pool slot
- */
- static uint32_t wbuff_get_len_from_pool_slot(uint16_t pool_slot)
- {
- uint32_t len = 0;
- switch (pool_slot) {
- case 0:
- len = WBUFF_LEN_POOL0;
- break;
- case 1:
- len = WBUFF_LEN_POOL1;
- break;
- case 2:
- len = WBUFF_LEN_POOL2;
- break;
- case 3:
- len = WBUFF_LEN_POOL3;
- break;
- default:
- len = 0;
- }
- return len;
- }
- /**
- * wbuff_get_free_mod_slot() - get free module slot
- *
- * Return: module slot
- */
- static uint8_t wbuff_get_free_mod_slot(void)
- {
- uint8_t mslot = 0;
- for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
- qdf_spin_lock_bh(&wbuff.mod[mslot].lock);
- if (!wbuff.mod[mslot].registered) {
- wbuff.mod[mslot].registered = true;
- qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
- break;
- }
- qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
- }
- return mslot;
- }
- /**
- * wbuff_is_valid_alloc_req() - validate alloc request
- * @req: allocation request from registered module
- * @num: number of pools required
- *
- * Return: true if valid wbuff_alloc_request
- * false if invalid wbuff_alloc_request
- */
- static bool wbuff_is_valid_alloc_req(struct wbuff_alloc_request *req,
- uint8_t num)
- {
- uint16_t psize = 0;
- uint8_t alloc = 0, pslot = 0;
- for (alloc = 0; alloc < num; alloc++) {
- pslot = req[alloc].slot;
- psize = req[alloc].size;
- if ((pslot > WBUFF_MAX_POOLS - 1) ||
- (psize > wbuff_alloc_max[pslot]))
- return false;
- }
- return true;
- }
- /**
- * wbuff_prepare_nbuf() - allocate nbuf
- * @mslot: module slot
- * @pslot: pool slot
- * @len: length of the buffer
- * @reserve: nbuf headroom to start with
- * @align: alignment for the nbuf
- *
- * Return: nbuf if success
- * NULL if failure
- */
- static qdf_nbuf_t wbuff_prepare_nbuf(uint8_t mslot, uint8_t pslot,
- uint32_t len, int reserve, int align)
- {
- qdf_nbuf_t buf;
- unsigned long dev_scratch = 0;
- buf = qdf_nbuf_alloc(NULL, roundup(len + reserve, align), reserve,
- align, false);
- if (!buf)
- return NULL;
- dev_scratch = mslot;
- dev_scratch <<= WBUFF_MSLOT_SHIFT;
- dev_scratch |= ((pslot << WBUFF_PSLOT_SHIFT) | 1);
- qdf_nbuf_set_dev_scratch(buf, dev_scratch);
- return buf;
- }
- /**
- * wbuff_is_valid_handle() - validate wbuff handle
- * @handle: wbuff handle passed by module
- *
- * Return: true - valid wbuff_handle
- * false - invalid wbuff_handle
- */
- static bool wbuff_is_valid_handle(struct wbuff_handle *handle)
- {
- if ((handle) && (handle->id < WBUFF_MAX_MODULES) &&
- (wbuff.mod[handle->id].registered))
- return true;
- return false;
- }
- QDF_STATUS wbuff_module_init(void)
- {
- struct wbuff_module *mod = NULL;
- uint8_t mslot = 0, pslot = 0;
- if (!qdf_nbuf_is_dev_scratch_supported()) {
- wbuff.initialized = false;
- return QDF_STATUS_E_NOSUPPORT;
- }
- for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
- mod = &wbuff.mod[mslot];
- qdf_spinlock_create(&mod->lock);
- for (pslot = 0; pslot < WBUFF_MAX_POOLS; pslot++)
- mod->pool[pslot] = NULL;
- mod->registered = false;
- }
- wbuff.initialized = true;
- return QDF_STATUS_SUCCESS;
- }
- QDF_STATUS wbuff_module_deinit(void)
- {
- struct wbuff_module *mod = NULL;
- uint8_t mslot = 0;
- if (!wbuff.initialized)
- return QDF_STATUS_E_INVAL;
- wbuff.initialized = false;
- for (mslot = 0; mslot < WBUFF_MAX_MODULES; mslot++) {
- mod = &wbuff.mod[mslot];
- if (mod->registered)
- wbuff_module_deregister((struct wbuff_mod_handle *)
- &mod->handle);
- qdf_spinlock_destroy(&mod->lock);
- }
- return QDF_STATUS_SUCCESS;
- }
- struct wbuff_mod_handle *
- wbuff_module_register(struct wbuff_alloc_request *req, uint8_t num,
- int reserve, int align)
- {
- struct wbuff_module *mod = NULL;
- qdf_nbuf_t buf = NULL;
- uint32_t len = 0;
- uint16_t idx = 0, psize = 0;
- uint8_t alloc = 0, mslot = 0, pslot = 0;
- if (!wbuff.initialized)
- return NULL;
- if ((num == 0) || (num > WBUFF_MAX_POOLS))
- return NULL;
- if (!wbuff_is_valid_alloc_req(req, num))
- return NULL;
- mslot = wbuff_get_free_mod_slot();
- if (mslot == WBUFF_MAX_MODULES)
- return NULL;
- mod = &wbuff.mod[mslot];
- mod->handle.id = mslot;
- for (alloc = 0; alloc < num; alloc++) {
- pslot = req[alloc].slot;
- psize = req[alloc].size;
- len = wbuff_get_len_from_pool_slot(pslot);
- /**
- * Allocate pool_cnt number of buffers for
- * the pool given by pslot
- */
- for (idx = 0; idx < psize; idx++) {
- buf = wbuff_prepare_nbuf(mslot, pslot, len, reserve,
- align);
- if (!buf)
- continue;
- if (!mod->pool[pslot]) {
- qdf_nbuf_set_next(buf, NULL);
- mod->pool[pslot] = buf;
- } else {
- qdf_nbuf_set_next(buf, mod->pool[pslot]);
- mod->pool[pslot] = buf;
- }
- }
- }
- mod->reserve = reserve;
- mod->align = align;
- return (struct wbuff_mod_handle *)&mod->handle;
- }
- QDF_STATUS wbuff_module_deregister(struct wbuff_mod_handle *hdl)
- {
- struct wbuff_handle *handle;
- struct wbuff_module *mod = NULL;
- uint8_t mslot = 0, pslot = 0;
- qdf_nbuf_t first = NULL, buf = NULL;
- handle = (struct wbuff_handle *)hdl;
- if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)))
- return QDF_STATUS_E_INVAL;
- mslot = handle->id;
- mod = &wbuff.mod[mslot];
- qdf_spin_lock_bh(&mod->lock);
- for (pslot = 0; pslot < WBUFF_MAX_POOLS; pslot++) {
- first = mod->pool[pslot];
- while (first) {
- buf = first;
- first = qdf_nbuf_next(buf);
- qdf_nbuf_free(buf);
- }
- }
- mod->registered = false;
- qdf_spin_unlock_bh(&mod->lock);
- return QDF_STATUS_SUCCESS;
- }
- qdf_nbuf_t wbuff_buff_get(struct wbuff_mod_handle *hdl, uint32_t len)
- {
- struct wbuff_handle *handle;
- struct wbuff_module *mod = NULL;
- uint8_t mslot = 0;
- uint8_t pslot = 0;
- qdf_nbuf_t buf = NULL;
- handle = (struct wbuff_handle *)hdl;
- if ((!wbuff.initialized) || (!wbuff_is_valid_handle(handle)) || !len ||
- (len > WBUFF_MAX_BUFFER_SIZE))
- return NULL;
- mslot = handle->id;
- pslot = wbuff_get_pool_slot_from_len(len);
- mod = &wbuff.mod[mslot];
- qdf_spin_lock_bh(&mod->lock);
- if (mod->pool[pslot]) {
- buf = mod->pool[pslot];
- mod->pool[pslot] = qdf_nbuf_next(buf);
- mod->pending_returns++;
- }
- qdf_spin_unlock_bh(&mod->lock);
- if (buf)
- qdf_nbuf_set_next(buf, NULL);
- return buf;
- }
- qdf_nbuf_t wbuff_buff_put(qdf_nbuf_t buf)
- {
- qdf_nbuf_t buffer = buf;
- unsigned long slot_info = 0;
- uint8_t mslot = 0, pslot = 0;
- if (!wbuff.initialized)
- return buffer;
- slot_info = qdf_nbuf_get_dev_scratch(buf);
- if (!slot_info)
- return buffer;
- mslot = (slot_info & WBUFF_MSLOT_BITMASK) >> WBUFF_MSLOT_SHIFT;
- pslot = (slot_info & WBUFF_PSLOT_BITMASK) >> WBUFF_PSLOT_SHIFT;
- qdf_nbuf_reset(buffer, wbuff.mod[mslot].reserve, wbuff.mod[mslot].
- align);
- qdf_spin_lock_bh(&wbuff.mod[mslot].lock);
- if (wbuff.mod[mslot].registered) {
- qdf_nbuf_set_next(buffer, wbuff.mod[mslot].pool[pslot]);
- wbuff.mod[mslot].pool[pslot] = buffer;
- wbuff.mod[mslot].pending_returns--;
- buffer = NULL;
- }
- qdf_spin_unlock_bh(&wbuff.mod[mslot].lock);
- return buffer;
- }
|