aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorArend van Spriel <arend@broadcom.com>2013-04-03 06:40:50 -0400
committerJohn W. Linville <linville@tuxdriver.com>2013-04-03 15:07:09 -0400
commit84bcc0c3c4b8ca4c0abed2d2dd63b7ce04f8be0e (patch)
tree0ba2a202c4454e61d49bf3af6aa0233bfb817f16 /drivers
parent290fb763a2a7c79c45d09c8523f37e96446a5a91 (diff)
brcmfmac: enable sk_buff queueing when credits deplete
Firmware provides the driver with credits used to transmit packets to the firmware. When credits run out the packets should be queued and dequeued when receiving creditback signals from the firmware. Reviewed-by: Pieter-Paul Giesberts <pieterpg@broadcom.com> Reviewed-by: Hante Meuleman <meuleman@broadcom.com> Signed-off-by: Arend van Spriel <arend@broadcom.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers')
-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}