From: Andreas Wendleder <gonsolo@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: Johannes Berg <johannes@sipsolutions.net>,
b43-dev@lists.infradead.org, Michael Buesch <m@bues.ch>,
Alessio Ferri <alessio.ferri@mythread.it>,
kvalo@kernel.org, julian.calaby@gmail.com, jpeisach@ubuntu.com,
rosenp@gmail.com, linux-kernel@vger.kernel.org
Subject: [PATCH RFC wireless-next 4/4] wifi: b43: A-MPDU for the AC microcode
Date: Thu, 12 Nov 2026 18:56:40 +0100 [thread overview]
Message-ID: <20261112175640.40603-5-gonsolo@gmail.com> (raw)
In-Reply-To: <20261112175640.40603-1-gonsolo@gmail.com>
The microcode builds the aggregates and sends the block acks. Accept block
ack sessions on both sides (ampdu_action) and set
IEEE80211_HW_AMPDU_AGGREGATION on the AC cores.
Frames of a session that the microcode gave up on are put back on the
ring, up to four times, with the retry bit set; the block ack window lets
them follow later frames. The cache info limits an aggregate to four MPDUs,
longer ones lose their later MPDUs.
Signed-off-by: Andreas Wendleder <gonsolo@gmail.com>
---
drivers/net/wireless/broadcom/b43/dma.c | 48 ++++++++++++++++++++++++
drivers/net/wireless/broadcom/b43/main.c | 37 ++++++++++++++++++
drivers/net/wireless/broadcom/b43/xmit.c | 22 ++++++++++-
drivers/net/wireless/broadcom/b43/xmit.h | 2 +
4 files changed, 108 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c
index 404f75f..ef05327 100644
--- a/drivers/net/wireless/broadcom/b43/dma.c
+++ b/drivers/net/wireless/broadcom/b43/dma.c
@@ -34,6 +34,9 @@
* into separate slots. */
#define TX_SLOTS_PER_FRAME 2
+/* Times an unacknowledged A-MPDU session frame is put back on the ring */
+#define B43_AC_AMPDU_REQUEUE 4
+
static u32 b43_dma_address(struct b43_dma *dma, dma_addr_t dmaaddr,
enum b43_addrtype addrtype)
{
@@ -1378,6 +1381,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
hdr = (struct ieee80211_hdr *)skb->data;
+ b43_get_priv_tx_info(info)->requeues = 0;
if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
/* The multicast ring will be sent after the DTIM */
ring = dev->dma.tx_ring_mcast;
@@ -1466,6 +1470,7 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
static const struct b43_txstatus fake; /* filled with 0 */
const struct b43_txstatus *txstat;
int slot, firstused;
+ struct sk_buff *requeue = NULL;
bool frame_succeed;
int skip;
static u8 err_out1;
@@ -1568,6 +1573,29 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
else
txstat = status;
+ /* A session frame the microcode gave up on goes back
+ * on the ring, as the stock driver requeues it; the
+ * block ack window lets it follow later frames.
+ */
+ if (!skip && !txstat->acked &&
+ (info->flags & IEEE80211_TX_CTL_AMPDU) &&
+ !(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
+ struct b43_private_tx_info *pi =
+ b43_get_priv_tx_info(info);
+
+ if (pi->requeues < B43_AC_AMPDU_REQUEUE) {
+ struct ieee80211_hdr *hdr =
+ (void *)meta->skb->data;
+
+ pi->requeues++;
+ hdr->frame_control |= cpu_to_le16(
+ IEEE80211_FCTL_RETRY);
+ requeue = meta->skb;
+ meta->skb = B43_DMA_PTR_POISON;
+ ring->used_slots--;
+ break;
+ }
+ }
frame_succeed = b43_fill_txstatus_report(dev, info,
txstat);
#ifdef CONFIG_B43_DEBUG
@@ -1606,6 +1634,26 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
if (skip > 0)
--skip;
}
+ if (requeue) {
+ if (dma_tx_fragment(ring, requeue)) {
+ struct ieee80211_tx_info *info =
+ IEEE80211_SKB_CB(requeue);
+
+ b43_fill_txstatus_report(dev, info, status);
+ ieee80211_tx_status_skb(dev->wl->hw, requeue);
+ } else if (free_slots(ring) < TX_SLOTS_PER_FRAME) {
+ /* The requeued frame took the slots this status freed:
+ * the ring is still full, keep the queue stopped.
+ */
+ if (!ring->stopped) {
+ b43_stop_queue(dev, ring->queue_prio);
+ dev->wl->tx_queue_stopped[ring->queue_prio] =
+ true;
+ ring->stopped = true;
+ }
+ return;
+ }
+ }
if (ring->stopped) {
B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
ring->stopped = false;
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 5830acb..6b80b5e 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -5479,6 +5479,39 @@ static int b43_op_get_survey(struct ieee80211_hw *hw, int idx,
return 0;
}
+static int b43_op_ampdu_action(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_ampdu_params *params)
+{
+ struct b43_wl *wl = hw_to_b43_wl(hw);
+
+ /* Only the AC-PHY path builds session frames */
+ if (!wl->current_dev || !b43_ucode_is_ac(wl->current_dev))
+ return -EOPNOTSUPP;
+
+ switch (params->action) {
+ case IEEE80211_AMPDU_TX_START:
+ return IEEE80211_AMPDU_TX_START_IMMEDIATE;
+ case IEEE80211_AMPDU_TX_STOP_CONT:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH:
+ case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, params->sta->addr,
+ params->tid);
+ return 0;
+ case IEEE80211_AMPDU_TX_OPERATIONAL:
+ return 0;
+ case IEEE80211_AMPDU_RX_START:
+ case IEEE80211_AMPDU_RX_STOP:
+ /*
+ * The microcode deaggregates and sends the block acks, mac80211
+ * reorders.
+ */
+ return 0;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct ieee80211_ops b43_hw_ops = {
.add_chanctx = ieee80211_emulate_add_chanctx,
.remove_chanctx = ieee80211_emulate_remove_chanctx,
@@ -5501,6 +5534,7 @@ static const struct ieee80211_ops b43_hw_ops = {
.stop = b43_op_stop,
.set_tim = b43_op_beacon_set_tim,
.sta_notify = b43_op_sta_notify,
+ .ampdu_action = b43_op_ampdu_action,
.sw_scan_start = b43_op_sw_scan_start_notifier,
.sw_scan_complete = b43_op_sw_scan_complete_notifier,
.get_survey = b43_op_get_survey,
@@ -5590,6 +5624,9 @@ static int b43_setup_bands(struct b43_wldev *dev,
hw->wiphy->bands[NL80211_BAND_5GHZ] = &b43_band_5GHz_aphy;
}
+ if (b43_is_ac_core(dev))
+ ieee80211_hw_set(hw, AMPDU_AGGREGATION);
+
dev->phy.supports_2ghz = have_2ghz_phy;
dev->phy.supports_5ghz = have_5ghz_phy;
diff --git a/drivers/net/wireless/broadcom/b43/xmit.c b/drivers/net/wireless/broadcom/b43/xmit.c
index dee6cc6..163e713 100644
--- a/drivers/net/wireless/broadcom/b43/xmit.c
+++ b/drivers/net/wireless/broadcom/b43/xmit.c
@@ -1160,7 +1160,27 @@ bool b43_fill_txstatus_report(struct b43_wldev *dev,
frame_success = false;
}
}
- if (status->frame_count == 0) {
+ if (report->flags & IEEE80211_TX_CTL_AMPDU) {
+ /*
+ * minstrel_ht ignores session frames without this; one report
+ * per MPDU
+ */
+ report->flags |= IEEE80211_TX_STAT_AMPDU;
+ report->status.ampdu_len = 1;
+ report->status.ampdu_ack_len = status->acked ? 1 : 0;
+ }
+ if ((report->flags & IEEE80211_TX_CTL_AMPDU) &&
+ (report->status.rates[0].flags &
+ (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS))) {
+ /* Sent with two rate blocks: attempts at each */
+ report->status.rates[0].count = status->frame_count;
+ if (status->fb_count && report->status.rates[1].idx >= 0 &&
+ (report->status.rates[1].flags &
+ (IEEE80211_TX_RC_MCS | IEEE80211_TX_RC_VHT_MCS)))
+ report->status.rates[1].count = status->fb_count;
+ else
+ report->status.rates[1].idx = -1;
+ } else if (status->frame_count == 0) {
/* The frame was not transmitted at all. */
report->status.rates[0].count = 0;
} else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) {
diff --git a/drivers/net/wireless/broadcom/b43/xmit.h b/drivers/net/wireless/broadcom/b43/xmit.h
index d403a28..b6723be 100644
--- a/drivers/net/wireless/broadcom/b43/xmit.h
+++ b/drivers/net/wireless/broadcom/b43/xmit.h
@@ -412,9 +412,11 @@ static inline u8 b43_kidx_to_raw(struct b43_wldev *dev, u8 firmware_kidx)
* The structure is placed in (struct ieee80211_tx_info *)->rate_driver_data
*
* @bouncebuffer: DMA Bouncebuffer (if used)
+ * @requeues: times the frame was put back on the ring (AC-PHY A-MPDU)
*/
struct b43_private_tx_info {
void *bouncebuffer;
+ u8 requeues;
};
static inline struct b43_private_tx_info *
prev parent reply other threads:[~2026-11-12 17:56 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 17:56 [PATCH RFC wireless-next 0/4] wifi: b43: AC microcode TX and RX formats (series 3/4) Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 1/4] wifi: b43: 11ac chanspec for the AC microcode Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 2/4] wifi: b43: TX descriptor and TX status " Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 3/4] wifi: b43: RX header handling " Andreas Wendleder
2026-11-12 17:56 ` Andreas Wendleder [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261112175640.40603-5-gonsolo@gmail.com \
--to=gonsolo@gmail.com \
--cc=alessio.ferri@mythread.it \
--cc=b43-dev@lists.infradead.org \
--cc=johannes@sipsolutions.net \
--cc=jpeisach@ubuntu.com \
--cc=julian.calaby@gmail.com \
--cc=kvalo@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=m@bues.ch \
--cc=rosenp@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®