Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/commonring.c
178665 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2014 Broadcom Corporation3*/45#include <linux/types.h>6#include <linux/netdevice.h>78#include <brcmu_utils.h>9#include <brcmu_wifi.h>1011#include "core.h"12#include "commonring.h"1314void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,15int (*cr_ring_bell)(void *ctx),16int (*cr_update_rptr)(void *ctx),17int (*cr_update_wptr)(void *ctx),18int (*cr_write_rptr)(void *ctx),19int (*cr_write_wptr)(void *ctx), void *ctx)20{21commonring->cr_ring_bell = cr_ring_bell;22commonring->cr_update_rptr = cr_update_rptr;23commonring->cr_update_wptr = cr_update_wptr;24commonring->cr_write_rptr = cr_write_rptr;25commonring->cr_write_wptr = cr_write_wptr;26commonring->cr_ctx = ctx;27}282930void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,31u16 item_len, void *buf_addr)32{33commonring->depth = depth;34commonring->item_len = item_len;35commonring->buf_addr = buf_addr;36if (!commonring->inited) {37spin_lock_init(&commonring->lock);38commonring->inited = true;39}40commonring->r_ptr = 0;41if (commonring->cr_write_rptr)42commonring->cr_write_rptr(commonring->cr_ctx);43commonring->w_ptr = 0;44if (commonring->cr_write_wptr)45commonring->cr_write_wptr(commonring->cr_ctx);46commonring->f_ptr = 0;47}484950void brcmf_commonring_lock(struct brcmf_commonring *commonring)51__acquires(&commonring->lock)52{53unsigned long flags;5455spin_lock_irqsave(&commonring->lock, flags);56commonring->flags = flags;57}585960void brcmf_commonring_unlock(struct brcmf_commonring *commonring)61__releases(&commonring->lock)62{63spin_unlock_irqrestore(&commonring->lock, commonring->flags);64}656667bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)68{69u16 available;70bool retry = true;7172again:73if (commonring->r_ptr <= commonring->w_ptr)74available = commonring->depth - commonring->w_ptr +75commonring->r_ptr;76else77available = commonring->r_ptr - commonring->w_ptr;7879if (available > 1) {80if (!commonring->was_full)81return true;82if (available > commonring->depth / 8) {83commonring->was_full = false;84return true;85}86if (retry) {87if (commonring->cr_update_rptr)88commonring->cr_update_rptr(commonring->cr_ctx);89retry = false;90goto again;91}92return false;93}9495if (retry) {96if (commonring->cr_update_rptr)97commonring->cr_update_rptr(commonring->cr_ctx);98retry = false;99goto again;100}101102commonring->was_full = true;103return false;104}105106107void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)108{109void *ret_ptr;110u16 available;111bool retry = true;112113again:114if (commonring->r_ptr <= commonring->w_ptr)115available = commonring->depth - commonring->w_ptr +116commonring->r_ptr;117else118available = commonring->r_ptr - commonring->w_ptr;119120if (available > 1) {121#if defined(__linux__)122ret_ptr = commonring->buf_addr +123(commonring->w_ptr * commonring->item_len);124#elif defined(__FreeBSD__)125ret_ptr = (void *)((uintptr_t)commonring->buf_addr +126(commonring->w_ptr * commonring->item_len));127#endif128commonring->w_ptr++;129if (commonring->w_ptr == commonring->depth)130commonring->w_ptr = 0;131return ret_ptr;132}133134if (retry) {135if (commonring->cr_update_rptr)136commonring->cr_update_rptr(commonring->cr_ctx);137retry = false;138goto again;139}140141commonring->was_full = true;142return NULL;143}144145146void *147brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,148u16 n_items, u16 *alloced)149{150void *ret_ptr;151u16 available;152bool retry = true;153154again:155if (commonring->r_ptr <= commonring->w_ptr)156available = commonring->depth - commonring->w_ptr +157commonring->r_ptr;158else159available = commonring->r_ptr - commonring->w_ptr;160161if (available > 1) {162#if defined(__linux__)163ret_ptr = commonring->buf_addr +164(commonring->w_ptr * commonring->item_len);165#elif defined(__FreeBSD__)166ret_ptr = (void *)((uintptr_t)commonring->buf_addr +167(commonring->w_ptr * commonring->item_len));168#endif169*alloced = min_t(u16, n_items, available - 1);170if (*alloced + commonring->w_ptr > commonring->depth)171*alloced = commonring->depth - commonring->w_ptr;172commonring->w_ptr += *alloced;173if (commonring->w_ptr == commonring->depth)174commonring->w_ptr = 0;175return ret_ptr;176}177178if (retry) {179if (commonring->cr_update_rptr)180commonring->cr_update_rptr(commonring->cr_ctx);181retry = false;182goto again;183}184185commonring->was_full = true;186return NULL;187}188189190int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)191{192if (commonring->f_ptr > commonring->w_ptr)193commonring->f_ptr = 0;194195commonring->f_ptr = commonring->w_ptr;196197if (commonring->cr_write_wptr)198commonring->cr_write_wptr(commonring->cr_ctx);199if (commonring->cr_ring_bell)200return commonring->cr_ring_bell(commonring->cr_ctx);201202return -EIO;203}204205206void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,207u16 n_items)208{209if (commonring->w_ptr == 0)210commonring->w_ptr = commonring->depth - n_items;211else212commonring->w_ptr -= n_items;213}214215216void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,217u16 *n_items)218{219if (commonring->cr_update_wptr)220commonring->cr_update_wptr(commonring->cr_ctx);221222*n_items = (commonring->w_ptr >= commonring->r_ptr) ?223(commonring->w_ptr - commonring->r_ptr) :224(commonring->depth - commonring->r_ptr);225226if (*n_items == 0)227return NULL;228229#if defined(__linux__)230return commonring->buf_addr +231(commonring->r_ptr * commonring->item_len);232#elif defined(__FreeBSD__)233return (void *)((uintptr_t)commonring->buf_addr +234(commonring->r_ptr * commonring->item_len));235#endif236}237238239int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,240u16 n_items)241{242commonring->r_ptr += n_items;243if (commonring->r_ptr == commonring->depth)244commonring->r_ptr = 0;245246if (commonring->cr_write_rptr)247return commonring->cr_write_rptr(commonring->cr_ctx);248249return -EIO;250}251252253