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

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
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -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,12 +457,10 @@ 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);
		}
	}
	}

	if (search) {
		if (prev)
+8 −6
Original line number Diff line number Diff line
@@ -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);
	}