]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
wifi: brcmfmac: fix continuous 802.1x tx pending timeout error
authorWright Feng <wright.feng@cypress.com>
Fri, 22 Jul 2022 11:56:26 +0000 (13:56 +0200)
committerKalle Valo <kvalo@kernel.org>
Wed, 10 Aug 2022 05:47:22 +0000 (08:47 +0300)
The race condition in brcmf_msgbuf_txflow and brcmf_msgbuf_delete_flowring
makes tx_msghdr writing after brcmf_msgbuf_remove_flowring. Host
driver should delete flowring after txflow complete and all txstatus back,
or pend_8021x_cnt will never be zero and cause every connection 950
milliseconds(MAX_WAIT_FOR_8021X_TX) delay.

Signed-off-by: Wright Feng <wright.feng@cypress.com>
Signed-off-by: Chi-hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: Kalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220722115632.620681-2-alvin@pqrs.dk
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c

index bd164a0821f9ffb725b7f38d302556371fffc755..e476d7d4539694a344113eac465ad11d132a2307 100644 (file)
@@ -1480,8 +1480,10 @@ int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
                                 !brcmf_get_pend_8021x_cnt(ifp),
                                 MAX_WAIT_FOR_8021X_TX);
 
-       if (!err)
+       if (!err) {
                bphy_err(drvr, "Timed out waiting for no pending 802.1x packets\n");
+               atomic_set(&ifp->pend_8021x_cnt, 0);
+       }
 
        return !err;
 }
index b2d0f7570aa97a37ba48393e100c01ffb979b5a6..174584b4297269e3fab8b31e7d039ee9bdcb9ba8 100644 (file)
@@ -71,6 +71,7 @@
 #define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS     32
 #define BRCMF_MSGBUF_UPDATE_RX_PTR_THRS                48
 
+#define BRCMF_MAX_TXSTATUS_WAIT_RETRIES                10
 
 struct msgbuf_common_hdr {
        u8                              msgtype;
@@ -806,8 +807,12 @@ static int brcmf_msgbuf_tx_queue_data(struct brcmf_pub *drvr, int ifidx,
        flowid = brcmf_flowring_lookup(flow, eh->h_dest, skb->priority, ifidx);
        if (flowid == BRCMF_FLOWRING_INVALID_ID) {
                flowid = brcmf_msgbuf_flowring_create(msgbuf, ifidx, skb);
-               if (flowid == BRCMF_FLOWRING_INVALID_ID)
+               if (flowid == BRCMF_FLOWRING_INVALID_ID) {
                        return -ENOMEM;
+               } else {
+                       brcmf_flowring_enqueue(flow, flowid, skb);
+                       return 0;
+               }
        }
        queue_count = brcmf_flowring_enqueue(flow, flowid, skb);
        force = ((queue_count % BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) == 0);
@@ -1395,9 +1400,25 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
        struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
        struct msgbuf_tx_flowring_delete_req *delete;
        struct brcmf_commonring *commonring;
+       struct brcmf_commonring *commonring_del;
+
        void *ret_ptr;
        u8 ifidx;
        int err;
+       int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;
+
+       /* wait for commonring txflow finished */
+       commonring_del = msgbuf->flowrings[flowid];
+       brcmf_commonring_lock(commonring_del);
+       while (retry && atomic_read(&commonring_del->outstanding_tx)) {
+               usleep_range(5000, 10000);
+               retry--;
+       }
+       brcmf_commonring_unlock(commonring_del);
+       if (!retry && atomic_read(&commonring_del->outstanding_tx)) {
+               brcmf_err("timed out waiting for txstatus\n");
+               atomic_set(&commonring_del->outstanding_tx, 0);
+       }
 
        /* no need to submit if firmware can not be reached */
        if (drvr->bus_if->state != BRCMF_BUS_UP) {