brintos

brintos / linux-shallow public Read only

0
0
Text · 5.4 KiB · e44236c Raw
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