mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Michael Reeves via B4 Relay <devnull+michael.reeves077.gmail.com@kernel.org>
To: Arend van Spriel <arend.vanspriel@broadcom.com>,
	 Pieter-Paul Giesberts <pieterpg@broadcom.com>,
	 "Franky Lin (Zhenhui)" <frankyl@broadcom.com>,
	 Mathy Vanhoef <vanhoefm@gmail.com>,
	Kalle Valo <kvalo@kernel.org>,  Kees Cook <kees@kernel.org>,
	"Gustavo A. R. Silva" <gustavoars@kernel.org>
Cc: linux-wireless@vger.kernel.org, brcm80211@lists.linux.dev,
	 brcm80211-dev-list.pdl@broadcom.com, asahi@lists.linux.dev,
	 Hector Martin <marcan@marcan.st>,
	Daniel Berlin <dberlin@dberlin.org>,  Janne Grunau <j@jannau.net>,
	linux-kernel@vger.kernel.org,
	 Hante Meuleman <meuleman@broadcom.com>,
	linux-hardening@vger.kernel.org,
	 Michael Reeves <michael.reeves077@gmail.com>
Subject: [PATCH 05/13] wifi: brcmfmac: Negotiate PCIe mailbox transport with firmware
Date: Fri, 25 Sep 2026 23:43:40 +1000	[thread overview]
Message-ID: <20260925-brcm4388-submit-v1-5-b5cbc2cde2fb@gmail.com> (raw)
In-Reply-To: <20260925-brcm4388-submit-v1-0-b5cbc2cde2fb@gmail.com>

From: Hector Martin <marcan@marcan.st>

Shared protocol version 6 and later allows mailbox messages over the
control ring as an alternative to the shared-memory mailbox.

Advertise host capabilities using the negotiated shared protocol
version. Select the control-ring transport when firmware does not set
BRCMF_PCIE_SHARED_USE_MAILBOX, and dispatch received mailbox data
through bus operations.

Signed-off-by: Hector Martin <marcan@marcan.st>
Co-developed-by: Michael Reeves <michael.reeves077@gmail.com>
Signed-off-by: Michael Reeves <michael.reeves077@gmail.com>
---
 .../net/wireless/broadcom/brcm80211/brcmfmac/bus.h |  9 +++
 .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c  | 57 +++++++++++++++
 .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.h  |  5 ++
 .../wireless/broadcom/brcm80211/brcmfmac/pcie.c    | 83 ++++++++++++++++++----
 4 files changed, 139 insertions(+), 15 deletions(-)

diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
index 9371c14899..421039759b 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
@@ -86,6 +86,8 @@ struct brcmf_bus_dcmd {
  * @get_ramsize: obtain size of device memory.
  * @get_memdump: obtain device memory dump in provided buffer.
  * @get_blob: obtain a firmware blob.
+ * @d2h_mb_rx: handle device-to-host mailbox data received through a transport
+ *	specific side channel.
  * @remove: initiate unbind of the device.
  *
  * This structure provides an abstract interface towards the
@@ -108,6 +110,7 @@ struct brcmf_bus_ops {
 	void (*debugfs_create)(struct device *dev);
 	int (*reset)(struct device *dev);
 	void (*remove)(struct device *dev);
+	void (*d2h_mb_rx)(struct device *dev, u32 data);
 };
 
 
@@ -292,6 +295,12 @@ static inline void brcmf_bus_remove(struct brcmf_bus *bus)
 	bus->ops->remove(bus->dev);
 }
 
+static inline void brcmf_bus_d2h_mb_rx(struct brcmf_bus *bus, u32 data)
+{
+	if (bus->ops->d2h_mb_rx)
+		bus->ops->d2h_mb_rx(bus->dev, data);
+}
+
 /*
  * interface functions from common layer
  */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
index 069ba70166..8e5c697e7f 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
@@ -47,6 +47,8 @@
 #define MSGBUF_TYPE_RX_CMPLT			0x12
 #define MSGBUF_TYPE_LPBK_DMAXFER		0x13
 #define MSGBUF_TYPE_LPBK_DMAXFER_CMPLT		0x14
+#define MSGBUF_TYPE_H2D_MAILBOX_DATA		0x23
+#define MSGBUF_TYPE_D2H_MAILBOX_DATA		0x24
 
 #define NR_TX_PKTIDS				2048
 #define NR_RX_PKTIDS				1024
@@ -218,6 +220,19 @@ struct msgbuf_flowring_flush_resp {
 	__le32				rsvd0[3];
 };
 
+struct msgbuf_h2d_mailbox_data {
+	struct msgbuf_common_hdr	msg;
+	__le32				data;
+	__le32				rsvd0[7];
+};
+
+struct msgbuf_d2h_mailbox_data {
+	struct msgbuf_common_hdr	msg;
+	struct msgbuf_completion_hdr	compl_hdr;
+	__le32				data;
+	__le32				rsvd0[2];
+};
+
 struct brcmf_msgbuf_work_item {
 	struct list_head queue;
 	u32 flowid;
@@ -1319,6 +1334,15 @@ brcmf_msgbuf_process_flow_ring_delete_response(struct brcmf_msgbuf *msgbuf,
 	brcmf_msgbuf_remove_flowring(msgbuf, flowid);
 }
 
+static void brcmf_msgbuf_process_d2h_mailbox_data(struct brcmf_msgbuf *msgbuf,
+						  void *buf)
+{
+	struct msgbuf_d2h_mailbox_data *d2h_mb_data = buf;
+
+	brcmf_bus_d2h_mb_rx(msgbuf->drvr->bus_if,
+			    le32_to_cpu(d2h_mb_data->data));
+}
+
 
 static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)
 {
@@ -1362,6 +1386,10 @@ static void brcmf_msgbuf_process_msgtype(struct brcmf_msgbuf *msgbuf, void *buf)
 		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_RX_CMPLT\n");
 		brcmf_msgbuf_process_rx_complete(msgbuf, buf);
 		break;
+	case MSGBUF_TYPE_D2H_MAILBOX_DATA:
+		brcmf_dbg(MSGBUF, "MSGBUF_TYPE_D2H_MAILBOX_DATA\n");
+		brcmf_msgbuf_process_d2h_mailbox_data(msgbuf, buf);
+		break;
 	default:
 		bphy_err(drvr, "Unsupported msgtype %d\n", msg->msgtype);
 		break;
@@ -1500,6 +1528,35 @@ void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
 	}
 }
 
+int brcmf_msgbuf_h2d_mb_write(struct brcmf_pub *drvr, u32 data)
+{
+	struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
+	struct brcmf_commonring *commonring;
+	struct msgbuf_h2d_mailbox_data *request;
+	void *ret_ptr;
+	int err;
+
+	commonring = msgbuf->commonrings[BRCMF_H2D_MSGRING_CONTROL_SUBMIT];
+	brcmf_commonring_lock(commonring);
+	ret_ptr = brcmf_commonring_reserve_for_write(commonring);
+	if (!ret_ptr) {
+		bphy_err(drvr, "Failed to reserve space in commonring\n");
+		brcmf_commonring_unlock(commonring);
+		return -ENOMEM;
+	}
+
+	request = (struct msgbuf_h2d_mailbox_data *)ret_ptr;
+	memset(request, 0, sizeof(*request));
+	request->msg.msgtype = MSGBUF_TYPE_H2D_MAILBOX_DATA;
+	request->msg.ifidx = 0xff;
+	request->data = cpu_to_le32(data);
+
+	err = brcmf_commonring_write_complete(commonring);
+	brcmf_commonring_unlock(commonring);
+
+	return err;
+}
+
 #ifdef DEBUG
 static int brcmf_msgbuf_stats_read(struct seq_file *seq, void *data)
 {
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
index 6a849f4a94..18b56d0789 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.h
@@ -32,12 +32,17 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
 void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);
 int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
 void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
+int brcmf_msgbuf_h2d_mb_write(struct brcmf_pub *drvr, u32 data);
 #else
 static inline int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
 {
 	return 0;
 }
 static inline void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr) {}
+static inline int brcmf_msgbuf_h2d_mb_write(struct brcmf_pub *drvr, u32 data)
+{
+	return -EOPNOTSUPP;
+}
 #endif
 
 #endif /* BRCMFMAC_MSGBUF_H */
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
index 5917ee5fd7..ad8567e2b9 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
@@ -219,9 +219,13 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
 #define BRCMF_PCIE_SHARED_VERSION_MASK		0x00FF
 #define BRCMF_PCIE_SHARED_DMA_INDEX		0x10000
 #define BRCMF_PCIE_SHARED_DMA_2B_IDX		0x100000
+#define BRCMF_PCIE_SHARED_USE_MAILBOX		0x2000000
 #define BRCMF_PCIE_SHARED_HOSTRDY_DB1		0x10000000
 #define BRCMF_PCIE_SHARED_DAR			0x80000000
 
+#define BRCMF_HOSTCAP_H2D_ENABLE_HOSTRDY	0x400
+#define BRCMF_HOSTCAP_DS_NO_OOB_DW		0x1000
+#define BRCMF_HOSTCAP_H2D_DAR			0x10000
 
 #define BRCMF_PCIE_FLAGS_HTOD_SPLIT		0x4000
 #define BRCMF_PCIE_FLAGS_DTOH_SPLIT		0x8000
@@ -237,6 +241,8 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
 #define BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET	56
 #define BRCMF_SHARED_DMA_RINGUPD_LEN_OFFSET	64
 #define BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET	68
+#define BRCMF_SHARED_HOST_CAP_OFFSET		84
+#define BRCMF_SHARED_HOST_CAP2_OFFSET		112
 
 #define BRCMF_RING_H2D_RING_COUNT_OFFSET	0
 #define BRCMF_RING_D2H_RING_COUNT_OFFSET	1
@@ -318,6 +324,7 @@ struct brcmf_pcie_shared_info {
 	void *ringupd;
 	dma_addr_t ringupd_dmahandle;
 	u8 version;
+	bool mb_via_ctl;
 };
 
 #define BRCMF_OTP_MAX_PARAM_LEN 16
@@ -843,6 +850,18 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
 	u32 i;
 
 	shared = &devinfo->shared;
+	if (shared->mb_via_ctl) {
+		struct pci_dev *pdev = devinfo->pdev;
+		struct brcmf_bus *bus = dev_get_drvdata(&pdev->dev);
+		int ret;
+
+		ret = brcmf_msgbuf_h2d_mb_write(bus->drvr, htod_mb_data);
+		if (ret < 0)
+			brcmf_err(bus, "Failed to send H2D mailbox data (%d)\n",
+				  ret);
+		return ret;
+	}
+
 	addr = shared->htod_mb_data_addr;
 	cur_htod_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
 
@@ -871,21 +890,9 @@ brcmf_pcie_send_mb_data(struct brcmf_pciedev_info *devinfo, u32 htod_mb_data)
 }
 
 
-static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
+static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo,
+				      u32 dtoh_mb_data)
 {
-	struct brcmf_pcie_shared_info *shared;
-	u32 addr;
-	u32 dtoh_mb_data;
-
-	shared = &devinfo->shared;
-	addr = shared->dtoh_mb_data_addr;
-	dtoh_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
-
-	if (!dtoh_mb_data)
-		return;
-
-	brcmf_pcie_write_tcm32(devinfo, addr, 0);
-
 	brcmf_dbg(PCIE, "D2H_MB_DATA: 0x%04x\n", dtoh_mb_data);
 	if (dtoh_mb_data & BRCMF_D2H_DEV_DS_ENTER_REQ)  {
 		brcmf_dbg(PCIE, "D2H_MB_DATA: DEEP SLEEP REQ\n");
@@ -906,6 +913,32 @@ static void brcmf_pcie_handle_mb_data(struct brcmf_pciedev_info *devinfo)
 }
 
 
+static void brcmf_pcie_poll_mb_data(struct brcmf_pciedev_info *devinfo)
+{
+	struct brcmf_pcie_shared_info *shared;
+	u32 addr;
+	u32 dtoh_mb_data;
+
+	shared = &devinfo->shared;
+	addr = shared->dtoh_mb_data_addr;
+	dtoh_mb_data = brcmf_pcie_read_tcm32(devinfo, addr);
+
+	if (!dtoh_mb_data)
+		return;
+
+	brcmf_pcie_write_tcm32(devinfo, addr, 0);
+
+	brcmf_pcie_handle_mb_data(devinfo, dtoh_mb_data);
+}
+
+static void brcmf_pcie_d2h_mb_rx(struct device *dev, u32 data)
+{
+	struct brcmf_bus *bus = dev_get_drvdata(dev);
+	struct brcmf_pciedev *buspub = bus->bus_priv.pcie;
+
+	brcmf_pcie_handle_mb_data(buspub->devinfo, data);
+}
+
 static void brcmf_pcie_bus_console_init(struct brcmf_pciedev_info *devinfo)
 {
 	struct brcmf_pcie_shared_info *shared;
@@ -1042,7 +1075,7 @@ static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
 	if (status) {
 		brcmf_pcie_write_pcie32(devinfo, devinfo->reginfo->mailboxint, status);
 		if (status & devinfo->reginfo->int_fn0)
-			brcmf_pcie_handle_mb_data(devinfo);
+			brcmf_pcie_poll_mb_data(devinfo);
 	}
 	if (devinfo->have_msi || status & devinfo->reginfo->int_d2h_db) {
 		if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
@@ -1695,6 +1728,7 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
 	.get_blob = brcmf_pcie_get_blob,
 	.reset = brcmf_pcie_reset,
 	.debugfs_create = brcmf_pcie_debugfs_create,
+	.d2h_mb_rx = brcmf_pcie_d2h_mb_rx,
 };
 
 
@@ -1726,6 +1760,7 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
 {
 	struct brcmf_bus *bus = dev_get_drvdata(&devinfo->pdev->dev);
 	struct brcmf_pcie_shared_info *shared;
+	u32 host_cap;
 	u32 addr;
 
 	shared = &devinfo->shared;
@@ -1766,6 +1801,24 @@ brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
 	addr = sharedram_addr + BRCMF_SHARED_RING_INFO_ADDR_OFFSET;
 	shared->ring_info_addr = brcmf_pcie_read_tcm32(devinfo, addr);
 
+	if (shared->version >= 6) {
+		shared->mb_via_ctl =
+			!(shared->flags & BRCMF_PCIE_SHARED_USE_MAILBOX);
+
+		host_cap = shared->version;
+		if (shared->flags & BRCMF_PCIE_SHARED_HOSTRDY_DB1)
+			host_cap |= BRCMF_HOSTCAP_H2D_ENABLE_HOSTRDY;
+		if (shared->flags & BRCMF_PCIE_SHARED_DAR)
+			host_cap |= BRCMF_HOSTCAP_H2D_DAR;
+		host_cap |= BRCMF_HOSTCAP_DS_NO_OOB_DW;
+
+		brcmf_pcie_write_tcm32(devinfo, sharedram_addr +
+				       BRCMF_SHARED_HOST_CAP_OFFSET,
+				       host_cap);
+		brcmf_pcie_write_tcm32(devinfo, sharedram_addr +
+				       BRCMF_SHARED_HOST_CAP2_OFFSET, 0);
+	}
+
 	brcmf_dbg(PCIE, "max rx buf post %d, rx dataoffset %d\n",
 		  shared->max_rxbufpost, shared->rx_dataoffset);
 

-- 
2.55.0



  parent reply	other threads:[~2026-09-25 13:43 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-25 13:43 [PATCH 00/13] wifi: brcmfmac: Add BCM4388 support Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 01/13] wifi: brcmfmac: pcie: Report the detected chip ID to the bus Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 02/13] wifi: brcmfmac: Match complete firmware capability names Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 03/13] wifi: brcmfmac: Fall back to RSSI-only default join preferences Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 04/13] wifi: brcmfmac: Support newer PCIe core startup and interrupts Michael Reeves via B4 Relay
2026-09-25 13:43 ` Michael Reeves via B4 Relay [this message]
2026-09-25 13:43 ` [PATCH 06/13] wifi: brcmfmac: Load signed PCIe firmware images Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 07/13] wifi: brcmfmac: Use event_msgs_ext for event masks Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 08/13] wifi: brcmfmac: Handle larger firmware band lists Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 09/13] wifi: brcmfmac: Accept newer BSS information versions Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 10/13] wifi: brcmfmac: Support versioned scan parameter layouts Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 11/13] wifi: brcmfmac: Support versioned join requests Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 12/13] wifi: brcmfmac: Handle extended PMK command payloads Michael Reeves via B4 Relay
2026-09-25 13:43 ` [PATCH 13/13] wifi: brcmfmac: Add BCM4388 support Michael Reeves via B4 Relay

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=20260925-brcm4388-submit-v1-5-b5cbc2cde2fb@gmail.com \
    --to=devnull+michael.reeves077.gmail.com@kernel.org \
    --cc=arend.vanspriel@broadcom.com \
    --cc=asahi@lists.linux.dev \
    --cc=brcm80211-dev-list.pdl@broadcom.com \
    --cc=brcm80211@lists.linux.dev \
    --cc=dberlin@dberlin.org \
    --cc=frankyl@broadcom.com \
    --cc=gustavoars@kernel.org \
    --cc=j@jannau.net \
    --cc=kees@kernel.org \
    --cc=kvalo@kernel.org \
    --cc=linux-hardening@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-wireless@vger.kernel.org \
    --cc=marcan@marcan.st \
    --cc=meuleman@broadcom.com \
    --cc=michael.reeves077@gmail.com \
    --cc=pieterpg@broadcom.com \
    --cc=vanhoefm@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®