brcmfmac: handle compressed tx status signal
authorChung-Hsien Hsu <stanley.hsu@cypress.com>
Mon, 5 Nov 2018 05:52:05 +0000 (05:52 +0000)
committerKalle Valo <kvalo@codeaurora.org>
Thu, 13 Dec 2018 14:56:27 +0000 (16:56 +0200)
Firmware inform the driver about tx status by normal tx status signal
or compressed tx status signal. This patch adds support to handle the
compressed tx status signal.

Signed-off-by: Chung-Hsien Hsu <stanley.hsu@cypress.com>
Signed-off-by: Chi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Wright Feng <wright.feng@cypress.com>
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c

index c75be2703b3e4284e4cda251076be8fb24e39544..02759ebd207c6ffad602ca735dbbd0e21784a71f 100644 (file)
@@ -1455,9 +1455,10 @@ static int brcmf_fws_txstatus_suppressed(struct brcmf_fws_info *fws, int fifo,
 
 static int
 brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
-                     u32 genbit, u16 seq)
+                     u32 genbit, u16 seq, u8 compcnt)
 {
        u32 fifo;
+       u8 cnt = 0;
        int ret;
        bool remove_from_hanger = true;
        struct sk_buff *skb;
@@ -1468,60 +1469,71 @@ brcmf_fws_txs_process(struct brcmf_fws_info *fws, u8 flags, u32 hslot,
        brcmf_dbg(DATA, "flags %d\n", flags);
 
        if (flags == BRCMF_FWS_TXSTATUS_DISCARD)
-               fws->stats.txs_discard++;
+               fws->stats.txs_discard += compcnt;
        else if (flags == BRCMF_FWS_TXSTATUS_CORE_SUPPRESS) {
-               fws->stats.txs_supp_core++;
+               fws->stats.txs_supp_core += compcnt;
                remove_from_hanger = false;
        } else if (flags == BRCMF_FWS_TXSTATUS_FW_PS_SUPPRESS) {
-               fws->stats.txs_supp_ps++;
+               fws->stats.txs_supp_ps += compcnt;
                remove_from_hanger = false;
        } else if (flags == BRCMF_FWS_TXSTATUS_FW_TOSSED)
-               fws->stats.txs_tossed++;
+               fws->stats.txs_tossed += compcnt;
        else if (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)
-               fws->stats.txs_host_tossed++;
+               fws->stats.txs_host_tossed += compcnt;
        else
                brcmf_err("unexpected txstatus\n");
 
-       ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
-                                     remove_from_hanger);
-       if (ret != 0) {
-               brcmf_err("no packet in hanger slot: hslot=%d\n", hslot);
-               return ret;
-       }
+       while (cnt < compcnt) {
+               ret = brcmf_fws_hanger_poppkt(&fws->hanger, hslot, &skb,
+                                             remove_from_hanger);
+               if (ret != 0) {
+                       brcmf_err("no packet in hanger slot: hslot=%d\n",
+                                 hslot);
+                       goto cont;
+               }
 
-       skcb = brcmf_skbcb(skb);
-       entry = skcb->mac;
-       if (WARN_ON(!entry)) {
-               brcmu_pkt_buf_free_skb(skb);
-               return -EINVAL;
-       }
-       entry->transit_count--;
-       if (entry->suppressed && entry->suppr_transit_count)
-               entry->suppr_transit_count--;
+               skcb = brcmf_skbcb(skb);
+               entry = skcb->mac;
+               if (WARN_ON(!entry)) {
+                       brcmu_pkt_buf_free_skb(skb);
+                       goto cont;
+               }
+               entry->transit_count--;
+               if (entry->suppressed && entry->suppr_transit_count)
+                       entry->suppr_transit_count--;
 
-       brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name, flags,
-                 skcb->htod, seq);
+               brcmf_dbg(DATA, "%s flags %d htod %X seq %X\n", entry->name,
+                         flags, skcb->htod, seq);
 
-       /* pick up the implicit credit from this packet */
-       fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
-       if ((fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT) ||
-           (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
-           (flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED)) {
-               brcmf_fws_return_credits(fws, fifo, 1);
-               brcmf_fws_schedule_deq(fws);
-       }
-       brcmf_fws_macdesc_return_req_credit(skb);
+               /* pick up the implicit credit from this packet */
+               fifo = brcmf_skb_htod_tag_get_field(skb, FIFO);
+               if (fws->fcmode == BRCMF_FWS_FCMODE_IMPLIED_CREDIT ||
+                   (brcmf_skb_if_flags_get_field(skb, REQ_CREDIT)) ||
+                   flags == BRCMF_FWS_TXSTATUS_HOST_TOSSED) {
+                       brcmf_fws_return_credits(fws, fifo, 1);
+                       brcmf_fws_schedule_deq(fws);
+               }
+               brcmf_fws_macdesc_return_req_credit(skb);
 
-       ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
-       if (ret) {
-               brcmu_pkt_buf_free_skb(skb);
-               return -EINVAL;
+               ret = brcmf_proto_hdrpull(fws->drvr, false, skb, &ifp);
+               if (ret) {
+                       brcmu_pkt_buf_free_skb(skb);
+                       goto cont;
+               }
+               if (!remove_from_hanger)
+                       ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
+                                                           genbit, seq);
+               if (remove_from_hanger || ret)
+                       brcmf_txfinalize(ifp, skb, true);
+
+cont:
+               hslot = (hslot + 1) & (BRCMF_FWS_TXSTAT_HSLOT_MASK >>
+                                      BRCMF_FWS_TXSTAT_HSLOT_SHIFT);
+               if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode))
+                       seq = (seq + 1) & BRCMF_SKB_HTOD_SEQ_NR_MASK;
+
+               cnt++;
        }
-       if (!remove_from_hanger)
-               ret = brcmf_fws_txstatus_suppressed(fws, fifo, skb,
-                                                   genbit, seq);
-       if (remove_from_hanger || ret)
-               brcmf_txfinalize(ifp, skb, true);
 
        return 0;
 }
@@ -1547,7 +1559,8 @@ static int brcmf_fws_fifocreditback_indicate(struct brcmf_fws_info *fws,
        return BRCMF_FWS_RET_OK_SCHEDULE;
 }
 
-static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
+static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 type,
+                                      u8 *data)
 {
        __le32 status_le;
        __le16 seq_le;
@@ -1556,23 +1569,31 @@ static int brcmf_fws_txstatus_indicate(struct brcmf_fws_info *fws, u8 *data)
        u32 genbit;
        u8 flags;
        u16 seq;
+       u8 compcnt;
+       u8 compcnt_offset = BRCMF_FWS_TYPE_TXSTATUS_LEN;
 
-       fws->stats.txs_indicate++;
        memcpy(&status_le, data, sizeof(status_le));
        status = le32_to_cpu(status_le);
        flags = brcmf_txstatus_get_field(status, FLAGS);
        hslot = brcmf_txstatus_get_field(status, HSLOT);
        genbit = brcmf_txstatus_get_field(status, GENERATION);
        if (BRCMF_FWS_MODE_GET_REUSESEQ(fws->mode)) {
-               memcpy(&seq_le, &data[BRCMF_FWS_TYPE_PKTTAG_LEN],
+               memcpy(&seq_le, &data[BRCMF_FWS_TYPE_TXSTATUS_LEN],
                       sizeof(seq_le));
                seq = le16_to_cpu(seq_le);
+               compcnt_offset += BRCMF_FWS_TYPE_SEQ_LEN;
        } else {
                seq = 0;
        }
 
+       if (type == BRCMF_FWS_TYPE_COMP_TXSTATUS)
+               compcnt = data[compcnt_offset];
+       else
+               compcnt = 1;
+       fws->stats.txs_indicate += compcnt;
+
        brcmf_fws_lock(fws);
-       brcmf_fws_txs_process(fws, flags, hslot, genbit, seq);
+       brcmf_fws_txs_process(fws, flags, hslot, genbit, seq, compcnt);
        brcmf_fws_unlock(fws);
        return BRCMF_FWS_RET_OK_NOSCHEDULE;
 }
@@ -1888,8 +1909,6 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
 
                err = BRCMF_FWS_RET_OK_NOSCHEDULE;
                switch (type) {
-               case BRCMF_FWS_TYPE_COMP_TXSTATUS:
-                       break;
                case BRCMF_FWS_TYPE_HOST_REORDER_RXPKTS:
                        rd = (struct brcmf_skb_reorder_data *)skb->cb;
                        rd->reorder = data;
@@ -1912,7 +1931,8 @@ void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
                        err = brcmf_fws_request_indicate(fws, type, data);
                        break;
                case BRCMF_FWS_TYPE_TXSTATUS:
-                       brcmf_fws_txstatus_indicate(fws, data);
+               case BRCMF_FWS_TYPE_COMP_TXSTATUS:
+                       brcmf_fws_txstatus_indicate(fws, type, data);
                        break;
                case BRCMF_FWS_TYPE_FIFO_CREDITBACK:
                        err = brcmf_fws_fifocreditback_indicate(fws, data);
@@ -2001,7 +2021,7 @@ static void brcmf_fws_rollback_toq(struct brcmf_fws_info *fws,
                fws->stats.rollback_failed++;
                hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
                brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED,
-                                     hslot, 0, 0);
+                                     hslot, 0, 0, 1);
        } else {
                fws->stats.rollback_success++;
                brcmf_fws_return_credits(fws, fifo, 1);
@@ -2462,7 +2482,8 @@ void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb)
        }
        brcmf_fws_lock(fws);
        hslot = brcmf_skb_htod_tag_get_field(skb, HSLOT);
-       brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0);
+       brcmf_fws_txs_process(fws, BRCMF_FWS_TXSTATUS_HOST_TOSSED, hslot, 0, 0,
+                             1);
        brcmf_fws_unlock(fws);
 }