From 34ef3f3f279cee6303ae6b891b0c428d331902b6 Mon Sep 17 00:00:00 2001 From: Owen Huang Date: Thu, 19 Jun 2025 20:59:58 -0500 Subject: [PATCH] non-upstream: handle receive error in SG case * FW Tx status also append on Rx SG list, so host driver also need to handle Rx error in SG case. * Fix H2 PCIE kernel trap in disconnect. * Refine debugfs format and show error counters here: header_pulls: 0 header_only_pkt: 0 tlv_parse_failed: 0 tlv_invalid_type: 0 mac_update_fails: 0 ps_update_fails: 0 if_update_fails: 0 pkt2bus: 0 generic_error: 0 rollback_success: 0 rollback_failed: 0 delayq_full: 0 supprq_full: 0 txs_indicate: 0 txs_discard: 0 txs_suppr_core: 0 txs_suppr_ps: 0 txs_tossed: 0 txs_host_tossed: 0 bus_flow_block: 0 fws_flow_block: 0 receive error: 0 cleanup if: 0 send_pkts: BK:0 BE:0 VO:0 VI:0 BCMC:0 requested_sent: BK:0 BE:0 VO:0 VI:0 BCMC:0 Fixes SWWLAN-153932 Signed-off-by: Owen Huang --- .../broadcom/brcm80211/brcmfmac/bcdc.c | 7 ++ .../broadcom/brcm80211/brcmfmac/bcmsdh.c | 3 + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 2 +- .../broadcom/brcm80211/brcmfmac/fwsignal.c | 69 +++++++++++-------- .../broadcom/brcm80211/brcmfmac/fwsignal.h | 2 +- .../broadcom/brcm80211/brcmfmac/proto.h | 9 +++ 6 files changed, 63 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c index 4fefd8587e5c6..cf9da000c52e6 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c @@ -421,6 +421,12 @@ brcmf_proto_bcdc_reset_if(struct brcmf_if *ifp) brcmf_fws_reset_interface(ifp); } +static void +brcmf_proto_bcdc_cleanup_if(struct brcmf_if *ifp) +{ + brcmf_fws_cleanup_interface(ifp); +} + static int brcmf_proto_bcdc_init_done(struct brcmf_pub *drvr) { @@ -466,6 +472,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr) drvr->proto->add_if = brcmf_proto_bcdc_add_if; drvr->proto->del_if = brcmf_proto_bcdc_del_if; drvr->proto->reset_if = brcmf_proto_bcdc_reset_if; + drvr->proto->cleanup_if = brcmf_proto_bcdc_cleanup_if; drvr->proto->init_done = brcmf_proto_bcdc_init_done; drvr->proto->debugfs_create = brcmf_proto_bcdc_debugfs_create; drvr->proto->pd = bcdc; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c index b41185544ca77..1fb8c01194c3d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c @@ -568,6 +568,9 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, while ((pkt_next = __skb_dequeue(&local_list)) != NULL) brcmu_pkt_buf_free_skb(pkt_next); + if (ret && sdiodev->func2->device == SDIO_DEVICE_ID_CYPRESS_55572) + brcmf_fws_recv_err(sdiodev->bus_if->drvr); + return ret; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c index 6eb48e033dea5..b336be05e0b07 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c @@ -8285,7 +8285,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp, complete(&cfg->vif_disabled); brcmf_net_setcarrier(ifp, false); } - brcmf_fws_wa_cleanup_by_ifidx(ifp->drvr, ifp->ifidx); + brcmf_proto_cleanup_if(ifp->drvr, ifp); } else if (brcmf_is_nonetwork(cfg, e)) { if (brcmf_is_ibssmode(ifp->vif)) clear_bit(BRCMF_VIF_STATUS_CONNECTING, diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c index 097ac6eeeb269..84bd38de35ff3 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c @@ -481,6 +481,8 @@ struct brcmf_fws_stats { u32 txs_host_tossed; u32 bus_flow_block; u32 fws_flow_block; + u32 cnt_recv_err; + u32 cnt_cleanup_if; }; struct brcmf_fws_info { @@ -1623,6 +1625,7 @@ void brcmf_fws_recv_err(struct brcmf_pub *drvr) brcmf_dbg(SDIO, "Enter\n"); brcmf_fws_lock(fws); + fws->stats.cnt_recv_err++; fws->credit_recover = true; fws->sdio_recv_error = true; brcmf_fws_unlock(fws); @@ -2437,35 +2440,35 @@ static void brcmf_fws_dequeue_worker(struct work_struct *worker) } #ifdef DEBUG + static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) { struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); - struct brcmf_fws_stats *fwstats = &(drvr_to_fws(bus_if->drvr)->stats); + struct brcmf_fws_info *fws = drvr_to_fws(bus_if->drvr); + struct brcmf_fws_stats *fwstats = &fws->stats; seq_printf(seq, - "header_pulls: %u\n" - "header_only_pkt: %u\n" - "tlv_parse_failed: %u\n" - "tlv_invalid_type: %u\n" - "mac_update_fails: %u\n" - "ps_update_fails: %u\n" - "if_update_fails: %u\n" - "pkt2bus: %u\n" - "generic_error: %u\n" - "rollback_success: %u\n" - "rollback_failed: %u\n" - "delayq_full: %u\n" - "supprq_full: %u\n" - "txs_indicate: %u\n" - "txs_discard: %u\n" - "txs_suppr_core: %u\n" - "txs_suppr_ps: %u\n" - "txs_tossed: %u\n" - "txs_host_tossed: %u\n" - "bus_flow_block: %u\n" - "fws_flow_block: %u\n" - "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" - "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n", + "header_pulls: %8u\t" + "header_only_pkt: %8u\n" + "tlv_parse_failed:%8u\t" + "tlv_invalid_type:%8u\n" + "mac_update_fails:%8u\t" + "ps_update_fails: %8u\t" + "if_update_fails: %8u\n" + "pkt2bus: %8u\t" + "generic_error: %8u\n" + "rollback_success:%8u\t" + "rollback_failed: %8u\n" + "delayq_full: %8u\t" + "supprq_full: %8u\n" + "txs_indicate: %8u\t" + "txs_discard: %8u\n" + "txs_suppr_core: %8u\t" + "txs_suppr_ps: %8u\n" + "txs_tossed: %8u\t" + "txs_host_tossed: %8u\n" + "bus_flow_block: %8u\t" + "fws_flow_block: %8u\n", fwstats->header_pulls, fwstats->header_only_pkt, fwstats->tlv_parse_failed, @@ -2486,7 +2489,17 @@ static int brcmf_debugfs_fws_stats_read(struct seq_file *seq, void *data) fwstats->txs_tossed, fwstats->txs_host_tossed, fwstats->bus_flow_block, - fwstats->fws_flow_block, + fwstats->fws_flow_block); + + seq_printf(seq, + "receive error: %8u\t" + "cleanup if: %8u\n\n", + fwstats->cnt_recv_err, + fwstats->cnt_cleanup_if); + + seq_printf(seq, + "send_pkts: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n" + "requested_sent: BK:%u BE:%u VO:%u VI:%u BCMC:%u\n\n", fwstats->send_pkts[0], fwstats->send_pkts[1], fwstats->send_pkts[2], fwstats->send_pkts[3], fwstats->send_pkts[4], @@ -2694,12 +2707,13 @@ void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked) } } -void brcmf_fws_wa_cleanup_by_ifidx(struct brcmf_pub *drvr, int ifidx) +void brcmf_fws_cleanup_interface(struct brcmf_if *ifp) { - struct brcmf_fws_info *fws = drvr_to_fws(drvr); + struct brcmf_fws_info *fws = drvr_to_fws(ifp->drvr); struct brcmf_fws_mac_descriptor *entry; struct brcmf_fws_mac_descriptor *table; bool (*matchfn)(struct sk_buff *, void *) = brcmf_fws_ifidx_match; + int ifidx = ifp->ifidx; int i; if (!fws->sdio_recv_error) @@ -2709,6 +2723,7 @@ void brcmf_fws_wa_cleanup_by_ifidx(struct brcmf_pub *drvr, int ifidx) brcmf_fws_lock(fws); + fws->stats.cnt_cleanup_if++; fws->sdio_recv_error = false; entry = &fws->desc.iface[ifidx]; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h index 0add173ebe358..87606687505c1 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h @@ -45,6 +45,6 @@ void brcmf_fws_bustxcomplete(struct brcmf_fws_info *fws, struct sk_buff *skb, void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked); void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb, bool inirq); void brcmf_fws_recv_err(struct brcmf_pub *drvr); -void brcmf_fws_wa_cleanup_by_ifidx(struct brcmf_pub *drvr, int ifidx); +void brcmf_fws_cleanup_interface(struct brcmf_if *ifp); #endif /* FWSIGNAL_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h index f4a79e217da5b..00c8633d10d10 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h @@ -36,6 +36,7 @@ struct brcmf_proto { void (*add_if)(struct brcmf_if *ifp); void (*del_if)(struct brcmf_if *ifp); void (*reset_if)(struct brcmf_if *ifp); + void (*cleanup_if)(struct brcmf_if *ifp); int (*init_done)(struct brcmf_pub *drvr); void (*debugfs_create)(struct brcmf_pub *drvr); void *pd; @@ -138,6 +139,14 @@ brcmf_proto_reset_if(struct brcmf_pub *drvr, struct brcmf_if *ifp) drvr->proto->reset_if(ifp); } +static inline void +brcmf_proto_cleanup_if(struct brcmf_pub *drvr, struct brcmf_if *ifp) +{ + if (!drvr->proto->cleanup_if) + return; + drvr->proto->cleanup_if(ifp); +} + static inline int brcmf_proto_init_done(struct brcmf_pub *drvr) {