mac80211: brcmfmac: backport remaining patches from the Linux 5.0
[openwrt/staging/lynxis.git] / package / kernel / mac80211 / patches / brcm / 328-v5.0-0003-brcmfmac-handle-compressed-tx-status-signal.patch
diff --git a/package/kernel/mac80211/patches/brcm/328-v5.0-0003-brcmfmac-handle-compressed-tx-status-signal.patch b/package/kernel/mac80211/patches/brcm/328-v5.0-0003-brcmfmac-handle-compressed-tx-status-signal.patch
new file mode 100644 (file)
index 0000000..f7e09ec
--- /dev/null
@@ -0,0 +1,227 @@
+From e4af3ffb43d50f070134aa1b40d5c3573f57deb1 Mon Sep 17 00:00:00 2001
+From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
+Date: Mon, 5 Nov 2018 05:52:05 +0000
+Subject: [PATCH] brcmfmac: handle compressed tx status signal
+
+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>
+---
+ .../broadcom/brcm80211/brcmfmac/fwsignal.c    | 121 ++++++++++--------
+ 1 file changed, 71 insertions(+), 50 deletions(-)
+
+--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
+@@ -1455,9 +1455,10 @@ static int brcmf_fws_txstatus_suppressed
+ 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_i
+       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_indi
+       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(s
+       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 *
+               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 *
+                       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(struc
+               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_fw
+       }
+       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);
+ }