Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/dev/broadcom/brcm80211/brcmfmac/fwsignal.c
178665 views
1
// SPDX-License-Identifier: ISC
2
/*
3
* Copyright (c) 2010 Broadcom Corporation
4
*/
5
#include <linux/types.h>
6
#include <linux/module.h>
7
#include <linux/if_ether.h>
8
#include <linux/spinlock.h>
9
#include <linux/skbuff.h>
10
#include <linux/netdevice.h>
11
#include <linux/etherdevice.h>
12
#include <linux/err.h>
13
#include <linux/jiffies.h>
14
#include <net/cfg80211.h>
15
16
#include <brcmu_utils.h>
17
#include <brcmu_wifi.h>
18
#include "core.h"
19
#include "debug.h"
20
#include "bus.h"
21
#include "fwil.h"
22
#include "fwil_types.h"
23
#include "fweh.h"
24
#include "fwsignal.h"
25
#include "p2p.h"
26
#include "cfg80211.h"
27
#include "proto.h"
28
#include "bcdc.h"
29
#include "common.h"
30
31
/**
32
* DOC: Firmware Signalling
33
*
34
* Firmware can send signals to host and vice versa, which are passed in the
35
* data packets using TLV based header. This signalling layer is on top of the
36
* BDC bus protocol layer.
37
*/
38
39
/*
40
* single definition for firmware-driver flow control tlv's.
41
*
42
* each tlv is specified by BRCMF_FWS_TLV_DEF(name, ID, length).
43
* A length value 0 indicates variable length tlv.
44
*/
45
#define BRCMF_FWS_TLV_DEFLIST \
46
BRCMF_FWS_TLV_DEF(MAC_OPEN, 1, 1) \
47
BRCMF_FWS_TLV_DEF(MAC_CLOSE, 2, 1) \
48
BRCMF_FWS_TLV_DEF(MAC_REQUEST_CREDIT, 3, 2) \
49
BRCMF_FWS_TLV_DEF(TXSTATUS, 4, 4) \
50
BRCMF_FWS_TLV_DEF(PKTTAG, 5, 4) \
51
BRCMF_FWS_TLV_DEF(MACDESC_ADD, 6, 8) \
52
BRCMF_FWS_TLV_DEF(MACDESC_DEL, 7, 8) \
53
BRCMF_FWS_TLV_DEF(RSSI, 8, 1) \
54
BRCMF_FWS_TLV_DEF(INTERFACE_OPEN, 9, 1) \
55
BRCMF_FWS_TLV_DEF(INTERFACE_CLOSE, 10, 1) \
56
BRCMF_FWS_TLV_DEF(FIFO_CREDITBACK, 11, 6) \
57
BRCMF_FWS_TLV_DEF(PENDING_TRAFFIC_BMP, 12, 2) \
58
BRCMF_FWS_TLV_DEF(MAC_REQUEST_PACKET, 13, 3) \
59
BRCMF_FWS_TLV_DEF(HOST_REORDER_RXPKTS, 14, 10) \
60
BRCMF_FWS_TLV_DEF(TRANS_ID, 18, 6) \
61
BRCMF_FWS_TLV_DEF(COMP_TXSTATUS, 19, 1) \
62
BRCMF_FWS_TLV_DEF(FILLER, 255, 0)
63
64
/*
65
* enum brcmf_fws_tlv_type - definition of tlv identifiers.
66
*/
67
#define BRCMF_FWS_TLV_DEF(name, id, len) \
68
BRCMF_FWS_TYPE_ ## name = id,
69
enum brcmf_fws_tlv_type {
70
BRCMF_FWS_TLV_DEFLIST
71
BRCMF_FWS_TYPE_INVALID
72
};
73
#undef BRCMF_FWS_TLV_DEF
74
75
/*
76
* enum brcmf_fws_tlv_len - definition of tlv lengths.
77
*/
78
#define BRCMF_FWS_TLV_DEF(name, id, len) \
79
BRCMF_FWS_TYPE_ ## name ## _LEN = (len),
80
enum brcmf_fws_tlv_len {
81
BRCMF_FWS_TLV_DEFLIST
82
};
83
#undef BRCMF_FWS_TLV_DEF
84
85
/* AMPDU rx reordering definitions */
86
#define BRCMF_RXREORDER_FLOWID_OFFSET 0
87
#define BRCMF_RXREORDER_MAXIDX_OFFSET 2
88
#define BRCMF_RXREORDER_FLAGS_OFFSET 4
89
#define BRCMF_RXREORDER_CURIDX_OFFSET 6
90
#define BRCMF_RXREORDER_EXPIDX_OFFSET 8
91
92
#define BRCMF_RXREORDER_DEL_FLOW 0x01
93
#define BRCMF_RXREORDER_FLUSH_ALL 0x02
94
#define BRCMF_RXREORDER_CURIDX_VALID 0x04
95
#define BRCMF_RXREORDER_EXPIDX_VALID 0x08
96
#define BRCMF_RXREORDER_NEW_HOLE 0x10
97
98
#ifdef DEBUG
99
/*
100
* brcmf_fws_tlv_names - array of tlv names.
101
*/
102
#define BRCMF_FWS_TLV_DEF(name, id, len) \
103
{ id, #name },
104
static struct {
105
enum brcmf_fws_tlv_type id;
106
const char *name;
107
} brcmf_fws_tlv_names[] = {
108
BRCMF_FWS_TLV_DEFLIST
109
};
110
#undef BRCMF_FWS_TLV_DEF
111
112
113
static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
114
{
115
int i;
116
117
for (i = 0; i < ARRAY_SIZE(brcmf_fws_tlv_names); i++)
118
if (brcmf_fws_tlv_names[i].id == id)
119
return brcmf_fws_tlv_names[i].name;
120
121
return "INVALID";
122
}
123
#else
124
static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
125
{
126
return "NODEBUG";
127
}
128
#endif /* DEBUG */
129
130
/*
131
* The PKTTAG tlv has additional bytes when firmware-signalling
132
* mode has REUSESEQ flag set.
133
*/
134
#define BRCMF_FWS_TYPE_SEQ_LEN 2
135
136
/*
137
* flags used to enable tlv signalling from firmware.
138
*/
139
#define BRCMF_FWS_FLAGS_RSSI_SIGNALS 0x0001
140
#define BRCMF_FWS_FLAGS_XONXOFF_SIGNALS 0x0002
141
#define BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS 0x0004
142
#define BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE 0x0008
143
#define BRCMF_FWS_FLAGS_PSQ_GENERATIONFSM_ENABLE 0x0010
144
#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
145
#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
146
147
#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
148
#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
149
150
#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
151
#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
152
#define BRCMF_FWS_FLOWCONTROL_HIWATER 128
153
#define BRCMF_FWS_FLOWCONTROL_LOWATER 64
154
155
#define BRCMF_FWS_PSQ_PREC_COUNT ((BRCMF_FWS_FIFO_COUNT + 1) * 2)
156
#define BRCMF_FWS_PSQ_LEN 256
157
158
#define BRCMF_FWS_HTOD_FLAG_PKTFROMHOST 0x01
159
#define BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED 0x02
160
161
#define BRCMF_FWS_RET_OK_NOSCHEDULE 0
162
#define BRCMF_FWS_RET_OK_SCHEDULE 1
163
164
#define BRCMF_FWS_MODE_REUSESEQ_SHIFT 3 /* seq reuse */
165
#define BRCMF_FWS_MODE_SET_REUSESEQ(x, val) ((x) = \
166
((x) & ~(1 << BRCMF_FWS_MODE_REUSESEQ_SHIFT)) | \
167
(((val) & 1) << BRCMF_FWS_MODE_REUSESEQ_SHIFT))
168
#define BRCMF_FWS_MODE_GET_REUSESEQ(x) \
169
(((x) >> BRCMF_FWS_MODE_REUSESEQ_SHIFT) & 1)
170
171
/**
172
* enum brcmf_fws_skb_state - indicates processing state of skb.
173
*
174
* @BRCMF_FWS_SKBSTATE_NEW: sk_buff is newly arrived in the driver.
175
* @BRCMF_FWS_SKBSTATE_DELAYED: sk_buff had to wait on queue.
176
* @BRCMF_FWS_SKBSTATE_SUPPRESSED: sk_buff has been suppressed by firmware.
177
* @BRCMF_FWS_SKBSTATE_TIM: allocated for TIM update info.
178
*/
179
enum brcmf_fws_skb_state {
180
BRCMF_FWS_SKBSTATE_NEW,
181
BRCMF_FWS_SKBSTATE_DELAYED,
182
BRCMF_FWS_SKBSTATE_SUPPRESSED,
183
BRCMF_FWS_SKBSTATE_TIM
184
};
185
186
/**
187
* struct brcmf_skbuff_cb - control buffer associated with skbuff.
188
*
189
* @bus_flags: 2 bytes reserved for bus specific parameters
190
* @if_flags: holds interface index and packet related flags.
191
* @htod: host to device packet identifier (used in PKTTAG tlv).
192
* @htod_seq: this 16-bit is original seq number for every suppress packet.
193
* @state: transmit state of the packet.
194
* @mac: descriptor related to destination for this packet.
195
*
196
* This information is stored in control buffer struct sk_buff::cb, which
197
* provides 48 bytes of storage so this structure should not exceed that.
198
*/
199
struct brcmf_skbuff_cb {
200
u16 bus_flags;
201
u16 if_flags;
202
u32 htod;
203
u16 htod_seq;
204
enum brcmf_fws_skb_state state;
205
struct brcmf_fws_mac_descriptor *mac;
206
};
207
208
/*
209
* macro casting skbuff control buffer to struct brcmf_skbuff_cb.
210
*/
211
#define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb))
212
213
/*
214
* sk_buff control if flags
215
*
216
* b[11] - packet sent upon firmware request.
217
* b[10] - packet only contains signalling data.
218
* b[9] - packet is a tx packet.
219
* b[8] - packet used requested credit
220
* b[7] - interface in AP mode.
221
* b[3:0] - interface index.
222
*/
223
#define BRCMF_SKB_IF_FLAGS_REQUESTED_MASK 0x0800
224
#define BRCMF_SKB_IF_FLAGS_REQUESTED_SHIFT 11
225
#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_MASK 0x0400
226
#define BRCMF_SKB_IF_FLAGS_SIGNAL_ONLY_SHIFT 10
227
#define BRCMF_SKB_IF_FLAGS_TRANSMIT_MASK 0x0200
228
#define BRCMF_SKB_IF_FLAGS_TRANSMIT_SHIFT 9
229
#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_MASK 0x0100
230
#define BRCMF_SKB_IF_FLAGS_REQ_CREDIT_SHIFT 8
231
#define BRCMF_SKB_IF_FLAGS_IF_AP_MASK 0x0080
232
#define BRCMF_SKB_IF_FLAGS_IF_AP_SHIFT 7
233
#define BRCMF_SKB_IF_FLAGS_INDEX_MASK 0x000f
234
#define BRCMF_SKB_IF_FLAGS_INDEX_SHIFT 0
235
236
#define brcmf_skb_if_flags_set_field(skb, field, value) \
237
brcmu_maskset16(&(brcmf_skbcb(skb)->if_flags), \
238
BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
239
BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT, (value))
240
#define brcmf_skb_if_flags_get_field(skb, field) \
241
brcmu_maskget16(brcmf_skbcb(skb)->if_flags, \
242
BRCMF_SKB_IF_FLAGS_ ## field ## _MASK, \
243
BRCMF_SKB_IF_FLAGS_ ## field ## _SHIFT)
244
245
/*
246
* sk_buff control packet identifier
247
*
248
* 32-bit packet identifier used in PKTTAG tlv from host to dongle.
249
*
250
* - Generated at the host (e.g. dhd)
251
* - Seen as a generic sequence number by firmware except for the flags field.
252
*
253
* Generation : b[31] => generation number for this packet [host->fw]
254
* OR, current generation number [fw->host]
255
* Flags : b[30:27] => command, status flags
256
* FIFO-AC : b[26:24] => AC-FIFO id
257
* h-slot : b[23:8] => hanger-slot
258
* freerun : b[7:0] => A free running counter
259
*/
260
#define BRCMF_SKB_HTOD_TAG_GENERATION_MASK 0x80000000
261
#define BRCMF_SKB_HTOD_TAG_GENERATION_SHIFT 31
262
#define BRCMF_SKB_HTOD_TAG_FLAGS_MASK 0x78000000
263
#define BRCMF_SKB_HTOD_TAG_FLAGS_SHIFT 27
264
#define BRCMF_SKB_HTOD_TAG_FIFO_MASK 0x07000000
265
#define BRCMF_SKB_HTOD_TAG_FIFO_SHIFT 24
266
#define BRCMF_SKB_HTOD_TAG_HSLOT_MASK 0x00ffff00
267
#define BRCMF_SKB_HTOD_TAG_HSLOT_SHIFT 8
268
#define BRCMF_SKB_HTOD_TAG_FREERUN_MASK 0x000000ff
269
#define BRCMF_SKB_HTOD_TAG_FREERUN_SHIFT 0
270
271
#define brcmf_skb_htod_tag_set_field(skb, field, value) \
272
brcmu_maskset32(&(brcmf_skbcb(skb)->htod), \
273
BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
274
BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT, (value))
275
#define brcmf_skb_htod_tag_get_field(skb, field) \
276
brcmu_maskget32(brcmf_skbcb(skb)->htod, \
277
BRCMF_SKB_HTOD_TAG_ ## field ## _MASK, \
278
BRCMF_SKB_HTOD_TAG_ ## field ## _SHIFT)
279
280
#define BRCMF_SKB_HTOD_SEQ_FROMFW_MASK 0x2000
281
#define BRCMF_SKB_HTOD_SEQ_FROMFW_SHIFT 13
282
#define BRCMF_SKB_HTOD_SEQ_FROMDRV_MASK 0x1000
283
#define BRCMF_SKB_HTOD_SEQ_FROMDRV_SHIFT 12
284
#define BRCMF_SKB_HTOD_SEQ_NR_MASK 0x0fff
285
#define BRCMF_SKB_HTOD_SEQ_NR_SHIFT 0
286
287
#define brcmf_skb_htod_seq_set_field(skb, field, value) \
288
brcmu_maskset16(&(brcmf_skbcb(skb)->htod_seq), \
289
BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
290
BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT, (value))
291
#define brcmf_skb_htod_seq_get_field(skb, field) \
292
brcmu_maskget16(brcmf_skbcb(skb)->htod_seq, \
293
BRCMF_SKB_HTOD_SEQ_ ## field ## _MASK, \
294
BRCMF_SKB_HTOD_SEQ_ ## field ## _SHIFT)
295
296
#define BRCMF_FWS_TXSTAT_GENERATION_MASK 0x80000000
297
#define BRCMF_FWS_TXSTAT_GENERATION_SHIFT 31
298
#define BRCMF_FWS_TXSTAT_FLAGS_MASK 0x78000000
299
#define BRCMF_FWS_TXSTAT_FLAGS_SHIFT 27
300
#define BRCMF_FWS_TXSTAT_FIFO_MASK 0x07000000
301
#define BRCMF_FWS_TXSTAT_FIFO_SHIFT 24
302
#define BRCMF_FWS_TXSTAT_HSLOT_MASK 0x00FFFF00
303
#define BRCMF_FWS_TXSTAT_HSLOT_SHIFT 8
304
#define BRCMF_FWS_TXSTAT_FREERUN_MASK 0x000000FF
305
#define BRCMF_FWS_TXSTAT_FREERUN_SHIFT 0
306
307
#define brcmf_txstatus_get_field(txs, field) \
308
brcmu_maskget32(txs, BRCMF_FWS_TXSTAT_ ## field ## _MASK, \
309
BRCMF_FWS_TXSTAT_ ## field ## _SHIFT)
310
311
/* How long to defer borrowing in jiffies */
312
#define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
313
314
315
/**
316
* enum brcmf_fws_txstatus - txstatus flag values.
317
*
318
* @BRCMF_FWS_TXSTATUS_DISCARD:
319
* host is free to discard the packet.
320
* @BRCMF_FWS_TXSTATUS_CORE_SUPPRESS:
321
* 802.11 core suppressed the packet.
322
* @BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS:
323
* firmware suppress the packet as device is already in PS mode.
324
* @BRCMF_FWS_TXSTATUS_FW_TOSSED:
325
* firmware tossed the packet.
326
* @BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK:
327
* firmware tossed the packet after retries.
328
* @BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED:
329
* firmware wrongly reported suppressed previously, now fixing to acked.
330
* @BRCMF_FWS_TXSTATUS_HOST_TOSSED:
331
* host tossed the packet.
332
*/
333
enum brcmf_fws_txstatus {
334
BRCMF_FWS_TXSTATUS_DISCARD,
335
BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
336
BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
337
BRCMF_FWS_TXSTATUS_FW_TOSSED,
338
BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK,
339
BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED,
340
BRCMF_FWS_TXSTATUS_HOST_TOSSED
341
};
342
343
enum brcmf_fws_fcmode {
344
BRCMF_FWS_FCMODE_NONE,
345
BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
346
BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
347
};
348
349
enum brcmf_fws_mac_desc_state {
350
BRCMF_FWS_STATE_OPEN = 1,
351
BRCMF_FWS_STATE_CLOSE
352
};
353
354
/**
355
* struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
356
*
357
* @name: name of the descriptor.
358
* @occupied: slot is in use.
359
* @mac_handle: handle for mac entry determined by firmware.
360
* @interface_id: interface index.
361
* @state: current state.
362
* @suppressed: mac entry is suppressed.
363
* @generation: generation bit.
364
* @ac_bitmap: ac queue bitmap.
365
* @requested_credit: credits requested by firmware.
366
* @requested_packet: packet requested by firmware.
367
* @ea: ethernet address.
368
* @seq: per-node free-running sequence.
369
* @psq: power-save queue.
370
* @transit_count: packet in transit to firmware.
371
* @suppr_transit_count: suppressed packet in transit to firmware.
372
* @send_tim_signal: if set tim signal will be sent.
373
* @traffic_pending_bmp: traffic pending bitmap.
374
* @traffic_lastreported_bmp: traffic last reported bitmap.
375
*/
376
struct brcmf_fws_mac_descriptor {
377
char name[16];
378
u8 occupied;
379
u8 mac_handle;
380
u8 interface_id;
381
u8 state;
382
bool suppressed;
383
u8 generation;
384
u8 ac_bitmap;
385
u8 requested_credit;
386
u8 requested_packet;
387
u8 ea[ETH_ALEN];
388
u8 seq[BRCMF_FWS_FIFO_COUNT];
389
struct pktq psq;
390
int transit_count;
391
int suppr_transit_count;
392
bool send_tim_signal;
393
u8 traffic_pending_bmp;
394
u8 traffic_lastreported_bmp;
395
};
396
397
#define BRCMF_FWS_HANGER_MAXITEMS 3072
398
#define BRCMF_BORROW_RATIO 3
399
400
/**
401
* enum brcmf_fws_hanger_item_state - state of hanger item.
402
*
403
* @BRCMF_FWS_HANGER_ITEM_STATE_FREE: item is free for use.
404
* @BRCMF_FWS_HANGER_ITEM_STATE_INUSE: item is in use.
405
* @BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED: item was suppressed.
406
*/
407
enum brcmf_fws_hanger_item_state {
408
BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
409
BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
410
BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
411
};
412
413
414
/**
415
* struct brcmf_fws_hanger_item - single entry for tx pending packet.
416
*
417
* @state: entry is either free or occupied.
418
* @pkt: packet itself.
419
*/
420
struct brcmf_fws_hanger_item {
421
enum brcmf_fws_hanger_item_state state;
422
struct sk_buff *pkt;
423
};
424
425
/**
426
* struct brcmf_fws_hanger - holds packets awaiting firmware txstatus.
427
*
428
* @pushed: packets pushed to await txstatus.
429
* @popped: packets popped upon handling txstatus.
430
* @failed_to_push: packets that could not be pushed.
431
* @failed_to_pop: packets that could not be popped.
432
* @failed_slotfind: packets for which failed to find an entry.
433
* @slot_pos: last returned item index for a free entry.
434
* @items: array of hanger items.
435
*/
436
struct brcmf_fws_hanger {
437
u32 pushed;
438
u32 popped;
439
u32 failed_to_push;
440
u32 failed_to_pop;
441
u32 failed_slotfind;
442
u32 slot_pos;
443
struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
444
};
445
446
struct brcmf_fws_macdesc_table {
447
struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
448
struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
449
struct brcmf_fws_mac_descriptor other;
450
};
451
452
struct brcmf_fws_stats {
453
u32 tlv_parse_failed;
454
u32 tlv_invalid_type;
455
u32 header_only_pkt;
456
u32 header_pulls;
457
u32 pkt2bus;
458
u32 send_pkts[5];
459
u32 requested_sent[5];
460
u32 generic_error;
461
u32 mac_update_failed;
462
u32 mac_ps_update_failed;
463
u32 if_update_failed;
464
u32 packet_request_failed;
465
u32 credit_request_failed;
466
u32 rollback_success;
467
u32 rollback_failed;
468
u32 delayq_full_error;
469
u32 supprq_full_error;
470
u32 txs_indicate;
471
u32 txs_discard;
472
u32 txs_supp_core;
473
u32 txs_supp_ps;
474
u32 txs_tossed;
475
u32 txs_host_tossed;
476
u32 bus_flow_block;
477
u32 fws_flow_block;
478
};
479
480
struct brcmf_fws_info {
481
struct brcmf_pub *drvr;
482
spinlock_t spinlock;
483
ulong flags;
484
struct brcmf_fws_stats stats;
485
struct brcmf_fws_hanger hanger;
486
enum brcmf_fws_fcmode fcmode;
487
bool fw_signals;
488
bool bcmc_credit_check;
489
struct brcmf_fws_macdesc_table desc;
490
struct workqueue_struct *fws_wq;
491
struct work_struct fws_dequeue_work;
492
u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
493
int fifo_credit[BRCMF_FWS_FIFO_COUNT];
494
int init_fifo_credit[BRCMF_FWS_FIFO_COUNT];
495
int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1]
496
[BRCMF_FWS_FIFO_AC_VO + 1];
497
int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
498
u32 fifo_credit_map;
499
u32 fifo_delay_map;
500
unsigned long borrow_defer_timestamp;
501
bool bus_flow_blocked;
502
bool creditmap_received;
503
u8 mode;
504
bool avoid_queueing;
505
};
506
507
#define BRCMF_FWS_TLV_DEF(name, id, len) \
508
case BRCMF_FWS_TYPE_ ## name: \
509
return len;
510
511
/**
512
* brcmf_fws_get_tlv_len() - returns defined length for given tlv id.
513
*
514
* @fws: firmware-signalling information.
515
* @id: identifier of the TLV.
516
*
517
* Return: the specified length for the given TLV; Otherwise -EINVAL.
518
*/
519
static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
520
enum brcmf_fws_tlv_type id)
521
{
522
switch (id) {
523
BRCMF_FWS_TLV_DEFLIST
524
default:
525
fws->stats.tlv_invalid_type++;
526
break;
527
}
528
return -EINVAL;
529
}
530
#undef BRCMF_FWS_TLV_DEF
531
532
static void brcmf_fws_lock(struct brcmf_fws_info *fws)
533
__acquires(&fws->spinlock)
534
{
535
spin_lock_irqsave(&fws->spinlock, fws->flags);
536
}
537
538
static void brcmf_fws_unlock(struct brcmf_fws_info *fws)
539
__releases(&fws->spinlock)
540
{
541
spin_unlock_irqrestore(&fws->spinlock, fws->flags);
542
}
543
544
static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
545
{
546
u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
547
return ifidx == *(int *)arg;
548
}
549
550
static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
551
{
552
int i;
553
554
memset(hanger, 0, sizeof(*hanger));
555
for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
556
hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
557
}
558
559
static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
560
{
561
u32 i;
562
563
i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
564
565
while (i != h->slot_pos) {
566
if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
567
h->slot_pos = i;
568
goto done;
569
}
570
i++;
571
if (i == BRCMF_FWS_HANGER_MAXITEMS)
572
i = 0;
573
}
574
brcmf_err("all slots occupied\n");
575
h->failed_slotfind++;
576
i = BRCMF_FWS_HANGER_MAXITEMS;
577
done:
578
return i;
579
}
580
581
static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
582
struct sk_buff *pkt, u32 slot_id)
583
{
584
if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
585
return -ENOENT;
586
587
if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
588
brcmf_err("slot is not free\n");
589
h->failed_to_push++;
590
return -EINVAL;
591
}
592
593
h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
594
h->items[slot_id].pkt = pkt;
595
h->pushed++;
596
return 0;
597
}
598
599
static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
600
u32 slot_id, struct sk_buff **pktout,
601
bool remove_item)
602
{
603
if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
604
return -ENOENT;
605
606
if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
607
brcmf_err("entry not in use\n");
608
h->failed_to_pop++;
609
return -EINVAL;
610
}
611
612
*pktout = h->items[slot_id].pkt;
613
if (remove_item) {
614
h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
615
h->items[slot_id].pkt = NULL;
616
h->popped++;
617
}
618
return 0;
619
}
620
621
static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
622
int ifidx)
623
{
624
struct brcmf_fws_hanger_item *hi;
625
bool (*matchfn)(struct sk_buff *, void *) = NULL;
626
struct sk_buff *skb;
627
int prec;
628
u32 hslot;
629
630
if (ifidx != -1)
631
matchfn = brcmf_fws_ifidx_match;
632
for (prec = 0; prec < q->num_prec; prec++) {
633
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
634
while (skb) {
635
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
636
hi = &fws->hanger.items[hslot];
637
WARN_ON(skb != hi->pkt);
638
hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
639
brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
640
true);
641
brcmu_pkt_buf_free_skb(skb);
642
skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
643
}
644
}
645
}
646
647
static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
648
u32 slot_id)
649
{
650
if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
651
return -ENOENT;
652
653
if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
654
brcmf_err("entry not in use\n");
655
return -EINVAL;
656
}
657
658
h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
659
return 0;
660
}
661
662
static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
663
bool (*fn)(struct sk_buff *, void *),
664
int ifidx)
665
{
666
struct brcmf_fws_hanger *h = &fws->hanger;
667
struct sk_buff *skb;
668
int i;
669
enum brcmf_fws_hanger_item_state s;
670
671
for (i = 0; i < ARRAY_SIZE(h->items); i++) {
672
s = h->items[i].state;
673
if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
674
s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
675
skb = h->items[i].pkt;
676
if (fn == NULL || fn(skb, &ifidx)) {
677
/* suppress packets freed from psq */
678
if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
679
brcmu_pkt_buf_free_skb(skb);
680
h->items[i].state =
681
BRCMF_FWS_HANGER_ITEM_STATE_FREE;
682
}
683
}
684
}
685
}
686
687
static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
688
struct brcmf_fws_mac_descriptor *desc)
689
{
690
if (desc == &fws->desc.other)
691
strscpy(desc->name, "MAC-OTHER", sizeof(desc->name));
692
else if (desc->mac_handle)
693
scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
694
desc->mac_handle, desc->interface_id);
695
else
696
scnprintf(desc->name, sizeof(desc->name), "MACIF:%d",
697
desc->interface_id);
698
}
699
700
static void brcmf_fws_macdesc_init(struct brcmf_fws_mac_descriptor *desc,
701
u8 *addr, u8 ifidx)
702
{
703
brcmf_dbg(TRACE,
704
"enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
705
desc->occupied = 1;
706
desc->state = BRCMF_FWS_STATE_OPEN;
707
desc->requested_credit = 0;
708
desc->requested_packet = 0;
709
/* depending on use may need ifp->bsscfgidx instead */
710
desc->interface_id = ifidx;
711
desc->ac_bitmap = 0xff; /* update this when handling APSD */
712
if (addr)
713
memcpy(&desc->ea[0], addr, ETH_ALEN);
714
}
715
716
static
717
void brcmf_fws_macdesc_deinit(struct brcmf_fws_mac_descriptor *desc)
718
{
719
brcmf_dbg(TRACE,
720
"enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
721
desc->occupied = 0;
722
desc->state = BRCMF_FWS_STATE_CLOSE;
723
desc->requested_credit = 0;
724
desc->requested_packet = 0;
725
}
726
727
static struct brcmf_fws_mac_descriptor *
728
brcmf_fws_macdesc_lookup(struct brcmf_fws_info *fws, u8 *ea)
729
{
730
struct brcmf_fws_mac_descriptor *entry;
731
int i;
732
733
if (ea == NULL)
734
return ERR_PTR(-EINVAL);
735
736
entry = &fws->desc.nodes[0];
737
for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
738
if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
739
return entry;
740
entry++;
741
}
742
743
return ERR_PTR(-ENOENT);
744
}
745
746
static struct brcmf_fws_mac_descriptor*
747
brcmf_fws_macdesc_find(struct brcmf_fws_info *fws, struct brcmf_if *ifp, u8 *da)
748
{
749
struct brcmf_fws_mac_descriptor *entry;
750
bool multicast;
751
752
multicast = is_multicast_ether_addr(da);
753
754
/* Multicast destination, STA and P2P clients get the interface entry.
755
* STA/GC gets the Mac Entry for TDLS destinations, TDLS destinations
756
* have their own entry.
757
*/
758
if (multicast && ifp->fws_desc) {
759
entry = ifp->fws_desc;
760
goto done;
761
}
762
763
entry = brcmf_fws_macdesc_lookup(fws, da);
764
if (IS_ERR(entry))
765
entry = ifp->fws_desc;
766
767
done:
768
return entry;
769
}
770
771
static bool brcmf_fws_macdesc_closed(struct brcmf_fws_info *fws,
772
struct brcmf_fws_mac_descriptor *entry,
773
int fifo)
774
{
775
struct brcmf_fws_mac_descriptor *if_entry;
776
bool closed;
777
778
/* for unique destination entries the related interface
779
* may be closed.
780
*/
781
if (entry->mac_handle) {
782
if_entry = &fws->desc.iface[entry->interface_id];
783
if (if_entry->state == BRCMF_FWS_STATE_CLOSE)
784
return true;
785
}
786
/* an entry is closed when the state is closed and
787
* the firmware did not request anything.
788
*/
789
closed = entry->state == BRCMF_FWS_STATE_CLOSE &&
790
!entry->requested_credit && !entry->requested_packet;
791
792
/* Or firmware does not allow traffic for given fifo */
793
return closed || !(entry->ac_bitmap & BIT(fifo));
794
}
795
796
static void brcmf_fws_macdesc_cleanup(struct brcmf_fws_info *fws,
797
struct brcmf_fws_mac_descriptor *entry,
798
int ifidx)
799
{
800
if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
801
brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
802
entry->occupied = !!(entry->psq.len);
803
}
804
}
805
806
static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
807
bool (*fn)(struct sk_buff *, void *),
808
int ifidx)
809
{
810
struct brcmf_fws_hanger_item *hi;
811
struct pktq *txq;
812
struct sk_buff *skb;
813
int prec;
814
u32 hslot;
815
816
txq = brcmf_bus_gettxq(fws->drvr->bus_if);
817
if (IS_ERR(txq)) {
818
brcmf_dbg(TRACE, "no txq to clean up\n");
819
return;
820
}
821
822
for (prec = 0; prec < txq->num_prec; prec++) {
823
skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
824
while (skb) {
825
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
826
hi = &fws->hanger.items[hslot];
827
WARN_ON(skb != hi->pkt);
828
hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
829
brcmu_pkt_buf_free_skb(skb);
830
skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
831
}
832
}
833
}
834
835
static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
836
{
837
int i;
838
struct brcmf_fws_mac_descriptor *table;
839
bool (*matchfn)(struct sk_buff *, void *) = NULL;
840
841
if (fws == NULL)
842
return;
843
844
if (ifidx != -1)
845
matchfn = brcmf_fws_ifidx_match;
846
847
/* cleanup individual nodes */
848
table = &fws->desc.nodes[0];
849
for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
850
brcmf_fws_macdesc_cleanup(fws, &table[i], ifidx);
851
852
brcmf_fws_macdesc_cleanup(fws, &fws->desc.other, ifidx);
853
brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
854
brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
855
}
856
857
static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
858
{
859
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
860
u8 *wlh;
861
u16 data_offset = 0;
862
u8 fillers;
863
__le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
864
__le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq);
865
866
brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",
867
entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
868
(le32_to_cpu(pkttag) >> 8) & 0xffff,
869
brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);
870
if (entry->send_tim_signal)
871
data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
872
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
873
data_offset += BRCMF_FWS_TYPE_SEQ_LEN;
874
/* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
875
data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
876
fillers = round_up(data_offset, 4) - data_offset;
877
data_offset += fillers;
878
879
skb_push(skb, data_offset);
880
wlh = skb->data;
881
882
wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
883
wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
884
memcpy(&wlh[2], &pkttag, sizeof(pkttag));
885
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
886
wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN;
887
memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq,
888
sizeof(pktseq));
889
}
890
wlh += wlh[1] + 2;
891
892
if (entry->send_tim_signal) {
893
entry->send_tim_signal = false;
894
wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
895
wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
896
wlh[2] = entry->mac_handle;
897
wlh[3] = entry->traffic_pending_bmp;
898
brcmf_dbg(TRACE, "adding TIM info: handle %d bmp 0x%X\n",
899
entry->mac_handle, entry->traffic_pending_bmp);
900
wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
901
entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
902
}
903
if (fillers)
904
memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
905
906
return (u8)(data_offset >> 2);
907
}
908
909
static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
910
struct brcmf_fws_mac_descriptor *entry,
911
int fifo, bool send_immediately)
912
{
913
struct sk_buff *skb;
914
struct brcmf_skbuff_cb *skcb;
915
s32 err;
916
u32 len;
917
u8 data_offset;
918
int ifidx;
919
920
/* check delayedQ and suppressQ in one call using bitmap */
921
if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
922
entry->traffic_pending_bmp &= ~NBITVAL(fifo);
923
else
924
entry->traffic_pending_bmp |= NBITVAL(fifo);
925
926
entry->send_tim_signal = false;
927
if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
928
entry->send_tim_signal = true;
929
if (send_immediately && entry->send_tim_signal &&
930
entry->state == BRCMF_FWS_STATE_CLOSE) {
931
/* create a dummy packet and sent that. The traffic */
932
/* bitmap info will automatically be attached to that packet */
933
len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
934
BRCMF_FWS_TYPE_SEQ_LEN +
935
BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
936
4 + fws->drvr->hdrlen;
937
skb = brcmu_pkt_buf_get_skb(len);
938
if (skb == NULL)
939
return false;
940
skb_pull(skb, len);
941
skcb = brcmf_skbcb(skb);
942
skcb->mac = entry;
943
skcb->state = BRCMF_FWS_SKBSTATE_TIM;
944
skcb->htod = 0;
945
skcb->htod_seq = 0;
946
data_offset = brcmf_fws_hdrpush(fws, skb);
947
ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
948
brcmf_fws_unlock(fws);
949
err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
950
brcmf_fws_lock(fws);
951
if (err)
952
brcmu_pkt_buf_free_skb(skb);
953
return true;
954
}
955
return false;
956
}
957
958
static void
959
brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
960
u8 if_id)
961
{
962
struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
963
964
if (WARN_ON(!ifp))
965
return;
966
967
if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
968
pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
969
brcmf_txflowblock_if(ifp,
970
BRCMF_NETIF_STOP_REASON_FWS_FC, false);
971
if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
972
pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER) {
973
fws->stats.fws_flow_block++;
974
brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
975
}
976
return;
977
}
978
979
static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
980
{
981
brcmf_dbg(CTL, "rssi %d\n", rssi);
982
return 0;
983
}
984
985
static
986
int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
987
{
988
struct brcmf_fws_mac_descriptor *entry, *existing;
989
u8 mac_handle;
990
u8 ifidx;
991
u8 *addr;
992
993
mac_handle = *data++;
994
ifidx = *data++;
995
addr = data;
996
997
entry = &fws->desc.nodes[mac_handle & 0x1F];
998
if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
999
if (entry->occupied) {
1000
brcmf_dbg(TRACE, "deleting %s mac %pM\n",
1001
entry->name, addr);
1002
brcmf_fws_lock(fws);
1003
brcmf_fws_macdesc_cleanup(fws, entry, -1);
1004
brcmf_fws_macdesc_deinit(entry);
1005
brcmf_fws_unlock(fws);
1006
} else
1007
fws->stats.mac_update_failed++;
1008
return 0;
1009
}
1010
1011
existing = brcmf_fws_macdesc_lookup(fws, addr);
1012
if (IS_ERR(existing)) {
1013
if (!entry->occupied) {
1014
brcmf_fws_lock(fws);
1015
entry->mac_handle = mac_handle;
1016
brcmf_fws_macdesc_init(entry, addr, ifidx);
1017
brcmf_fws_macdesc_set_name(fws, entry);
1018
brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
1019
BRCMF_FWS_PSQ_LEN);
1020
brcmf_fws_unlock(fws);
1021
brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
1022
} else {
1023
fws->stats.mac_update_failed++;
1024
}
1025
} else {
1026
if (entry != existing) {
1027
brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
1028
brcmf_fws_lock(fws);
1029
memcpy(entry, existing,
1030
offsetof(struct brcmf_fws_mac_descriptor, psq));
1031
entry->mac_handle = mac_handle;
1032
brcmf_fws_macdesc_deinit(existing);
1033
brcmf_fws_macdesc_set_name(fws, entry);
1034
brcmf_fws_unlock(fws);
1035
brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
1036
addr);
1037
} else {
1038
brcmf_dbg(TRACE, "use existing\n");
1039
WARN_ON(entry->mac_handle != mac_handle);
1040
/* TODO: what should we do here: continue, reinit, .. */
1041
}
1042
}
1043
return 0;
1044
}
1045
1046
static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
1047
u8 type, u8 *data)
1048
{
1049
struct brcmf_fws_mac_descriptor *entry;
1050
u8 mac_handle;
1051
int ret;
1052
1053
mac_handle = data[0];
1054
entry = &fws->desc.nodes[mac_handle & 0x1F];
1055
if (!entry->occupied) {
1056
fws->stats.mac_ps_update_failed++;
1057
return -ESRCH;
1058
}
1059
brcmf_fws_lock(fws);
1060
/* a state update should wipe old credits */
1061
entry->requested_credit = 0;
1062
entry->requested_packet = 0;
1063
if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
1064
entry->state = BRCMF_FWS_STATE_OPEN;
1065
ret = BRCMF_FWS_RET_OK_SCHEDULE;
1066
} else {
1067
entry->state = BRCMF_FWS_STATE_CLOSE;
1068
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
1069
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
1070
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
1071
brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
1072
ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1073
}
1074
brcmf_fws_unlock(fws);
1075
return ret;
1076
}
1077
1078
static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
1079
u8 type, u8 *data)
1080
{
1081
struct brcmf_fws_mac_descriptor *entry;
1082
u8 ifidx;
1083
int ret;
1084
1085
ifidx = data[0];
1086
1087
if (ifidx >= BRCMF_MAX_IFS) {
1088
ret = -ERANGE;
1089
goto fail;
1090
}
1091
1092
entry = &fws->desc.iface[ifidx];
1093
if (!entry->occupied) {
1094
ret = -ESRCH;
1095
goto fail;
1096
}
1097
1098
brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
1099
entry->name);
1100
brcmf_fws_lock(fws);
1101
switch (type) {
1102
case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1103
entry->state = BRCMF_FWS_STATE_OPEN;
1104
ret = BRCMF_FWS_RET_OK_SCHEDULE;
1105
break;
1106
case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1107
entry->state = BRCMF_FWS_STATE_CLOSE;
1108
ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1109
break;
1110
default:
1111
ret = -EINVAL;
1112
brcmf_fws_unlock(fws);
1113
goto fail;
1114
}
1115
brcmf_fws_unlock(fws);
1116
return ret;
1117
1118
fail:
1119
fws->stats.if_update_failed++;
1120
return ret;
1121
}
1122
1123
static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
1124
u8 *data)
1125
{
1126
struct brcmf_fws_mac_descriptor *entry;
1127
1128
entry = &fws->desc.nodes[data[1] & 0x1F];
1129
if (!entry->occupied) {
1130
if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1131
fws->stats.credit_request_failed++;
1132
else
1133
fws->stats.packet_request_failed++;
1134
return -ESRCH;
1135
}
1136
1137
brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
1138
brcmf_fws_get_tlv_name(type), type, entry->name,
1139
data[0], data[2]);
1140
brcmf_fws_lock(fws);
1141
if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1142
entry->requested_credit = data[0];
1143
else
1144
entry->requested_packet = data[0];
1145
1146
entry->ac_bitmap = data[2];
1147
brcmf_fws_unlock(fws);
1148
return BRCMF_FWS_RET_OK_SCHEDULE;
1149
}
1150
1151
static void
1152
brcmf_fws_macdesc_use_req_credit(struct brcmf_fws_mac_descriptor *entry,
1153
struct sk_buff *skb)
1154
{
1155
if (entry->requested_credit > 0) {
1156
entry->requested_credit--;
1157
brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1158
brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
1159
if (entry->state != BRCMF_FWS_STATE_CLOSE)
1160
brcmf_err("requested credit set while mac not closed!\n");
1161
} else if (entry->requested_packet > 0) {
1162
entry->requested_packet--;
1163
brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1164
brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1165
if (entry->state != BRCMF_FWS_STATE_CLOSE)
1166
brcmf_err("requested packet set while mac not closed!\n");
1167
} else {
1168
brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
1169
brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1170
}
1171
}
1172
1173
static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
1174
{
1175
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1176
1177
if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
1178
(entry->state == BRCMF_FWS_STATE_CLOSE))
1179
entry->requested_credit++;
1180
}
1181
1182
static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
1183
u8 fifo, u8 credits)
1184
{
1185
int lender_ac;
1186
int *borrowed;
1187
int *fifo_credit;
1188
1189
if (!credits)
1190
return;
1191
1192
fws->fifo_credit_map |= 1 << fifo;
1193
1194
if (fifo > BRCMF_FWS_FIFO_AC_BK &&
1195
fifo <= BRCMF_FWS_FIFO_AC_VO) {
1196
for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
1197
lender_ac--) {
1198
borrowed = &fws->credits_borrowed[fifo][lender_ac];
1199
if (*borrowed) {
1200
fws->fifo_credit_map |= (1 << lender_ac);
1201
fifo_credit = &fws->fifo_credit[lender_ac];
1202
if (*borrowed >= credits) {
1203
*borrowed -= credits;
1204
*fifo_credit += credits;
1205
return;
1206
} else {
1207
credits -= *borrowed;
1208
*fifo_credit += *borrowed;
1209
*borrowed = 0;
1210
}
1211
}
1212
}
1213
}
1214
1215
if (credits) {
1216
fws->fifo_credit[fifo] += credits;
1217
}
1218
1219
if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo])
1220
fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo];
1221
1222
}
1223
1224
static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
1225
{
1226
/* only schedule dequeue when there are credits for delayed traffic */
1227
if ((fws->fifo_credit_map & fws->fifo_delay_map) ||
1228
(!brcmf_fws_fc_active(fws) && fws->fifo_delay_map))
1229
queue_work(fws->fws_wq, &fws->fws_dequeue_work);
1230
}
1231
1232
static int brcmf_fws_enq(struct brcmf_fws_info *fws,
1233
enum brcmf_fws_skb_state state, int fifo,
1234
struct sk_buff *p)
1235
{
1236
struct brcmf_pub *drvr = fws->drvr;
1237
int prec = 2 * fifo;
1238
u32 *qfull_stat = &fws->stats.delayq_full_error;
1239
struct brcmf_fws_mac_descriptor *entry;
1240
struct pktq *pq;
1241
struct sk_buff_head *queue;
1242
struct sk_buff *p_head;
1243
struct sk_buff *p_tail;
1244
u32 fr_new;
1245
u32 fr_compare;
1246
1247
entry = brcmf_skbcb(p)->mac;
1248
if (entry == NULL) {
1249
bphy_err(drvr, "no mac descriptor found for skb %p\n", p);
1250
return -ENOENT;
1251
}
1252
1253
brcmf_dbg(DATA, "enter: fifo %d skb %p\n", fifo, p);
1254
if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
1255
prec += 1;
1256
qfull_stat = &fws->stats.supprq_full_error;
1257
1258
/* Fix out of order delivery of frames. Dont assume frame */
1259
/* can be inserted at the end, but look for correct position */
1260
pq = &entry->psq;
1261
if (pktq_full(pq) || pktq_pfull(pq, prec)) {
1262
*qfull_stat += 1;
1263
return -ENFILE;
1264
}
1265
queue = &pq->q[prec].skblist;
1266
1267
p_head = skb_peek(queue);
1268
p_tail = skb_peek_tail(queue);
1269
fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN);
1270
1271
while (p_head != p_tail) {
1272
fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1273
FREERUN);
1274
/* be sure to handle wrap of 256 */
1275
if (((fr_new > fr_compare) &&
1276
((fr_new - fr_compare) < 128)) ||
1277
((fr_new < fr_compare) &&
1278
((fr_compare - fr_new) > 128)))
1279
break;
1280
p_tail = skb_queue_prev(queue, p_tail);
1281
}
1282
/* Position found. Determine what to do */
1283
if (p_tail == NULL) {
1284
/* empty list */
1285
__skb_queue_tail(queue, p);
1286
} else {
1287
fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1288
FREERUN);
1289
if (((fr_new > fr_compare) &&
1290
((fr_new - fr_compare) < 128)) ||
1291
((fr_new < fr_compare) &&
1292
((fr_compare - fr_new) > 128))) {
1293
/* After tail */
1294
__skb_queue_after(queue, p_tail, p);
1295
} else {
1296
/* Before tail */
1297
__skb_insert(p, p_tail->prev, p_tail, queue);
1298
}
1299
}
1300
1301
/* Complete the counters and statistics */
1302
pq->len++;
1303
if (pq->hi_prec < prec)
1304
pq->hi_prec = (u8) prec;
1305
} else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
1306
*qfull_stat += 1;
1307
return -ENFILE;
1308
}
1309
1310
/* increment total enqueued packet count */
1311
fws->fifo_delay_map |= 1 << fifo;
1312
fws->fifo_enqpkt[fifo]++;
1313
1314
/* update the sk_buff state */
1315
brcmf_skbcb(p)->state = state;
1316
1317
/*
1318
* A packet has been pushed so update traffic
1319
* availability bitmap, if applicable
1320
*/
1321
brcmf_fws_tim_update(fws, entry, fifo, true);
1322
brcmf_fws_flow_control_check(fws, &entry->psq,
1323
brcmf_skb_if_flags_get_field(p, INDEX));
1324
return 0;
1325
}
1326
1327
static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
1328
{
1329
struct brcmf_fws_mac_descriptor *table;
1330
struct brcmf_fws_mac_descriptor *entry;
1331
struct sk_buff *p;
1332
int num_nodes;
1333
int node_pos;
1334
int prec_out;
1335
int pmsk;
1336
int i;
1337
1338
table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
1339
num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
1340
node_pos = fws->deq_node_pos[fifo];
1341
1342
for (i = 0; i < num_nodes; i++) {
1343
entry = &table[(node_pos + i) % num_nodes];
1344
if (!entry->occupied ||
1345
brcmf_fws_macdesc_closed(fws, entry, fifo))
1346
continue;
1347
1348
if (entry->suppressed)
1349
pmsk = 2;
1350
else
1351
pmsk = 3;
1352
p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
1353
if (p == NULL) {
1354
if (entry->suppressed) {
1355
if (entry->suppr_transit_count)
1356
continue;
1357
entry->suppressed = false;
1358
p = brcmu_pktq_mdeq(&entry->psq,
1359
1 << (fifo * 2), &prec_out);
1360
}
1361
}
1362
if (p == NULL)
1363
continue;
1364
1365
brcmf_fws_macdesc_use_req_credit(entry, p);
1366
1367
/* move dequeue position to ensure fair round-robin */
1368
fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
1369
brcmf_fws_flow_control_check(fws, &entry->psq,
1370
brcmf_skb_if_flags_get_field(p,
1371
INDEX)
1372
);
1373
/*
1374
* A packet has been picked up, update traffic
1375
* availability bitmap, if applicable
1376
*/
1377
brcmf_fws_tim_update(fws, entry, fifo, false);
1378
1379
/*
1380
* decrement total enqueued fifo packets and
1381
* clear delay bitmap if done.
1382
*/
1383
fws->fifo_enqpkt[fifo]--;
1384
if (fws->fifo_enqpkt[fifo] == 0)
1385
fws->fifo_delay_map &= ~(1 << fifo);
1386
goto done;
1387
}
1388
p = NULL;
1389
done:
1390
brcmf_dbg(DATA, "exit: fifo %d skb %p\n", fifo, p);
1391
return p;
1392
}
1393
1394
static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1395
struct sk_buff *skb,
1396
u32 genbit, u16 seq)
1397
{
1398
struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1399
u32 hslot;
1400
int ret;
1401
1402
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1403
1404
/* this packet was suppressed */
1405
if (!entry->suppressed) {
1406
entry->suppressed = true;
1407
entry->suppr_transit_count = entry->transit_count;
1408
brcmf_dbg(DATA, "suppress %s: transit %d\n",
1409
entry->name, entry->transit_count);
1410
}
1411
1412
entry->generation = genbit;
1413
1414
brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
1415
brcmf_skbcb(skb)->htod_seq = seq;
1416
if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
1417
brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
1418
brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
1419
} else {
1420
brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
1421
}
1422
ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
1423
1424
if (ret != 0) {
1425
/* suppress q is full drop this packet */
1426
brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true);
1427
} else {
1428
/* Mark suppressed to avoid a double free during wlfc cleanup */
1429
brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
1430
}
1431
1432
return ret;
1433
}
1434
1435
static int
1436
brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1437
u32 genbit, u16 seq, u8 compcnt)
1438
{
1439
struct brcmf_pub *drvr = fws->drvr;
1440
u32 fifo;
1441
u8 cnt = 0;
1442
int ret;
1443
bool remove_from_hanger = true;
1444
struct sk_buff *skb;
1445
struct brcmf_skbuff_cb *skcb;
1446
struct brcmf_fws_mac_descriptor *entry = NULL;
1447
struct brcmf_if *ifp;
1448
1449
brcmf_dbg(DATA, "flags %d\n", flags);
1450
1451
if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
1452
fws->stats.txs_discard += compcnt;
1453
else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
1454
fws->stats.txs_supp_core += compcnt;
1455
remove_from_hanger = false;
1456
} else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
1457
fws->stats.txs_supp_ps += compcnt;
1458
remove_from_hanger = false;
1459
} else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
1460
fws->stats.txs_tossed += compcnt;
1461
else if (flags == BRCMF_FWS_TXSTATUS_FW_DISCARD_NOACK)
1462
fws->stats.txs_discard += compcnt;
1463
else if (flags == BRCMF_FWS_TXSTATUS_FW_SUPPRESS_ACKED)
1464
fws->stats.txs_discard += compcnt;
1465
else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
1466
fws->stats.txs_host_tossed += compcnt;
1467
else
1468
bphy_err(drvr, "unexpected txstatus\n");
1469
1470
while (cnt < compcnt) {
1471
ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1472
remove_from_hanger);
1473
if (ret != 0) {
1474
bphy_err(drvr, "no packet in hanger slot: hslot=%d\n",
1475
hslot);
1476
goto cont;
1477
}
1478
1479
skcb = brcmf_skbcb(skb);
1480
entry = skcb->mac;
1481
if (WARN_ON(!entry)) {
1482
brcmu_pkt_buf_free_skb(skb);
1483
goto cont;
1484
}
1485
entry->transit_count--;
1486
if (entry->suppressed && entry->suppr_transit_count)
1487
entry->suppr_transit_count--;
1488
1489
brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name,
1490
flags, skcb->htod, seq);
1491
1492
/* pick up the implicit credit from this packet */
1493
fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
1494
if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT ||
1495
(brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
1496
flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) {
1497
brcmf_fws_return_credits(fws, fifo, 1);
1498
brcmf_fws_schedule_deq(fws);
1499
}
1500
brcmf_fws_macdesc_return_req_credit(skb);
1501
1502
ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
1503
if (ret) {
1504
brcmu_pkt_buf_free_skb(skb);
1505
goto cont;
1506
}
1507
if (!remove_from_hanger)
1508
ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
1509
genbit, seq);
1510
if (remove_from_hanger || ret)
1511
brcmf_txfinalize(ifp, skb, true);
1512
1513
cont:
1514
hslot = (hslot + 1) & (BRCMF_FWS_TXSTAT_HSLOT_MASK >>
1515
BRCMF_FWS_TXSTAT_HSLOT_SHIFT);
1516
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
1517
seq = (seq + 1) & BRCMF_SKB_HTOD_SEQ_NR_MASK;
1518
1519
cnt++;
1520
}
1521
1522
return 0;
1523
}
1524
1525
static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
1526
u8 *data)
1527
{
1528
int i;
1529
1530
if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
1531
brcmf_dbg(INFO, "ignored\n");
1532
return BRCMF_FWS_RET_OK_NOSCHEDULE;
1533
}
1534
1535
brcmf_dbg(DATA, "enter: data %pM\n", data);
1536
brcmf_fws_lock(fws);
1537
for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
1538
brcmf_fws_return_credits(fws, i, data[i]);
1539
1540
brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
1541
fws->fifo_delay_map);
1542
brcmf_fws_unlock(fws);
1543
return BRCMF_FWS_RET_OK_SCHEDULE;
1544
}
1545
1546
static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 type,
1547
u8 *data)
1548
{
1549
__le32 status_le;
1550
__le16 seq_le;
1551
u32 status;
1552
u32 hslot;
1553
u32 genbit;
1554
u8 flags;
1555
u16 seq;
1556
u8 compcnt;
1557
u8 compcnt_offset = BRCMF_FWS_TYPE_TXSTATUS_LEN;
1558
1559
memcpy(&status_le, data, sizeof(status_le));
1560
status = le32_to_cpu(status_le);
1561
flags = brcmf_txstatus_get_field(status, FLAGS);
1562
hslot = brcmf_txstatus_get_field(status, HSLOT);
1563
genbit = brcmf_txstatus_get_field(status, GENERATION);
1564
if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
1565
memcpy(&seq_le, &data[BRCMF_FWS_TYPE_TXSTATUS_LEN],
1566
sizeof(seq_le));
1567
seq = le16_to_cpu(seq_le);
1568
compcnt_offset += BRCMF_FWS_TYPE_SEQ_LEN;
1569
} else {
1570
seq = 0;
1571
}
1572
1573
if (type == BRCMF_FWS_TYPE_COMP_TXSTATUS)
1574
compcnt = data[compcnt_offset];
1575
else
1576
compcnt = 1;
1577
fws->stats.txs_indicate += compcnt;
1578
1579
brcmf_fws_lock(fws);
1580
brcmf_fws_txs_process(fws, flags, hslot, genbit, seq, compcnt);
1581
brcmf_fws_unlock(fws);
1582
return BRCMF_FWS_RET_OK_NOSCHEDULE;
1583
}
1584
1585
static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
1586
{
1587
__le32 timestamp;
1588
1589
memcpy(&timestamp, &data[2], sizeof(timestamp));
1590
brcmf_dbg(CTL, "received: seq %d, timestamp %d\n", data[1],
1591
le32_to_cpu(timestamp));
1592
return 0;
1593
}
1594
1595
static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
1596
const struct brcmf_event_msg *e,
1597
void *data)
1598
{
1599
struct brcmf_pub *drvr = ifp->drvr;
1600
struct brcmf_fws_info *fws = drvr_to_fws(drvr);
1601
int i;
1602
u8 *credits = data;
1603
1604
if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
1605
bphy_err(drvr, "event payload too small (%d)\n", e->datalen);
1606
return -EINVAL;
1607
}
1608
1609
fws->creditmap_received = true;
1610
1611
brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
1612
brcmf_fws_lock(fws);
1613
for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
1614
fws->fifo_credit[i] += credits[i] - fws->init_fifo_credit[i];
1615
fws->init_fifo_credit[i] = credits[i];
1616
if (fws->fifo_credit[i] > 0)
1617
fws->fifo_credit_map |= 1 << i;
1618
else
1619
fws->fifo_credit_map &= ~(1 << i);
1620
WARN_ONCE(fws->fifo_credit[i] < 0,
1621
"fifo_credit[%d] is negative(%d)\n", i,
1622
fws->fifo_credit[i]);
1623
}
1624
brcmf_fws_schedule_deq(fws);
1625
brcmf_fws_unlock(fws);
1626
return 0;
1627
}
1628
1629
static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
1630
const struct brcmf_event_msg *e,
1631
void *data)
1632
{
1633
struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1634
1635
if (fws) {
1636
brcmf_fws_lock(fws);
1637
fws->bcmc_credit_check = true;
1638
brcmf_fws_unlock(fws);
1639
}
1640
return 0;
1641
}
1642
1643
static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
1644
u8 start, u8 end,
1645
struct sk_buff_head *skb_list)
1646
{
1647
/* initialize return list */
1648
__skb_queue_head_init(skb_list);
1649
1650
if (rfi->pend_pkts == 0) {
1651
brcmf_dbg(INFO, "no packets in reorder queue\n");
1652
return;
1653
}
1654
1655
do {
1656
if (rfi->pktslots[start]) {
1657
__skb_queue_tail(skb_list, rfi->pktslots[start]);
1658
rfi->pktslots[start] = NULL;
1659
}
1660
start++;
1661
if (start > rfi->max_idx)
1662
start = 0;
1663
} while (start != end);
1664
rfi->pend_pkts -= skb_queue_len(skb_list);
1665
}
1666
1667
void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
1668
{
1669
struct brcmf_pub *drvr = ifp->drvr;
1670
u8 *reorder_data;
1671
u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
1672
struct brcmf_ampdu_rx_reorder *rfi;
1673
struct sk_buff_head reorder_list;
1674
struct sk_buff *pnext;
1675
u8 flags;
1676
1677
reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
1678
flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
1679
flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
1680
1681
/* validate flags and flow id */
1682
if (flags == 0xFF) {
1683
bphy_err(drvr, "invalid flags...so ignore this packet\n");
1684
brcmf_netif_rx(ifp, pkt);
1685
return;
1686
}
1687
1688
rfi = ifp->drvr->reorder_flows[flow_id];
1689
if (flags & BRCMF_RXREORDER_DEL_FLOW) {
1690
brcmf_dbg(INFO, "flow-%d: delete\n",
1691
flow_id);
1692
1693
if (rfi == NULL) {
1694
brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
1695
flow_id);
1696
brcmf_netif_rx(ifp, pkt);
1697
return;
1698
}
1699
1700
brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
1701
&reorder_list);
1702
/* add the last packet */
1703
__skb_queue_tail(&reorder_list, pkt);
1704
kfree(rfi);
1705
ifp->drvr->reorder_flows[flow_id] = NULL;
1706
goto netif_rx;
1707
}
1708
/* from here on we need a flow reorder instance */
1709
if (rfi == NULL) {
1710
max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1711
1712
/* allocate space for flow reorder info */
1713
brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
1714
flow_id, max_idx);
1715
rfi = kzalloc(struct_size(rfi, pktslots, max_idx + 1),
1716
GFP_ATOMIC);
1717
if (rfi == NULL) {
1718
bphy_err(drvr, "failed to alloc buffer\n");
1719
brcmf_netif_rx(ifp, pkt);
1720
return;
1721
}
1722
1723
ifp->drvr->reorder_flows[flow_id] = rfi;
1724
rfi->max_idx = max_idx;
1725
}
1726
if (flags & BRCMF_RXREORDER_NEW_HOLE) {
1727
if (rfi->pend_pkts) {
1728
brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
1729
rfi->exp_idx,
1730
&reorder_list);
1731
WARN_ON(rfi->pend_pkts);
1732
} else {
1733
__skb_queue_head_init(&reorder_list);
1734
}
1735
rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1736
rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1737
rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1738
rfi->pktslots[rfi->cur_idx] = pkt;
1739
rfi->pend_pkts++;
1740
brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
1741
flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
1742
} else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
1743
cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1744
exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1745
1746
if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
1747
/* still in the current hole */
1748
/* enqueue the current on the buffer chain */
1749
if (rfi->pktslots[cur_idx] != NULL) {
1750
brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
1751
brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1752
rfi->pktslots[cur_idx] = NULL;
1753
}
1754
rfi->pktslots[cur_idx] = pkt;
1755
rfi->pend_pkts++;
1756
rfi->cur_idx = cur_idx;
1757
brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
1758
flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1759
1760
/* can return now as there is no reorder
1761
* list to process.
1762
*/
1763
return;
1764
}
1765
if (rfi->exp_idx == cur_idx) {
1766
if (rfi->pktslots[cur_idx] != NULL) {
1767
brcmf_dbg(INFO, "error buffer pending..free it\n");
1768
brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1769
rfi->pktslots[cur_idx] = NULL;
1770
}
1771
rfi->pktslots[cur_idx] = pkt;
1772
rfi->pend_pkts++;
1773
1774
/* got the expected one. flush from current to expected
1775
* and update expected
1776
*/
1777
brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
1778
flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1779
1780
rfi->cur_idx = cur_idx;
1781
rfi->exp_idx = exp_idx;
1782
1783
brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
1784
&reorder_list);
1785
brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
1786
flow_id, skb_queue_len(&reorder_list),
1787
rfi->pend_pkts);
1788
} else {
1789
u8 end_idx;
1790
1791
brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
1792
flow_id, flags, rfi->cur_idx, rfi->exp_idx,
1793
cur_idx, exp_idx);
1794
if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1795
end_idx = rfi->exp_idx;
1796
else
1797
end_idx = exp_idx;
1798
1799
/* flush pkts first */
1800
brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1801
&reorder_list);
1802
1803
if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
1804
__skb_queue_tail(&reorder_list, pkt);
1805
} else {
1806
rfi->pktslots[cur_idx] = pkt;
1807
rfi->pend_pkts++;
1808
}
1809
rfi->exp_idx = exp_idx;
1810
rfi->cur_idx = cur_idx;
1811
}
1812
} else {
1813
/* explicitly window move updating the expected index */
1814
exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1815
1816
brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
1817
flow_id, flags, rfi->exp_idx, exp_idx);
1818
if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1819
end_idx = rfi->exp_idx;
1820
else
1821
end_idx = exp_idx;
1822
1823
brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1824
&reorder_list);
1825
__skb_queue_tail(&reorder_list, pkt);
1826
/* set the new expected idx */
1827
rfi->exp_idx = exp_idx;
1828
}
1829
netif_rx:
1830
skb_queue_walk_safe(&reorder_list, pkt, pnext) {
1831
__skb_unlink(pkt, &reorder_list);
1832
brcmf_netif_rx(ifp, pkt);
1833
}
1834
}
1835
1836
void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
1837
{
1838
struct brcmf_skb_reorder_data *rd;
1839
struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1840
u8 *signal_data;
1841
s16 data_len;
1842
u8 type;
1843
u8 len;
1844
u8 *data;
1845
s32 status;
1846
s32 err;
1847
1848
brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
1849
ifp->ifidx, skb->len, siglen);
1850
1851
WARN_ON(siglen > skb->len);
1852
1853
if (siglen > skb->len)
1854
siglen = skb->len;
1855
1856
if (!siglen)
1857
return;
1858
/* if flow control disabled, skip to packet data and leave */
1859
if ((!fws) || (!fws->fw_signals)) {
1860
skb_pull(skb, siglen);
1861
return;
1862
}
1863
1864
fws->stats.header_pulls++;
1865
data_len = siglen;
1866
signal_data = skb->data;
1867
1868
status = BRCMF_FWS_RET_OK_NOSCHEDULE;
1869
while (data_len > 0) {
1870
/* extract tlv info */
1871
type = signal_data[0];
1872
1873
/* FILLER type is actually not a TLV, but
1874
* a single byte that can be skipped.
1875
*/
1876
if (type == BRCMF_FWS_TYPE_FILLER) {
1877
signal_data += 1;
1878
data_len -= 1;
1879
continue;
1880
}
1881
len = signal_data[1];
1882
data = signal_data + 2;
1883
1884
brcmf_dbg(HDRS, "tlv type=%s (%d), len=%d (%d)\n",
1885
brcmf_fws_get_tlv_name(type), type, len,
1886
brcmf_fws_get_tlv_len(fws, type));
1887
1888
/* abort parsing when length invalid */
1889
if (data_len < len + 2)
1890
break;
1891
1892
if (len < brcmf_fws_get_tlv_len(fws, type))
1893
break;
1894
1895
err = BRCMF_FWS_RET_OK_NOSCHEDULE;
1896
switch (type) {
1897
case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
1898
rd = (struct brcmf_skb_reorder_data *)skb->cb;
1899
rd->reorder = data;
1900
break;
1901
case BRCMF_FWS_TYPE_MACDESC_ADD:
1902
case BRCMF_FWS_TYPE_MACDESC_DEL:
1903
brcmf_fws_macdesc_indicate(fws, type, data);
1904
break;
1905
case BRCMF_FWS_TYPE_MAC_OPEN:
1906
case BRCMF_FWS_TYPE_MAC_CLOSE:
1907
err = brcmf_fws_macdesc_state_indicate(fws, type, data);
1908
break;
1909
case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1910
case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1911
err = brcmf_fws_interface_state_indicate(fws, type,
1912
data);
1913
break;
1914
case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
1915
case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
1916
err = brcmf_fws_request_indicate(fws, type, data);
1917
break;
1918
case BRCMF_FWS_TYPE_TXSTATUS:
1919
case BRCMF_FWS_TYPE_COMP_TXSTATUS:
1920
brcmf_fws_txstatus_indicate(fws, type, data);
1921
break;
1922
case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
1923
err = brcmf_fws_fifocreditback_indicate(fws, data);
1924
break;
1925
case BRCMF_FWS_TYPE_RSSI:
1926
brcmf_fws_rssi_indicate(fws, *data);
1927
break;
1928
case BRCMF_FWS_TYPE_TRANS_ID:
1929
brcmf_fws_dbg_seqnum_check(fws, data);
1930
break;
1931
case BRCMF_FWS_TYPE_PKTTAG:
1932
case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
1933
default:
1934
fws->stats.tlv_invalid_type++;
1935
break;
1936
}
1937
if (err == BRCMF_FWS_RET_OK_SCHEDULE)
1938
status = BRCMF_FWS_RET_OK_SCHEDULE;
1939
signal_data += len + 2;
1940
data_len -= len + 2;
1941
}
1942
1943
if (data_len != 0)
1944
fws->stats.tlv_parse_failed++;
1945
1946
if (status == BRCMF_FWS_RET_OK_SCHEDULE)
1947
brcmf_fws_schedule_deq(fws);
1948
1949
/* signalling processing result does
1950
* not affect the actual ethernet packet.
1951
*/
1952
skb_pull(skb, siglen);
1953
1954
/* this may be a signal-only packet
1955
*/
1956
if (skb->len == 0)
1957
fws->stats.header_only_pkt++;
1958
}
1959
1960
static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1961
struct sk_buff *p)
1962
{
1963
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1964
struct brcmf_fws_mac_descriptor *entry = skcb->mac;
1965
u8 flags;
1966
1967
if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED)
1968
brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
1969
flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
1970
if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
1971
/*
1972
* Indicate that this packet is being sent in response to an
1973
* explicit request from the firmware side.
1974
*/
1975
flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
1976
}
1977
brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
1978
return brcmf_fws_hdrpush(fws, p);
1979
}
1980
1981
static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
1982
struct sk_buff *skb, int fifo)
1983
{
1984
struct brcmf_pub *drvr = fws->drvr;
1985
struct brcmf_fws_mac_descriptor *entry;
1986
struct sk_buff *pktout;
1987
int qidx, hslot;
1988
int rc = 0;
1989
1990
entry = brcmf_skbcb(skb)->mac;
1991
if (entry->occupied) {
1992
qidx = 2 * fifo;
1993
if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
1994
qidx++;
1995
1996
pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
1997
if (pktout == NULL) {
1998
bphy_err(drvr, "%s queue %d full\n", entry->name, qidx);
1999
rc = -ENOSPC;
2000
}
2001
} else {
2002
bphy_err(drvr, "%s entry removed\n", entry->name);
2003
rc = -ENOENT;
2004
}
2005
2006
if (rc) {
2007
fws->stats.rollback_failed++;
2008
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2009
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
2010
hslot, 0, 0, 1);
2011
} else {
2012
fws->stats.rollback_success++;
2013
brcmf_fws_return_credits(fws, fifo, 1);
2014
brcmf_fws_macdesc_return_req_credit(skb);
2015
}
2016
}
2017
2018
static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws,
2019
int highest_lender_ac, int borrower_ac,
2020
bool borrow_all)
2021
{
2022
int lender_ac, borrow_limit = 0;
2023
2024
for (lender_ac = 0; lender_ac <= highest_lender_ac; lender_ac++) {
2025
2026
if (!borrow_all)
2027
borrow_limit =
2028
fws->init_fifo_credit[lender_ac] / BRCMF_BORROW_RATIO;
2029
else
2030
borrow_limit = 0;
2031
2032
if (fws->fifo_credit[lender_ac] > borrow_limit) {
2033
fws->credits_borrowed[borrower_ac][lender_ac]++;
2034
fws->fifo_credit[lender_ac]--;
2035
if (fws->fifo_credit[lender_ac] == 0)
2036
fws->fifo_credit_map &= ~(1 << lender_ac);
2037
fws->fifo_credit_map |= (1 << borrower_ac);
2038
brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
2039
return 0;
2040
}
2041
}
2042
fws->fifo_credit_map &= ~(1 << borrower_ac);
2043
return -ENAVAIL;
2044
}
2045
2046
static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
2047
struct sk_buff *skb)
2048
{
2049
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2050
struct brcmf_fws_mac_descriptor *entry;
2051
int rc;
2052
u8 ifidx;
2053
u8 data_offset;
2054
2055
entry = skcb->mac;
2056
if (IS_ERR(entry))
2057
return PTR_ERR(entry);
2058
2059
data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);
2060
entry->transit_count++;
2061
if (entry->suppressed)
2062
entry->suppr_transit_count++;
2063
ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
2064
brcmf_fws_unlock(fws);
2065
rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
2066
brcmf_fws_lock(fws);
2067
brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
2068
skcb->if_flags, skcb->htod, rc);
2069
if (rc < 0) {
2070
entry->transit_count--;
2071
if (entry->suppressed)
2072
entry->suppr_transit_count--;
2073
(void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
2074
goto rollback;
2075
}
2076
2077
fws->stats.pkt2bus++;
2078
fws->stats.send_pkts[fifo]++;
2079
if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
2080
fws->stats.requested_sent[fifo]++;
2081
2082
return rc;
2083
2084
rollback:
2085
brcmf_fws_rollback_toq(fws, skb, fifo);
2086
return rc;
2087
}
2088
2089
static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
2090
int fifo)
2091
{
2092
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
2093
int rc, hslot;
2094
2095
skcb->htod = 0;
2096
skcb->htod_seq = 0;
2097
hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
2098
brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
2099
brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
2100
brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
2101
rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
2102
if (!rc)
2103
skcb->mac->seq[fifo]++;
2104
else
2105
fws->stats.generic_error++;
2106
return rc;
2107
}
2108
2109
int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
2110
{
2111
struct brcmf_pub *drvr = ifp->drvr;
2112
struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2113
struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2114
struct ethhdr *eh = (struct ethhdr *)(skb->data);
2115
int fifo = BRCMF_FWS_FIFO_BCMC;
2116
bool multicast = is_multicast_ether_addr(eh->h_dest);
2117
int rc = 0;
2118
2119
brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
2120
2121
/* set control buffer information */
2122
skcb->if_flags = 0;
2123
skcb->state = BRCMF_FWS_SKBSTATE_NEW;
2124
brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
2125
2126
/* mapping from 802.1d priority to firmware fifo index */
2127
if (!multicast)
2128
fifo = brcmf_map_prio_to_aci(drvr->config, skb->priority);
2129
2130
brcmf_fws_lock(fws);
2131
if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
2132
fws->borrow_defer_timestamp = jiffies +
2133
BRCMF_FWS_BORROW_DEFER_PERIOD;
2134
2135
skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
2136
brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
2137
eh->h_dest, multicast, fifo);
2138
if (!brcmf_fws_assign_htod(fws, skb, fifo)) {
2139
brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
2140
brcmf_fws_schedule_deq(fws);
2141
} else {
2142
bphy_err(drvr, "no hanger slot available\n");
2143
rc = -ENOMEM;
2144
}
2145
brcmf_fws_unlock(fws);
2146
2147
return rc;
2148
}
2149
2150
void brcmf_fws_reset_interface(struct brcmf_if *ifp)
2151
{
2152
struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2153
2154
brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
2155
if (!entry)
2156
return;
2157
2158
brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2159
}
2160
2161
void brcmf_fws_add_interface(struct brcmf_if *ifp)
2162
{
2163
struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2164
struct brcmf_fws_mac_descriptor *entry;
2165
2166
if (!ifp->ndev || !brcmf_fws_queue_skbs(fws))
2167
return;
2168
2169
entry = &fws->desc.iface[ifp->ifidx];
2170
ifp->fws_desc = entry;
2171
brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2172
brcmf_fws_macdesc_set_name(fws, entry);
2173
brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
2174
BRCMF_FWS_PSQ_LEN);
2175
brcmf_dbg(TRACE, "added %s\n", entry->name);
2176
}
2177
2178
void brcmf_fws_del_interface(struct brcmf_if *ifp)
2179
{
2180
struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2181
struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2182
2183
if (!entry)
2184
return;
2185
2186
brcmf_fws_lock(fws);
2187
ifp->fws_desc = NULL;
2188
brcmf_dbg(TRACE, "deleting %s\n", entry->name);
2189
brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx],
2190
ifp->ifidx);
2191
brcmf_fws_macdesc_deinit(entry);
2192
brcmf_fws_cleanup(fws, ifp->ifidx);
2193
brcmf_fws_unlock(fws);
2194
}
2195
2196
static void brcmf_fws_dequeue_worker(struct work_struct *worker)
2197
{
2198
struct brcmf_fws_info *fws;
2199
struct brcmf_pub *drvr;
2200
struct sk_buff *skb;
2201
int fifo;
2202
u32 hslot;
2203
u32 ifidx;
2204
int ret;
2205
2206
fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
2207
drvr = fws->drvr;
2208
2209
brcmf_fws_lock(fws);
2210
for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
2211
fifo--) {
2212
if (!brcmf_fws_fc_active(fws)) {
2213
while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) {
2214
hslot = brcmf_skb_htod_tag_get_field(skb,
2215
HSLOT);
2216
brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
2217
&skb, true);
2218
ifidx = brcmf_skb_if_flags_get_field(skb,
2219
INDEX);
2220
/* Use proto layer to send data frame */
2221
brcmf_fws_unlock(fws);
2222
ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
2223
brcmf_fws_lock(fws);
2224
if (ret < 0)
2225
brcmf_txfinalize(brcmf_get_ifp(drvr,
2226
ifidx),
2227
skb, false);
2228
if (fws->bus_flow_blocked)
2229
break;
2230
}
2231
continue;
2232
}
2233
2234
while ((fws->fifo_credit[fifo]) ||
2235
((!fws->bcmc_credit_check) &&
2236
(fifo == BRCMF_FWS_FIFO_BCMC))) {
2237
skb = brcmf_fws_deq(fws, fifo);
2238
if (!skb)
2239
break;
2240
fws->fifo_credit[fifo]--;
2241
if (brcmf_fws_commit_skb(fws, fifo, skb))
2242
break;
2243
if (fws->bus_flow_blocked)
2244
break;
2245
}
2246
2247
if (fifo >= BRCMF_FWS_FIFO_AC_BE &&
2248
fifo <= BRCMF_FWS_FIFO_AC_VO &&
2249
fws->fifo_credit[fifo] == 0 &&
2250
!fws->bus_flow_blocked) {
2251
while (brcmf_fws_borrow_credit(fws,
2252
fifo - 1, fifo,
2253
true) == 0) {
2254
skb = brcmf_fws_deq(fws, fifo);
2255
if (!skb) {
2256
brcmf_fws_return_credits(fws, fifo, 1);
2257
break;
2258
}
2259
if (brcmf_fws_commit_skb(fws, fifo, skb))
2260
break;
2261
if (fws->bus_flow_blocked)
2262
break;
2263
}
2264
}
2265
}
2266
brcmf_fws_unlock(fws);
2267
}
2268
2269
#ifdef DEBUG
2270
static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2271
{
2272
struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
2273
struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats);
2274
2275
seq_printf(seq,
2276
"header_pulls: %u\n"
2277
"header_only_pkt: %u\n"
2278
"tlv_parse_failed: %u\n"
2279
"tlv_invalid_type: %u\n"
2280
"mac_update_fails: %u\n"
2281
"ps_update_fails: %u\n"
2282
"if_update_fails: %u\n"
2283
"pkt2bus: %u\n"
2284
"generic_error: %u\n"
2285
"rollback_success: %u\n"
2286
"rollback_failed: %u\n"
2287
"delayq_full: %u\n"
2288
"supprq_full: %u\n"
2289
"txs_indicate: %u\n"
2290
"txs_discard: %u\n"
2291
"txs_suppr_core: %u\n"
2292
"txs_suppr_ps: %u\n"
2293
"txs_tossed: %u\n"
2294
"txs_host_tossed: %u\n"
2295
"bus_flow_block: %u\n"
2296
"fws_flow_block: %u\n"
2297
"send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
2298
"requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
2299
fwstats->header_pulls,
2300
fwstats->header_only_pkt,
2301
fwstats->tlv_parse_failed,
2302
fwstats->tlv_invalid_type,
2303
fwstats->mac_update_failed,
2304
fwstats->mac_ps_update_failed,
2305
fwstats->if_update_failed,
2306
fwstats->pkt2bus,
2307
fwstats->generic_error,
2308
fwstats->rollback_success,
2309
fwstats->rollback_failed,
2310
fwstats->delayq_full_error,
2311
fwstats->supprq_full_error,
2312
fwstats->txs_indicate,
2313
fwstats->txs_discard,
2314
fwstats->txs_supp_core,
2315
fwstats->txs_supp_ps,
2316
fwstats->txs_tossed,
2317
fwstats->txs_host_tossed,
2318
fwstats->bus_flow_block,
2319
fwstats->fws_flow_block,
2320
fwstats->send_pkts[0], fwstats->send_pkts[1],
2321
fwstats->send_pkts[2], fwstats->send_pkts[3],
2322
fwstats->send_pkts[4],
2323
fwstats->requested_sent[0],
2324
fwstats->requested_sent[1],
2325
fwstats->requested_sent[2],
2326
fwstats->requested_sent[3],
2327
fwstats->requested_sent[4]);
2328
2329
return 0;
2330
}
2331
#else
2332
static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2333
{
2334
return 0;
2335
}
2336
#endif
2337
2338
struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
2339
{
2340
struct brcmf_fws_info *fws;
2341
struct brcmf_if *ifp;
2342
u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
2343
int rc;
2344
u32 mode;
2345
2346
fws = kzalloc(sizeof(*fws), GFP_KERNEL);
2347
if (!fws) {
2348
rc = -ENOMEM;
2349
goto fail;
2350
}
2351
2352
spin_lock_init(&fws->spinlock);
2353
2354
/* store drvr reference */
2355
fws->drvr = drvr;
2356
fws->fcmode = drvr->settings->fcmode;
2357
2358
if (!drvr->bus_if->always_use_fws_queue &&
2359
(fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
2360
fws->avoid_queueing = true;
2361
brcmf_dbg(INFO, "FWS queueing will be avoided\n");
2362
return fws;
2363
}
2364
2365
fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
2366
if (fws->fws_wq == NULL) {
2367
bphy_err(drvr, "workqueue creation failed\n");
2368
rc = -EBADF;
2369
goto fail;
2370
}
2371
INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
2372
2373
/* enable firmware signalling if fcmode active */
2374
if (fws->fcmode != BRCMF_FWS_FCMODE_NONE)
2375
tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
2376
BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
2377
BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
2378
BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE;
2379
2380
rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
2381
brcmf_fws_notify_credit_map);
2382
if (rc < 0) {
2383
bphy_err(drvr, "register credit map handler failed\n");
2384
goto fail;
2385
}
2386
rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT,
2387
brcmf_fws_notify_bcmc_credit_support);
2388
if (rc < 0) {
2389
bphy_err(drvr, "register bcmc credit handler failed\n");
2390
brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
2391
goto fail;
2392
}
2393
2394
/* Setting the iovar may fail if feature is unsupported
2395
* so leave the rc as is so driver initialization can
2396
* continue. Set mode back to none indicating not enabled.
2397
*/
2398
fws->fw_signals = true;
2399
ifp = brcmf_get_ifp(drvr, 0);
2400
if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
2401
bphy_err(drvr, "failed to set bdcv2 tlv signaling\n");
2402
fws->fcmode = BRCMF_FWS_FCMODE_NONE;
2403
fws->fw_signals = false;
2404
}
2405
2406
if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
2407
brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
2408
2409
/* Enable seq number reuse, if supported */
2410
if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
2411
if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
2412
mode = 0;
2413
BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
2414
if (brcmf_fil_iovar_int_set(ifp,
2415
"wlfc_mode", mode) == 0) {
2416
BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
2417
}
2418
}
2419
}
2420
2421
brcmf_fws_hanger_init(&fws->hanger);
2422
brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
2423
brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
2424
brcmf_dbg(INFO, "added %s\n", fws->desc.other.name);
2425
brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
2426
BRCMF_FWS_PSQ_LEN);
2427
2428
brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
2429
fws->fw_signals ? "enabled" : "disabled", tlv);
2430
return fws;
2431
2432
fail:
2433
brcmf_fws_detach(fws);
2434
return ERR_PTR(rc);
2435
}
2436
2437
void brcmf_fws_detach(struct brcmf_fws_info *fws)
2438
{
2439
if (!fws)
2440
return;
2441
2442
if (fws->fws_wq)
2443
destroy_workqueue(fws->fws_wq);
2444
2445
/* cleanup */
2446
brcmf_fws_lock(fws);
2447
brcmf_fws_cleanup(fws, -1);
2448
brcmf_fws_unlock(fws);
2449
2450
/* free top structure */
2451
kfree(fws);
2452
}
2453
2454
void brcmf_fws_debugfs_create(struct brcmf_pub *drvr)
2455
{
2456
/* create debugfs file for statistics */
2457
brcmf_debugfs_add_entry(drvr, "fws_stats",
2458
brcmf_debugfs_fws_stats_read);
2459
}
2460
2461
bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws)
2462
{
2463
return !fws->avoid_queueing;
2464
}
2465
2466
bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
2467
{
2468
if (!fws->creditmap_received)
2469
return false;
2470
2471
return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
2472
}
2473
2474
void brcmf_fws_bustxcomplete(struct brcmf_fws_info *fws, struct sk_buff *skb,
2475
bool success)
2476
{
2477
u32 hslot;
2478
2479
if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
2480
brcmu_pkt_buf_free_skb(skb);
2481
return;
2482
}
2483
2484
if (!success) {
2485
brcmf_fws_lock(fws);
2486
hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2487
brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot,
2488
0, 0, 1);
2489
brcmf_fws_unlock(fws);
2490
}
2491
}
2492
2493
void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
2494
{
2495
struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2496
struct brcmf_if *ifp;
2497
int i;
2498
2499
if (fws->avoid_queueing) {
2500
for (i = 0; i < BRCMF_MAX_IFS; i++) {
2501
ifp = drvr->iflist[i];
2502
if (!ifp || !ifp->ndev)
2503
continue;
2504
brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
2505
flow_blocked);
2506
}
2507
} else {
2508
fws->bus_flow_blocked = flow_blocked;
2509
if (!flow_blocked)
2510
brcmf_fws_schedule_deq(fws);
2511
else
2512
fws->stats.bus_flow_block++;
2513
}
2514
}
2515
2516