aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c20
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c661
3 files changed, 627 insertions, 60 deletions
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
index 757701d57e5a..bd16f0b17aab 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
@@ -130,7 +130,7 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
130 size_t count, loff_t *ppos) 130 size_t count, loff_t *ppos)
131{ 131{
132 struct brcmf_fws_stats *fwstats = f->private_data; 132 struct brcmf_fws_stats *fwstats = f->private_data;
133 char buf[100]; 133 char buf[650];
134 int res; 134 int res;
135 135
136 /* only allow read from start */ 136 /* only allow read from start */
@@ -145,12 +145,17 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
145 "mac_update_fails: %u\n" 145 "mac_update_fails: %u\n"
146 "pkt2bus: %u\n" 146 "pkt2bus: %u\n"
147 "generic_error: %u\n" 147 "generic_error: %u\n"
148 "rollback_success: %u\n"
149 "rollback_failed: %u\n"
150 "delayq_full: %u\n"
151 "supprq_full: %u\n"
148 "txs_indicate: %u\n" 152 "txs_indicate: %u\n"
149 "txs_discard: %u\n" 153 "txs_discard: %u\n"
150 "txs_suppr_core: %u\n" 154 "txs_suppr_core: %u\n"
151 "txs_suppr_ps: %u\n" 155 "txs_suppr_ps: %u\n"
152 "txs_tossed: %u\n" 156 "txs_tossed: %u\n"
153 "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", 157 "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n"
158 "fifo_credits_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n",
154 fwstats->header_pulls, 159 fwstats->header_pulls,
155 fwstats->header_only_pkt, 160 fwstats->header_only_pkt,
156 fwstats->tlv_parse_failed, 161 fwstats->tlv_parse_failed,
@@ -158,6 +163,10 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
158 fwstats->mac_update_failed, 163 fwstats->mac_update_failed,
159 fwstats->pkt2bus, 164 fwstats->pkt2bus,
160 fwstats->generic_error, 165 fwstats->generic_error,
166 fwstats->rollback_success,
167 fwstats->rollback_failed,
168 fwstats->delayq_full_error,
169 fwstats->supprq_full_error,
161 fwstats->txs_indicate, 170 fwstats->txs_indicate,
162 fwstats->txs_discard, 171 fwstats->txs_discard,
163 fwstats->txs_supp_core, 172 fwstats->txs_supp_core,
@@ -165,7 +174,12 @@ ssize_t brcmf_debugfs_fws_stats_read(struct file *f, char __user *data,
165 fwstats->txs_tossed, 174 fwstats->txs_tossed,
166 fwstats->send_pkts[0], fwstats->send_pkts[1], 175 fwstats->send_pkts[0], fwstats->send_pkts[1],
167 fwstats->send_pkts[2], fwstats->send_pkts[3], 176 fwstats->send_pkts[2], fwstats->send_pkts[3],
168 fwstats->send_pkts[4]); 177 fwstats->send_pkts[4],
178 fwstats->fifo_credits_sent[0],
179 fwstats->fifo_credits_sent[1],
180 fwstats->fifo_credits_sent[2],
181 fwstats->fifo_credits_sent[3],
182 fwstats->fifo_credits_sent[4]);
169 183
170 return simple_read_from_buffer(data, count, ppos, buf, res); 184 return simple_read_from_buffer(data, count, ppos, buf, res);
171} 185}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
index 30c2e9b9fadd..a6b16a1e72fb 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
@@ -140,8 +140,14 @@ struct brcmf_fws_stats {
140 u32 header_pulls; 140 u32 header_pulls;
141 u32 pkt2bus; 141 u32 pkt2bus;
142 u32 send_pkts[5]; 142 u32 send_pkts[5];
143 u32 fifo_credits_sent[5];
144 u32 fifo_credits_back[6];
143 u32 generic_error; 145 u32 generic_error;
144 u32 mac_update_failed; 146 u32 mac_update_failed;
147 u32 rollback_success;
148 u32 rollback_failed;
149 u32 delayq_full_error;
150 u32 supprq_full_error;
145 u32 txs_indicate; 151 u32 txs_indicate;
146 u32 txs_discard; 152 u32 txs_discard;
147 u32 txs_supp_core; 153 u32 txs_supp_core;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
index 22a6eb2c7bf7..8ce79af47e66 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwsignal.c
@@ -130,15 +130,13 @@ static const char *brcmf_fws_get_tlv_name(enum brcmf_fws_tlv_type id)
130#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020 130#define BRCMF_FWS_FLAGS_PSQ_ZERO_BUFFER_ENABLE 0x0020
131#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040 131#define BRCMF_FWS_FLAGS_HOST_RXREORDER_ACTIVE 0x0040
132 132
133#define BRCMF_FWS_STATE_OPEN 1
134#define BRCMF_FWS_STATE_CLOSE 2
135
136#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32 133#define BRCMF_FWS_MAC_DESC_TABLE_SIZE 32
137#define BRCMF_FWS_MAX_IFNUM 16
138#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff 134#define BRCMF_FWS_MAC_DESC_ID_INVALID 0xff
139 135
140#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0 136#define BRCMF_FWS_HOSTIF_FLOWSTATE_OFF 0
141#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1 137#define BRCMF_FWS_HOSTIF_FLOWSTATE_ON 1
138#define BRCMF_FWS_FLOWCONTROL_HIWATER 128
139#define BRCMF_FWS_FLOWCONTROL_LOWATER 64
142 140
143#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2) 141#define BRCMF_FWS_PSQ_PREC_COUNT ((NL80211_NUM_ACS + 1) * 2)
144#define BRCMF_FWS_PSQ_LEN 256 142#define BRCMF_FWS_PSQ_LEN 256
@@ -313,6 +311,11 @@ enum brcmf_fws_fcmode {
313 BRCMF_FWS_FCMODE_EXPLICIT_CREDIT 311 BRCMF_FWS_FCMODE_EXPLICIT_CREDIT
314}; 312};
315 313
314enum brcmf_fws_mac_desc_state {
315 BRCMF_FWS_STATE_OPEN = 1,
316 BRCMF_FWS_STATE_CLOSE
317};
318
316/** 319/**
317 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface 320 * struct brcmf_fws_mac_descriptor - firmware signalling data per node/interface
318 * 321 *
@@ -338,10 +341,16 @@ struct brcmf_fws_mac_descriptor {
338 u8 generation; 341 u8 generation;
339 u8 ac_bitmap; 342 u8 ac_bitmap;
340 u8 requested_credit; 343 u8 requested_credit;
344 u8 requested_packet;
341 u8 ea[ETH_ALEN]; 345 u8 ea[ETH_ALEN];
342 u8 seq[BRCMF_FWS_FIFO_COUNT]; 346 u8 seq[BRCMF_FWS_FIFO_COUNT];
343 struct pktq psq; 347 struct pktq psq;
344 int transit_count; 348 int transit_count;
349 int suppress_count;
350 int suppr_transit_count;
351 bool send_tim_signal;
352 u8 traffic_pending_bmp;
353 u8 traffic_lastreported_bmp;
345}; 354};
346 355
347#define BRCMF_FWS_HANGER_MAXITEMS 1024 356#define BRCMF_FWS_HANGER_MAXITEMS 1024
@@ -394,14 +403,25 @@ struct brcmf_fws_hanger {
394 struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS]; 403 struct brcmf_fws_hanger_item items[BRCMF_FWS_HANGER_MAXITEMS];
395}; 404};
396 405
406struct brcmf_fws_macdesc_table {
407 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
408 struct brcmf_fws_mac_descriptor iface[BRCMF_MAX_IFS];
409 struct brcmf_fws_mac_descriptor other;
410};
411
397struct brcmf_fws_info { 412struct brcmf_fws_info {
398 struct brcmf_pub *drvr; 413 struct brcmf_pub *drvr;
399 struct brcmf_fws_stats stats; 414 struct brcmf_fws_stats stats;
400 struct brcmf_fws_hanger hanger; 415 struct brcmf_fws_hanger hanger;
401 struct brcmf_fws_mac_descriptor nodes[BRCMF_FWS_MAC_DESC_TABLE_SIZE];
402 struct brcmf_fws_mac_descriptor other;
403 enum brcmf_fws_fcmode fcmode; 416 enum brcmf_fws_fcmode fcmode;
417 struct brcmf_fws_macdesc_table desc;
418 struct workqueue_struct *fws_wq;
419 struct work_struct fws_dequeue_work;
420 u32 fifo_enqpkt[BRCMF_FWS_FIFO_COUNT];
404 int fifo_credit[BRCMF_FWS_FIFO_COUNT]; 421 int fifo_credit[BRCMF_FWS_FIFO_COUNT];
422 int deq_node_pos[BRCMF_FWS_FIFO_COUNT];
423 u32 fifo_credit_map;
424 u32 fifo_delay_map;
405}; 425};
406 426
407/* 427/*
@@ -465,7 +485,7 @@ static void brcmf_fws_psq_flush(struct brcmf_fws_info *fws, struct pktq *q,
465 for (prec = 0; prec < q->num_prec; prec++) { 485 for (prec = 0; prec < q->num_prec; prec++) {
466 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); 486 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
467 while (skb) { 487 while (skb) {
468 brcmf_txfinalize(fws->drvr, skb, false); 488 brcmu_pkt_buf_free_skb(skb);
469 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx); 489 skb = brcmu_pktq_pdeq_match(q, prec, matchfn, &ifidx);
470 } 490 }
471 } 491 }
@@ -491,7 +511,7 @@ static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
491 while (i != h->slot_pos) { 511 while (i != h->slot_pos) {
492 if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) { 512 if (h->items[i].state == BRCMF_FWS_HANGER_ITEM_STATE_FREE) {
493 h->slot_pos = i; 513 h->slot_pos = i;
494 return i; 514 goto done;
495 } 515 }
496 i++; 516 i++;
497 if (i == BRCMF_FWS_HANGER_MAXITEMS) 517 if (i == BRCMF_FWS_HANGER_MAXITEMS)
@@ -499,7 +519,10 @@ static u32 brcmf_fws_hanger_get_free_slot(struct brcmf_fws_hanger *h)
499 } 519 }
500 brcmf_err("all slots occupied\n"); 520 brcmf_err("all slots occupied\n");
501 h->failed_slotfind++; 521 h->failed_slotfind++;
502 return BRCMF_FWS_HANGER_MAXITEMS; 522 i = BRCMF_FWS_HANGER_MAXITEMS;
523done:
524 brcmf_dbg(TRACE, "exit: %d\n", i);
525 return i;
503} 526}
504 527
505static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h, 528static int brcmf_fws_hanger_pushpkt(struct brcmf_fws_hanger *h,
@@ -545,7 +568,7 @@ static int brcmf_fws_hanger_poppkt(struct brcmf_fws_hanger *h,
545 return 0; 568 return 0;
546} 569}
547 570
548static __used int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h, 571static int brcmf_fws_hanger_mark_suppressed(struct brcmf_fws_hanger *h,
549 u32 slot_id, u8 gen) 572 u32 slot_id, u8 gen)
550{ 573{
551 brcmf_dbg(TRACE, "enter\n"); 574 brcmf_dbg(TRACE, "enter\n");
@@ -583,10 +606,11 @@ static int brcmf_fws_hanger_get_genbit(struct brcmf_fws_hanger *hanger,
583 return 0; 606 return 0;
584} 607}
585 608
586static void brcmf_fws_hanger_cleanup(struct brcmf_fws_hanger *h, 609static void brcmf_fws_hanger_cleanup(struct brcmf_fws_info *fws,
587 bool (*fn)(struct sk_buff *, void *), 610 bool (*fn)(struct sk_buff *, void *),
588 int ifidx) 611 int ifidx)
589{ 612{
613 struct brcmf_fws_hanger *h = &fws->hanger;
590 struct sk_buff *skb; 614 struct sk_buff *skb;
591 int i; 615 int i;
592 enum brcmf_fws_hanger_item_state s; 616 enum brcmf_fws_hanger_item_state s;
@@ -611,14 +635,16 @@ static void brcmf_fws_hanger_cleanup(struct brcmf_fws_hanger *h,
611static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc, 635static void brcmf_fws_init_mac_descriptor(struct brcmf_fws_mac_descriptor *desc,
612 u8 *addr, u8 ifidx) 636 u8 *addr, u8 ifidx)
613{ 637{
614 brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u\n", addr, ifidx); 638 brcmf_dbg(TRACE,
639 "enter: desc %p ea=%pM, ifidx=%u\n", desc, addr, ifidx);
615 desc->occupied = 1; 640 desc->occupied = 1;
616 desc->state = BRCMF_FWS_STATE_OPEN; 641 desc->state = BRCMF_FWS_STATE_OPEN;
617 desc->requested_credit = 0; 642 desc->requested_credit = 0;
618 /* depending on use may need ifp->bssidx instead */ 643 /* depending on use may need ifp->bssidx instead */
619 desc->interface_id = ifidx; 644 desc->interface_id = ifidx;
620 desc->ac_bitmap = 0xff; /* update this when handling APSD */ 645 desc->ac_bitmap = 0xff; /* update this when handling APSD */
621 memcpy(&desc->ea[0], addr, ETH_ALEN); 646 if (addr)
647 memcpy(&desc->ea[0], addr, ETH_ALEN);
622} 648}
623 649
624static 650static
@@ -641,8 +667,8 @@ brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
641 if (ea == NULL) 667 if (ea == NULL)
642 return ERR_PTR(-EINVAL); 668 return ERR_PTR(-EINVAL);
643 669
644 entry = &fws->nodes[0]; 670 entry = &fws->desc.nodes[0];
645 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) { 671 for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++) {
646 if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN)) 672 if (entry->occupied && !memcmp(entry->ea, ea, ETH_ALEN))
647 return entry; 673 return entry;
648 entry++; 674 entry++;
@@ -654,7 +680,7 @@ brcmf_fws_mac_descriptor_lookup(struct brcmf_fws_info *fws, u8 *ea)
654static struct brcmf_fws_mac_descriptor* 680static struct brcmf_fws_mac_descriptor*
655brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da) 681brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da)
656{ 682{
657 struct brcmf_fws_mac_descriptor *entry = &fws->other; 683 struct brcmf_fws_mac_descriptor *entry = &fws->desc.other;
658 struct brcmf_if *ifp; 684 struct brcmf_if *ifp;
659 bool multicast; 685 bool multicast;
660 686
@@ -670,7 +696,7 @@ brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da)
670 * example, TDLS destinations have their own entry. 696 * example, TDLS destinations have their own entry.
671 */ 697 */
672 entry = NULL; 698 entry = NULL;
673 if ((/* ifp->iftype == 0 ||*/ multicast) && ifp->fws_desc) 699 if (multicast && ifp->fws_desc)
674 entry = ifp->fws_desc; 700 entry = ifp->fws_desc;
675 701
676 if (entry != NULL && multicast) 702 if (entry != NULL && multicast)
@@ -678,13 +704,35 @@ brcmf_fws_find_mac_desc(struct brcmf_fws_info *fws, int ifidx, u8 *da)
678 704
679 entry = brcmf_fws_mac_descriptor_lookup(fws, da); 705 entry = brcmf_fws_mac_descriptor_lookup(fws, da);
680 if (IS_ERR(entry)) 706 if (IS_ERR(entry))
681 entry = &fws->other; 707 entry = &fws->desc.other;
682 708
683done: 709done:
684 brcmf_dbg(TRACE, "exit: entry=%p\n", entry); 710 brcmf_dbg(TRACE, "exit: entry=%p\n", entry);
685 return entry; 711 return entry;
686} 712}
687 713
714static bool brcmf_fws_mac_desc_ready(struct brcmf_fws_mac_descriptor *entry,
715 int fifo)
716{
717 bool ready;
718
719 /*
720 * destination entry is ready when firmware says it is OPEN
721 * and there are no packets enqueued for it.
722 */
723 ready = entry->state == BRCMF_FWS_STATE_OPEN &&
724 !entry->suppressed &&
725 brcmu_pktq_mlen(&entry->psq, 3 << (fifo * 2)) == 0;
726
727 /*
728 * Or when the destination entry is CLOSED, but firmware has
729 * specifically requested packets for this entry.
730 */
731 ready = ready || (entry->state == BRCMF_FWS_STATE_CLOSE &&
732 (entry->requested_credit + entry->requested_packet));
733 return ready;
734}
735
688static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws, 736static void brcmf_fws_mac_desc_cleanup(struct brcmf_fws_info *fws,
689 struct brcmf_fws_mac_descriptor *entry, 737 struct brcmf_fws_mac_descriptor *entry,
690 int ifidx) 738 int ifidx)
@@ -743,13 +791,53 @@ static void brcmf_fws_cleanup(struct brcmf_fws_info *fws, int ifidx)
743 matchfn = brcmf_fws_ifidx_match; 791 matchfn = brcmf_fws_ifidx_match;
744 792
745 /* cleanup individual nodes */ 793 /* cleanup individual nodes */
746 table = &fws->nodes[0]; 794 table = &fws->desc.nodes[0];
747 for (i = 0; i < ARRAY_SIZE(fws->nodes); i++) 795 for (i = 0; i < ARRAY_SIZE(fws->desc.nodes); i++)
748 brcmf_fws_mac_desc_cleanup(fws, &table[i], ifidx); 796 brcmf_fws_mac_desc_cleanup(fws, &table[i], ifidx);
749 797
750 brcmf_fws_mac_desc_cleanup(fws, &fws->other, ifidx); 798 brcmf_fws_mac_desc_cleanup(fws, &fws->desc.other, ifidx);
751 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx); 799 brcmf_fws_bus_txq_cleanup(fws, matchfn, ifidx);
752 brcmf_fws_hanger_cleanup(&fws->hanger, matchfn, ifidx); 800 brcmf_fws_hanger_cleanup(fws, matchfn, ifidx);
801}
802
803static void brcmf_fws_tim_update(struct brcmf_fws_info *ctx,
804 struct brcmf_fws_mac_descriptor *entry,
805 int prec)
806{
807 brcmf_dbg(TRACE, "enter: ea=%pM\n", entry->ea);
808 if (entry->state == BRCMF_FWS_STATE_CLOSE) {
809 /* check delayedQ and suppressQ in one call using bitmap */
810 if (brcmu_pktq_mlen(&entry->psq, 3 << (prec * 2)) == 0)
811 entry->traffic_pending_bmp =
812 entry->traffic_pending_bmp & ~NBITVAL(prec);
813 else
814 entry->traffic_pending_bmp =
815 entry->traffic_pending_bmp | NBITVAL(prec);
816 }
817 /* request a TIM update to firmware at the next piggyback opportunity */
818 if (entry->traffic_lastreported_bmp != entry->traffic_pending_bmp)
819 entry->send_tim_signal = true;
820}
821
822static void
823brcmf_fws_flow_control_check(struct brcmf_fws_info *fws, struct pktq *pq,
824 u8 if_id)
825{
826 struct brcmf_if *ifp = fws->drvr->iflist[if_id];
827
828 brcmf_dbg(TRACE,
829 "enter: bssidx=%d, ifidx=%d\n", ifp->bssidx, ifp->ifidx);
830 if (WARN_ON(!ifp))
831 return;
832
833 if ((ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
834 pq->len <= BRCMF_FWS_FLOWCONTROL_LOWATER)
835 brcmf_txflowblock_if(ifp,
836 BRCMF_NETIF_STOP_REASON_FWS_FC, false);
837 if (!(ifp->netif_stop & BRCMF_NETIF_STOP_REASON_FWS_FC) &&
838 pq->len >= BRCMF_FWS_FLOWCONTROL_HIWATER)
839 brcmf_txflowblock_if(ifp, BRCMF_NETIF_STOP_REASON_FWS_FC, true);
840 return;
753} 841}
754 842
755static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi) 843static int brcmf_fws_rssi_indicate(struct brcmf_fws_info *fws, s8 rssi)
@@ -770,7 +858,7 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
770 ifidx = *data++; 858 ifidx = *data++;
771 addr = data; 859 addr = data;
772 860
773 entry = &fws->nodes[mac_handle & 0x1F]; 861 entry = &fws->desc.nodes[mac_handle & 0x1F];
774 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) { 862 if (type == BRCMF_FWS_TYPE_MACDESC_DEL) {
775 brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx); 863 brcmf_dbg(TRACE, "deleting mac %pM idx %d\n", addr, ifidx);
776 if (entry->occupied) 864 if (entry->occupied)
@@ -808,25 +896,241 @@ int brcmf_fws_macdesc_indicate(struct brcmf_fws_info *fws, u8 type, u8 *data)
808 return 0; 896 return 0;
809} 897}
810 898
899static void brcmf_fws_return_credits(struct brcmf_fws_info *fws,
900 u8 fifo, u8 credits)
901{
902 if (!credits)
903 return;
904
905 fws->fifo_credit_map |= 1 << fifo;
906 fws->fifo_credit[fifo] += credits;
907}
908
909static void brcmf_fws_schedule_deq(struct brcmf_fws_info *fws)
910{
911 /* only schedule dequeue when there are credits for delayed traffic */
912 if (fws->fifo_credit_map & fws->fifo_delay_map)
913 queue_work(fws->fws_wq, &fws->fws_dequeue_work);
914}
915
916static void brcmf_skb_pick_up_credit(struct brcmf_fws_info *fws, int fifo,
917 struct sk_buff *p)
918{
919 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(p)->mac;
920
921 if (brcmf_skbcb(p)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
922 if (fws->fcmode != BRCMF_FWS_FCMODE_IMPLIED_CREDIT)
923 return;
924 brcmf_fws_return_credits(fws, fifo, 1);
925 } else {
926 /*
927 * if this packet did not count against FIFO credit, it
928 * must have taken a requested_credit from the destination
929 * entry (for pspoll etc.)
930 */
931 if (!brcmf_skb_if_flags_get_field(p, REQUESTED))
932 entry->requested_credit++;
933 }
934 brcmf_fws_schedule_deq(fws);
935}
936
937static int brcmf_fws_enq(struct brcmf_fws_info *fws,
938 enum brcmf_fws_skb_state state, int fifo,
939 struct sk_buff *p)
940{
941 int prec = 2 * fifo;
942 u32 *qfull_stat = &fws->stats.delayq_full_error;
943
944 struct brcmf_fws_mac_descriptor *entry;
945
946 entry = brcmf_skbcb(p)->mac;
947 if (entry == NULL) {
948 brcmf_err("no mac descriptor found for skb %p\n", p);
949 return -ENOENT;
950 }
951
952 brcmf_dbg(TRACE, "enter: ea=%pM, qlen=%d\n", entry->ea, entry->psq.len);
953 if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
954 prec += 1;
955 qfull_stat = &fws->stats.supprq_full_error;
956 }
957
958 if (brcmu_pktq_penq(&entry->psq, prec, p) == NULL) {
959 *qfull_stat += 1;
960 return -ENFILE;
961 }
962
963 /* increment total enqueued packet count */
964 fws->fifo_delay_map |= 1 << fifo;
965 fws->fifo_enqpkt[fifo]++;
966
967 /* update the sk_buff state */
968 brcmf_skbcb(p)->state = state;
969 if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED)
970 entry->suppress_count++;
971
972 /*
973 * A packet has been pushed so update traffic
974 * availability bitmap, if applicable
975 */
976 brcmf_fws_tim_update(fws, entry, fifo);
977 brcmf_fws_flow_control_check(fws, &entry->psq,
978 brcmf_skb_if_flags_get_field(p, INDEX));
979 return 0;
980}
981
982static struct sk_buff *brcmf_fws_deq(struct brcmf_fws_info *fws, int fifo)
983{
984 struct brcmf_fws_mac_descriptor *table;
985 struct brcmf_fws_mac_descriptor *entry;
986 struct sk_buff *p;
987 int use_credit = 1;
988 int num_nodes;
989 int node_pos;
990 int prec_out;
991 int pmsk = 3;
992 int i;
993
994 table = (struct brcmf_fws_mac_descriptor *)&fws->desc;
995 num_nodes = sizeof(fws->desc) / sizeof(struct brcmf_fws_mac_descriptor);
996 node_pos = fws->deq_node_pos[fifo];
997
998 for (i = 0; i < num_nodes; i++) {
999 entry = &table[(node_pos + i) % num_nodes];
1000 if (!entry->occupied)
1001 continue;
1002
1003 if (entry->suppressed)
1004 pmsk = 2;
1005 p = brcmu_pktq_mdeq(&entry->psq, pmsk << (fifo * 2), &prec_out);
1006 if (p == NULL) {
1007 if (entry->suppressed) {
1008 if (entry->suppr_transit_count >
1009 entry->suppress_count)
1010 return NULL;
1011 entry->suppressed = false;
1012 p = brcmu_pktq_mdeq(&entry->psq,
1013 1 << (fifo * 2), &prec_out);
1014 }
1015 }
1016 if (p == NULL)
1017 continue;
1018
1019 /* did the packet come from suppress sub-queue? */
1020 if (entry->requested_credit > 0) {
1021 entry->requested_credit--;
1022 /*
1023 * if the packet was pulled out while destination is in
1024 * closed state but had a non-zero packets requested,
1025 * then this should not count against the FIFO credit.
1026 * That is due to the fact that the firmware will
1027 * most likely hold onto this packet until a suitable
1028 * time later to push it to the appropriate AC FIFO.
1029 */
1030 if (entry->state == BRCMF_FWS_STATE_CLOSE)
1031 use_credit = 0;
1032 } else if (entry->requested_packet > 0) {
1033 entry->requested_packet--;
1034 brcmf_skb_if_flags_set_field(p, REQUESTED, 1);
1035 if (entry->state == BRCMF_FWS_STATE_CLOSE)
1036 use_credit = 0;
1037 }
1038 brcmf_skb_if_flags_set_field(p, CREDITCHECK, use_credit);
1039
1040 /* move dequeue position to ensure fair round-robin */
1041 fws->deq_node_pos[fifo] = (node_pos + i + 1) % num_nodes;
1042 brcmf_fws_flow_control_check(fws, &entry->psq,
1043 brcmf_skb_if_flags_get_field(p,
1044 INDEX)
1045 );
1046 /*
1047 * A packet has been picked up, update traffic
1048 * availability bitmap, if applicable
1049 */
1050 brcmf_fws_tim_update(fws, entry, fifo);
1051
1052 /*
1053 * decrement total enqueued fifo packets and
1054 * clear delay bitmap if done.
1055 */
1056 fws->fifo_enqpkt[fifo]--;
1057 if (fws->fifo_enqpkt[fifo] == 0)
1058 fws->fifo_delay_map &= ~(1 << fifo);
1059 goto done;
1060 }
1061 p = NULL;
1062done:
1063 brcmf_dbg(TRACE, "exit: fifo %d skb %p\n", fifo, p);
1064 return p;
1065}
1066
1067static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
1068 struct sk_buff *skb, u32 genbit)
1069{
1070 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1071 u32 hslot;
1072 int ret;
1073
1074 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1075
1076 /* this packet was suppressed */
1077 if (!entry->suppressed || entry->generation != genbit) {
1078 entry->suppressed = true;
1079 entry->suppress_count = brcmu_pktq_mlen(&entry->psq,
1080 1 << (fifo * 2 + 1));
1081 entry->suppr_transit_count = entry->transit_count;
1082 }
1083
1084 entry->generation = genbit;
1085
1086 ret = brcmf_fws_enq(fws, BRCMF_FWS_SKBSTATE_SUPPRESSED, fifo, skb);
1087 if (ret != 0) {
1088 /* suppress q is full, drop this packet */
1089 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
1090 true);
1091 } else {
1092 /*
1093 * Mark suppressed to avoid a double free during
1094 * wlfc cleanup
1095 */
1096 brcmf_fws_hanger_mark_suppressed(&fws->hanger, hslot,
1097 genbit);
1098 entry->suppress_count++;
1099 }
1100
1101 return ret;
1102}
1103
811static int 1104static int
812brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot) 1105brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
1106 u32 genbit)
813{ 1107{
1108 u32 fifo;
814 int ret; 1109 int ret;
1110 bool remove_from_hanger = true;
815 struct sk_buff *skb; 1111 struct sk_buff *skb;
816 struct brcmf_fws_mac_descriptor *entry = NULL; 1112 struct brcmf_fws_mac_descriptor *entry = NULL;
817 1113
1114 fws->stats.txs_indicate++;
1115
818 brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n", 1116 brcmf_dbg(TRACE, "status: flags=0x%X, hslot=%d\n",
819 flags, hslot); 1117 flags, hslot);
820 1118
821 if (flags == BRCMF_FWS_TXSTATUS_DISCARD) 1119 if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
822 fws->stats.txs_discard++; 1120 fws->stats.txs_discard++;
823 else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED) 1121 else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
1122 fws->stats.txs_supp_core++;
1123 remove_from_hanger = false;
1124 } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
1125 fws->stats.txs_supp_ps++;
1126 remove_from_hanger = false;
1127 } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
824 fws->stats.txs_tossed++; 1128 fws->stats.txs_tossed++;
825 else 1129 else
826 brcmf_err("unexpected txstatus\n"); 1130 brcmf_err("unexpected txstatus\n");
827 1131
828 ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb, 1132 ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
829 true); 1133 remove_from_hanger);
830 if (ret != 0) { 1134 if (ret != 0) {
831 brcmf_err("no packet in hanger slot: hslot=%d\n", hslot); 1135 brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
832 return ret; 1136 return ret;
@@ -834,29 +1138,61 @@ brcmf_fws_txstatus_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot)
834 1138
835 entry = brcmf_skbcb(skb)->mac; 1139 entry = brcmf_skbcb(skb)->mac;
836 if (WARN_ON(!entry)) { 1140 if (WARN_ON(!entry)) {
837 ret = -EINVAL; 1141 brcmu_pkt_buf_free_skb(skb);
838 goto done; 1142 return -EINVAL;
839 } 1143 }
840 1144
841 entry->transit_count--; 1145 /* pick up the implicit credit from this packet */
1146 fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
1147 brcmf_skb_pick_up_credit(fws, fifo, skb);
842 1148
843done: 1149 if (!remove_from_hanger)
844 brcmf_txfinalize(fws->drvr, skb, true); 1150 ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb, genbit);
845 return ret; 1151
1152 if (remove_from_hanger || ret) {
1153 entry->transit_count--;
1154 if (entry->suppressed)
1155 entry->suppr_transit_count--;
1156
1157 brcmf_txfinalize(fws->drvr, skb, true);
1158 }
1159 return 0;
1160}
1161
1162static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
1163 u8 *data)
1164{
1165 int i;
1166
1167 if (fws->fcmode != BRCMF_FWS_FCMODE_EXPLICIT_CREDIT) {
1168 brcmf_dbg(INFO, "ignored\n");
1169 return 0;
1170 }
1171
1172 brcmf_dbg(TRACE, "enter: data %pM\n", data);
1173 for (i = 0; i < BRCMF_FWS_FIFO_COUNT; i++)
1174 brcmf_fws_return_credits(fws, i, data[i]);
1175
1176 brcmf_dbg(INFO, "map: credit %x delay %x\n", fws->fifo_credit_map,
1177 fws->fifo_delay_map);
1178 brcmf_fws_schedule_deq(fws);
1179 return 0;
846} 1180}
847 1181
848static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data) 1182static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
849{ 1183{
850 u32 status; 1184 u32 status;
851 u32 hslot; 1185 u32 hslot;
1186 u32 genbit;
852 u8 flags; 1187 u8 flags;
853 1188
854 fws->stats.txs_indicate++; 1189 fws->stats.txs_indicate++;
855 status = le32_to_cpu(*(__le32 *)data); 1190 status = le32_to_cpu(*(__le32 *)data);
856 flags = brcmf_txstatus_get_field(status, FLAGS); 1191 flags = brcmf_txstatus_get_field(status, FLAGS);
857 hslot = brcmf_txstatus_get_field(status, HSLOT); 1192 hslot = brcmf_txstatus_get_field(status, HSLOT);
1193 genbit = brcmf_txstatus_get_field(status, GENERATION);
858 1194
859 return brcmf_fws_txstatus_process(fws, flags, hslot); 1195 return brcmf_fws_txstatus_process(fws, flags, hslot, genbit);
860} 1196}
861 1197
862static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data) 1198static int brcmf_fws_dbg_seqnum_check(struct brcmf_fws_info *fws, u8 *data)
@@ -893,9 +1229,21 @@ static int brcmf_fws_notify_credit_map(struct brcmf_if *ifp,
893 ulong flags; 1229 ulong flags;
894 u8 *credits = data; 1230 u8 *credits = data;
895 1231
1232 if (e->datalen < BRCMF_FWS_FIFO_COUNT) {
1233 brcmf_err("event payload too small (%d)\n", e->datalen);
1234 return -EINVAL;
1235 }
1236
1237 brcmf_dbg(TRACE, "enter: credits %pM\n", credits);
896 brcmf_fws_lock(ifp->drvr, flags); 1238 brcmf_fws_lock(ifp->drvr, flags);
897 for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) 1239 for (i = 0; i < ARRAY_SIZE(fws->fifo_credit); i++) {
1240 if (*credits)
1241 fws->fifo_credit_map |= 1 << i;
1242 else
1243 fws->fifo_credit_map &= ~(1 << i);
898 fws->fifo_credit[i] = *credits++; 1244 fws->fifo_credit[i] = *credits++;
1245 }
1246 brcmf_fws_schedule_deq(fws);
899 brcmf_fws_unlock(ifp->drvr, flags); 1247 brcmf_fws_unlock(ifp->drvr, flags);
900 return 0; 1248 return 0;
901} 1249}
@@ -958,11 +1306,8 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
958 case BRCMF_FWS_TYPE_MAC_OPEN: 1306 case BRCMF_FWS_TYPE_MAC_OPEN:
959 case BRCMF_FWS_TYPE_MAC_CLOSE: 1307 case BRCMF_FWS_TYPE_MAC_CLOSE:
960 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT: 1308 case BRCMF_FWS_TYPE_MAC_REQUEST_CREDIT:
961 case BRCMF_FWS_TYPE_PKTTAG:
962 case BRCMF_FWS_TYPE_INTERFACE_OPEN: 1309 case BRCMF_FWS_TYPE_INTERFACE_OPEN:
963 case BRCMF_FWS_TYPE_INTERFACE_CLOSE: 1310 case BRCMF_FWS_TYPE_INTERFACE_CLOSE:
964 case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
965 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
966 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET: 1311 case BRCMF_FWS_TYPE_MAC_REQUEST_PACKET:
967 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS: 1312 case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
968 case BRCMF_FWS_TYPE_COMP_TXSTATUS: 1313 case BRCMF_FWS_TYPE_COMP_TXSTATUS:
@@ -974,12 +1319,17 @@ int brcmf_fws_hdrpull(struct brcmf_pub *drvr, int ifidx, s16 signal_len,
974 case BRCMF_FWS_TYPE_TXSTATUS: 1319 case BRCMF_FWS_TYPE_TXSTATUS:
975 brcmf_fws_txstatus_indicate(fws, data); 1320 brcmf_fws_txstatus_indicate(fws, data);
976 break; 1321 break;
1322 case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
1323 brcmf_fws_fifocreditback_indicate(fws, data);
1324 break;
977 case BRCMF_FWS_TYPE_RSSI: 1325 case BRCMF_FWS_TYPE_RSSI:
978 brcmf_fws_rssi_indicate(fws, *data); 1326 brcmf_fws_rssi_indicate(fws, *data);
979 break; 1327 break;
980 case BRCMF_FWS_TYPE_TRANS_ID: 1328 case BRCMF_FWS_TYPE_TRANS_ID:
981 brcmf_fws_dbg_seqnum_check(fws, data); 1329 brcmf_fws_dbg_seqnum_check(fws, data);
982 break; 1330 break;
1331 case BRCMF_FWS_TYPE_PKTTAG:
1332 case BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP:
983 default: 1333 default:
984 fws->stats.tlv_invalid_type++; 1334 fws->stats.tlv_invalid_type++;
985 break; 1335 break;
@@ -1010,14 +1360,17 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
1010{ 1360{
1011 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac; 1361 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1012 u8 *wlh; 1362 u8 *wlh;
1013 u16 data_offset; 1363 u16 data_offset = 0;
1014 u8 fillers; 1364 u8 fillers;
1015 __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod); 1365 __le32 pkttag = cpu_to_le32(brcmf_skbcb(skb)->htod);
1016 1366
1017 brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n", 1367 brcmf_dbg(TRACE, "enter: ea=%pM, ifidx=%u, pkttag=0x%08X\n",
1018 entry->ea, entry->interface_id, le32_to_cpu(pkttag)); 1368 entry->ea, entry->interface_id, le32_to_cpu(pkttag));
1369 if (entry->send_tim_signal)
1370 data_offset += 2 + BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
1371
1019 /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */ 1372 /* +2 is for Type[1] and Len[1] in TLV, plus TIM signal */
1020 data_offset = 2 + BRCMF_FWS_TYPE_PKTTAG_LEN; 1373 data_offset += 2 + BRCMF_FWS_TYPE_PKTTAG_LEN;
1021 fillers = round_up(data_offset, 4) - data_offset; 1374 fillers = round_up(data_offset, 4) - data_offset;
1022 data_offset += fillers; 1375 data_offset += fillers;
1023 1376
@@ -1029,6 +1382,15 @@ static int brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb)
1029 memcpy(&wlh[2], &pkttag, sizeof(pkttag)); 1382 memcpy(&wlh[2], &pkttag, sizeof(pkttag));
1030 wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2; 1383 wlh += BRCMF_FWS_TYPE_PKTTAG_LEN + 2;
1031 1384
1385 if (entry->send_tim_signal) {
1386 entry->send_tim_signal = 0;
1387 wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP;
1388 wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN;
1389 wlh[2] = entry->mac_handle;
1390 wlh[3] = entry->traffic_pending_bmp;
1391 wlh += BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN + 2;
1392 entry->traffic_lastreported_bmp = entry->traffic_pending_bmp;
1393 }
1032 if (fillers) 1394 if (fillers)
1033 memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers); 1395 memset(wlh, BRCMF_FWS_TYPE_FILLER, fillers);
1034 1396
@@ -1049,7 +1411,7 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1049 u8 ifidx; 1411 u8 ifidx;
1050 u8 flags; 1412 u8 flags;
1051 1413
1052 header_needed = skcb->state == BRCMF_FWS_SKBSTATE_NEW; 1414 header_needed = skcb->state != BRCMF_FWS_SKBSTATE_SUPPRESSED;
1053 1415
1054 if (header_needed) { 1416 if (header_needed) {
1055 /* obtaining free slot may fail, but that will be caught 1417 /* obtaining free slot may fail, but that will be caught
@@ -1099,6 +1461,133 @@ static int brcmf_fws_precommit_skb(struct brcmf_fws_info *fws, int fifo,
1099 return rc; 1461 return rc;
1100} 1462}
1101 1463
1464static int
1465brcmf_fws_rollback_toq(struct brcmf_fws_info *fws, struct sk_buff *skb)
1466{
1467 /*
1468 put the packet back to the head of queue
1469
1470 - suppressed packet goes back to suppress sub-queue
1471 - pull out the header, if new or delayed packet
1472
1473 Note: hslot is used only when header removal is done.
1474 */
1475 struct brcmf_fws_mac_descriptor *entry;
1476 enum brcmf_fws_skb_state state;
1477 struct sk_buff *pktout;
1478 int rc = 0;
1479 int fifo;
1480 int hslot;
1481 u8 ifidx;
1482
1483 fifo = brcmf_skb_if_flags_get_field(skb, FIFO);
1484 state = brcmf_skbcb(skb)->state;
1485 entry = brcmf_skbcb(skb)->mac;
1486
1487 if (entry != NULL) {
1488 if (state == BRCMF_FWS_SKBSTATE_SUPPRESSED) {
1489 /* wl-header is saved for suppressed packets */
1490 pktout = brcmu_pktq_penq_head(&entry->psq, 2 * fifo + 1,
1491 skb);
1492 if (pktout == NULL) {
1493 brcmf_err("suppress queue full\n");
1494 rc = -ENOSPC;
1495 }
1496 } else {
1497 hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
1498
1499 /* remove header first */
1500 rc = brcmf_proto_hdrpull(fws->drvr, false, &ifidx, skb);
1501 if (rc) {
1502 brcmf_err("header removal failed\n");
1503 /* free the hanger slot */
1504 brcmf_fws_hanger_poppkt(&fws->hanger, hslot,
1505 &pktout, true);
1506 brcmf_txfinalize(fws->drvr, skb, false);
1507 rc = -EINVAL;
1508 goto fail;
1509 }
1510
1511 /* delay-q packets are going to delay-q */
1512 pktout = brcmu_pktq_penq_head(&entry->psq,
1513 2 * fifo, skb);
1514 if (pktout == NULL) {
1515 brcmf_err("delay queue full\n");
1516 rc = -ENOSPC;
1517 }
1518
1519 /* free the hanger slot */
1520 brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &pktout,
1521 true);
1522
1523 /* decrement sequence count */
1524 entry->seq[fifo]--;
1525 }
1526 /*
1527 if this packet did not count against FIFO credit, it must have
1528 taken a requested_credit from the firmware (for pspoll etc.)
1529 */
1530 if (!(brcmf_skbcb(skb)->if_flags &
1531 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK))
1532 entry->requested_credit++;
1533 } else {
1534 brcmf_err("no mac entry linked\n");
1535 rc = -ENOENT;
1536 }
1537
1538
1539fail:
1540 if (rc)
1541 fws->stats.rollback_failed++;
1542 else
1543 fws->stats.rollback_success++;
1544 return rc;
1545}
1546
1547static int brcmf_fws_consume_credit(struct brcmf_fws_info *fws, int fifo,
1548 struct sk_buff *skb)
1549{
1550 struct brcmf_fws_mac_descriptor *entry = brcmf_skbcb(skb)->mac;
1551 int *credit = &fws->fifo_credit[fifo];
1552 int use_credit = 1;
1553
1554 brcmf_dbg(TRACE, "enter: ac=%d, credits=%d\n", fifo, *credit);
1555
1556 if (entry->requested_credit > 0) {
1557 /*
1558 * if the packet was pulled out while destination is in
1559 * closed state but had a non-zero packets requested,
1560 * then this should not count against the FIFO credit.
1561 * That is due to the fact that the firmware will
1562 * most likely hold onto this packet until a suitable
1563 * time later to push it to the appropriate AC FIFO.
1564 */
1565 entry->requested_credit--;
1566 if (entry->state == BRCMF_FWS_STATE_CLOSE)
1567 use_credit = 0;
1568 } else if (entry->requested_packet > 0) {
1569 entry->requested_packet--;
1570 brcmf_skb_if_flags_set_field(skb, REQUESTED, 1);
1571 if (entry->state == BRCMF_FWS_STATE_CLOSE)
1572 use_credit = 0;
1573 }
1574 brcmf_skb_if_flags_set_field(skb, CREDITCHECK, use_credit);
1575 if (!use_credit) {
1576 brcmf_dbg(TRACE, "exit: no creditcheck set\n");
1577 return 0;
1578 }
1579
1580 if (!(*credit)) {
1581 brcmf_dbg(TRACE, "exit: credits depleted\n");
1582 return -ENAVAIL;
1583 }
1584 (*credit)--;
1585 if (!(*credit))
1586 fws->fifo_credit_map &= ~(1 << fifo);
1587 brcmf_dbg(TRACE, "exit: ac=%d, credits=%d\n", fifo, *credit);
1588 return 0;
1589}
1590
1102static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo, 1591static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
1103 struct sk_buff *skb) 1592 struct sk_buff *skb)
1104{ 1593{
@@ -1114,19 +1603,24 @@ static int brcmf_fws_commit_skb(struct brcmf_fws_info *fws, int fifo,
1114 rc = brcmf_fws_precommit_skb(fws, fifo, skb); 1603 rc = brcmf_fws_precommit_skb(fws, fifo, skb);
1115 if (rc < 0) { 1604 if (rc < 0) {
1116 fws->stats.generic_error++; 1605 fws->stats.generic_error++;
1117 goto done; 1606 goto rollback;
1118 } 1607 }
1119 1608
1120 rc = brcmf_bus_txdata(bus, skb); 1609 rc = brcmf_bus_txdata(bus, skb);
1121 if (rc < 0) 1610 if (rc < 0)
1122 goto done; 1611 goto rollback;
1123 1612
1124 entry->seq[fifo]++; 1613 entry->seq[fifo]++;
1125 fws->stats.pkt2bus++; 1614 fws->stats.pkt2bus++;
1615 if (brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
1616 fws->stats.send_pkts[fifo]++;
1617 fws->stats.fifo_credits_sent[fifo]++;
1618 }
1619
1126 return rc; 1620 return rc;
1127 1621
1128done: 1622rollback:
1129 brcmf_txfinalize(fws->drvr, skb, false); 1623 rc = brcmf_fws_rollback_toq(fws, skb);
1130 return rc; 1624 return rc;
1131} 1625}
1132 1626
@@ -1157,19 +1651,27 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
1157 } 1651 }
1158 1652
1159 /* set control buffer information */ 1653 /* set control buffer information */
1654 skcb->if_flags = 0;
1160 skcb->mac = brcmf_fws_find_mac_desc(drvr->fws, ifidx, eh->h_dest); 1655 skcb->mac = brcmf_fws_find_mac_desc(drvr->fws, ifidx, eh->h_dest);
1161 skcb->state = BRCMF_FWS_SKBSTATE_NEW; 1656 skcb->state = BRCMF_FWS_SKBSTATE_NEW;
1162 brcmf_skb_if_flags_set_field(skb, INDEX, ifidx); 1657 brcmf_skb_if_flags_set_field(skb, INDEX, ifidx);
1163 if (!multicast) 1658 if (!multicast)
1164 fifo = brcmf_fws_prio2fifo[skb->priority]; 1659 fifo = brcmf_fws_prio2fifo[skb->priority];
1165 brcmf_skb_if_flags_set_field(skb, FIFO, fifo); 1660 brcmf_skb_if_flags_set_field(skb, FIFO, fifo);
1166 brcmf_skb_if_flags_set_field(skb, CREDITCHECK, 0);
1167 1661
1168 brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest, 1662 brcmf_dbg(TRACE, "ea=%pM, multi=%d, fifo=%d\n", eh->h_dest,
1169 multicast, fifo); 1663 multicast, fifo);
1170 1664
1171 brcmf_fws_lock(drvr, flags); 1665 brcmf_fws_lock(drvr, flags);
1172 brcmf_fws_commit_skb(drvr->fws, fifo, skb); 1666 if (!brcmf_fws_mac_desc_ready(skcb->mac, fifo) ||
1667 (!multicast &&
1668 brcmf_fws_consume_credit(drvr->fws, fifo, skb) < 0)) {
1669 /* enqueue the packet in delayQ */
1670 drvr->fws->fifo_delay_map |= 1 << fifo;
1671 brcmf_fws_enq(drvr->fws, BRCMF_FWS_SKBSTATE_DELAYED, fifo, skb);
1672 } else {
1673 brcmf_fws_commit_skb(drvr->fws, fifo, skb);
1674 }
1173 brcmf_fws_unlock(drvr, flags); 1675 brcmf_fws_unlock(drvr, flags);
1174 return 0; 1676 return 0;
1175} 1677}
@@ -1187,6 +1689,7 @@ void brcmf_fws_reset_interface(struct brcmf_if *ifp)
1187 1689
1188void brcmf_fws_add_interface(struct brcmf_if *ifp) 1690void brcmf_fws_add_interface(struct brcmf_if *ifp)
1189{ 1691{
1692 struct brcmf_fws_info *fws = ifp->drvr->fws;
1190 struct brcmf_fws_mac_descriptor *entry; 1693 struct brcmf_fws_mac_descriptor *entry;
1191 1694
1192 brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n", 1695 brcmf_dbg(TRACE, "enter: idx=%d, mac=%pM\n",
@@ -1194,15 +1697,11 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp)
1194 if (!ifp->drvr->fw_signals) 1697 if (!ifp->drvr->fw_signals)
1195 return; 1698 return;
1196 1699
1197 entry = kzalloc(sizeof(*entry), GFP_ATOMIC); 1700 entry = &fws->desc.iface[ifp->ifidx];
1198 if (entry) { 1701 ifp->fws_desc = entry;
1199 ifp->fws_desc = entry; 1702 brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx);
1200 brcmf_fws_init_mac_descriptor(entry, ifp->mac_addr, ifp->ifidx); 1703 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT,
1201 brcmu_pktq_init(&entry->psq, BRCMF_FWS_PSQ_PREC_COUNT, 1704 BRCMF_FWS_PSQ_LEN);
1202 BRCMF_FWS_PSQ_LEN);
1203 } else {
1204 brcmf_err("no firmware signalling\n");
1205 }
1206} 1705}
1207 1706
1208void brcmf_fws_del_interface(struct brcmf_if *ifp) 1707void brcmf_fws_del_interface(struct brcmf_if *ifp)
@@ -1216,7 +1715,35 @@ void brcmf_fws_del_interface(struct brcmf_if *ifp)
1216 ifp->fws_desc = NULL; 1715 ifp->fws_desc = NULL;
1217 brcmf_fws_clear_mac_descriptor(entry); 1716 brcmf_fws_clear_mac_descriptor(entry);
1218 brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx); 1717 brcmf_fws_cleanup(ifp->drvr->fws, ifp->ifidx);
1219 kfree(entry); 1718}
1719
1720static void brcmf_fws_dequeue_worker(struct work_struct *worker)
1721{
1722 struct brcmf_fws_info *fws;
1723 struct sk_buff *skb;
1724 ulong flags;
1725 int fifo;
1726 int credit;
1727
1728 fws = container_of(worker, struct brcmf_fws_info, fws_dequeue_work);
1729
1730 brcmf_dbg(TRACE, "enter: fws=%p\n", fws);
1731 brcmf_fws_lock(fws->drvr, flags);
1732 for (fifo = NL80211_NUM_ACS; fifo >= 0; fifo--) {
1733 brcmf_dbg(TRACE, "fifo %d credit %d\n", fifo,
1734 fws->fifo_credit[fifo]);
1735 for (credit = 0; credit < fws->fifo_credit[fifo]; /* nop */) {
1736 skb = brcmf_fws_deq(fws, fifo);
1737 if (!skb)
1738 break;
1739 if (!brcmf_fws_commit_skb(fws, fifo, skb) &&
1740 brcmf_skbcb(skb)->if_flags &
1741 BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK)
1742 credit++;
1743 }
1744 fws->fifo_credit[fifo] -= credit;
1745 }
1746 brcmf_fws_unlock(fws->drvr, flags);
1220} 1747}
1221 1748
1222int brcmf_fws_init(struct brcmf_pub *drvr) 1749int brcmf_fws_init(struct brcmf_pub *drvr)
@@ -1239,6 +1766,14 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
1239 drvr->fws->drvr = drvr; 1766 drvr->fws->drvr = drvr;
1240 drvr->fws->fcmode = fcmode; 1767 drvr->fws->fcmode = fcmode;
1241 1768
1769 drvr->fws->fws_wq = create_singlethread_workqueue("brcmf_fws_wq");
1770 if (drvr->fws->fws_wq == NULL) {
1771 brcmf_err("workqueue creation failed\n");
1772 rc = -EBADF;
1773 goto fail;
1774 }
1775 INIT_WORK(&drvr->fws->fws_dequeue_work, brcmf_fws_dequeue_worker);
1776
1242 /* enable firmware signalling if fcmode active */ 1777 /* enable firmware signalling if fcmode active */
1243 if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE) 1778 if (drvr->fws->fcmode != BRCMF_FWS_FCMODE_NONE)
1244 tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS | 1779 tlv |= BRCMF_FWS_FLAGS_XONXOFF_SIGNALS |
@@ -1257,6 +1792,9 @@ int brcmf_fws_init(struct brcmf_pub *drvr)
1257 } 1792 }
1258 1793
1259 brcmf_fws_hanger_init(&drvr->fws->hanger); 1794 brcmf_fws_hanger_init(&drvr->fws->hanger);
1795 brcmf_fws_init_mac_descriptor(&drvr->fws->desc.other, NULL, 0);
1796 brcmu_pktq_init(&drvr->fws->desc.other.psq, BRCMF_FWS_PSQ_PREC_COUNT,
1797 BRCMF_FWS_PSQ_LEN);
1260 1798
1261 /* create debugfs file for statistics */ 1799 /* create debugfs file for statistics */
1262 brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats); 1800 brcmf_debugfs_create_fws_stats(drvr, &drvr->fws->stats);
@@ -1306,6 +1844,15 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
1306 1844
1307 brcmf_fws_lock(fws->drvr, flags); 1845 brcmf_fws_lock(fws->drvr, flags);
1308 brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED, 1846 brcmf_fws_txstatus_process(fws, BRCMF_FWS_TXSTATUS_FW_TOSSED,
1309 brcmf_skb_htod_tag_get_field(skb, HSLOT)); 1847 brcmf_skb_htod_tag_get_field(skb, HSLOT), 0);
1848 /* the packet never reached firmware so reclaim credit */
1849 if (fws->fcmode == BRCMF_FWS_FCMODE_EXPLICIT_CREDIT &&
1850 brcmf_skbcb(skb)->if_flags & BRCMF_SKB_IF_FLAGS_CREDITCHECK_MASK) {
1851 brcmf_fws_return_credits(fws,
1852 brcmf_skb_htod_tag_get_field(skb,
1853 FIFO),
1854 1);
1855 brcmf_fws_schedule_deq(fws);
1856 }
1310 brcmf_fws_unlock(fws->drvr, flags); 1857 brcmf_fws_unlock(fws->drvr, flags);
1311} 1858}