Commit 09be7546 authored by Wright Feng's avatar Wright Feng Committed by Kalle Valo

wifi: brcmfmac: fix scheduling while atomic issue when deleting flowring

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: default avatarWright Feng <wright.feng@cypress.com>
Signed-off-by: default avatarChi-Hsien Lin <chi-hsien.lin@cypress.com>
Signed-off-by: default avatarAhmad Fatoum <a.fatoum@pengutronix.de>
Signed-off-by: default avatarAlvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: default avatarKalle Valo <kvalo@kernel.org>
Link: https://lore.kernel.org/r/20220722115632.620681-3-alvin@pqrs.dk
parent 0fa24196
...@@ -419,7 +419,6 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx, ...@@ -419,7 +419,6 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
flowid = flow->hash[i].flowid; flowid = flow->hash[i].flowid;
if (flow->rings[flowid]->status != RING_OPEN) if (flow->rings[flowid]->status != RING_OPEN)
continue; continue;
flow->rings[flowid]->status = RING_CLOSING;
brcmf_msgbuf_delete_flowring(drvr, flowid); brcmf_msgbuf_delete_flowring(drvr, flowid);
} }
} }
...@@ -458,12 +457,10 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx, ...@@ -458,12 +457,10 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) && if ((sta || (memcmp(hash[i].mac, peer, ETH_ALEN) == 0)) &&
(hash[i].ifidx == ifidx)) { (hash[i].ifidx == ifidx)) {
flowid = flow->hash[i].flowid; flowid = flow->hash[i].flowid;
if (flow->rings[flowid]->status == RING_OPEN) { if (flow->rings[flowid]->status == RING_OPEN)
flow->rings[flowid]->status = RING_CLOSING;
brcmf_msgbuf_delete_flowring(drvr, flowid); brcmf_msgbuf_delete_flowring(drvr, flowid);
} }
} }
}
if (search) { if (search) {
if (prev) if (prev)
......
...@@ -1400,22 +1400,24 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) ...@@ -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 brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
struct msgbuf_tx_flowring_delete_req *delete; struct msgbuf_tx_flowring_delete_req *delete;
struct brcmf_commonring *commonring; 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; void *ret_ptr;
u8 ifidx; u8 ifidx;
int err; int err;
int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES; int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES;
/* wait for commonring txflow finished */ /* make sure it is not in txflow */
commonring_del = msgbuf->flowrings[flowid];
brcmf_commonring_lock(commonring_del); 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)) { while (retry && atomic_read(&commonring_del->outstanding_tx)) {
usleep_range(5000, 10000); usleep_range(5000, 10000);
retry--; retry--;
} }
brcmf_commonring_unlock(commonring_del); if (!retry) {
if (!retry && atomic_read(&commonring_del->outstanding_tx)) {
brcmf_err("timed out waiting for txstatus\n"); brcmf_err("timed out waiting for txstatus\n");
atomic_set(&commonring_del->outstanding_tx, 0); atomic_set(&commonring_del->outstanding_tx, 0);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment