Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: ISC
0002 /*
0003  * Copyright (c) 2014 Broadcom Corporation
0004  */
0005 
0006 #include <linux/types.h>
0007 #include <linux/netdevice.h>
0008 
0009 #include <brcmu_utils.h>
0010 #include <brcmu_wifi.h>
0011 
0012 #include "core.h"
0013 #include "commonring.h"
0014 
0015 void brcmf_commonring_register_cb(struct brcmf_commonring *commonring,
0016                   int (*cr_ring_bell)(void *ctx),
0017                   int (*cr_update_rptr)(void *ctx),
0018                   int (*cr_update_wptr)(void *ctx),
0019                   int (*cr_write_rptr)(void *ctx),
0020                   int (*cr_write_wptr)(void *ctx), void *ctx)
0021 {
0022     commonring->cr_ring_bell = cr_ring_bell;
0023     commonring->cr_update_rptr = cr_update_rptr;
0024     commonring->cr_update_wptr = cr_update_wptr;
0025     commonring->cr_write_rptr = cr_write_rptr;
0026     commonring->cr_write_wptr = cr_write_wptr;
0027     commonring->cr_ctx = ctx;
0028 }
0029 
0030 
0031 void brcmf_commonring_config(struct brcmf_commonring *commonring, u16 depth,
0032                  u16 item_len, void *buf_addr)
0033 {
0034     commonring->depth = depth;
0035     commonring->item_len = item_len;
0036     commonring->buf_addr = buf_addr;
0037     if (!commonring->inited) {
0038         spin_lock_init(&commonring->lock);
0039         commonring->inited = true;
0040     }
0041     commonring->r_ptr = 0;
0042     if (commonring->cr_write_rptr)
0043         commonring->cr_write_rptr(commonring->cr_ctx);
0044     commonring->w_ptr = 0;
0045     if (commonring->cr_write_wptr)
0046         commonring->cr_write_wptr(commonring->cr_ctx);
0047     commonring->f_ptr = 0;
0048 }
0049 
0050 
0051 void brcmf_commonring_lock(struct brcmf_commonring *commonring)
0052         __acquires(&commonring->lock)
0053 {
0054     unsigned long flags;
0055 
0056     spin_lock_irqsave(&commonring->lock, flags);
0057     commonring->flags = flags;
0058 }
0059 
0060 
0061 void brcmf_commonring_unlock(struct brcmf_commonring *commonring)
0062         __releases(&commonring->lock)
0063 {
0064     spin_unlock_irqrestore(&commonring->lock, commonring->flags);
0065 }
0066 
0067 
0068 bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)
0069 {
0070     u16 available;
0071     bool retry = true;
0072 
0073 again:
0074     if (commonring->r_ptr <= commonring->w_ptr)
0075         available = commonring->depth - commonring->w_ptr +
0076                 commonring->r_ptr;
0077     else
0078         available = commonring->r_ptr - commonring->w_ptr;
0079 
0080     if (available > 1) {
0081         if (!commonring->was_full)
0082             return true;
0083         if (available > commonring->depth / 8) {
0084             commonring->was_full = false;
0085             return true;
0086         }
0087         if (retry) {
0088             if (commonring->cr_update_rptr)
0089                 commonring->cr_update_rptr(commonring->cr_ctx);
0090             retry = false;
0091             goto again;
0092         }
0093         return false;
0094     }
0095 
0096     if (retry) {
0097         if (commonring->cr_update_rptr)
0098             commonring->cr_update_rptr(commonring->cr_ctx);
0099         retry = false;
0100         goto again;
0101     }
0102 
0103     commonring->was_full = true;
0104     return false;
0105 }
0106 
0107 
0108 void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)
0109 {
0110     void *ret_ptr;
0111     u16 available;
0112     bool retry = true;
0113 
0114 again:
0115     if (commonring->r_ptr <= commonring->w_ptr)
0116         available = commonring->depth - commonring->w_ptr +
0117                 commonring->r_ptr;
0118     else
0119         available = commonring->r_ptr - commonring->w_ptr;
0120 
0121     if (available > 1) {
0122         ret_ptr = commonring->buf_addr +
0123               (commonring->w_ptr * commonring->item_len);
0124         commonring->w_ptr++;
0125         if (commonring->w_ptr == commonring->depth)
0126             commonring->w_ptr = 0;
0127         return ret_ptr;
0128     }
0129 
0130     if (retry) {
0131         if (commonring->cr_update_rptr)
0132             commonring->cr_update_rptr(commonring->cr_ctx);
0133         retry = false;
0134         goto again;
0135     }
0136 
0137     commonring->was_full = true;
0138     return NULL;
0139 }
0140 
0141 
0142 void *
0143 brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring,
0144                         u16 n_items, u16 *alloced)
0145 {
0146     void *ret_ptr;
0147     u16 available;
0148     bool retry = true;
0149 
0150 again:
0151     if (commonring->r_ptr <= commonring->w_ptr)
0152         available = commonring->depth - commonring->w_ptr +
0153                 commonring->r_ptr;
0154     else
0155         available = commonring->r_ptr - commonring->w_ptr;
0156 
0157     if (available > 1) {
0158         ret_ptr = commonring->buf_addr +
0159               (commonring->w_ptr * commonring->item_len);
0160         *alloced = min_t(u16, n_items, available - 1);
0161         if (*alloced + commonring->w_ptr > commonring->depth)
0162             *alloced = commonring->depth - commonring->w_ptr;
0163         commonring->w_ptr += *alloced;
0164         if (commonring->w_ptr == commonring->depth)
0165             commonring->w_ptr = 0;
0166         return ret_ptr;
0167     }
0168 
0169     if (retry) {
0170         if (commonring->cr_update_rptr)
0171             commonring->cr_update_rptr(commonring->cr_ctx);
0172         retry = false;
0173         goto again;
0174     }
0175 
0176     commonring->was_full = true;
0177     return NULL;
0178 }
0179 
0180 
0181 int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
0182 {
0183     if (commonring->f_ptr > commonring->w_ptr)
0184         commonring->f_ptr = 0;
0185 
0186     commonring->f_ptr = commonring->w_ptr;
0187 
0188     if (commonring->cr_write_wptr)
0189         commonring->cr_write_wptr(commonring->cr_ctx);
0190     if (commonring->cr_ring_bell)
0191         return commonring->cr_ring_bell(commonring->cr_ctx);
0192 
0193     return -EIO;
0194 }
0195 
0196 
0197 void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
0198                    u16 n_items)
0199 {
0200     if (commonring->w_ptr == 0)
0201         commonring->w_ptr = commonring->depth - n_items;
0202     else
0203         commonring->w_ptr -= n_items;
0204 }
0205 
0206 
0207 void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
0208                     u16 *n_items)
0209 {
0210     if (commonring->cr_update_wptr)
0211         commonring->cr_update_wptr(commonring->cr_ctx);
0212 
0213     *n_items = (commonring->w_ptr >= commonring->r_ptr) ?
0214                 (commonring->w_ptr - commonring->r_ptr) :
0215                 (commonring->depth - commonring->r_ptr);
0216 
0217     if (*n_items == 0)
0218         return NULL;
0219 
0220     return commonring->buf_addr +
0221            (commonring->r_ptr * commonring->item_len);
0222 }
0223 
0224 
0225 int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
0226                    u16 n_items)
0227 {
0228     commonring->r_ptr += n_items;
0229     if (commonring->r_ptr == commonring->depth)
0230         commonring->r_ptr = 0;
0231 
0232     if (commonring->cr_write_rptr)
0233         return commonring->cr_write_rptr(commonring->cr_ctx);
0234 
0235     return -EIO;
0236 }