Commit 0fa24196 authored by Wright Feng's avatar Wright Feng Committed by Kalle Valo
Browse files

wifi: brcmfmac: fix continuous 802.1x tx pending timeout error



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: 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-2-alvin@pqrs.dk
parent bafe9528
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -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;
}
+22 −1
Original line number Diff line number Diff line
@@ -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) {