0001
0002
0003
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 }