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 #if defined(__linux__) 123 ret_ptr = commonring->buf_addr + 124 (commonring->w_ptr * commonring->item_len); 125 #elif defined(__FreeBSD__) 126 ret_ptr = (void *)((uintptr_t)commonring->buf_addr + 127 (commonring->w_ptr * commonring->item_len)); 128 #endif 129 commonring->w_ptr++; 130 if (commonring->w_ptr == commonring->depth) 131 commonring->w_ptr = 0; 132 return ret_ptr; 133 } 134 135 if (retry) { 136 if (commonring->cr_update_rptr) 137 commonring->cr_update_rptr(commonring->cr_ctx); 138 retry = false; 139 goto again; 140 } 141 142 commonring->was_full = true; 143 return NULL; 144 } 145 146 147 void * 148 brcmf_commonring_reserve_for_write_multiple(struct brcmf_commonring *commonring, 149 u16 n_items, u16 *alloced) 150 { 151 void *ret_ptr; 152 u16 available; 153 bool retry = true; 154 155 again: 156 if (commonring->r_ptr <= commonring->w_ptr) 157 available = commonring->depth - commonring->w_ptr + 158 commonring->r_ptr; 159 else 160 available = commonring->r_ptr - commonring->w_ptr; 161 162 if (available > 1) { 163 #if defined(__linux__) 164 ret_ptr = commonring->buf_addr + 165 (commonring->w_ptr * commonring->item_len); 166 #elif defined(__FreeBSD__) 167 ret_ptr = (void *)((uintptr_t)commonring->buf_addr + 168 (commonring->w_ptr * commonring->item_len)); 169 #endif 170 *alloced = min_t(u16, n_items, available - 1); 171 if (*alloced + commonring->w_ptr > commonring->depth) 172 *alloced = commonring->depth - commonring->w_ptr; 173 commonring->w_ptr += *alloced; 174 if (commonring->w_ptr == commonring->depth) 175 commonring->w_ptr = 0; 176 return ret_ptr; 177 } 178 179 if (retry) { 180 if (commonring->cr_update_rptr) 181 commonring->cr_update_rptr(commonring->cr_ctx); 182 retry = false; 183 goto again; 184 } 185 186 commonring->was_full = true; 187 return NULL; 188 } 189 190 191 int brcmf_commonring_write_complete(struct brcmf_commonring *commonring) 192 { 193 if (commonring->f_ptr > commonring->w_ptr) 194 commonring->f_ptr = 0; 195 196 commonring->f_ptr = commonring->w_ptr; 197 198 if (commonring->cr_write_wptr) 199 commonring->cr_write_wptr(commonring->cr_ctx); 200 if (commonring->cr_ring_bell) 201 return commonring->cr_ring_bell(commonring->cr_ctx); 202 203 return -EIO; 204 } 205 206 207 void brcmf_commonring_write_cancel(struct brcmf_commonring *commonring, 208 u16 n_items) 209 { 210 if (commonring->w_ptr == 0) 211 commonring->w_ptr = commonring->depth - n_items; 212 else 213 commonring->w_ptr -= n_items; 214 } 215 216 217 void *brcmf_commonring_get_read_ptr(struct brcmf_commonring *commonring, 218 u16 *n_items) 219 { 220 if (commonring->cr_update_wptr) 221 commonring->cr_update_wptr(commonring->cr_ctx); 222 223 *n_items = (commonring->w_ptr >= commonring->r_ptr) ? 224 (commonring->w_ptr - commonring->r_ptr) : 225 (commonring->depth - commonring->r_ptr); 226 227 if (*n_items == 0) 228 return NULL; 229 230 #if defined(__linux__) 231 return commonring->buf_addr + 232 (commonring->r_ptr * commonring->item_len); 233 #elif defined(__FreeBSD__) 234 return (void *)((uintptr_t)commonring->buf_addr + 235 (commonring->r_ptr * commonring->item_len)); 236 #endif 237 } 238 239 240 int brcmf_commonring_read_complete(struct brcmf_commonring *commonring, 241 u16 n_items) 242 { 243 commonring->r_ptr += n_items; 244 if (commonring->r_ptr == commonring->depth) 245 commonring->r_ptr = 0; 246 247 if (commonring->cr_write_rptr) 248 return commonring->cr_write_rptr(commonring->cr_ctx); 249 250 return -EIO; 251 } 252