* [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips
@ 2026-11-07 15:48 Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 1/4] wifi: brcmfmac: pcie: set the state before D0_INFORM on resume Andre Eikmeyer
` (3 more replies)
0 siblings, 4 replies; 10+ messages in thread
From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw)
To: Arend van Spriel
Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel,
Michael Reeves, Hector Martin, Janne Grunau, asahi,
Sebastian Reichel
This goes on top of Michael Reeves' BCM4388 series [1], which also
changes how brcmfmac talks to the BCM4364 and BCM4377 of the T2 Macs.
These patches are follow-ups to it.
Michael's Patch 5 moves the mailbox to the control ring when the
firmware does not set BRCMF_PCIE_SHARED_USE_MAILBOX. On the BCM4377
of the T2 Macs that makes D3 work at all, since this firmware doesn't
read the TCM mailbox the driver used before. But that caused some
other issues as an aftermath.
Patches 1 and 2 fix two things in that path. D0_INFORM on resume fails
while the PCIe state is still DOWN, which I reported on patch 5 [2].
And with host ready as a capability, the host ready doorbell at init
halts the BCM4364 firmware.
Patch 3 probes again after a resume through the platform firmware,
since the chip loses its firmware in S3. Patch 4 stands on its own and
drops a tx status wait on flowring delete that the BCM4377 firmware
doesnt satisfy.
The Bluetooth function of the BCM4377 gets the same resume handling in
"Bluetooth: hci_bcm4377: resume after ACPI S3" on linux-bluetooth.
Tested with S3 on the BCM4377 (MacBookAir9,1) and BCM4364B2
(MacBookPro15,1), and probe on the BCM4364B3 (MacBookPro16,1).
[1] https://lore.kernel.org/all/20260925-brcm4388-submit-v1-0-b5cbc2cde2fb@gmail.com/
[2] https://lore.kernel.org/all/20261106153612.2aadef2a@kait2en-mbp15-1/
Andre Eikmeyer (4):
wifi: brcmfmac: pcie: set the state before D0_INFORM on resume
wifi: brcmfmac: pcie: skip the host ready doorbell at init once it is
a capability
wifi: brcmfmac: pcie: probe again after a resume through firmware
wifi: brcmfmac: msgbuf: send the flowring delete without waiting for
tx status
.../broadcom/brcm80211/brcmfmac/msgbuf.c | 23 +++++++---------
.../broadcom/brcm80211/brcmfmac/pcie.c | 26 ++++++++++++++++---
2 files changed, 33 insertions(+), 16 deletions(-)
base-commit: 991a73f4909f1348ffb4b38765cdb522a775e4c2
prerequisite-patch-id: e3427132df0f9740b79d9b3f84bc14c25f787514
prerequisite-patch-id: 1a0aae8b057854813ca6d1f20d3bf153a7b761ec
prerequisite-patch-id: 3453364de54d0d786a6126fca792567f13aa3679
prerequisite-patch-id: d40a127ef83ad7d898ca7c3d643b45b829051477
prerequisite-patch-id: 5bd50905bb42d138eb6fda7d5ad795615348ecdd
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 1/4] wifi: brcmfmac: pcie: set the state before D0_INFORM on resume 2026-11-07 15:48 [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips Andre Eikmeyer @ 2026-11-07 15:48 ` Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 2/4] wifi: brcmfmac: pcie: skip the host ready doorbell at init once it is a capability Andre Eikmeyer ` (2 subsequent siblings) 3 siblings, 0 replies; 10+ messages in thread From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw) To: Arend van Spriel Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel, Michael Reeves, Hector Martin, Janne Grunau, asahi, Sebastian Reichel With the mailbox on the control ring, D0_INFORM goes through the ring write path, which refuses to write while devinfo->state is DOWN. brcmf_pcie_pm_leave_D3() sets the state only after D0_INFORM, so every hot resume fails and falls back to remove and re-probe: brcmf_pcie_send_mb_data: Failed to send H2D mailbox data (-5) Set the state before D0_INFORM and back to DOWN when the hot resume fails. Signed-off-by: Andre Eikmeyer <dev@deq.rocks> --- drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 4de157d18ff..231a2fb89f0 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -2838,10 +2838,10 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) /* Check if device is still up and running, if so we are ready */ if (brcmf_pcie_read_pcie32(devinfo, devinfo->reginfo->intmask) != 0) { brcmf_dbg(PCIE, "Try to wakeup device....\n"); + devinfo->state = BRCMFMAC_PCIE_STATE_UP; if (brcmf_pcie_send_mb_data(devinfo, BRCMF_H2D_HOST_D0_INFORM)) goto cleanup; brcmf_dbg(PCIE, "Hot resume, continue....\n"); - devinfo->state = BRCMFMAC_PCIE_STATE_UP; brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2); brcmf_bus_change_state(bus, BRCMF_BUS_UP); brcmf_pcie_intr_enable(devinfo); @@ -2851,6 +2851,7 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) } cleanup: + devinfo->state = BRCMFMAC_PCIE_STATE_DOWN; brcmf_chip_detach(devinfo->ci); devinfo->ci = NULL; pdev = devinfo->pdev; ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/4] wifi: brcmfmac: pcie: skip the host ready doorbell at init once it is a capability 2026-11-07 15:48 [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 1/4] wifi: brcmfmac: pcie: set the state before D0_INFORM on resume Andre Eikmeyer @ 2026-11-07 15:48 ` Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 3/4] wifi: brcmfmac: pcie: probe again after a resume through firmware Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status Andre Eikmeyer 3 siblings, 0 replies; 10+ messages in thread From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw) To: Arend van Spriel Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel, Michael Reeves, Hector Martin, Janne Grunau, asahi, Sebastian Reichel With host ready in the host capabilities, the BCM4364 firmware halts on the doorbell that brcmf_pcie_preinit() rings, before it answers the first ioctl. The B3 of the MacBookPro16,1 does so on every load, the B2 of the MacBookPro15,1 on some: brcmf_pcie_handle_mb_data D2H_MB_DATA: FW HALT brcmf_attach: dongle is not responding: err=-5 The BCM4377 stays silent without the capability, so it stays. Once host ready is a capability the firmware takes the doorbell as the exit from D3, where Broadcom's DHD driver rings it, after D0_INFORM. Ring it at init only when host ready is not a capability. Signed-off-by: Andre Eikmeyer <dev@deq.rocks> --- .../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index 231a2fb89f0..fc0f23477eb 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -325,6 +325,7 @@ struct brcmf_pcie_shared_info { dma_addr_t ringupd_dmahandle; u8 version; bool mb_via_ctl; + bool hostrdy; }; #define BRCMF_OTP_MAX_PARAM_LEN 16 @@ -1599,7 +1600,13 @@ static int brcmf_pcie_preinit(struct device *dev) brcmf_dbg(PCIE, "Enter\n"); brcmf_pcie_intr_enable(buspub->devinfo); - brcmf_pcie_hostready(buspub->devinfo); + /* + * Once the host capabilities enable host ready, the firmware takes the + * doorbell as the exit from D3 only. The BCM4364 firmware halts on it + * here. + */ + if (!buspub->devinfo->shared.hostrdy) + brcmf_pcie_hostready(buspub->devinfo); return 0; } @@ -1806,8 +1813,10 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo, !(shared->flags & BRCMF_PCIE_SHARED_USE_MAILBOX); host_cap = shared->version; - if (shared->flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1) + if (shared->flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1) { host_cap |= BRCMF_HOSTCAP_H2D_ENABLE_HOSTRDY; + shared->hostrdy = true; + } if (shared->flags & BRCMF_PCIE_SHARED_DAR) host_cap |= BRCMF_HOSTCAP_H2D_DAR; host_cap |= BRCMF_HOSTCAP_DS_NO_OOB_DW; ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/4] wifi: brcmfmac: pcie: probe again after a resume through firmware 2026-11-07 15:48 [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 1/4] wifi: brcmfmac: pcie: set the state before D0_INFORM on resume Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 2/4] wifi: brcmfmac: pcie: skip the host ready doorbell at init once it is a capability Andre Eikmeyer @ 2026-11-07 15:48 ` Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status Andre Eikmeyer 3 siblings, 0 replies; 10+ messages in thread From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw) To: Arend van Spriel Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel, Michael Reeves, Hector Martin, Janne Grunau, asahi, Sebastian Reichel After ACPI S3 the chip comes back without its firmware, but the interrupt mask can read back nonzero, so brcmf_pcie_pm_leave_D3() takes the hot resume path and every command times out afterwards. Seen on the BCM4377 and BCM4364 of the T2 Macs. When the platform firmware handled the resume and WoWL is off, go straight to the existing remove and re-probe path. Signed-off-by: Andre Eikmeyer <dev@deq.rocks> --- .../net/wireless/broadcom/brcm80211/brcmfmac/pcie.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c index fc0f23477eb..faa1e16ed4f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/firmware.h> #include <linux/pci.h> +#include <linux/suspend.h> #include <linux/vmalloc.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -2844,6 +2845,15 @@ static int brcmf_pcie_pm_leave_D3(struct device *dev) devinfo = bus->bus_priv.pcie->devinfo; brcmf_dbg(PCIE, "Enter, dev=%p, bus=%p\n", dev, bus); + /* + * Without WoWL the device is powered off when the platform firmware + * handles the system sleep, as with ACPI S3, and comes back without + * its firmware. Its registers can still read back nonzero, so probe + * it again. + */ + if (pm_resume_via_firmware() && !devinfo->wowl_enabled) + goto cleanup; + /* Check if device is still up and running, if so we are ready */ if (brcmf_pcie_read_pcie32(devinfo, devinfo->reginfo->intmask) != 0) { brcmf_dbg(PCIE, "Try to wakeup device....\n"); ^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status 2026-11-07 15:48 [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips Andre Eikmeyer ` (2 preceding siblings ...) 2026-11-07 15:48 ` [PATCH 3/4] wifi: brcmfmac: pcie: probe again after a resume through firmware Andre Eikmeyer @ 2026-11-07 15:48 ` Andre Eikmeyer 2026-11-10 23:12 ` Kordian Chmielewski (mlody1212) 3 siblings, 1 reply; 10+ messages in thread From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw) To: Arend van Spriel Cc: linux-wireless, brcm80211, brcm80211-dev-list.pdl, linux-kernel, Michael Reeves, Hector Martin, Janne Grunau, asahi, Sebastian Reichel The BCM4377 firmware returns the tx status of queued packets only when it gets the flowring delete request. brcmf_msgbuf_delete_flowring() waits up to 100 ms for them before it sends the request, so every disconnect logs a timeout, and the cleared counter goes below zero when the status arrives. The race the wait was added for in commit 0fa24196e425 ("wifi: brcmfmac: fix continuous 802.1x tx pending timeout error") is covered by RING_CLOSING since commit 09be7546a602 ("wifi: brcmfmac: fix scheduling while atomic issue when deleting flowring"), and late tx status still releases the packet. Send the delete right away and reset the counter when the ring is created. Signed-off-by: Andre Eikmeyer <dev@deq.rocks> --- .../broadcom/brcm80211/brcmfmac/msgbuf.c | 23 ++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 8e5c697e7f1..a9ccf647f9a 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -73,7 +73,6 @@ #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; @@ -645,6 +644,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf, brcmf_commonring_config(msgbuf->flowrings[flowid], BRCMF_H2D_TXFLOWRING_MAX_ITEM, BRCMF_H2D_TXFLOWRING_ITEMSIZE, dma_buf); + atomic_set(&msgbuf->flowrings[flowid]->outstanding_tx, 0); commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT]; brcmf_commonring_lock(commonring); @@ -1330,6 +1330,10 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf, } brcmf_dbg(MSGBUF, "Flowring %d Delete response status %d\n", flowid, status); + if (atomic_read(&msgbuf->flowrings[flowid]->outstanding_tx)) + brcmf_dbg(MSGBUF, "Flowring %d deleted with %d tx status outstanding\n", + flowid, + atomic_read(&msgbuf->flowrings[flowid]->outstanding_tx)); brcmf_msgbuf_remove_flowring(msgbuf, flowid); } @@ -1471,23 +1475,16 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid) void *ret_ptr; u8 ifidx; int err; - int retry = BRCMF_MAX_TXSTATUS_WAIT_RETRIES; - /* make sure it is not in txflow */ + /* + * Make sure txflow posts nothing more to the ring. The firmware returns + * the tx status of the posted packets when it deletes the ring, before + * it sends the delete response. + */ 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--; - } - if (!retry) { - 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) { brcmf_dbg(MSGBUF, "bus down, flowring will be removed\n"); ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status 2026-11-07 15:48 ` [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status Andre Eikmeyer @ 2026-11-10 23:12 ` Kordian Chmielewski (mlody1212) 2026-11-11 19:07 ` André Eikmeyer 0 siblings, 1 reply; 10+ messages in thread From: Kordian Chmielewski (mlody1212) @ 2026-11-10 23:12 UTC (permalink / raw) To: dev Cc: arend.vanspriel, asahi, brcm80211-dev-list.pdl, brcm80211, j, linux-kernel, linux-wireless, marcan, michael.reeves077, sebastian.reichel On Sat, Nov 07, 2026 at 15:48 UTC, Andre Eikmeyer wrote: > The BCM4377 firmware returns the tx status of queued packets only when > it gets the flowring delete request. The same happens on a BCM43684 (firmware 17.10.188.75, an access point with about 15 clients on two radios; this chip also needs patches for its BCA firmware that I haven't posted yet). In 10.5 hours the wait timed out 23 times. 2835 frames were still out when their flowring was deleted, and every one of them was completed later, at most 81 s after it was posted. No pktid was lost, so the 100 ms wait did not help here either. What I can't tell from these numbers is whether a tx status can still come after the delete response. If it can, it lands on a new ring that got the same flowid in the meantime and decrements its outstanding_tx, which also drives brcmf_msgbuf_schedule_txdata(). Do you know how the firmware orders them? In my tree each tx pktid keeps the generation of its flowring for that case; I can send it on top of your patch if it turns out to be needed. Kordian ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status 2026-11-10 23:12 ` Kordian Chmielewski (mlody1212) @ 2026-11-11 19:07 ` André Eikmeyer 2026-11-11 19:55 ` [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring Kordian Chmielewski (mlody1212) 0 siblings, 1 reply; 10+ messages in thread From: André Eikmeyer @ 2026-11-11 19:07 UTC (permalink / raw) To: Kordian Chmielewski (mlody1212) Cc: arend.vanspriel, asahi, brcm80211-dev-list.pdl, brcm80211, j, linux-kernel, linux-wireless, marcan, michael.reeves077, sebastian.reichel On Wed, 11 Nov 2026 00:12:47 +0100 "Kordian Chmielewski (mlody1212)" <kudzo51@gmail.com> wrote: > Do you know how the > firmware orders them? In my tree each tx pktid keeps the generation of > its flowring for that case; I can send it on top of your patch if it > turns out to be needed. Hi Kordian, On the BCM4377 I have a trace of a disconnect with debug output. The status messages are processed before both delete responses. But they come on the complete ring and the responses on the control complete ring. And brcmf_proto_msgbuf_rx_trigger() always drains the tx complete ring first. So that only shows the order within one interrupt. Please send your generation patch on top. That should close it independent of firmware ordering. Andre ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring 2026-11-11 19:07 ` André Eikmeyer @ 2026-11-11 19:55 ` Kordian Chmielewski (mlody1212) 2026-11-12 13:18 ` Kordian Chmielewski (mlody1212) 0 siblings, 1 reply; 10+ messages in thread From: Kordian Chmielewski (mlody1212) @ 2026-11-11 19:55 UTC (permalink / raw) To: dev Cc: arend.vanspriel, asahi, brcm80211-dev-list.pdl, brcm80211, j, linux-kernel, linux-wireless, marcan, michael.reeves077, sebastian.reichel, Kordian Chmielewski (mlody1212) brcmf_proto_msgbuf_rx_trigger() reads the tx complete ring before the control complete ring. When the firmware writes the tx status of a packet shortly before the delete response of its flowring, the host can see the response in one pass and the status only in the next one, after brcmf_msgbuf_remove_flowring() has released the flowid. If a new flowring got the flowid in the meantime, the status decrements its outstanding_tx, which brcmf_msgbuf_schedule_txdata() and the trickle check in brcmf_proto_msgbuf_rx_trigger() rely on. This happens whatever order the firmware sends the two messages in. Give each flowid a generation that goes up when the flowid is released, and keep it in the tx pktid of every packet posted to the flowring. A tx status of an older generation still releases its packet, but no longer touches the counter. Signed-off-by: Kordian Chmielewski (mlody1212) <kudzo51@gmail.com> --- Notes: Hi Andre, thanks for checking the trace. Here is the patch, on top of your [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status https://lore.kernel.org/all/20261107154810.89780-5-dev@deq.rocks/ The generation goes up when the flowid is released, not when the delete is sent, so the debug message in your patch still counts the tx status that comes before the response. My tree for a BCM43684 access point bumps it when the delete is sent; this version is compile-tested only. Feel free to take it into the next version of your series. .../broadcom/brcm80211/brcmfmac/msgbuf.c | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c index 8fd970571..9d8360d3e 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c @@ -247,6 +247,7 @@ struct brcmf_msgbuf { struct brcmf_commonring **commonrings; struct brcmf_commonring **flowrings; dma_addr_t *flowring_dma_handle; + u16 *flowring_gen; u16 max_flowrings; u16 max_submissionrings; @@ -293,6 +294,7 @@ struct brcmf_msgbuf { struct brcmf_msgbuf_pktid { atomic_t allocated; u16 data_offset; + u16 gen; /* tx: flowring_gen of its flowid when posted */ struct sk_buff *skb; dma_addr_t physaddr; }; @@ -559,6 +561,21 @@ static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb) { } +/* + * Called when a flowid is released. A tx status can still come for a packet + * of the old flowring after that: brcmf_proto_msgbuf_rx_trigger() reads the + * tx complete ring before the control complete ring, so it can see a delete + * response before a tx status the firmware wrote first. The flowid may have + * gone to a new flowring by then, and the status must not decrement the + * outstanding_tx of the new one. + */ +static void brcmf_msgbuf_flowring_next_gen(struct brcmf_msgbuf *msgbuf, + u16 flowid) +{ + WRITE_ONCE(msgbuf->flowring_gen[flowid], + msgbuf->flowring_gen[flowid] + 1); +} + static void brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid) { @@ -566,6 +583,7 @@ brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid) void *dma_buf; brcmf_dbg(MSGBUF, "Removing flowring %d\n", flowid); + brcmf_msgbuf_flowring_next_gen(msgbuf, flowid); dma_sz = BRCMF_H2D_TXFLOWRING_MAX_ITEM * BRCMF_H2D_TXFLOWRING_ITEMSIZE; dma_buf = msgbuf->flowrings[flowid]->buf_addr; @@ -768,6 +786,8 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid) bphy_err(drvr, "No PKTID available !!\n"); break; } + msgbuf->tx_pktids->array[pktid].gen = + READ_ONCE(msgbuf->flowring_gen[flowid]); ret_ptr = brcmf_commonring_reserve_for_write(commonring); if (!ret_ptr) { brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, @@ -920,10 +940,13 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) struct sk_buff *skb; u16 flow_ring_id; u16 flowid; + u16 gen = 0; tx_status = (struct msgbuf_tx_status *)buf; idx = le32_to_cpu(tx_status->msg.request_id) - 1; flow_ring_id = le16_to_cpu(tx_status->compl_hdr.flow_ring_id); + if (idx < msgbuf->tx_pktids->array_size) + gen = msgbuf->tx_pktids->array[idx].gen; skb = brcmf_msgbuf_get_pktid(msgbuf->drvr->bus_if->dev, msgbuf->tx_pktids, idx); if (!skb) @@ -937,7 +960,9 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf) set_bit(flowid, msgbuf->txstatus_done_map); commonring = msgbuf->flowrings[flowid]; - atomic_dec(&commonring->outstanding_tx); + /* not for a packet of a flowring that had the flowid before */ + if (gen == READ_ONCE(msgbuf->flowring_gen[flowid])) + atomic_dec(&commonring->outstanding_tx); brcmf_txfinalize(brcmf_get_ifp(msgbuf->drvr, tx_status->msg.ifidx), skb, true); @@ -1325,6 +1350,7 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf, if (status) { bphy_err(drvr, "Flowring deletion failed, code %d\n", status); + brcmf_msgbuf_flowring_next_gen(msgbuf, flowid); brcmf_flowring_delete(msgbuf->flow, flowid); return; } @@ -1681,6 +1707,10 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) msgbuf->max_flowrings); if (!msgbuf->flowring_dma_handle) goto fail; + msgbuf->flowring_gen = kzalloc_objs(*msgbuf->flowring_gen, + msgbuf->max_flowrings); + if (!msgbuf->flowring_gen) + goto fail; msgbuf->rx_dataoffset = if_msgbuf->rx_dataoffset; msgbuf->max_rxbufpost = if_msgbuf->max_rxbufpost; @@ -1732,6 +1762,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr) kfree(msgbuf->txstatus_done_map); brcmf_msgbuf_release_pktids(msgbuf); kfree(msgbuf->flowring_dma_handle); + kfree(msgbuf->flowring_gen); if (msgbuf->ioctbuf) dma_free_coherent(drvr->bus_if->dev, BRCMF_TX_IOCTL_MAX_MSG_SIZE, @@ -1772,6 +1803,7 @@ void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr) msgbuf->ioctbuf, msgbuf->ioctbuf_handle); brcmf_msgbuf_release_pktids(msgbuf); kfree(msgbuf->flowring_dma_handle); + kfree(msgbuf->flowring_gen); kfree(msgbuf); drvr->proto->pd = NULL; } -- 2.56.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring 2026-11-11 19:55 ` [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring Kordian Chmielewski (mlody1212) @ 2026-11-12 13:18 ` Kordian Chmielewski (mlody1212) 2026-11-12 17:31 ` André Eikmeyer 0 siblings, 1 reply; 10+ messages in thread From: Kordian Chmielewski (mlody1212) @ 2026-11-12 13:18 UTC (permalink / raw) To: dev Cc: arend.vanspriel, asahi, brcm80211-dev-list.pdl, brcm80211, j, linux-kernel, linux-wireless, marcan, michael.reeves077, sebastian.reichel Hi Andre, I have now run it on a BCM43684 (firmware 17.10.188.75) as an access point, with the logic of your 4/4 and this patch ported to my tree (its tx status path is the BCA one, with the flowid and generation kept per pktid), plus counters for the test. The AP sent a client a 150 Mbit/s UDP stream while the client was deauthenticated 60 times. In 62 flowring deletes, 2130 frames were out when the delete request was sent. The tx status of every one of them came before the delete response, none came after it, and outstanding_tx never went below zero. Here too the host saw every status before the delete response, as in your BCM4377 trace, and the generation check did not trigger. To see the case itself, I then held back the tx status of a flowring being deleted for 3 s in the driver, so the host handled the delete response first and the new flowring of the reconnected client got the same flowid. With the generation check, all 531 such statuses came for a reused flowid and left its counter alone: at each of the 15 deletes it matched the frames still out. With the generation check turned off, the counter of the new flowring was wrong at 14 of 15 deletes, by 787 frames in total, and went below zero. One wording fix in the patch: "This happens whatever order the firmware sends the two messages in" is too strong, it should say "This can happen". Without holding a status back I have not seen it. Kordian ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring 2026-11-12 13:18 ` Kordian Chmielewski (mlody1212) @ 2026-11-12 17:31 ` André Eikmeyer 0 siblings, 0 replies; 10+ messages in thread From: André Eikmeyer @ 2026-11-12 17:31 UTC (permalink / raw) To: Kordian Chmielewski (mlody1212) Cc: arend.vanspriel, asahi, brcm80211-dev-list.pdl, brcm80211, j, linux-kernel, linux-wireless, marcan, michael.reeves077, sebastian.reichel On Thu, 12 Nov 2026 14:18:59 +0100 "Kordian Chmielewski (mlody1212)" <kudzo51@gmail.com> wrote: > Here too the host saw every status before the delete response, as in > your BCM4377 trace, and the generation check did not trigger. Thanks for measuring. So both chips complete everything before the delete response in normal operation, which is what 4/4 relies on. I'd rather not fold your patch into my series. The stale decrement is older than 4/4, the old wait reset the counter on timeout as well, and your patch applies without it. On the T2 Macs a new flowring only comes after a new association, long after any late status, so I can't show the case there. Your AP numbers can, so please send it on its own. Andre ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-11-12 17:32 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-11-07 15:48 [PATCH 0/4] wifi: brcmfmac: pcie: S3 suspend and resume on the T2 Mac chips Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 1/4] wifi: brcmfmac: pcie: set the state before D0_INFORM on resume Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 2/4] wifi: brcmfmac: pcie: skip the host ready doorbell at init once it is a capability Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 3/4] wifi: brcmfmac: pcie: probe again after a resume through firmware Andre Eikmeyer 2026-11-07 15:48 ` [PATCH 4/4] wifi: brcmfmac: msgbuf: send the flowring delete without waiting for tx status Andre Eikmeyer 2026-11-10 23:12 ` Kordian Chmielewski (mlody1212) 2026-11-11 19:07 ` André Eikmeyer 2026-11-11 19:55 ` [PATCH wireless-next] wifi: brcmfmac: msgbuf: count tx status only for the current flowring Kordian Chmielewski (mlody1212) 2026-11-12 13:18 ` Kordian Chmielewski (mlody1212) 2026-11-12 17:31 ` André Eikmeyer
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox