237 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2014 Broadcom Corporation4 */5 6#include <linux/types.h>7#include <linux/netdevice.h>8 9#include <brcmu_utils.h>10#include <brcmu_wifi.h>11 12#include "core.h"13#include "commonring.h"14 15void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,16 int (*cr_ring_bell)(void *ctx),17 int (*cr_update_rptr)(void *ctx),18 int (*cr_update_wptr)(void *ctx),19 int (*cr_write_rptr)(void *ctx),20 int (*cr_write_wptr)(void *ctx), void *ctx)21{22 commonring->cr_ring_bell = cr_ring_bell;23 commonring->cr_update_rptr = cr_update_rptr;24 commonring->cr_update_wptr = cr_update_wptr;25 commonring->cr_write_rptr = cr_write_rptr;26 commonring->cr_write_wptr = cr_write_wptr;27 commonring->cr_ctx = ctx;28}29 30 31void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,32 u16 item_len, void *buf_addr)33{34 commonring->depth = depth;35 commonring->item_len = item_len;36 commonring->buf_addr = buf_addr;37 if (!commonring->inited) {38 spin_lock_init(&commonring->lock);39 commonring->inited = true;40 }41 commonring->r_ptr = 0;42 if (commonring->cr_write_rptr)43 commonring->cr_write_rptr(commonring->cr_ctx);44 commonring->w_ptr = 0;45 if (commonring->cr_write_wptr)46 commonring->cr_write_wptr(commonring->cr_ctx);47 commonring->f_ptr = 0;48}49 50 51void brcmf_commonring_lock(struct brcmf_commonring *commonring)52 __acquires(&commonring->lock)53{54 unsigned long flags;55 56 spin_lock_irqsave(&commonring->lock, flags);57 commonring->flags = flags;58}59 60 61void brcmf_commonring_unlock(struct brcmf_commonring *commonring)62 __releases(&commonring->lock)63{64 spin_unlock_irqrestore(&commonring->lock, commonring->flags);65}66 67 68bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)69{70 u16 available;71 bool retry = true;72 73again:74 if (commonring->r_ptr <= commonring->w_ptr)75 available = commonring->depth - commonring->w_ptr +76 commonring->r_ptr;77 else78 available = commonring->r_ptr - commonring->w_ptr;79 80 if (available > 1) {81 if (!commonring->was_full)82 return true;83 if (available > commonring->depth / 8) {84 commonring->was_full = false;85 return true;86 }87 if (retry) {88 if (commonring->cr_update_rptr)89 commonring->cr_update_rptr(commonring->cr_ctx);90 retry = false;91 goto again;92 }93 return false;94 }95 96 if (retry) {97 if (commonring->cr_update_rptr)98 commonring->cr_update_rptr(commonring->cr_ctx);99 retry = false;100 goto again;101 }102 103 commonring->was_full = true;104 return false;105}106 107 108void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)109{110 void *ret_ptr;111 u16 available;112 bool retry = true;113 114again:115 if (commonring->r_ptr <= commonring->w_ptr)116 available = commonring->depth - commonring->w_ptr +117 commonring->r_ptr;118 else119 available = commonring->r_ptr - commonring->w_ptr;120 121 if (available > 1) {122 ret_ptr = commonring->buf_addr +123 (commonring->w_ptr * commonring->item_len);124 commonring->w_ptr++;125 if (commonring->w_ptr == commonring->depth)126 commonring->w_ptr = 0;127 return ret_ptr;128 }129 130 if (retry) {131 if (commonring->cr_update_rptr)132 commonring->cr_update_rptr(commonring->cr_ctx);133 retry = false;134 goto again;135 }136 137 commonring->was_full = true;138 return NULL;139}140 141 142void *143brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,144 u16 n_items, u16 *alloced)145{146 void *ret_ptr;147 u16 available;148 bool retry = true;149 150again:151 if (commonring->r_ptr <= commonring->w_ptr)152 available = commonring->depth - commonring->w_ptr +153 commonring->r_ptr;154 else155 available = commonring->r_ptr - commonring->w_ptr;156 157 if (available > 1) {158 ret_ptr = commonring->buf_addr +159 (commonring->w_ptr * commonring->item_len);160 *alloced = min_t(u16, n_items, available - 1);161 if (*alloced + commonring->w_ptr > commonring->depth)162 *alloced = commonring->depth - commonring->w_ptr;163 commonring->w_ptr += *alloced;164 if (commonring->w_ptr == commonring->depth)165 commonring->w_ptr = 0;166 return ret_ptr;167 }168 169 if (retry) {170 if (commonring->cr_update_rptr)171 commonring->cr_update_rptr(commonring->cr_ctx);172 retry = false;173 goto again;174 }175 176 commonring->was_full = true;177 return NULL;178}179 180 181int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)182{183 if (commonring->f_ptr > commonring->w_ptr)184 commonring->f_ptr = 0;185 186 commonring->f_ptr = commonring->w_ptr;187 188 if (commonring->cr_write_wptr)189 commonring->cr_write_wptr(commonring->cr_ctx);190 if (commonring->cr_ring_bell)191 return commonring->cr_ring_bell(commonring->cr_ctx);192 193 return -EIO;194}195 196 197void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,198 u16 n_items)199{200 if (commonring->w_ptr == 0)201 commonring->w_ptr = commonring->depth - n_items;202 else203 commonring->w_ptr -= n_items;204}205 206 207void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,208 u16 *n_items)209{210 if (commonring->cr_update_wptr)211 commonring->cr_update_wptr(commonring->cr_ctx);212 213 *n_items = (commonring->w_ptr >= commonring->r_ptr) ?214 (commonring->w_ptr - commonring->r_ptr) :215 (commonring->depth - commonring->r_ptr);216 217 if (*n_items == 0)218 return NULL;219 220 return commonring->buf_addr +221 (commonring->r_ptr * commonring->item_len);222}223 224 225int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,226 u16 n_items)227{228 commonring->r_ptr += n_items;229 if (commonring->r_ptr == commonring->depth)230 commonring->r_ptr = 0;231 232 if (commonring->cr_write_rptr)233 return commonring->cr_write_rptr(commonring->cr_ctx);234 235 return -EIO;236}237