This source file includes following definitions.
- brcmf_fws_get_tlv_name
- brcmf_fws_get_tlv_name
- brcmf_fws_get_tlv_len
- brcmf_fws_lock
- brcmf_fws_unlock
- brcmf_fws_ifidx_match
- brcmf_fws_hanger_init
- brcmf_fws_hanger_get_free_slot
- brcmf_fws_hanger_pushpkt
- brcmf_fws_hanger_poppkt
- brcmf_fws_psq_flush
- brcmf_fws_hanger_mark_suppressed
- brcmf_fws_hanger_cleanup
- brcmf_fws_macdesc_set_name
- brcmf_fws_macdesc_init
- brcmf_fws_macdesc_deinit
- brcmf_fws_macdesc_lookup
- brcmf_fws_macdesc_find
- brcmf_fws_macdesc_closed
- brcmf_fws_macdesc_cleanup
- brcmf_fws_bus_txq_cleanup
- brcmf_fws_cleanup
- brcmf_fws_hdrpush
- brcmf_fws_tim_update
- brcmf_fws_flow_control_check
- brcmf_fws_rssi_indicate
- brcmf_fws_macdesc_indicate
- brcmf_fws_macdesc_state_indicate
- brcmf_fws_interface_state_indicate
- brcmf_fws_request_indicate
- brcmf_fws_macdesc_use_req_credit
- brcmf_fws_macdesc_return_req_credit
- brcmf_fws_return_credits
- brcmf_fws_schedule_deq
- brcmf_fws_enq
- brcmf_fws_deq
- brcmf_fws_txstatus_suppressed
- brcmf_fws_txs_process
- brcmf_fws_fifocreditback_indicate
- brcmf_fws_txstatus_indicate
- brcmf_fws_dbg_seqnum_check
- brcmf_fws_notify_credit_map
- brcmf_fws_notify_bcmc_credit_support
- brcmf_rxreorder_get_skb_list
- brcmf_fws_rxreorder
- brcmf_fws_hdrpull
- brcmf_fws_precommit_skb
- brcmf_fws_rollback_toq
- brcmf_fws_borrow_credit
- brcmf_fws_commit_skb
- brcmf_fws_assign_htod
- brcmf_fws_process_skb
- brcmf_fws_reset_interface
- brcmf_fws_add_interface
- brcmf_fws_del_interface
- brcmf_fws_dequeue_worker
- brcmf_debugfs_fws_stats_read
- brcmf_debugfs_fws_stats_read
- brcmf_fws_attach
- brcmf_fws_detach
- brcmf_fws_debugfs_create
- brcmf_fws_queue_skbs
- brcmf_fws_fc_active
- brcmf_fws_bustxfail
- brcmf_fws_bus_blocked
1
2
3
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
33
34
35
36
37
38
39
40
41
42
43
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
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
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
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
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
129
130
131
132
133
134 #define BRCMF_FWS_TYPE_SEQ_LEN 2
135
136
137
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
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
173
174
175
176
177
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
188
189
190
191
192
193
194
195
196
197
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
210
211 #define brcmf_skbcb(skb) ((struct brcmf_skbuff_cb *)((skb)->cb))
212
213
214
215
216
217
218
219
220
221
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
247
248
249
250
251
252
253
254
255
256
257
258
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
312 #define BRCMF_FWS_BORROW_DEFER_PERIOD (HZ / 10)
313
314
315
316
317
318
319
320
321
322
323
324
325
326 enum brcmf_fws_fifo {
327 BRCMF_FWS_FIFO_FIRST,
328 BRCMF_FWS_FIFO_AC_BK = BRCMF_FWS_FIFO_FIRST,
329 BRCMF_FWS_FIFO_AC_BE,
330 BRCMF_FWS_FIFO_AC_VI,
331 BRCMF_FWS_FIFO_AC_VO,
332 BRCMF_FWS_FIFO_BCMC,
333 BRCMF_FWS_FIFO_ATIM,
334 BRCMF_FWS_FIFO_COUNT
335 };
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351 enum brcmf_fws_txstatus {
352 BRCMF_FWS_TXSTATUS_DISCARD,
353 BRCMF_FWS_TXSTATUS_CORE_SUPPRESS,
354 BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS,
355 BRCMF_FWS_TXSTATUS_FW_TOSSED,
356 BRCMF_FWS_TXSTATUS_HOST_TOSSED
357 };
358
359 enum brcmf_fws_fcmode {
360 BRCMF_FWS_FCMODE_NONE,
361 BRCMF_FWS_FCMODE_IMPLIED_CREDIT,
362 BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
363 };
364
365 enum brcmf_fws_mac_desc_state {
366 BRCMF_FWS_STATE_OPEN = 1,
367 BRCMF_FWS_STATE_CLOSE
368 };
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386 struct brcmf_fws_mac_descriptor {
387 char name[16];
388 u8 occupied;
389 u8 mac_handle;
390 u8 interface_id;
391 u8 state;
392 bool suppressed;
393 u8 generation;
394 u8 ac_bitmap;
395 u8 requested_credit;
396 u8 requested_packet;
397 u8 ea[ETH_ALEN];
398 u8 seq[BRCMF_FWS_FIFO_COUNT];
399 struct pktq psq;
400 int transit_count;
401 int suppr_transit_count;
402 bool send_tim_signal;
403 u8 traffic_pending_bmp;
404 u8 traffic_lastreported_bmp;
405 };
406
407 #define BRCMF_FWS_HANGER_MAXITEMS 1024
408
409
410
411
412
413
414
415
416 enum brcmf_fws_hanger_item_state {
417 BRCMF_FWS_HANGER_ITEM_STATE_FREE = 1,
418 BRCMF_FWS_HANGER_ITEM_STATE_INUSE,
419 BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED
420 };
421
422
423
424
425
426
427
428
429 struct brcmf_fws_hanger_item {
430 enum brcmf_fws_hanger_item_state state;
431 struct sk_buff *pkt;
432 };
433
434
435
436
437
438
439
440
441
442
443
444
445 struct brcmf_fws_hanger {
446 u32 pushed;
447 u32 popped;
448 u32 failed_to_push;
449 u32 failed_to_pop;
450 u32 failed_slotfind;
451 u32 slot_pos;
452 struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
453 };
454
455 struct brcmf_fws_macdesc_table {
456 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
457 struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
458 struct brcmf_fws_mac_descriptor other;
459 };
460
461 struct brcmf_fws_stats {
462 u32 tlv_parse_failed;
463 u32 tlv_invalid_type;
464 u32 header_only_pkt;
465 u32 header_pulls;
466 u32 pkt2bus;
467 u32 send_pkts[5];
468 u32 requested_sent[5];
469 u32 generic_error;
470 u32 mac_update_failed;
471 u32 mac_ps_update_failed;
472 u32 if_update_failed;
473 u32 packet_request_failed;
474 u32 credit_request_failed;
475 u32 rollback_success;
476 u32 rollback_failed;
477 u32 delayq_full_error;
478 u32 supprq_full_error;
479 u32 txs_indicate;
480 u32 txs_discard;
481 u32 txs_supp_core;
482 u32 txs_supp_ps;
483 u32 txs_tossed;
484 u32 txs_host_tossed;
485 u32 bus_flow_block;
486 u32 fws_flow_block;
487 };
488
489 struct brcmf_fws_info {
490 struct brcmf_pub *drvr;
491 spinlock_t spinlock;
492 ulong flags;
493 struct brcmf_fws_stats stats;
494 struct brcmf_fws_hanger hanger;
495 enum brcmf_fws_fcmode fcmode;
496 bool fw_signals;
497 bool bcmc_credit_check;
498 struct brcmf_fws_macdesc_table desc;
499 struct workqueue_struct *fws_wq;
500 struct work_struct fws_dequeue_work;
501 u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
502 int fifo_credit[BRCMF_FWS_FIFO_COUNT];
503 int init_fifo_credit[BRCMF_FWS_FIFO_COUNT];
504 int credits_borrowed[BRCMF_FWS_FIFO_AC_VO + 1];
505 int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
506 u32 fifo_credit_map;
507 u32 fifo_delay_map;
508 unsigned long borrow_defer_timestamp;
509 bool bus_flow_blocked;
510 bool creditmap_received;
511 u8 mode;
512 bool avoid_queueing;
513 };
514
515
516
517
518 static const int brcmf_fws_prio2fifo[] = {
519 BRCMF_FWS_FIFO_AC_BE,
520 BRCMF_FWS_FIFO_AC_BK,
521 BRCMF_FWS_FIFO_AC_BK,
522 BRCMF_FWS_FIFO_AC_BE,
523 BRCMF_FWS_FIFO_AC_VI,
524 BRCMF_FWS_FIFO_AC_VI,
525 BRCMF_FWS_FIFO_AC_VO,
526 BRCMF_FWS_FIFO_AC_VO
527 };
528
529 #define BRCMF_FWS_TLV_DEF(name, id, len) \
530 case BRCMF_FWS_TYPE_ ## name: \
531 return len;
532
533
534
535
536
537
538
539
540
541 static int brcmf_fws_get_tlv_len(struct brcmf_fws_info *fws,
542 enum brcmf_fws_tlv_type id)
543 {
544 switch (id) {
545 BRCMF_FWS_TLV_DEFLIST
546 default:
547 fws->stats.tlv_invalid_type++;
548 break;
549 }
550 return -EINVAL;
551 }
552 #undef BRCMF_FWS_TLV_DEF
553
554 static void brcmf_fws_lock(struct brcmf_fws_info *fws)
555 __acquires(&fws->spinlock)
556 {
557 spin_lock_irqsave(&fws->spinlock, fws->flags);
558 }
559
560 static void brcmf_fws_unlock(struct brcmf_fws_info *fws)
561 __releases(&fws->spinlock)
562 {
563 spin_unlock_irqrestore(&fws->spinlock, fws->flags);
564 }
565
566 static bool brcmf_fws_ifidx_match(struct sk_buff *skb, void *arg)
567 {
568 u32 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
569 return ifidx == *(int *)arg;
570 }
571
572 static void brcmf_fws_hanger_init(struct brcmf_fws_hanger *hanger)
573 {
574 int i;
575
576 memset(hanger, 0, sizeof(*hanger));
577 for (i = 0; i < ARRAY_SIZE(hanger->items); i++)
578 hanger->items[i].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
579 }
580
581 static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
582 {
583 u32 i;
584
585 i = (h->slot_pos + 1) % BRCMF_FWS_HANGER_MAXITEMS;
586
587 while (i != h->slot_pos) {
588 if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
589 h->slot_pos = i;
590 goto done;
591 }
592 i++;
593 if (i == BRCMF_FWS_HANGER_MAXITEMS)
594 i = 0;
595 }
596 brcmf_err("all slots occupied\n");
597 h->failed_slotfind++;
598 i = BRCMF_FWS_HANGER_MAXITEMS;
599 done:
600 return i;
601 }
602
603 static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
604 struct sk_buff *pkt, u32 slot_id)
605 {
606 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
607 return -ENOENT;
608
609 if (h->items[slot_id].state != BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
610 brcmf_err("slot is not free\n");
611 h->failed_to_push++;
612 return -EINVAL;
613 }
614
615 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE;
616 h->items[slot_id].pkt = pkt;
617 h->pushed++;
618 return 0;
619 }
620
621 static inline int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
622 u32 slot_id, struct sk_buff **pktout,
623 bool remove_item)
624 {
625 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
626 return -ENOENT;
627
628 if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
629 brcmf_err("entry not in use\n");
630 h->failed_to_pop++;
631 return -EINVAL;
632 }
633
634 *pktout = h->items[slot_id].pkt;
635 if (remove_item) {
636 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
637 h->items[slot_id].pkt = NULL;
638 h->popped++;
639 }
640 return 0;
641 }
642
643 static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
644 int ifidx)
645 {
646 bool (*matchfn)(struct sk_buff *, void *) = NULL;
647 struct sk_buff *skb;
648 int prec;
649 u32 hslot;
650
651 if (ifidx != -1)
652 matchfn = brcmf_fws_ifidx_match;
653 for (prec = 0; prec < q->num_prec; prec++) {
654 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
655 while (skb) {
656 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
657 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
658 true);
659 brcmu_pkt_buf_free_skb(skb);
660 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
661 }
662 }
663 }
664
665 static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
666 u32 slot_id)
667 {
668 if (slot_id >= BRCMF_FWS_HANGER_MAXITEMS)
669 return -ENOENT;
670
671 if (h->items[slot_id].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
672 brcmf_err("entry not in use\n");
673 return -EINVAL;
674 }
675
676 h->items[slot_id].state = BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED;
677 return 0;
678 }
679
680 static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
681 bool (*fn)(struct sk_buff *, void *),
682 int ifidx)
683 {
684 struct brcmf_fws_hanger *h = &fws->hanger;
685 struct sk_buff *skb;
686 int i;
687 enum brcmf_fws_hanger_item_state s;
688
689 for (i = 0; i < ARRAY_SIZE(h->items); i++) {
690 s = h->items[i].state;
691 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE ||
692 s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE_SUPPRESSED) {
693 skb = h->items[i].pkt;
694 if (fn == NULL || fn(skb, &ifidx)) {
695
696 if (s == BRCMF_FWS_HANGER_ITEM_STATE_INUSE)
697 brcmu_pkt_buf_free_skb(skb);
698 h->items[i].state =
699 BRCMF_FWS_HANGER_ITEM_STATE_FREE;
700 }
701 }
702 }
703 }
704
705 static void brcmf_fws_macdesc_set_name(struct brcmf_fws_info *fws,
706 struct brcmf_fws_mac_descriptor *desc)
707 {
708 if (desc == &fws->desc.other)
709 strlcpy(desc->name, "MAC-OTHER", sizeof(desc->name));
710 else if (desc->mac_handle)
711 scnprintf(desc->name, sizeof(desc->name), "MAC-%d:%d",
712 desc->mac_handle, desc->interface_id);
713 else
714 scnprintf(desc->name, sizeof(desc->name), "MACIF:%d",
715 desc->interface_id);
716 }
717
718 static void brcmf_fws_macdesc_init(struct brcmf_fws_mac_descriptor *desc,
719 u8 *addr, u8 ifidx)
720 {
721 brcmf_dbg(TRACE,
722 "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
723 desc->occupied = 1;
724 desc->state = BRCMF_FWS_STATE_OPEN;
725 desc->requested_credit = 0;
726 desc->requested_packet = 0;
727
728 desc->interface_id = ifidx;
729 desc->ac_bitmap = 0xff;
730 if (addr)
731 memcpy(&desc->ea[0], addr, ETH_ALEN);
732 }
733
734 static
735 void brcmf_fws_macdesc_deinit(struct brcmf_fws_mac_descriptor *desc)
736 {
737 brcmf_dbg(TRACE,
738 "enter: ea=%pM, ifidx=%u\n", desc->ea, desc->interface_id);
739 desc->occupied = 0;
740 desc->state = BRCMF_FWS_STATE_CLOSE;
741 desc->requested_credit = 0;
742 desc->requested_packet = 0;
743 }
744
745 static struct brcmf_fws_mac_descriptor *
746 brcmf_fws_macdesc_lookup(struct brcmf_fws_info *fws, u8 *ea)
747 {
748 struct brcmf_fws_mac_descriptor *entry;
749 int i;
750
751 if (ea == NULL)
752 return ERR_PTR(-EINVAL);
753
754 entry = &fws->desc.nodes[0];
755 for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
756 if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
757 return entry;
758 entry++;
759 }
760
761 return ERR_PTR(-ENOENT);
762 }
763
764 static struct brcmf_fws_mac_descriptor*
765 brcmf_fws_macdesc_find(struct brcmf_fws_info *fws, struct brcmf_if *ifp, u8 *da)
766 {
767 struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
768 bool multicast;
769
770 multicast = is_multicast_ether_addr(da);
771
772
773
774
775
776 if (multicast && ifp->fws_desc) {
777 entry = ifp->fws_desc;
778 goto done;
779 }
780
781 entry = brcmf_fws_macdesc_lookup(fws, da);
782 if (IS_ERR(entry))
783 entry = ifp->fws_desc;
784
785 done:
786 return entry;
787 }
788
789 static bool brcmf_fws_macdesc_closed(struct brcmf_fws_info *fws,
790 struct brcmf_fws_mac_descriptor *entry,
791 int fifo)
792 {
793 struct brcmf_fws_mac_descriptor *if_entry;
794 bool closed;
795
796
797
798
799 if (entry->mac_handle) {
800 if_entry = &fws->desc.iface[entry->interface_id];
801 if (if_entry->state == BRCMF_FWS_STATE_CLOSE)
802 return true;
803 }
804
805
806
807 closed = entry->state == BRCMF_FWS_STATE_CLOSE &&
808 !entry->requested_credit && !entry->requested_packet;
809
810
811 return closed || !(entry->ac_bitmap & BIT(fifo));
812 }
813
814 static void brcmf_fws_macdesc_cleanup(struct brcmf_fws_info *fws,
815 struct brcmf_fws_mac_descriptor *entry,
816 int ifidx)
817 {
818 if (entry->occupied && (ifidx == -1 || ifidx == entry->interface_id)) {
819 brcmf_fws_psq_flush(fws, &entry->psq, ifidx);
820 entry->occupied = !!(entry->psq.len);
821 }
822 }
823
824 static void brcmf_fws_bus_txq_cleanup(struct brcmf_fws_info *fws,
825 bool (*fn)(struct sk_buff *, void *),
826 int ifidx)
827 {
828 struct brcmf_fws_hanger_item *hi;
829 struct pktq *txq;
830 struct sk_buff *skb;
831 int prec;
832 u32 hslot;
833
834 txq = brcmf_bus_gettxq(fws->drvr->bus_if);
835 if (IS_ERR(txq)) {
836 brcmf_dbg(TRACE, "no txq to clean up\n");
837 return;
838 }
839
840 for (prec = 0; prec < txq->num_prec; prec++) {
841 skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
842 while (skb) {
843 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
844 hi = &fws->hanger.items[hslot];
845 WARN_ON(skb != hi->pkt);
846 hi->state = BRCMF_FWS_HANGER_ITEM_STATE_FREE;
847 brcmu_pkt_buf_free_skb(skb);
848 skb = brcmu_pktq_pdeq_match(txq, prec, fn, &ifidx);
849 }
850 }
851 }
852
853 static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
854 {
855 int i;
856 struct brcmf_fws_mac_descriptor *table;
857 bool (*matchfn)(struct sk_buff *, void *) = NULL;
858
859 if (fws == NULL)
860 return;
861
862 if (ifidx != -1)
863 matchfn = brcmf_fws_ifidx_match;
864
865
866 table = &fws->desc.nodes[0];
867 for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
868 brcmf_fws_macdesc_cleanup(fws, &table[i], ifidx);
869
870 brcmf_fws_macdesc_cleanup(fws, &fws->desc.other, ifidx);
871 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
872 brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
873 }
874
875 static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
876 {
877 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
878 u8 *wlh;
879 u16 data_offset = 0;
880 u8 fillers;
881 __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
882 __le16 pktseq = cpu_to_le16(brcmf_skbcb(skb)->htod_seq);
883
884 brcmf_dbg(TRACE, "enter: %s, idx=%d hslot=%d htod %X seq %X\n",
885 entry->name, brcmf_skb_if_flags_get_field(skb, INDEX),
886 (le32_to_cpu(pkttag) >> 8) & 0xffff,
887 brcmf_skbcb(skb)->htod, brcmf_skbcb(skb)->htod_seq);
888 if (entry->send_tim_signal)
889 data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
890 if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
891 data_offset += BRCMF_FWS_TYPE_SEQ_LEN;
892
893 data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
894 fillers = round_up(data_offset, 4) - data_offset;
895 data_offset += fillers;
896
897 skb_push(skb, data_offset);
898 wlh = skb->data;
899
900 wlh[0] = BRCMF_FWS_TYPE_PKTTAG;
901 wlh[1] = BRCMF_FWS_TYPE_PKTTAG_LEN;
902 memcpy(&wlh[2], &pkttag, sizeof(pkttag));
903 if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
904 wlh[1] += BRCMF_FWS_TYPE_SEQ_LEN;
905 memcpy(&wlh[2 + BRCMF_FWS_TYPE_PKTTAG_LEN], &pktseq,
906 sizeof(pktseq));
907 }
908 wlh += wlh[1] + 2;
909
910 if (entry->send_tim_signal) {
911 entry->send_tim_signal = 0;
912 wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
913 wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
914 wlh[2] = entry->mac_handle;
915 wlh[3] = entry->traffic_pending_bmp;
916 brcmf_dbg(TRACE, "adding TIM info: handle %d bmp 0x%X\n",
917 entry->mac_handle, entry->traffic_pending_bmp);
918 wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
919 entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
920 }
921 if (fillers)
922 memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
923
924 return (u8)(data_offset >> 2);
925 }
926
927 static bool brcmf_fws_tim_update(struct brcmf_fws_info *fws,
928 struct brcmf_fws_mac_descriptor *entry,
929 int fifo, bool send_immediately)
930 {
931 struct sk_buff *skb;
932 struct brcmf_skbuff_cb *skcb;
933 s32 err;
934 u32 len;
935 u8 data_offset;
936 int ifidx;
937
938
939 if (brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0)
940 entry->traffic_pending_bmp &= ~NBITVAL(fifo);
941 else
942 entry->traffic_pending_bmp |= NBITVAL(fifo);
943
944 entry->send_tim_signal = false;
945 if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
946 entry->send_tim_signal = true;
947 if (send_immediately && entry->send_tim_signal &&
948 entry->state == BRCMF_FWS_STATE_CLOSE) {
949
950
951 len = BRCMF_FWS_TYPE_PKTTAG_LEN + 2 +
952 BRCMF_FWS_TYPE_SEQ_LEN +
953 BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2 +
954 4 + fws->drvr->hdrlen;
955 skb = brcmu_pkt_buf_get_skb(len);
956 if (skb == NULL)
957 return false;
958 skb_pull(skb, len);
959 skcb = brcmf_skbcb(skb);
960 skcb->mac = entry;
961 skcb->state = BRCMF_FWS_SKBSTATE_TIM;
962 skcb->htod = 0;
963 skcb->htod_seq = 0;
964 data_offset = brcmf_fws_hdrpush(fws, skb);
965 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
966 brcmf_fws_unlock(fws);
967 err = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
968 brcmf_fws_lock(fws);
969 if (err)
970 brcmu_pkt_buf_free_skb(skb);
971 return true;
972 }
973 return false;
974 }
975
976 static void
977 brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
978 u8 if_id)
979 {
980 struct brcmf_if *ifp = brcmf_get_ifp(fws->drvr, if_id);
981
982 if (WARN_ON(!ifp))
983 return;
984
985 if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
986 pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
987 brcmf_txflowblock_if(ifp,
988 BRCMF_NETIF_STOP_REASON_FWS_FC, false);
989 if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
990 pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER) {
991 fws->stats.fws_flow_block++;
992 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
993 }
994 return;
995 }
996
997 static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
998 {
999 brcmf_dbg(CTL, "rssi %d\n", rssi);
1000 return 0;
1001 }
1002
1003 static
1004 int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
1005 {
1006 struct brcmf_fws_mac_descriptor *entry, *existing;
1007 u8 mac_handle;
1008 u8 ifidx;
1009 u8 *addr;
1010
1011 mac_handle = *data++;
1012 ifidx = *data++;
1013 addr = data;
1014
1015 entry = &fws->desc.nodes[mac_handle & 0x1F];
1016 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
1017 if (entry->occupied) {
1018 brcmf_dbg(TRACE, "deleting %s mac %pM\n",
1019 entry->name, addr);
1020 brcmf_fws_lock(fws);
1021 brcmf_fws_macdesc_cleanup(fws, entry, -1);
1022 brcmf_fws_macdesc_deinit(entry);
1023 brcmf_fws_unlock(fws);
1024 } else
1025 fws->stats.mac_update_failed++;
1026 return 0;
1027 }
1028
1029 existing = brcmf_fws_macdesc_lookup(fws, addr);
1030 if (IS_ERR(existing)) {
1031 if (!entry->occupied) {
1032 brcmf_fws_lock(fws);
1033 entry->mac_handle = mac_handle;
1034 brcmf_fws_macdesc_init(entry, addr, ifidx);
1035 brcmf_fws_macdesc_set_name(fws, entry);
1036 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
1037 BRCMF_FWS_PSQ_LEN);
1038 brcmf_fws_unlock(fws);
1039 brcmf_dbg(TRACE, "add %s mac %pM\n", entry->name, addr);
1040 } else {
1041 fws->stats.mac_update_failed++;
1042 }
1043 } else {
1044 if (entry != existing) {
1045 brcmf_dbg(TRACE, "copy mac %s\n", existing->name);
1046 brcmf_fws_lock(fws);
1047 memcpy(entry, existing,
1048 offsetof(struct brcmf_fws_mac_descriptor, psq));
1049 entry->mac_handle = mac_handle;
1050 brcmf_fws_macdesc_deinit(existing);
1051 brcmf_fws_macdesc_set_name(fws, entry);
1052 brcmf_fws_unlock(fws);
1053 brcmf_dbg(TRACE, "relocate %s mac %pM\n", entry->name,
1054 addr);
1055 } else {
1056 brcmf_dbg(TRACE, "use existing\n");
1057 WARN_ON(entry->mac_handle != mac_handle);
1058
1059 }
1060 }
1061 return 0;
1062 }
1063
1064 static int brcmf_fws_macdesc_state_indicate(struct brcmf_fws_info *fws,
1065 u8 type, u8 *data)
1066 {
1067 struct brcmf_fws_mac_descriptor *entry;
1068 u8 mac_handle;
1069 int ret;
1070
1071 mac_handle = data[0];
1072 entry = &fws->desc.nodes[mac_handle & 0x1F];
1073 if (!entry->occupied) {
1074 fws->stats.mac_ps_update_failed++;
1075 return -ESRCH;
1076 }
1077 brcmf_fws_lock(fws);
1078
1079 entry->requested_credit = 0;
1080 entry->requested_packet = 0;
1081 if (type == BRCMF_FWS_TYPE_MAC_OPEN) {
1082 entry->state = BRCMF_FWS_STATE_OPEN;
1083 ret = BRCMF_FWS_RET_OK_SCHEDULE;
1084 } else {
1085 entry->state = BRCMF_FWS_STATE_CLOSE;
1086 brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BK, false);
1087 brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_BE, false);
1088 brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VI, false);
1089 brcmf_fws_tim_update(fws, entry, BRCMF_FWS_FIFO_AC_VO, true);
1090 ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1091 }
1092 brcmf_fws_unlock(fws);
1093 return ret;
1094 }
1095
1096 static int brcmf_fws_interface_state_indicate(struct brcmf_fws_info *fws,
1097 u8 type, u8 *data)
1098 {
1099 struct brcmf_fws_mac_descriptor *entry;
1100 u8 ifidx;
1101 int ret;
1102
1103 ifidx = data[0];
1104
1105 if (ifidx >= BRCMF_MAX_IFS) {
1106 ret = -ERANGE;
1107 goto fail;
1108 }
1109
1110 entry = &fws->desc.iface[ifidx];
1111 if (!entry->occupied) {
1112 ret = -ESRCH;
1113 goto fail;
1114 }
1115
1116 brcmf_dbg(TRACE, "%s (%d): %s\n", brcmf_fws_get_tlv_name(type), type,
1117 entry->name);
1118 brcmf_fws_lock(fws);
1119 switch (type) {
1120 case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1121 entry->state = BRCMF_FWS_STATE_OPEN;
1122 ret = BRCMF_FWS_RET_OK_SCHEDULE;
1123 break;
1124 case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1125 entry->state = BRCMF_FWS_STATE_CLOSE;
1126 ret = BRCMF_FWS_RET_OK_NOSCHEDULE;
1127 break;
1128 default:
1129 ret = -EINVAL;
1130 brcmf_fws_unlock(fws);
1131 goto fail;
1132 }
1133 brcmf_fws_unlock(fws);
1134 return ret;
1135
1136 fail:
1137 fws->stats.if_update_failed++;
1138 return ret;
1139 }
1140
1141 static int brcmf_fws_request_indicate(struct brcmf_fws_info *fws, u8 type,
1142 u8 *data)
1143 {
1144 struct brcmf_fws_mac_descriptor *entry;
1145
1146 entry = &fws->desc.nodes[data[1] & 0x1F];
1147 if (!entry->occupied) {
1148 if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1149 fws->stats.credit_request_failed++;
1150 else
1151 fws->stats.packet_request_failed++;
1152 return -ESRCH;
1153 }
1154
1155 brcmf_dbg(TRACE, "%s (%d): %s cnt %d bmp %d\n",
1156 brcmf_fws_get_tlv_name(type), type, entry->name,
1157 data[0], data[2]);
1158 brcmf_fws_lock(fws);
1159 if (type == BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT)
1160 entry->requested_credit = data[0];
1161 else
1162 entry->requested_packet = data[0];
1163
1164 entry->ac_bitmap = data[2];
1165 brcmf_fws_unlock(fws);
1166 return BRCMF_FWS_RET_OK_SCHEDULE;
1167 }
1168
1169 static void
1170 brcmf_fws_macdesc_use_req_credit(struct brcmf_fws_mac_descriptor *entry,
1171 struct sk_buff *skb)
1172 {
1173 if (entry->requested_credit > 0) {
1174 entry->requested_credit--;
1175 brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1176 brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 1);
1177 if (entry->state != BRCMF_FWS_STATE_CLOSE)
1178 brcmf_err("requested credit set while mac not closed!\n");
1179 } else if (entry->requested_packet > 0) {
1180 entry->requested_packet--;
1181 brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1182 brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1183 if (entry->state != BRCMF_FWS_STATE_CLOSE)
1184 brcmf_err("requested packet set while mac not closed!\n");
1185 } else {
1186 brcmf_skb_if_flags_set_field(skb, REQUESTED, 0);
1187 brcmf_skb_if_flags_set_field(skb, REQ_CREDIT, 0);
1188 }
1189 }
1190
1191 static void brcmf_fws_macdesc_return_req_credit(struct sk_buff *skb)
1192 {
1193 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1194
1195 if ((brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) &&
1196 (entry->state == BRCMF_FWS_STATE_CLOSE))
1197 entry->requested_credit++;
1198 }
1199
1200 static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
1201 u8 fifo, u8 credits)
1202 {
1203 int lender_ac;
1204 int *borrowed;
1205 int *fifo_credit;
1206
1207 if (!credits)
1208 return;
1209
1210 fws->fifo_credit_map |= 1 << fifo;
1211
1212 if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
1213 (fws->credits_borrowed[0])) {
1214 for (lender_ac = BRCMF_FWS_FIFO_AC_VO; lender_ac >= 0;
1215 lender_ac--) {
1216 borrowed = &fws->credits_borrowed[lender_ac];
1217 if (*borrowed) {
1218 fws->fifo_credit_map |= (1 << lender_ac);
1219 fifo_credit = &fws->fifo_credit[lender_ac];
1220 if (*borrowed >= credits) {
1221 *borrowed -= credits;
1222 *fifo_credit += credits;
1223 return;
1224 } else {
1225 credits -= *borrowed;
1226 *fifo_credit += *borrowed;
1227 *borrowed = 0;
1228 }
1229 }
1230 }
1231 }
1232
1233 fws->fifo_credit[fifo] += credits;
1234 if (fws->fifo_credit[fifo] > fws->init_fifo_credit[fifo])
1235 fws->fifo_credit[fifo] = fws->init_fifo_credit[fifo];
1236
1237 }
1238
1239 static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
1240 {
1241
1242 if ((fws->fifo_credit_map & fws->fifo_delay_map) ||
1243 (!brcmf_fws_fc_active(fws) && fws->fifo_delay_map))
1244 queue_work(fws->fws_wq, &fws->fws_dequeue_work);
1245 }
1246
1247 static int brcmf_fws_enq(struct brcmf_fws_info *fws,
1248 enum brcmf_fws_skb_state state, int fifo,
1249 struct sk_buff *p)
1250 {
1251 struct brcmf_pub *drvr = fws->drvr;
1252 int prec = 2 * fifo;
1253 u32 *qfull_stat = &fws->stats.delayq_full_error;
1254 struct brcmf_fws_mac_descriptor *entry;
1255 struct pktq *pq;
1256 struct sk_buff_head *queue;
1257 struct sk_buff *p_head;
1258 struct sk_buff *p_tail;
1259 u32 fr_new;
1260 u32 fr_compare;
1261
1262 entry = brcmf_skbcb(p)->mac;
1263 if (entry == NULL) {
1264 bphy_err(drvr, "no mac descriptor found for skb %p\n", p);
1265 return -ENOENT;
1266 }
1267
1268 brcmf_dbg(DATA, "enter: fifo %d skb %p\n", fifo, p);
1269 if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
1270 prec += 1;
1271 qfull_stat = &fws->stats.supprq_full_error;
1272
1273
1274
1275 pq = &entry->psq;
1276 if (pktq_full(pq) || pktq_pfull(pq, prec)) {
1277 *qfull_stat += 1;
1278 return -ENFILE;
1279 }
1280 queue = &pq->q[prec].skblist;
1281
1282 p_head = skb_peek(queue);
1283 p_tail = skb_peek_tail(queue);
1284 fr_new = brcmf_skb_htod_tag_get_field(p, FREERUN);
1285
1286 while (p_head != p_tail) {
1287 fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1288 FREERUN);
1289
1290 if (((fr_new > fr_compare) &&
1291 ((fr_new - fr_compare) < 128)) ||
1292 ((fr_new < fr_compare) &&
1293 ((fr_compare - fr_new) > 128)))
1294 break;
1295 p_tail = skb_queue_prev(queue, p_tail);
1296 }
1297
1298 if (p_tail == NULL) {
1299
1300 __skb_queue_tail(queue, p);
1301 } else {
1302 fr_compare = brcmf_skb_htod_tag_get_field(p_tail,
1303 FREERUN);
1304 if (((fr_new > fr_compare) &&
1305 ((fr_new - fr_compare) < 128)) ||
1306 ((fr_new < fr_compare) &&
1307 ((fr_compare - fr_new) > 128))) {
1308
1309 __skb_queue_after(queue, p_tail, p);
1310 } else {
1311
1312 __skb_insert(p, p_tail->prev, p_tail, queue);
1313 }
1314 }
1315
1316
1317 pq->len++;
1318 if (pq->hi_prec < prec)
1319 pq->hi_prec = (u8) prec;
1320 } else if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
1321 *qfull_stat += 1;
1322 return -ENFILE;
1323 }
1324
1325
1326 fws->fifo_delay_map |= 1 << fifo;
1327 fws->fifo_enqpkt[fifo]++;
1328
1329
1330 brcmf_skbcb(p)->state = state;
1331
1332
1333
1334
1335
1336 brcmf_fws_tim_update(fws, entry, fifo, true);
1337 brcmf_fws_flow_control_check(fws, &entry->psq,
1338 brcmf_skb_if_flags_get_field(p, INDEX));
1339 return 0;
1340 }
1341
1342 static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
1343 {
1344 struct brcmf_fws_mac_descriptor *table;
1345 struct brcmf_fws_mac_descriptor *entry;
1346 struct sk_buff *p;
1347 int num_nodes;
1348 int node_pos;
1349 int prec_out;
1350 int pmsk;
1351 int i;
1352
1353 table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
1354 num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
1355 node_pos = fws->deq_node_pos[fifo];
1356
1357 for (i = 0; i < num_nodes; i++) {
1358 entry = &table[(node_pos + i) % num_nodes];
1359 if (!entry->occupied ||
1360 brcmf_fws_macdesc_closed(fws, entry, fifo))
1361 continue;
1362
1363 if (entry->suppressed)
1364 pmsk = 2;
1365 else
1366 pmsk = 3;
1367 p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
1368 if (p == NULL) {
1369 if (entry->suppressed) {
1370 if (entry->suppr_transit_count)
1371 continue;
1372 entry->suppressed = false;
1373 p = brcmu_pktq_mdeq(&entry->psq,
1374 1 << (fifo * 2), &prec_out);
1375 }
1376 }
1377 if (p == NULL)
1378 continue;
1379
1380 brcmf_fws_macdesc_use_req_credit(entry, p);
1381
1382
1383 fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
1384 brcmf_fws_flow_control_check(fws, &entry->psq,
1385 brcmf_skb_if_flags_get_field(p,
1386 INDEX)
1387 );
1388
1389
1390
1391
1392 brcmf_fws_tim_update(fws, entry, fifo, false);
1393
1394
1395
1396
1397
1398 fws->fifo_enqpkt[fifo]--;
1399 if (fws->fifo_enqpkt[fifo] == 0)
1400 fws->fifo_delay_map &= ~(1 << fifo);
1401 goto done;
1402 }
1403 p = NULL;
1404 done:
1405 brcmf_dbg(DATA, "exit: fifo %d skb %p\n", fifo, p);
1406 return p;
1407 }
1408
1409 static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1410 struct sk_buff *skb,
1411 u32 genbit, u16 seq)
1412 {
1413 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1414 u32 hslot;
1415 int ret;
1416
1417 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1418
1419
1420 if (!entry->suppressed) {
1421 entry->suppressed = true;
1422 entry->suppr_transit_count = entry->transit_count;
1423 brcmf_dbg(DATA, "suppress %s: transit %d\n",
1424 entry->name, entry->transit_count);
1425 }
1426
1427 entry->generation = genbit;
1428
1429 brcmf_skb_htod_tag_set_field(skb, GENERATION, genbit);
1430 brcmf_skbcb(skb)->htod_seq = seq;
1431 if (brcmf_skb_htod_seq_get_field(skb, FROMFW)) {
1432 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 1);
1433 brcmf_skb_htod_seq_set_field(skb, FROMFW, 0);
1434 } else {
1435 brcmf_skb_htod_seq_set_field(skb, FROMDRV, 0);
1436 }
1437 ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
1438
1439 if (ret != 0) {
1440
1441 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, true);
1442 } else {
1443
1444 brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot);
1445 }
1446
1447 return ret;
1448 }
1449
1450 static int
1451 brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1452 u32 genbit, u16 seq, u8 compcnt)
1453 {
1454 struct brcmf_pub *drvr = fws->drvr;
1455 u32 fifo;
1456 u8 cnt = 0;
1457 int ret;
1458 bool remove_from_hanger = true;
1459 struct sk_buff *skb;
1460 struct brcmf_skbuff_cb *skcb;
1461 struct brcmf_fws_mac_descriptor *entry = NULL;
1462 struct brcmf_if *ifp;
1463
1464 brcmf_dbg(DATA, "flags %d\n", flags);
1465
1466 if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
1467 fws->stats.txs_discard += compcnt;
1468 else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
1469 fws->stats.txs_supp_core += compcnt;
1470 remove_from_hanger = false;
1471 } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
1472 fws->stats.txs_supp_ps += compcnt;
1473 remove_from_hanger = false;
1474 } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
1475 fws->stats.txs_tossed += compcnt;
1476 else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
1477 fws->stats.txs_host_tossed += compcnt;
1478 else
1479 bphy_err(drvr, "unexpected txstatus\n");
1480
1481 while (cnt < compcnt) {
1482 ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1483 remove_from_hanger);
1484 if (ret != 0) {
1485 bphy_err(drvr, "no packet in hanger slot: hslot=%d\n",
1486 hslot);
1487 goto cont;
1488 }
1489
1490 skcb = brcmf_skbcb(skb);
1491 entry = skcb->mac;
1492 if (WARN_ON(!entry)) {
1493 brcmu_pkt_buf_free_skb(skb);
1494 goto cont;
1495 }
1496 entry->transit_count--;
1497 if (entry->suppressed && entry->suppr_transit_count)
1498 entry->suppr_transit_count--;
1499
1500 brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name,
1501 flags, skcb->htod, seq);
1502
1503
1504 fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
1505 if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT ||
1506 (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
1507 flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) {
1508 brcmf_fws_return_credits(fws, fifo, 1);
1509 brcmf_fws_schedule_deq(fws);
1510 }
1511 brcmf_fws_macdesc_return_req_credit(skb);
1512
1513 ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
1514 if (ret) {
1515 brcmu_pkt_buf_free_skb(skb);
1516 goto cont;
1517 }
1518 if (!remove_from_hanger)
1519 ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
1520 genbit, seq);
1521 if (remove_from_hanger || ret)
1522 brcmf_txfinalize(ifp, skb, true);
1523
1524 cont:
1525 hslot = (hslot + 1) & (BRCMF_FWS_TXSTAT_HSLOT_MASK >>
1526 BRCMF_FWS_TXSTAT_HSLOT_SHIFT);
1527 if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
1528 seq = (seq + 1) & BRCMF_SKB_HTOD_SEQ_NR_MASK;
1529
1530 cnt++;
1531 }
1532
1533 return 0;
1534 }
1535
1536 static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
1537 u8 *data)
1538 {
1539 int i;
1540
1541 if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
1542 brcmf_dbg(INFO, "ignored\n");
1543 return BRCMF_FWS_RET_OK_NOSCHEDULE;
1544 }
1545
1546 brcmf_dbg(DATA, "enter: data %pM\n", data);
1547 brcmf_fws_lock(fws);
1548 for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
1549 brcmf_fws_return_credits(fws, i, data[i]);
1550
1551 brcmf_dbg(DATA, "map: credit %x delay %x\n", fws->fifo_credit_map,
1552 fws->fifo_delay_map);
1553 brcmf_fws_unlock(fws);
1554 return BRCMF_FWS_RET_OK_SCHEDULE;
1555 }
1556
1557 static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 type,
1558 u8 *data)
1559 {
1560 __le32 status_le;
1561 __le16 seq_le;
1562 u32 status;
1563 u32 hslot;
1564 u32 genbit;
1565 u8 flags;
1566 u16 seq;
1567 u8 compcnt;
1568 u8 compcnt_offset = BRCMF_FWS_TYPE_TXSTATUS_LEN;
1569
1570 memcpy(&status_le, data, sizeof(status_le));
1571 status = le32_to_cpu(status_le);
1572 flags = brcmf_txstatus_get_field(status, FLAGS);
1573 hslot = brcmf_txstatus_get_field(status, HSLOT);
1574 genbit = brcmf_txstatus_get_field(status, GENERATION);
1575 if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
1576 memcpy(&seq_le, &data[BRCMF_FWS_TYPE_TXSTATUS_LEN],
1577 sizeof(seq_le));
1578 seq = le16_to_cpu(seq_le);
1579 compcnt_offset += BRCMF_FWS_TYPE_SEQ_LEN;
1580 } else {
1581 seq = 0;
1582 }
1583
1584 if (type == BRCMF_FWS_TYPE_COMP_TXSTATUS)
1585 compcnt = data[compcnt_offset];
1586 else
1587 compcnt = 1;
1588 fws->stats.txs_indicate += compcnt;
1589
1590 brcmf_fws_lock(fws);
1591 brcmf_fws_txs_process(fws, flags, hslot, genbit, seq, compcnt);
1592 brcmf_fws_unlock(fws);
1593 return BRCMF_FWS_RET_OK_NOSCHEDULE;
1594 }
1595
1596 static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
1597 {
1598 __le32 timestamp;
1599
1600 memcpy(×tamp, &data[2], sizeof(timestamp));
1601 brcmf_dbg(CTL, "received: seq %d, timestamp %d\n", data[1],
1602 le32_to_cpu(timestamp));
1603 return 0;
1604 }
1605
1606 static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
1607 const struct brcmf_event_msg *e,
1608 void *data)
1609 {
1610 struct brcmf_pub *drvr = ifp->drvr;
1611 struct brcmf_fws_info *fws = drvr_to_fws(drvr);
1612 int i;
1613 u8 *credits = data;
1614
1615 if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
1616 bphy_err(drvr, "event payload too small (%d)\n", e->datalen);
1617 return -EINVAL;
1618 }
1619
1620 fws->creditmap_received = true;
1621
1622 brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
1623 brcmf_fws_lock(fws);
1624 for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
1625 fws->fifo_credit[i] += credits[i] - fws->init_fifo_credit[i];
1626 fws->init_fifo_credit[i] = credits[i];
1627 if (fws->fifo_credit[i] > 0)
1628 fws->fifo_credit_map |= 1 << i;
1629 else
1630 fws->fifo_credit_map &= ~(1 << i);
1631 WARN_ONCE(fws->fifo_credit[i] < 0,
1632 "fifo_credit[%d] is negative(%d)\n", i,
1633 fws->fifo_credit[i]);
1634 }
1635 brcmf_fws_schedule_deq(fws);
1636 brcmf_fws_unlock(fws);
1637 return 0;
1638 }
1639
1640 static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
1641 const struct brcmf_event_msg *e,
1642 void *data)
1643 {
1644 struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1645
1646 if (fws) {
1647 brcmf_fws_lock(fws);
1648 fws->bcmc_credit_check = true;
1649 brcmf_fws_unlock(fws);
1650 }
1651 return 0;
1652 }
1653
1654 static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
1655 u8 start, u8 end,
1656 struct sk_buff_head *skb_list)
1657 {
1658
1659 __skb_queue_head_init(skb_list);
1660
1661 if (rfi->pend_pkts == 0) {
1662 brcmf_dbg(INFO, "no packets in reorder queue\n");
1663 return;
1664 }
1665
1666 do {
1667 if (rfi->pktslots[start]) {
1668 __skb_queue_tail(skb_list, rfi->pktslots[start]);
1669 rfi->pktslots[start] = NULL;
1670 }
1671 start++;
1672 if (start > rfi->max_idx)
1673 start = 0;
1674 } while (start != end);
1675 rfi->pend_pkts -= skb_queue_len(skb_list);
1676 }
1677
1678 void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
1679 {
1680 struct brcmf_pub *drvr = ifp->drvr;
1681 u8 *reorder_data;
1682 u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
1683 struct brcmf_ampdu_rx_reorder *rfi;
1684 struct sk_buff_head reorder_list;
1685 struct sk_buff *pnext;
1686 u8 flags;
1687 u32 buf_size;
1688
1689 reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
1690 flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
1691 flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
1692
1693
1694 if (flags == 0xFF) {
1695 bphy_err(drvr, "invalid flags...so ignore this packet\n");
1696 brcmf_netif_rx(ifp, pkt);
1697 return;
1698 }
1699
1700 rfi = ifp->drvr->reorder_flows[flow_id];
1701 if (flags & BRCMF_RXREORDER_DEL_FLOW) {
1702 brcmf_dbg(INFO, "flow-%d: delete\n",
1703 flow_id);
1704
1705 if (rfi == NULL) {
1706 brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
1707 flow_id);
1708 brcmf_netif_rx(ifp, pkt);
1709 return;
1710 }
1711
1712 brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
1713 &reorder_list);
1714
1715 __skb_queue_tail(&reorder_list, pkt);
1716 kfree(rfi);
1717 ifp->drvr->reorder_flows[flow_id] = NULL;
1718 goto netif_rx;
1719 }
1720
1721 if (rfi == NULL) {
1722 buf_size = sizeof(*rfi);
1723 max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1724
1725 buf_size += (max_idx + 1) * sizeof(pkt);
1726
1727
1728 brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
1729 flow_id, max_idx);
1730 rfi = kzalloc(buf_size, GFP_ATOMIC);
1731 if (rfi == NULL) {
1732 bphy_err(drvr, "failed to alloc buffer\n");
1733 brcmf_netif_rx(ifp, pkt);
1734 return;
1735 }
1736
1737 ifp->drvr->reorder_flows[flow_id] = rfi;
1738 rfi->pktslots = (struct sk_buff **)(rfi + 1);
1739 rfi->max_idx = max_idx;
1740 }
1741 if (flags & BRCMF_RXREORDER_NEW_HOLE) {
1742 if (rfi->pend_pkts) {
1743 brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
1744 rfi->exp_idx,
1745 &reorder_list);
1746 WARN_ON(rfi->pend_pkts);
1747 } else {
1748 __skb_queue_head_init(&reorder_list);
1749 }
1750 rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1751 rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1752 rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
1753 rfi->pktslots[rfi->cur_idx] = pkt;
1754 rfi->pend_pkts++;
1755 brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
1756 flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
1757 } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
1758 cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
1759 exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1760
1761 if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
1762
1763
1764 if (rfi->pktslots[cur_idx] != NULL) {
1765 brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
1766 brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1767 rfi->pktslots[cur_idx] = NULL;
1768 }
1769 rfi->pktslots[cur_idx] = pkt;
1770 rfi->pend_pkts++;
1771 rfi->cur_idx = cur_idx;
1772 brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
1773 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1774
1775
1776
1777
1778 return;
1779 }
1780 if (rfi->exp_idx == cur_idx) {
1781 if (rfi->pktslots[cur_idx] != NULL) {
1782 brcmf_dbg(INFO, "error buffer pending..free it\n");
1783 brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
1784 rfi->pktslots[cur_idx] = NULL;
1785 }
1786 rfi->pktslots[cur_idx] = pkt;
1787 rfi->pend_pkts++;
1788
1789
1790
1791
1792 brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
1793 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
1794
1795 rfi->cur_idx = cur_idx;
1796 rfi->exp_idx = exp_idx;
1797
1798 brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
1799 &reorder_list);
1800 brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
1801 flow_id, skb_queue_len(&reorder_list),
1802 rfi->pend_pkts);
1803 } else {
1804 u8 end_idx;
1805
1806 brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
1807 flow_id, flags, rfi->cur_idx, rfi->exp_idx,
1808 cur_idx, exp_idx);
1809 if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1810 end_idx = rfi->exp_idx;
1811 else
1812 end_idx = exp_idx;
1813
1814
1815 brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1816 &reorder_list);
1817
1818 if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
1819 __skb_queue_tail(&reorder_list, pkt);
1820 } else {
1821 rfi->pktslots[cur_idx] = pkt;
1822 rfi->pend_pkts++;
1823 }
1824 rfi->exp_idx = exp_idx;
1825 rfi->cur_idx = cur_idx;
1826 }
1827 } else {
1828
1829 exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
1830
1831 brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
1832 flow_id, flags, rfi->exp_idx, exp_idx);
1833 if (flags & BRCMF_RXREORDER_FLUSH_ALL)
1834 end_idx = rfi->exp_idx;
1835 else
1836 end_idx = exp_idx;
1837
1838 brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
1839 &reorder_list);
1840 __skb_queue_tail(&reorder_list, pkt);
1841
1842 rfi->exp_idx = exp_idx;
1843 }
1844 netif_rx:
1845 skb_queue_walk_safe(&reorder_list, pkt, pnext) {
1846 __skb_unlink(pkt, &reorder_list);
1847 brcmf_netif_rx(ifp, pkt);
1848 }
1849 }
1850
1851 void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
1852 {
1853 struct brcmf_skb_reorder_data *rd;
1854 struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
1855 u8 *signal_data;
1856 s16 data_len;
1857 u8 type;
1858 u8 len;
1859 u8 *data;
1860 s32 status;
1861 s32 err;
1862
1863 brcmf_dbg(HDRS, "enter: ifidx %d, skblen %u, sig %d\n",
1864 ifp->ifidx, skb->len, siglen);
1865
1866 WARN_ON(siglen > skb->len);
1867
1868 if (!siglen)
1869 return;
1870
1871 if ((!fws) || (!fws->fw_signals)) {
1872 skb_pull(skb, siglen);
1873 return;
1874 }
1875
1876 fws->stats.header_pulls++;
1877 data_len = siglen;
1878 signal_data = skb->data;
1879
1880 status = BRCMF_FWS_RET_OK_NOSCHEDULE;
1881 while (data_len > 0) {
1882
1883 type = signal_data[0];
1884
1885
1886
1887
1888 if (type == BRCMF_FWS_TYPE_FILLER) {
1889 signal_data += 1;
1890 data_len -= 1;
1891 continue;
1892 }
1893 len = signal_data[1];
1894 data = signal_data + 2;
1895
1896 brcmf_dbg(HDRS, "tlv type=%s (%d), len=%d (%d)\n",
1897 brcmf_fws_get_tlv_name(type), type, len,
1898 brcmf_fws_get_tlv_len(fws, type));
1899
1900
1901 if (data_len < len + 2)
1902 break;
1903
1904 if (len < brcmf_fws_get_tlv_len(fws, type))
1905 break;
1906
1907 err = BRCMF_FWS_RET_OK_NOSCHEDULE;
1908 switch (type) {
1909 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
1910 rd = (struct brcmf_skb_reorder_data *)skb->cb;
1911 rd->reorder = data;
1912 break;
1913 case BRCMF_FWS_TYPE_MACDESC_ADD:
1914 case BRCMF_FWS_TYPE_MACDESC_DEL:
1915 brcmf_fws_macdesc_indicate(fws, type, data);
1916 break;
1917 case BRCMF_FWS_TYPE_MAC_OPEN:
1918 case BRCMF_FWS_TYPE_MAC_CLOSE:
1919 err = brcmf_fws_macdesc_state_indicate(fws, type, data);
1920 break;
1921 case BRCMF_FWS_TYPE_INTERFACE_OPEN:
1922 case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
1923 err = brcmf_fws_interface_state_indicate(fws, type,
1924 data);
1925 break;
1926 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
1927 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
1928 err = brcmf_fws_request_indicate(fws, type, data);
1929 break;
1930 case BRCMF_FWS_TYPE_TXSTATUS:
1931 case BRCMF_FWS_TYPE_COMP_TXSTATUS:
1932 brcmf_fws_txstatus_indicate(fws, type, data);
1933 break;
1934 case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
1935 err = brcmf_fws_fifocreditback_indicate(fws, data);
1936 break;
1937 case BRCMF_FWS_TYPE_RSSI:
1938 brcmf_fws_rssi_indicate(fws, *data);
1939 break;
1940 case BRCMF_FWS_TYPE_TRANS_ID:
1941 brcmf_fws_dbg_seqnum_check(fws, data);
1942 break;
1943 case BRCMF_FWS_TYPE_PKTTAG:
1944 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
1945 default:
1946 fws->stats.tlv_invalid_type++;
1947 break;
1948 }
1949 if (err == BRCMF_FWS_RET_OK_SCHEDULE)
1950 status = BRCMF_FWS_RET_OK_SCHEDULE;
1951 signal_data += len + 2;
1952 data_len -= len + 2;
1953 }
1954
1955 if (data_len != 0)
1956 fws->stats.tlv_parse_failed++;
1957
1958 if (status == BRCMF_FWS_RET_OK_SCHEDULE)
1959 brcmf_fws_schedule_deq(fws);
1960
1961
1962
1963
1964 skb_pull(skb, siglen);
1965
1966
1967
1968 if (skb->len == 0)
1969 fws->stats.header_only_pkt++;
1970 }
1971
1972 static u8 brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1973 struct sk_buff *p)
1974 {
1975 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
1976 struct brcmf_fws_mac_descriptor *entry = skcb->mac;
1977 u8 flags;
1978
1979 if (skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED)
1980 brcmf_skb_htod_tag_set_field(p, GENERATION, entry->generation);
1981 flags = BRCMF_FWS_HTOD_FLAG_PKTFROMHOST;
1982 if (brcmf_skb_if_flags_get_field(p, REQUESTED)) {
1983
1984
1985
1986
1987 flags |= BRCMF_FWS_HTOD_FLAG_PKT_REQUESTED;
1988 }
1989 brcmf_skb_htod_tag_set_field(p, FLAGS, flags);
1990 return brcmf_fws_hdrpush(fws, p);
1991 }
1992
1993 static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
1994 struct sk_buff *skb, int fifo)
1995 {
1996 struct brcmf_pub *drvr = fws->drvr;
1997 struct brcmf_fws_mac_descriptor *entry;
1998 struct sk_buff *pktout;
1999 int qidx, hslot;
2000 int rc = 0;
2001
2002 entry = brcmf_skbcb(skb)->mac;
2003 if (entry->occupied) {
2004 qidx = 2 * fifo;
2005 if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
2006 qidx++;
2007
2008 pktout = brcmu_pktq_penq_head(&entry->psq, qidx, skb);
2009 if (pktout == NULL) {
2010 bphy_err(drvr, "%s queue %d full\n", entry->name, qidx);
2011 rc = -ENOSPC;
2012 }
2013 } else {
2014 bphy_err(drvr, "%s entry removed\n", entry->name);
2015 rc = -ENOENT;
2016 }
2017
2018 if (rc) {
2019 fws->stats.rollback_failed++;
2020 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2021 brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
2022 hslot, 0, 0, 1);
2023 } else {
2024 fws->stats.rollback_success++;
2025 brcmf_fws_return_credits(fws, fifo, 1);
2026 brcmf_fws_macdesc_return_req_credit(skb);
2027 }
2028 }
2029
2030 static int brcmf_fws_borrow_credit(struct brcmf_fws_info *fws)
2031 {
2032 int lender_ac;
2033
2034 if (time_after(fws->borrow_defer_timestamp, jiffies)) {
2035 fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
2036 return -ENAVAIL;
2037 }
2038
2039 for (lender_ac = 0; lender_ac <= BRCMF_FWS_FIFO_AC_VO; lender_ac++) {
2040 if (fws->fifo_credit[lender_ac] > 0) {
2041 fws->credits_borrowed[lender_ac]++;
2042 fws->fifo_credit[lender_ac]--;
2043 if (fws->fifo_credit[lender_ac] == 0)
2044 fws->fifo_credit_map &= ~(1 << lender_ac);
2045 fws->fifo_credit_map |= (1 << BRCMF_FWS_FIFO_AC_BE);
2046 brcmf_dbg(DATA, "borrow credit from: %d\n", lender_ac);
2047 return 0;
2048 }
2049 }
2050 fws->fifo_credit_map &= ~(1 << BRCMF_FWS_FIFO_AC_BE);
2051 return -ENAVAIL;
2052 }
2053
2054 static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
2055 struct sk_buff *skb)
2056 {
2057 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2058 struct brcmf_fws_mac_descriptor *entry;
2059 int rc;
2060 u8 ifidx;
2061 u8 data_offset;
2062
2063 entry = skcb->mac;
2064 if (IS_ERR(entry))
2065 return PTR_ERR(entry);
2066
2067 data_offset = brcmf_fws_precommit_skb(fws, fifo, skb);
2068 entry->transit_count++;
2069 if (entry->suppressed)
2070 entry->suppr_transit_count++;
2071 ifidx = brcmf_skb_if_flags_get_field(skb, INDEX);
2072 brcmf_fws_unlock(fws);
2073 rc = brcmf_proto_txdata(fws->drvr, ifidx, data_offset, skb);
2074 brcmf_fws_lock(fws);
2075 brcmf_dbg(DATA, "%s flags %X htod %X bus_tx %d\n", entry->name,
2076 skcb->if_flags, skcb->htod, rc);
2077 if (rc < 0) {
2078 entry->transit_count--;
2079 if (entry->suppressed)
2080 entry->suppr_transit_count--;
2081 (void)brcmf_proto_hdrpull(fws->drvr, false, skb, NULL);
2082 goto rollback;
2083 }
2084
2085 fws->stats.pkt2bus++;
2086 fws->stats.send_pkts[fifo]++;
2087 if (brcmf_skb_if_flags_get_field(skb, REQUESTED))
2088 fws->stats.requested_sent[fifo]++;
2089
2090 return rc;
2091
2092 rollback:
2093 brcmf_fws_rollback_toq(fws, skb, fifo);
2094 return rc;
2095 }
2096
2097 static int brcmf_fws_assign_htod(struct brcmf_fws_info *fws, struct sk_buff *p,
2098 int fifo)
2099 {
2100 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(p);
2101 int rc, hslot;
2102
2103 skcb->htod = 0;
2104 skcb->htod_seq = 0;
2105 hslot = brcmf_fws_hanger_get_free_slot(&fws->hanger);
2106 brcmf_skb_htod_tag_set_field(p, HSLOT, hslot);
2107 brcmf_skb_htod_tag_set_field(p, FREERUN, skcb->mac->seq[fifo]);
2108 brcmf_skb_htod_tag_set_field(p, FIFO, fifo);
2109 rc = brcmf_fws_hanger_pushpkt(&fws->hanger, p, hslot);
2110 if (!rc)
2111 skcb->mac->seq[fifo]++;
2112 else
2113 fws->stats.generic_error++;
2114 return rc;
2115 }
2116
2117 int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
2118 {
2119 struct brcmf_pub *drvr = ifp->drvr;
2120 struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2121 struct brcmf_skbuff_cb *skcb = brcmf_skbcb(skb);
2122 struct ethhdr *eh = (struct ethhdr *)(skb->data);
2123 int fifo = BRCMF_FWS_FIFO_BCMC;
2124 bool multicast = is_multicast_ether_addr(eh->h_dest);
2125 int rc = 0;
2126
2127 brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
2128
2129
2130 skcb->if_flags = 0;
2131 skcb->state = BRCMF_FWS_SKBSTATE_NEW;
2132 brcmf_skb_if_flags_set_field(skb, INDEX, ifp->ifidx);
2133 if (!multicast)
2134 fifo = brcmf_fws_prio2fifo[skb->priority];
2135
2136 brcmf_fws_lock(fws);
2137 if (fifo != BRCMF_FWS_FIFO_AC_BE && fifo < BRCMF_FWS_FIFO_BCMC)
2138 fws->borrow_defer_timestamp = jiffies +
2139 BRCMF_FWS_BORROW_DEFER_PERIOD;
2140
2141 skcb->mac = brcmf_fws_macdesc_find(fws, ifp, eh->h_dest);
2142 brcmf_dbg(DATA, "%s mac %pM multi %d fifo %d\n", skcb->mac->name,
2143 eh->h_dest, multicast, fifo);
2144 if (!brcmf_fws_assign_htod(fws, skb, fifo)) {
2145 brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
2146 brcmf_fws_schedule_deq(fws);
2147 } else {
2148 bphy_err(drvr, "drop skb: no hanger slot\n");
2149 brcmf_txfinalize(ifp, skb, false);
2150 rc = -ENOMEM;
2151 }
2152 brcmf_fws_unlock(fws);
2153
2154 return rc;
2155 }
2156
2157 void brcmf_fws_reset_interface(struct brcmf_if *ifp)
2158 {
2159 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2160
2161 brcmf_dbg(TRACE, "enter: bsscfgidx=%d\n", ifp->bsscfgidx);
2162 if (!entry)
2163 return;
2164
2165 brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2166 }
2167
2168 void brcmf_fws_add_interface(struct brcmf_if *ifp)
2169 {
2170 struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2171 struct brcmf_fws_mac_descriptor *entry;
2172
2173 if (!ifp->ndev || !brcmf_fws_queue_skbs(fws))
2174 return;
2175
2176 entry = &fws->desc.iface[ifp->ifidx];
2177 ifp->fws_desc = entry;
2178 brcmf_fws_macdesc_init(entry, ifp->mac_addr, ifp->ifidx);
2179 brcmf_fws_macdesc_set_name(fws, entry);
2180 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
2181 BRCMF_FWS_PSQ_LEN);
2182 brcmf_dbg(TRACE, "added %s\n", entry->name);
2183 }
2184
2185 void brcmf_fws_del_interface(struct brcmf_if *ifp)
2186 {
2187 struct brcmf_fws_mac_descriptor *entry = ifp->fws_desc;
2188 struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr);
2189
2190 if (!entry)
2191 return;
2192
2193 brcmf_fws_lock(fws);
2194 ifp->fws_desc = NULL;
2195 brcmf_dbg(TRACE, "deleting %s\n", entry->name);
2196 brcmf_fws_macdesc_cleanup(fws, &fws->desc.iface[ifp->ifidx],
2197 ifp->ifidx);
2198 brcmf_fws_macdesc_deinit(entry);
2199 brcmf_fws_cleanup(fws, ifp->ifidx);
2200 brcmf_fws_unlock(fws);
2201 }
2202
2203 static void brcmf_fws_dequeue_worker(struct work_struct *worker)
2204 {
2205 struct brcmf_fws_info *fws;
2206 struct brcmf_pub *drvr;
2207 struct sk_buff *skb;
2208 int fifo;
2209 u32 hslot;
2210 u32 ifidx;
2211 int ret;
2212
2213 fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
2214 drvr = fws->drvr;
2215
2216 brcmf_fws_lock(fws);
2217 for (fifo = BRCMF_FWS_FIFO_BCMC; fifo >= 0 && !fws->bus_flow_blocked;
2218 fifo--) {
2219 if (!brcmf_fws_fc_active(fws)) {
2220 while ((skb = brcmf_fws_deq(fws, fifo)) != NULL) {
2221 hslot = brcmf_skb_htod_tag_get_field(skb,
2222 HSLOT);
2223 brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
2224 &skb, true);
2225 ifidx = brcmf_skb_if_flags_get_field(skb,
2226 INDEX);
2227
2228 brcmf_fws_unlock(fws);
2229 ret = brcmf_proto_txdata(drvr, ifidx, 0, skb);
2230 brcmf_fws_lock(fws);
2231 if (ret < 0)
2232 brcmf_txfinalize(brcmf_get_ifp(drvr,
2233 ifidx),
2234 skb, false);
2235 if (fws->bus_flow_blocked)
2236 break;
2237 }
2238 continue;
2239 }
2240 while ((fws->fifo_credit[fifo] > 0) ||
2241 ((!fws->bcmc_credit_check) &&
2242 (fifo == BRCMF_FWS_FIFO_BCMC))) {
2243 skb = brcmf_fws_deq(fws, fifo);
2244 if (!skb)
2245 break;
2246 fws->fifo_credit[fifo]--;
2247 if (brcmf_fws_commit_skb(fws, fifo, skb))
2248 break;
2249 if (fws->bus_flow_blocked)
2250 break;
2251 }
2252 if ((fifo == BRCMF_FWS_FIFO_AC_BE) &&
2253 (fws->fifo_credit[fifo] <= 0) &&
2254 (!fws->bus_flow_blocked)) {
2255 while (brcmf_fws_borrow_credit(fws) == 0) {
2256 skb = brcmf_fws_deq(fws, fifo);
2257 if (!skb) {
2258 brcmf_fws_return_credits(fws, fifo, 1);
2259 break;
2260 }
2261 if (brcmf_fws_commit_skb(fws, fifo, skb))
2262 break;
2263 if (fws->bus_flow_blocked)
2264 break;
2265 }
2266 }
2267 }
2268 brcmf_fws_unlock(fws);
2269 }
2270
2271 #ifdef DEBUG
2272 static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2273 {
2274 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private);
2275 struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats);
2276
2277 seq_printf(seq,
2278 "header_pulls: %u\n"
2279 "header_only_pkt: %u\n"
2280 "tlv_parse_failed: %u\n"
2281 "tlv_invalid_type: %u\n"
2282 "mac_update_fails: %u\n"
2283 "ps_update_fails: %u\n"
2284 "if_update_fails: %u\n"
2285 "pkt2bus: %u\n"
2286 "generic_error: %u\n"
2287 "rollback_success: %u\n"
2288 "rollback_failed: %u\n"
2289 "delayq_full: %u\n"
2290 "supprq_full: %u\n"
2291 "txs_indicate: %u\n"
2292 "txs_discard: %u\n"
2293 "txs_suppr_core: %u\n"
2294 "txs_suppr_ps: %u\n"
2295 "txs_tossed: %u\n"
2296 "txs_host_tossed: %u\n"
2297 "bus_flow_block: %u\n"
2298 "fws_flow_block: %u\n"
2299 "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
2300 "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
2301 fwstats->header_pulls,
2302 fwstats->header_only_pkt,
2303 fwstats->tlv_parse_failed,
2304 fwstats->tlv_invalid_type,
2305 fwstats->mac_update_failed,
2306 fwstats->mac_ps_update_failed,
2307 fwstats->if_update_failed,
2308 fwstats->pkt2bus,
2309 fwstats->generic_error,
2310 fwstats->rollback_success,
2311 fwstats->rollback_failed,
2312 fwstats->delayq_full_error,
2313 fwstats->supprq_full_error,
2314 fwstats->txs_indicate,
2315 fwstats->txs_discard,
2316 fwstats->txs_supp_core,
2317 fwstats->txs_supp_ps,
2318 fwstats->txs_tossed,
2319 fwstats->txs_host_tossed,
2320 fwstats->bus_flow_block,
2321 fwstats->fws_flow_block,
2322 fwstats->send_pkts[0], fwstats->send_pkts[1],
2323 fwstats->send_pkts[2], fwstats->send_pkts[3],
2324 fwstats->send_pkts[4],
2325 fwstats->requested_sent[0],
2326 fwstats->requested_sent[1],
2327 fwstats->requested_sent[2],
2328 fwstats->requested_sent[3],
2329 fwstats->requested_sent[4]);
2330
2331 return 0;
2332 }
2333 #else
2334 static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data)
2335 {
2336 return 0;
2337 }
2338 #endif
2339
2340 struct brcmf_fws_info *brcmf_fws_attach(struct brcmf_pub *drvr)
2341 {
2342 struct brcmf_fws_info *fws;
2343 struct brcmf_if *ifp;
2344 u32 tlv = BRCMF_FWS_FLAGS_RSSI_SIGNALS;
2345 int rc;
2346 u32 mode;
2347
2348 fws = kzalloc(sizeof(*fws), GFP_KERNEL);
2349 if (!fws) {
2350 rc = -ENOMEM;
2351 goto fail;
2352 }
2353
2354 spin_lock_init(&fws->spinlock);
2355
2356
2357 fws->drvr = drvr;
2358 fws->fcmode = drvr->settings->fcmode;
2359
2360 if ((drvr->bus_if->always_use_fws_queue == false) &&
2361 (fws->fcmode == BRCMF_FWS_FCMODE_NONE)) {
2362 fws->avoid_queueing = true;
2363 brcmf_dbg(INFO, "FWS queueing will be avoided\n");
2364 return fws;
2365 }
2366
2367 fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
2368 if (fws->fws_wq == NULL) {
2369 bphy_err(drvr, "workqueue creation failed\n");
2370 rc = -EBADF;
2371 goto fail;
2372 }
2373 INIT_WORK(&fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
2374
2375
2376 if (fws->fcmode != BRCMF_FWS_FCMODE_NONE)
2377 tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
2378 BRCMF_FWS_FLAGS_CREDIT_STATUS_SIGNALS |
2379 BRCMF_FWS_FLAGS_HOST_PROPTXSTATUS_ACTIVE |
2380 BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE;
2381
2382 rc = brcmf_fweh_register(drvr, BRCMF_E_FIFO_CREDIT_MAP,
2383 brcmf_fws_notify_credit_map);
2384 if (rc < 0) {
2385 bphy_err(drvr, "register credit map handler failed\n");
2386 goto fail;
2387 }
2388 rc = brcmf_fweh_register(drvr, BRCMF_E_BCMC_CREDIT_SUPPORT,
2389 brcmf_fws_notify_bcmc_credit_support);
2390 if (rc < 0) {
2391 bphy_err(drvr, "register bcmc credit handler failed\n");
2392 brcmf_fweh_unregister(drvr, BRCMF_E_FIFO_CREDIT_MAP);
2393 goto fail;
2394 }
2395
2396
2397
2398
2399
2400 fws->fw_signals = true;
2401 ifp = brcmf_get_ifp(drvr, 0);
2402 if (brcmf_fil_iovar_int_set(ifp, "tlv", tlv)) {
2403 bphy_err(drvr, "failed to set bdcv2 tlv signaling\n");
2404 fws->fcmode = BRCMF_FWS_FCMODE_NONE;
2405 fws->fw_signals = false;
2406 }
2407
2408 if (brcmf_fil_iovar_int_set(ifp, "ampdu_hostreorder", 1))
2409 brcmf_dbg(INFO, "enabling AMPDU host-reorder failed\n");
2410
2411
2412 if (brcmf_fil_iovar_int_get(ifp, "wlfc_mode", &mode) == 0) {
2413 if (BRCMF_FWS_MODE_GET_REUSESEQ(mode)) {
2414 mode = 0;
2415 BRCMF_FWS_MODE_SET_REUSESEQ(mode, 1);
2416 if (brcmf_fil_iovar_int_set(ifp,
2417 "wlfc_mode", mode) == 0) {
2418 BRCMF_FWS_MODE_SET_REUSESEQ(fws->mode, 1);
2419 }
2420 }
2421 }
2422
2423 brcmf_fws_hanger_init(&fws->hanger);
2424 brcmf_fws_macdesc_init(&fws->desc.other, NULL, 0);
2425 brcmf_fws_macdesc_set_name(fws, &fws->desc.other);
2426 brcmf_dbg(INFO, "added %s\n", fws->desc.other.name);
2427 brcmu_pktq_init(&fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
2428 BRCMF_FWS_PSQ_LEN);
2429
2430 brcmf_dbg(INFO, "%s bdcv2 tlv signaling [%x]\n",
2431 fws->fw_signals ? "enabled" : "disabled", tlv);
2432 return fws;
2433
2434 fail:
2435 brcmf_fws_detach(fws);
2436 return ERR_PTR(rc);
2437 }
2438
2439 void brcmf_fws_detach(struct brcmf_fws_info *fws)
2440 {
2441 if (!fws)
2442 return;
2443
2444 if (fws->fws_wq)
2445 destroy_workqueue(fws->fws_wq);
2446
2447
2448 brcmf_fws_lock(fws);
2449 brcmf_fws_cleanup(fws, -1);
2450 brcmf_fws_unlock(fws);
2451
2452
2453 kfree(fws);
2454 }
2455
2456 void brcmf_fws_debugfs_create(struct brcmf_pub *drvr)
2457 {
2458
2459 brcmf_debugfs_add_entry(drvr, "fws_stats",
2460 brcmf_debugfs_fws_stats_read);
2461 }
2462
2463 bool brcmf_fws_queue_skbs(struct brcmf_fws_info *fws)
2464 {
2465 return !fws->avoid_queueing;
2466 }
2467
2468 bool brcmf_fws_fc_active(struct brcmf_fws_info *fws)
2469 {
2470 if (!fws->creditmap_received)
2471 return false;
2472
2473 return fws->fcmode != BRCMF_FWS_FCMODE_NONE;
2474 }
2475
2476 void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
2477 {
2478 u32 hslot;
2479
2480 if (brcmf_skbcb(skb)->state == BRCMF_FWS_SKBSTATE_TIM) {
2481 brcmu_pkt_buf_free_skb(skb);
2482 return;
2483 }
2484 brcmf_fws_lock(fws);
2485 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
2486 brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0,
2487 1);
2488 brcmf_fws_unlock(fws);
2489 }
2490
2491 void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked)
2492 {
2493 struct brcmf_fws_info *fws = drvr_to_fws(drvr);
2494 struct brcmf_if *ifp;
2495 int i;
2496
2497 if (fws->avoid_queueing) {
2498 for (i = 0; i < BRCMF_MAX_IFS; i++) {
2499 ifp = drvr->iflist[i];
2500 if (!ifp || !ifp->ndev)
2501 continue;
2502 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FLOW,
2503 flow_blocked);
2504 }
2505 } else {
2506 fws->bus_flow_blocked = flow_blocked;
2507 if (!flow_blocked)
2508 brcmf_fws_schedule_deq(fws);
2509 else
2510 fws->stats.bus_flow_block++;
2511 }
2512 }