root/drivers/net/wireless/broadcom/brcm80211/brcmfmac/commonring.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. brcmf_commonring_register_cb
  2. brcmf_commonring_config
  3. brcmf_commonring_lock
  4. brcmf_commonring_unlock
  5. brcmf_commonring_write_available
  6. brcmf_commonring_reserve_for_write
  7. brcmf_commonring_reserve_for_write_multiple
  8. brcmf_commonring_write_complete
  9. brcmf_commonring_write_cancel
  10. brcmf_commonring_get_read_ptr
  11. brcmf_commonring_read_complete

   1 // SPDX-License-Identifier: ISC
   2 /*
   3  * Copyright (c) 2014 Broadcom Corporation
   4  */
   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 
  15 void 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 
  31 void 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 
  51 void 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 
  61 void brcmf_commonring_unlock(struct brcmf_commonring *commonring)
  62                 __releases(&commonring->lock)
  63 {
  64         spin_unlock_irqrestore(&commonring->lock, commonring->flags);
  65 }
  66 
  67 
  68 bool brcmf_commonring_write_available(struct brcmf_commonring *commonring)
  69 {
  70         u16 available;
  71         bool retry = true;
  72 
  73 again:
  74         if (commonring->r_ptr <= commonring->w_ptr)
  75                 available = commonring->depth - commonring->w_ptr +
  76                             commonring->r_ptr;
  77         else
  78                 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 
 108 void *brcmf_commonring_reserve_for_write(struct brcmf_commonring *commonring)
 109 {
 110         void *ret_ptr;
 111         u16 available;
 112         bool retry = true;
 113 
 114 again:
 115         if (commonring->r_ptr <= commonring->w_ptr)
 116                 available = commonring->depth - commonring->w_ptr +
 117                             commonring->r_ptr;
 118         else
 119                 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 
 142 void *
 143 brcmf_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 
 150 again:
 151         if (commonring->r_ptr <= commonring->w_ptr)
 152                 available = commonring->depth - commonring->w_ptr +
 153                             commonring->r_ptr;
 154         else
 155                 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 
 181 int brcmf_commonring_write_complete(struct brcmf_commonring *commonring)
 182 {
 183         void *address;
 184 
 185         address = commonring->buf_addr;
 186         address += (commonring->f_ptr * commonring->item_len);
 187         if (commonring->f_ptr > commonring->w_ptr) {
 188                 address = commonring->buf_addr;
 189                 commonring->f_ptr = 0;
 190         }
 191 
 192         commonring->f_ptr = commonring->w_ptr;
 193 
 194         if (commonring->cr_write_wptr)
 195                 commonring->cr_write_wptr(commonring->cr_ctx);
 196         if (commonring->cr_ring_bell)
 197                 return commonring->cr_ring_bell(commonring->cr_ctx);
 198 
 199         return -EIO;
 200 }
 201 
 202 
 203 void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring,
 204                                    u16 n_items)
 205 {
 206         if (commonring->w_ptr == 0)
 207                 commonring->w_ptr = commonring->depth - n_items;
 208         else
 209                 commonring->w_ptr -= n_items;
 210 }
 211 
 212 
 213 void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring,
 214                                     u16 *n_items)
 215 {
 216         if (commonring->cr_update_wptr)
 217                 commonring->cr_update_wptr(commonring->cr_ctx);
 218 
 219         *n_items = (commonring->w_ptr >= commonring->r_ptr) ?
 220                                 (commonring->w_ptr - commonring->r_ptr) :
 221                                 (commonring->depth - commonring->r_ptr);
 222 
 223         if (*n_items == 0)
 224                 return NULL;
 225 
 226         return commonring->buf_addr +
 227                (commonring->r_ptr * commonring->item_len);
 228 }
 229 
 230 
 231 int brcmf_commonring_read_complete(struct brcmf_commonring *commonring,
 232                                    u16 n_items)
 233 {
 234         commonring->r_ptr += n_items;
 235         if (commonring->r_ptr == commonring->depth)
 236                 commonring->r_ptr = 0;
 237 
 238         if (commonring->cr_write_rptr)
 239                 return commonring->cr_write_rptr(commonring->cr_ctx);
 240 
 241         return -EIO;
 242 }

/* [<][>][^][v][top][bottom][index][help] */