b43-dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC wireless-next 0/3] wifi: b43: core revision 40 and 42 MAC setup (series 2/4)
@ 2026-11-12 17:56 Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 1/3] wifi: b43: set the DMA burst and prefetch bits of core revisions 40 and 42 Andreas Wendleder
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Andreas Wendleder @ 2026-11-12 17:56 UTC (permalink / raw)
  To: linux-wireless
  Cc: jpeisach, julian.calaby, kvalo, linux-kernel, rosenp, b43-dev,
	Michael Buesch, Johannes Berg

MAC core support for the BCM4352/BCM4360 core revisions 40 and 42. Things
that depend on the core revision are gated on it (b43_is_ac_core()),
things that depend on the microcode layout are gated on the microcode
revision (b43_ucode_is_ac(), revision 784 and above, set once the
microcode is loaded). The TX and RX formats and the PHY are not in this
series. Based on series 1/4.

This is posted as RFC so that people with these chips can use and test
it now; b43 is orphaned and nobody is set to take these patches at the
moment. Series 1/4 is on the list:
https://lore.kernel.org/linux-wireless/20261014143225.82149-1-gonsolo@gmail.com/

Where the values come from: the register sequences and table contents were
taken from Broadcom's wl driver running on this MacBook, by tracing its
register accesses (bpftrace on wl's MMIO accessors), and reduced to what
the hardware needs. Parts come from Alessio Ferri's AC-PHY work (the PHY
init sequence, the 40 and 80 MHz coefficient tables, a TX gain table, the
Farrow resampler formula, the VHT fields of the TX descriptor, register
and table names), and some formats follow brcmsmac.
The result was tested on the hardware as described below.

Each patch compiles on its own (kernel 7.2.10 headers). The four series
together were run on a MacBookAir6,1 (14e4:43a0, BCM4360, core revision 42,
microcode 832.127, 2 of 3 chains wired) on top of v7.3-rc5's b43. The AC PHY
only comes with series 4, so the earlier series cannot be exercised on this
hardware alone.

Andreas Wendleder (3):
  wifi: b43: set the DMA burst and prefetch bits of core revisions 40
    and 42
  wifi: b43: MAC core setup for core revisions 40 and 42
  wifi: b43: address match table, templates and beacons for the AC
    microcode

 drivers/net/wireless/broadcom/b43/b43.h  |  14 ++
 drivers/net/wireless/broadcom/b43/dma.c  |   4 +
 drivers/net/wireless/broadcom/b43/dma.h  |   2 +
 drivers/net/wireless/broadcom/b43/main.c | 242 +++++++++++++++++++++--
 4 files changed, 246 insertions(+), 16 deletions(-)


_______________________________________________
b43-dev mailing list
b43-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH RFC wireless-next 1/3] wifi: b43: set the DMA burst and prefetch bits of core revisions 40 and 42
  2026-11-12 17:56 [PATCH RFC wireless-next 0/3] wifi: b43: core revision 40 and 42 MAC setup (series 2/4) Andreas Wendleder
@ 2026-11-12 17:56 ` Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 2/3] wifi: b43: MAC core setup for " Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 3/3] wifi: b43: address match table, templates and beacons for the AC microcode Andreas Wendleder
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Wendleder @ 2026-11-12 17:56 UTC (permalink / raw)
  To: linux-wireless
  Cc: jpeisach, julian.calaby, kvalo, linux-kernel, rosenp, b43-dev,
	Michael Buesch, Johannes Berg

The DMA engines of the core revisions 40 and 42 (BCM4352, BCM4360) need
the burst length and prefetch bits of the TX and RX control words that the
vendor driver sets (0x03780040 and 0x036c0000). Without them the engine
moves about 6 MB/s and every link tops out near 50 Mbit/s.

Add b43_is_ac_core() for these core revisions.
Signed-off-by: Andreas Wendleder <gonsolo@gmail.com>
---
 drivers/net/wireless/broadcom/b43/b43.h | 6 ++++++
 drivers/net/wireless/broadcom/b43/dma.c | 4 ++++
 drivers/net/wireless/broadcom/b43/dma.h | 2 ++
 3 files changed, 12 insertions(+)

diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h
index e1e8083..80b299b 100644
--- a/drivers/net/wireless/broadcom/b43/b43.h
+++ b/drivers/net/wireless/broadcom/b43/b43.h
@@ -1001,6 +1001,12 @@ static inline enum nl80211_band b43_current_band(struct b43_wl *wl)
 	return wl->hw->conf.chandef.chan->band;
 }
 
+/* MAC core of the BCM4352 and BCM4360 (core revisions 40 and 42). */
+static inline bool b43_is_ac_core(struct b43_wldev *dev)
+{
+	return dev->dev->core_rev == 40 || dev->dev->core_rev == 42;
+}
+
 static inline int b43_bus_may_powerdown(struct b43_wldev *wldev)
 {
 	return wldev->dev->bus_may_powerdown(wldev->dev);
diff --git a/drivers/net/wireless/broadcom/b43/dma.c b/drivers/net/wireless/broadcom/b43/dma.c
index 5e1b30a..5f968b0 100644
--- a/drivers/net/wireless/broadcom/b43/dma.c
+++ b/drivers/net/wireless/broadcom/b43/dma.c
@@ -691,6 +691,8 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			    & B43_DMA64_TXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA64_TXPARITYDISABLE;
+			if (b43_is_ac_core(ring->dev))
+				value |= B43_DMA64_TXCTL_AC;
 			if (ring->dev->dma.ptr_is_addr) {
 				ring->ptr_base = lower_32_bits(ring->dmabase);
 				value |= b43_dma_read(ring, B43_DMA64_TXCTL) &
@@ -733,6 +735,8 @@ static int dmacontroller_setup(struct b43_dmaring *ring)
 			    & B43_DMA64_RXADDREXT_MASK;
 			if (!parity)
 				value |= B43_DMA64_RXPARITYDISABLE;
+			if (b43_is_ac_core(ring->dev))
+				value |= B43_DMA64_RXCTL_AC;
 			if (ring->dev->dma.ptr_is_addr) {
 				ring->ptr_base = lower_32_bits(ring->dmabase);
 				value |= b43_dma_read(ring, B43_DMA64_RXCTL) &
diff --git a/drivers/net/wireless/broadcom/b43/dma.h b/drivers/net/wireless/broadcom/b43/dma.h
index eddc882..14de4cb 100644
--- a/drivers/net/wireless/broadcom/b43/dma.h
+++ b/drivers/net/wireless/broadcom/b43/dma.h
@@ -91,6 +91,7 @@ struct b43_dmadesc32 {
 #define		B43_DMA64_TXADDREXT_MASK		0x00030000
 #define		B43_DMA64_TXADDREXT_SHIFT		16
 #define B43_DMA64_TXCTL_KEEP				0x03FC00C0
+#define B43_DMA64_TXCTL_AC				0x03780040
 #define B43_DMA64_TXINDEX				0x04
 #define B43_DMA64_TXRINGLO				0x08
 #define B43_DMA64_TXRINGHI				0x0C
@@ -120,6 +121,7 @@ struct b43_dmadesc32 {
 #define		B43_DMA64_RXADDREXT_MASK		0x00030000
 #define		B43_DMA64_RXADDREXT_SHIFT		16
 #define B43_DMA64_RXCTL_KEEP				0x03FC0000
+#define B43_DMA64_RXCTL_AC				0x036c0000
 #define B43_DMA64_RXINDEX				0x24
 #define B43_DMA64_RXRINGLO				0x28
 #define B43_DMA64_RXRINGHI				0x2C

_______________________________________________
b43-dev mailing list
b43-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH RFC wireless-next 2/3] wifi: b43: MAC core setup for core revisions 40 and 42
  2026-11-12 17:56 [PATCH RFC wireless-next 0/3] wifi: b43: core revision 40 and 42 MAC setup (series 2/4) Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 1/3] wifi: b43: set the DMA burst and prefetch bits of core revisions 40 and 42 Andreas Wendleder
@ 2026-11-12 17:56 ` Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 3/3] wifi: b43: address match table, templates and beacons for the AC microcode Andreas Wendleder
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Wendleder @ 2026-11-12 17:56 UTC (permalink / raw)
  To: linux-wireless
  Cc: jpeisach, julian.calaby, kvalo, linux-kernel, rosenp, b43-dev,
	Michael Buesch, Johannes Berg

The core revisions 40 and 42 of the BCM4352 and BCM4360 need these
differences from the older cores:

 - PHY reset: the reset is asserted with the clock forced and released
   with the clock free, in the order the vendor driver uses.
 - GPIOs: the pins are host driven with GPIO1 and GPIO2 high. This is the
   pattern of the MacBookAir6,1 (front end control); other boards may
   need other values.
 - The template and TX FIFOs are carved out of the MAC memory and the TX
   queue table is set up, because the microcode does not size them.
 - MACCTL is written without SHM_ENABLED, which the vendor driver never
   sets on this core.
 - The RX interrupt lazy timeout (register 0x100) is set so that an
   interrupt is raised after every frame.

The microcode (revision 784 and above, b43_ucode_is_ac()) has no key
table pointer at the legacy KTP word, it reads 0, so b43_security_init()
must not clear the "key table": that zeroed SHM 0x000-0x3a0 (rate maps,
ACK/CTS PHY control, microcode state) on every core init.
b43_op_set_key() returns -EOPNOTSUPP, mac80211 does the crypto in
software.
Signed-off-by: Andreas Wendleder <gonsolo@gmail.com>
---
 drivers/net/wireless/broadcom/b43/b43.h  |   8 ++
 drivers/net/wireless/broadcom/b43/main.c | 101 ++++++++++++++++++++++-
 2 files changed, 108 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/broadcom/b43/b43.h b/drivers/net/wireless/broadcom/b43/b43.h
index 80b299b..92227ff 100644
--- a/drivers/net/wireless/broadcom/b43/b43.h
+++ b/drivers/net/wireless/broadcom/b43/b43.h
@@ -1030,6 +1030,14 @@ static inline void b43_device_disable(struct b43_wldev *wldev,
 	wldev->dev->device_disable(wldev->dev, core_specific_flags);
 }
 
+/* Microcode of the AC cores (revisions 784, 832 and 928). Valid once the
+ * microcode is loaded; only revision 832 has been tested.
+ */
+static inline bool b43_ucode_is_ac(struct b43_wldev *dev)
+{
+	return dev->fw.rev >= 784;
+}
+
 static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
 {
 	return dev->dev->read16(dev->dev, offset);
diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index e2e8ca0..205d429 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -1235,6 +1235,24 @@ static void b43_bcma_phy_reset(struct b43_wldev *dev)
 {
 	u32 flags;
 
+	if (b43_is_ac_core(dev)) {
+		flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+		flags |= B43_BCMA_IOCTL_PHY_RESET |
+			 B43_BCMA_IOCTL_PHY_BW_20MHZ | BCMA_IOCTL_FGC |
+			 B43_BCMA_IOCTL_PHY_CLKEN;
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+		udelay(2);
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+		flags &= ~(B43_BCMA_IOCTL_PHY_RESET | BCMA_IOCTL_FGC |
+			   B43_BCMA_IOCTL_PHY_CLKEN);
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+		udelay(1);
+		flags |= B43_BCMA_IOCTL_PHY_CLKEN;
+		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, flags);
+		udelay(1);
+		return;
+	}
+
 	/* Put PHY into reset */
 	flags = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
 	flags |= B43_BCMA_IOCTL_PHY_RESET;
@@ -2914,6 +2932,18 @@ static int b43_gpio_init(struct b43_wldev *dev)
 	switch (dev->dev->bus_type) {
 #ifdef CONFIG_B43_BCMA
 	case B43_BUS_BCMA:
+		if (b43_is_ac_core(dev)) {
+			struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
+
+			/*
+			 * the vendor driver keeps the pins host-driven with
+			 * GPIO1+2 high (front-end control on MacBookAir6,1).
+			 */
+			bcma_chipco_gpio_control(cc, mask | 0xa7, 0);
+			bcma_chipco_gpio_out(cc, 0xa7, 0x06);
+			bcma_chipco_gpio_outen(cc, 0xa7, 0xa7);
+			break;
+		}
 		bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc, mask, set);
 		break;
 #endif
@@ -3245,6 +3275,53 @@ static void b43_chip_exit(struct b43_wldev *dev)
 /* Initialize the chip
  * https://bcm-specs.sipsolutions.net/ChipInit
  */
+/*
+ * rev 40+ MAC: carve template/TX FIFOs out of MAC memory and set up the TX
+ * queue table (as the vendor driver does it).
+ */
+
+static void b43_ac_fifo_init(struct b43_wldev *dev)
+{
+	static const u8 fifos[] = { 7, 0, 1, 2, 3, 4, 5 };
+	u16 total = (b43_read32(dev, 0x15c) >> 1) & 0xffc;
+	const u16 tpl = 0x2a, fifo_sz = 0x20, blk = 0xb;
+	unsigned int i;
+	int t;
+
+	b43_write16(dev, 0x542, total);
+	b43_write16(dev, 0x540, 5);
+	for (t = 0; t < 20 && (b43_read16(dev, 0x540) & 1); t++)
+		udelay(10);
+	for (i = 0; i < ARRAY_SIZE(fifos); i++) {
+		if (fifos[i] == 7) {
+			b43_write16(dev, 0x54a, tpl);
+			b43_write16(dev, 0x54c, tpl);
+			b43_write16(dev, 0x520, tpl);
+			b43_write16(dev, 0x54e, ((tpl - 4) << 8) | tpl);
+		} else {
+			b43_write16(dev, 0x54a, total - tpl);
+			b43_write16(dev, 0x54c, fifo_sz);
+			b43_write16(dev, 0x520, blk);
+			b43_write16(dev, 0x54e,
+				    ((blk * 2 - 4) << 8) | (blk * 2));
+		}
+		b43_write16(dev, 0x550, 0x740c);
+		b43_write16(dev, 0x548, fifos[i] | 0x10);
+	}
+	for (i = 0; i < 0x2a; i++) {
+		u16 end = min_t(u16, i + 2, 0x29);
+
+		b43_write16(dev, 0x534, i);
+		b43_write16(dev, 0x536, end);
+		b43_write16(dev, 0x532, end + 1 - i);
+		b43_write16(dev, 0x530, (i << 4) | 0x8007);
+		for (t = 0; t < 20 && b43_read16(dev, 0x530); t++)
+			udelay(10);
+	}
+	b43dbg(dev->wl, "AC FIFO init: total %#x, 0x540=%04x 0x530=%04x\n",
+	       total, b43_read16(dev, 0x540), b43_read16(dev, 0x530));
+}
+
 static int b43_chip_init(struct b43_wldev *dev)
 {
 	struct b43_phy *phy = &dev->phy;
@@ -3253,7 +3330,10 @@ static int b43_chip_init(struct b43_wldev *dev)
 	u16 value16;
 
 	/* Initialize the MAC control */
-	macctl = B43_MACCTL_IHR_ENABLED | B43_MACCTL_SHM_ENABLED;
+	macctl = B43_MACCTL_IHR_ENABLED;
+	/* The vendor driver never sets SHM_ENABLED on AC-PHY cores. */
+	if (!b43_is_ac_core(dev))
+		macctl |= B43_MACCTL_SHM_ENABLED;
 	if (dev->phy.gmode)
 		macctl |= B43_MACCTL_GMODE;
 	macctl |= B43_MACCTL_INFRA;
@@ -3275,6 +3355,9 @@ static int b43_chip_init(struct b43_wldev *dev)
 	if (err)
 		goto err_gpio_clean;
 
+	if (b43_is_ac_core(dev))
+		b43_ac_fifo_init(dev);
+
 	/* Turn the Analog on and initialize the PHY. */
 	phy->ops->switch_analog(dev, 1);
 	err = b43_phy_init(dev);
@@ -3325,6 +3408,10 @@ static int b43_chip_init(struct b43_wldev *dev)
 	b43_write32(dev, B43_MMIO_DMA3_IRQ_MASK, 0x0001DC00);
 	b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
 	b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
+	if (b43_is_ac_core(dev)) {
+		/* intrcvlazy0: raise the RX interrupt after every frame. */
+		b43_write32(dev, 0x100, 1 << 24);
+	}
 
 	b43_mac_phy_clock_set(dev, true);
 
@@ -3529,6 +3616,15 @@ error:
 
 static void b43_security_init(struct b43_wldev *dev)
 {
+	/*
+	 * rev 40+ (AC) ucode has no key table pointer at the legacy KTP word:
+	 * it reads 0 there, so clearing the "key table" zeroed SHM 0x000-0x3a0
+	 * (rate maps, ACK/CTS PHY control, ucode state) on every core init. AC
+	 * has no hardware crypto support yet, so leave the key memory alone.
+	 */
+	if (b43_ucode_is_ac(dev))
+		return;
+
 	dev->ktp = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_KTP);
 	/* KTP is a word address, but we address SHM bytewise.
 	 * So multiply by two.
@@ -4178,6 +4274,9 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
 	if (modparam_nohwcrypt)
 		return -ENOSPC; /* User disabled HW-crypto */
+	if (b43_ucode_is_ac(wl->current_dev))
+		/* no AC key table yet, see b43_security_init */
+		return -EOPNOTSUPP;
 
 	if ((vif->type == NL80211_IFTYPE_ADHOC ||
 	     vif->type == NL80211_IFTYPE_MESH_POINT) &&

_______________________________________________
b43-dev mailing list
b43-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH RFC wireless-next 3/3] wifi: b43: address match table, templates and beacons for the AC microcode
  2026-11-12 17:56 [PATCH RFC wireless-next 0/3] wifi: b43: core revision 40 and 42 MAC setup (series 2/4) Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 1/3] wifi: b43: set the DMA burst and prefetch bits of core revisions 40 and 42 Andreas Wendleder
  2026-11-12 17:56 ` [PATCH RFC wireless-next 2/3] wifi: b43: MAC core setup for " Andreas Wendleder
@ 2026-11-12 17:56 ` Andreas Wendleder
  2 siblings, 0 replies; 4+ messages in thread
From: Andreas Wendleder @ 2026-11-12 17:56 UTC (permalink / raw)
  To: linux-wireless
  Cc: jpeisach, julian.calaby, kvalo, linux-kernel, rosenp, b43-dev,
	Michael Buesch, Johannes Berg

The microcode of revisions 784 and above lays out several things
differently:

 - the address match table is in the RCMTA object memory, 8 bytes per
   entry (MAC[0..3], then MAC[4..5] and the attributes); the vendor driver
   uses entry 63 for its own address and 62 for the BSSID,
 - the templates in template RAM: 0x30 holds BSSID, MAC, BSSID, 0x48 the
   MAC, plus the default null frame at 0x2c and a header at 0,
 - the ACK/CTS PHY control word and the antenna selection use the AC
   PhyTxControlWord_0 format,
 - the two beacon template slots are at 0x200 and 0x480, and the beacon's
   PHY TX control words are at SHM 0xcc, 0xce and 0xd0 instead of the
   legacy BEACPHYCTL word.
Signed-off-by: Andreas Wendleder <gonsolo@gmail.com>
---
 drivers/net/wireless/broadcom/b43/main.c | 141 ++++++++++++++++++++---
 1 file changed, 126 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c
index 205d429..da7e420 100644
--- a/drivers/net/wireless/broadcom/b43/main.c
+++ b/drivers/net/wireless/broadcom/b43/main.c
@@ -662,6 +662,26 @@ void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
 	if (!mac)
 		mac = zero_addr;
 
+	if (b43_ucode_is_ac(dev)) {
+		/*
+		 * rev 40+ ucode: address match table (AMT) in RCMTA object
+		 * memory, 8 bytes per entry: MAC[0..3], MAC[4..5] | attr << 16.
+		 * the vendor driver uses entry 63 for its own MAC and 62 for
+		 * the BSSID.
+		 */
+		bool self = offset == B43_MACFILTER_SELF;
+		u16 idx = self ? 0x3f : 0x3e;
+		u16 attr = is_zero_ether_addr(mac) ? 0 :
+						     (self ? 0x8008 : 0x8006);
+
+		b43_shm_write32(dev, B43_SHM_RCMTA, idx * 2,
+				mac[0] | (mac[1] << 8) | (mac[2] << 16) |
+				((u32)mac[3] << 24));
+		b43_shm_write32(dev, B43_SHM_RCMTA, idx * 2 + 1,
+				mac[4] | (mac[5] << 8) | ((u32)attr << 16));
+		return;
+	}
+
 	offset |= 0x0020;
 	b43_write16(dev, B43_MMIO_MACFILTER_CONTROL, offset);
 
@@ -689,6 +709,39 @@ static void b43_write_mac_bssid_templates(struct b43_wldev *dev)
 
 	b43_macfilter_set(dev, B43_MACFILTER_BSSID, bssid);
 
+	if (b43_ucode_is_ac(dev)) {
+		/*
+		 * rev 40+ ucode (as wl): template RAM 0x30 = BSSID, MAC, BSSID;
+		 * 0x48 = MAC. Also the vendor driver's default null-frame
+		 * template at 0x2c and the header at 0x0.
+		 */
+		static const u32 hdr0[] = {
+			0x00000094, 0x75749000, 0x00007776,
+			0x00000000, 0xffff0005, 0x0000ffff
+		};
+		static const u32 null2c[] = {
+			0x00e0040a, 0x0048beef, 0xff000005, 0xff02ff01,
+			0x01181000, 0x10000302, 0xf3f2f118, 0x0000ccbb
+		};
+		u8 blk[20] = { 0 };
+		u8 m[8] = { 0 };
+
+		for (i = 0; i < ARRAY_SIZE(hdr0); i++)
+			b43_ram_write(dev, 0x00 + i * 4, hdr0[i]);
+		for (i = 0; i < ARRAY_SIZE(null2c); i++)
+			b43_ram_write(dev, 0x2c + i * 4, null2c[i]);
+		memcpy(blk, bssid, ETH_ALEN);
+		memcpy(blk + 6, mac, ETH_ALEN);
+		memcpy(blk + 12, bssid, ETH_ALEN);
+		for (i = 0; i < sizeof(blk); i += 4)
+			b43_ram_write(dev, 0x30 + i,
+				      get_unaligned_le32(blk + i));
+		memcpy(m, mac, ETH_ALEN);
+		b43_ram_write(dev, 0x48, get_unaligned_le32(m));
+		b43_ram_write(dev, 0x4c, get_unaligned_le32(m + 4));
+		return;
+	}
+
 	memcpy(mac_bssid, mac, ETH_ALEN);
 	memcpy(mac_bssid + ETH_ALEN, bssid, ETH_ALEN);
 
@@ -1657,19 +1710,56 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
 				  len, ram_offset, shm_size_offset, rate);
 
 	/* Write the PHY TX control parameters. */
-	antenna = B43_ANTENNA_DEFAULT;
-	antenna = b43_antenna_to_phyctl(antenna);
-	ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL);
-	/* We can't send beacons with short preamble. Would get PHY errors. */
-	ctl &= ~B43_TXH_PHY_SHORTPRMBL;
-	ctl &= ~B43_TXH_PHY_ANT;
-	ctl &= ~B43_TXH_PHY_ENC;
-	ctl |= antenna;
-	if (b43_is_cck_rate(rate))
-		ctl |= B43_TXH_PHY_ENC_CCK;
-	else
-		ctl |= B43_TXH_PHY_ENC_OFDM;
-	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL, ctl);
+	if (b43_ucode_is_ac(dev)) {
+		/*
+		 * rev 40+ ucode (wlc_beacon_phytxctl, core_rev > 0x27): the
+		 * beacon slot's PhyTxControlWord_0/1/2 live at SHM 0xcc/ce/d0,
+		 * not the legacy BEACPHYCTL word (0x54, unused here). Compute
+		 * them the same way as a normal AC TX descriptor rate entry
+		 * (b43_generate_txhdr_ac): CCK/OFDM bit, core mask, PLCP rate
+		 * index; no sub-band (this is 20 MHz single-channel only).
+		 */
+		static const u8 cck[] = { B43_CCK_RATE_1MB, B43_CCK_RATE_2MB,
+					  B43_CCK_RATE_5MB, B43_CCK_RATE_11MB };
+		static const u8 ofdm[] = {
+			B43_OFDM_RATE_6MB,  B43_OFDM_RATE_9MB,
+			B43_OFDM_RATE_12MB, B43_OFDM_RATE_18MB,
+			B43_OFDM_RATE_24MB, B43_OFDM_RATE_36MB,
+			B43_OFDM_RATE_48MB, B43_OFDM_RATE_54MB
+		};
+		bool is_ofdm = b43_is_ofdm_rate(rate);
+		const u8 *tbl = is_ofdm ? ofdm : cck;
+		unsigned int n = is_ofdm ? ARRAY_SIZE(ofdm) : ARRAY_SIZE(cck);
+		unsigned int idx = 0;
+		u16 phy0 = (is_ofdm ? 1 : 0) | 0x0004 | (1 << 6);
+
+		while (idx < n && tbl[idx] != rate)
+			idx++;
+		if (idx == n)
+			idx = 0;
+		b43_shm_write16(dev, B43_SHM_SHARED, 0xcc, phy0);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0xce, 0);
+		b43_shm_write16(dev, B43_SHM_SHARED, 0xd0, idx);
+	} else {
+		antenna = B43_ANTENNA_DEFAULT;
+		antenna = b43_antenna_to_phyctl(antenna);
+		ctl = b43_shm_read16(dev, B43_SHM_SHARED,
+				     B43_SHM_SH_BEACPHYCTL);
+		/*
+		 * We can't send beacons with short preamble. Would get PHY
+		 * errors.
+		 */
+		ctl &= ~B43_TXH_PHY_SHORTPRMBL;
+		ctl &= ~B43_TXH_PHY_ANT;
+		ctl &= ~B43_TXH_PHY_ENC;
+		ctl |= antenna;
+		if (b43_is_cck_rate(rate))
+			ctl |= B43_TXH_PHY_ENC_CCK;
+		else
+			ctl |= B43_TXH_PHY_ENC_OFDM;
+		b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL,
+				ctl);
+	}
 
 	/* Find the position of the TIM and the DTIM_period value
 	 * and write them to SHM. */
@@ -1726,20 +1816,28 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
 static void b43_upload_beacon0(struct b43_wldev *dev)
 {
 	struct b43_wl *wl = dev->wl;
+	/*
+	 * rev 40+ ucode keeps the two beacon template slots at RAM 0x200 and
+	 * 0x480 (wlc_bmac_write_hw_bcntemplates, core_rev > 0x27), not the
+	 * legacy 0x68/0x468. Length (SHM 0x18/0x1a) and the valid bits (MMIO
+	 * MACCMD, unchanged) are the same on both.
+	 */
+	u16 base = b43_ucode_is_ac(dev) ? 0x200 : B43_SHM_SH_BT_BASE0;
 
 	if (wl->beacon0_uploaded)
 		return;
-	b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE0, B43_SHM_SH_BTL0);
+	b43_write_beacon_template(dev, base, B43_SHM_SH_BTL0);
 	wl->beacon0_uploaded = true;
 }
 
 static void b43_upload_beacon1(struct b43_wldev *dev)
 {
 	struct b43_wl *wl = dev->wl;
+	u16 base = b43_ucode_is_ac(dev) ? 0x480 : B43_SHM_SH_BT_BASE1;
 
 	if (wl->beacon1_uploaded)
 		return;
-	b43_write_beacon_template(dev, B43_SHM_SH_BT_BASE1, B43_SHM_SH_BTL1);
+	b43_write_beacon_template(dev, base, B43_SHM_SH_BTL1);
 	wl->beacon1_uploaded = true;
 }
 
@@ -3237,6 +3335,17 @@ static void b43_set_phytxctl_defaults(struct b43_wldev *dev)
 {
 	u16 ctl = 0;
 
+	if (b43_ucode_is_ac(dev)) {
+		/*
+		 * rev 40+ ucode: AC PhyTxControlWord_0 format (CCK, core 0), as
+		 * the vendor driver sets it. 0x54/0x188 mean something else
+		 * here.
+		 */
+		b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_ACKCTSPHYCTL,
+				0x0040);
+		return;
+	}
+
 	ctl |= B43_TXH_PHY_ENC_CCK;
 	ctl |= B43_TXH_PHY_ANT01AUTO;
 	ctl |= B43_TXH_PHY_TXPWR;
@@ -3252,6 +3361,8 @@ static void b43_mgmtframe_txantenna(struct b43_wldev *dev, int antenna)
 	u16 ant;
 	u16 tmp;
 
+	if (b43_ucode_is_ac(dev))
+		return;
 	ant = b43_antenna_to_phyctl(antenna);
 
 	/* For ACK/CTS */

_______________________________________________
b43-dev mailing list
b43-dev@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/b43-dev

^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-11-12 17:56 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 17:56 [PATCH RFC wireless-next 0/3] wifi: b43: core revision 40 and 42 MAC setup (series 2/4) Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 1/3] wifi: b43: set the DMA burst and prefetch bits of core revisions 40 and 42 Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 2/3] wifi: b43: MAC core setup for " Andreas Wendleder
2026-11-12 17:56 ` [PATCH RFC wireless-next 3/3] wifi: b43: address match table, templates and beacons for the AC microcode Andreas Wendleder

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox