Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/commonring.c
178665 views
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
253