wifi: brcmfmac: fix scheduling while atomic issue when deleting flowring
authorWright Feng <wright.feng@cypress.com>
Fri, 22 Jul 2022 11:56:27 +0000 (13:56 +0200)
committerKalle Valo <kvalo@kernel.org>
Wed, 10 Aug 2022 05:47:22 +0000 (08:47 +0300)
We should not sleep while holding the spin lock. It makes
'scheduling while atomic' in brcmf_msgbuf_delete_flowring.
And to avoid race condition between deleting flowring and txflow,
we only hold spin lock when seting flowring status to RING_CLOSING.

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-3-alvin@pqrs.dk
drivers/net/wireless/broadcom/brcm80211/brcmfmac/flowring.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c

index 096f6b9..e1127d7 100644 (file)
@@ -419,7 +419,6 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
                                flowid = flow->hash[i].flowid;
                                if (flow->rings[flowid]->status != RING_OPEN)
                                        continue;
-                               flow->rings[flowid]->status = RING_CLOSING;
                                brcmf_msgbuf_delete_flowring(drvr, flowid);
                        }
                }
@@ -458,10 +457,8 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
                if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
                    (hash[i].ifidx == ifidx)) {
                        flowid = flow->hash[i].flowid;
-                       if (flow->rings[flowid]->status == RING_OPEN) {
-                               flow->rings[flowid]->status = RING_CLOSING;
+                       if (flow->rings[flowid]->status == RING_OPEN)
                                brcmf_msgbuf_delete_flowring(drvr, flowid);
-                       }
                }
        }
 
index 174584b..cec53f9 100644 (file)
@@ -1400,22 +1400,24 @@ 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;
-
+       struct brcmf_commonring *commonring_del = msgbuf->flowrings[flowid];
+       struct brcmf_flowring *flow = msgbuf->flow;
        void *ret_ptr;
        u8 ifidx;
        int err;
        int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;
 
-       /* wait for commonring txflow finished */
-       commonring_del = msgbuf->flowrings[flowid];
+       /* make sure it is not in txflow */
        brcmf_commonring_lock(commonring_del);
+       flow->rings[flowid]->status = RING_CLOSING;
+       brcmf_commonring_unlock(commonring_del);
+
+       /* wait for commonring txflow finished */
        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)) {
+       if (!retry) {
                brcmf_err("timed out waiting for txstatus\n");
                atomic_set(&commonring_del->outstanding_tx, 0);
        }