[PATCH 4/4] wifi: ath12k: Connect to the QMI server belonging to the device owned by this driver

From: Manivannan Sadhasivam via B4 Relay

Date: Fri Sep 18 2026 - 13:38:36 EST


From: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxxxxxxxx>

When two identical ath12k PCIe devices are connected to the same host, both
advertise the WLFW service with the same service and instance id. The QMI
lookup reports both servers to each device, so a device may connect to the
firmware running on the other device.

But now, QRTR provides each MHI endpoint a unique node id which is
different from the node id announced by the device. So use the same id to
pick the correct server. Add a get_qrtr_node_id() HIF callback that returns
the node id derived from the MHI controller index and zero for transports
that do not assign one. In the new_server callback, skip any service whose
node id does not match. A node id of zero disables the check, so transports
that do not assign one keep their current behavior.

Signed-off-by: Manivannan Sadhasivam <manivannan.sadhasivam@xxxxxxxxxxxxxxxx>
---
drivers/net/wireless/ath/ath12k/hif.h | 9 +++++++++
drivers/net/wireless/ath/ath12k/pci.c | 9 +++++++++
drivers/net/wireless/ath/ath12k/qmi.c | 11 +++++++++++
3 files changed, 29 insertions(+)

diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h
index 4de8667690e9..be9c070cf716 100644
--- a/drivers/net/wireless/ath/ath12k/hif.h
+++ b/drivers/net/wireless/ath/ath12k/hif.h
@@ -32,6 +32,7 @@ struct ath12k_hif_ops {
void (*get_ce_msi_idx)(struct ath12k_base *ab, u32 ce_id, u32 *msi_idx);
int (*panic_handler)(struct ath12k_base *ab);
void (*coredump_download)(struct ath12k_base *ab);
+ int (*get_qrtr_node_id)(struct ath12k_base *ab);
};

static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id,
@@ -162,4 +163,12 @@ static inline void ath12k_hif_coredump_download(struct ath12k_base *ab)
if (ab->hif.ops->coredump_download)
ab->hif.ops->coredump_download(ab);
}
+
+static inline int ath12k_hif_get_qrtr_node_id(struct ath12k_base *ab)
+{
+ if (!ab->hif.ops->get_qrtr_node_id)
+ return 0;
+
+ return ab->hif.ops->get_qrtr_node_id(ab);
+}
#endif /* ATH12K_HIF_H */
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 6441927b5382..2b1b122bbb3b 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -10,6 +10,7 @@
#include <linux/pci.h>
#include <linux/time.h>
#include <linux/vmalloc.h>
+#include <net/qrtr.h>

#include "pci.h"
#include "core.h"
@@ -1491,6 +1492,13 @@ static int ath12k_pci_panic_handler(struct ath12k_base *ab)
return NOTIFY_OK;
}

+static int ath12k_pci_get_qrtr_node_id(struct ath12k_base *ab)
+{
+ struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
+
+ return qrtr_host_node_id(ab_pci->mhi_ctrl->index);
+}
+
static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
.start = ath12k_pci_start,
.stop = ath12k_pci_stop,
@@ -1512,6 +1520,7 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
#ifdef CONFIG_ATH12K_COREDUMP
.coredump_download = ath12k_pci_coredump_download,
#endif
+ .get_qrtr_node_id = ath12k_pci_get_qrtr_node_id,
};

static enum ath12k_device_family
diff --git a/drivers/net/wireless/ath/ath12k/qmi.c b/drivers/net/wireless/ath/ath12k/qmi.c
index 280e50a1f31d..22b8cbbbf4f4 100644
--- a/drivers/net/wireless/ath/ath12k/qmi.c
+++ b/drivers/net/wireless/ath/ath12k/qmi.c
@@ -9,6 +9,7 @@
#include "qmi.h"
#include "core.h"
#include "debug.h"
+#include "hif.h"
#include <linux/of.h>
#include <linux/firmware.h>
#include <linux/of_address.h>
@@ -3940,8 +3941,18 @@ static int ath12k_qmi_ops_new_server(struct qmi_handle *qmi_hdl,
struct ath12k_qmi *qmi = container_of(qmi_hdl, struct ath12k_qmi, handle);
struct ath12k_base *ab = qmi->ab;
struct sockaddr_qrtr *sq = &qmi->sq;
+ int node_id;
int ret;

+ /* Identical devices advertise the same QMI services, so connect only to
+ * the QMI server on this device's node. A node id of 0 means the
+ * transport has not assigned a unique node id, so accept the server
+ * unfiltered.
+ */
+ node_id = ath12k_hif_get_qrtr_node_id(ab);
+ if (node_id && service->node != node_id)
+ return 0;
+
sq->sq_family = AF_QIPCRTR;
sq->sq_node = service->node;
sq->sq_port = service->port;

--
2.43.0