From: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
To: Johannes Berg <johannes@sipsolutions.net>,
Rob Herring <robh@kernel.org>,
Krzysztof Kozlowski <krzk+dt@kernel.org>,
Conor Dooley <conor+dt@kernel.org>,
Jeff Johnson <jjohnson@kernel.org>
Cc: linux-wireless@vger.kernel.org, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, ath12k@lists.infradead.org,
Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>,
Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
Subject: [PATCH ath-next v3 11/17] wifi: ath12k: Add platform MSI support for CE
Date: Fri, 23 Oct 2026 12:31:14 +0530 [thread overview]
Message-ID: <20261023-mpp-bringup-v3-11-19f3fcbf7b5f@oss.qualcomm.com> (raw)
In-Reply-To: <20261023-mpp-bringup-v3-0-19f3fcbf7b5f@oss.qualcomm.com>
QCN6432 is attached through AHB but provides Copy Engine (CE) interrupts
using platform MSI vectors instead of dedicated platform IRQ lines. The
existing ath12k AHB interrupt setup only requests named CE IRQs from
the platform and therefore cannot configure CE interrupts on QCN6432.
Add support for configuring CE interrupts through platform MSI on
hybrid AHB devices. Introduce an IPCI MSI configuration for these
platforms, allocate MSI vectors from the platform MSI domain, and
register CE interrupt handlers using the allocated vectors.
Ensure that configured interrupts are properly freed if device probe
fails after interrupt configuration.
Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01322-QCAHKSWPL_SILICONZ-1
Tested-on: QCN6432 hw1.0 AHB WLAN.WBE.1.6-01322-QCAHKSWPL_SILICONZ-1
Co-developed-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
Signed-off-by: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/ahb.c | 18 ++--
drivers/net/wireless/ath/ath12k/ce.h | 4 +
drivers/net/wireless/ath/ath12k/core.h | 7 ++
drivers/net/wireless/ath/ath12k/pci.c | 9 ++
drivers/net/wireless/ath/ath12k/pcic.c | 155 +++++++++++++++++++++++++++++++++
drivers/net/wireless/ath/ath12k/pcic.h | 2 +
6 files changed, 190 insertions(+), 5 deletions(-)
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index bcb49ff07aa8..b9ec14e86def 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -208,8 +208,13 @@ static void ath12k_ahb_free_napi(struct ath12k_base *ab, int num_ext_irq_grp)
ath12k_ahb_free_napi_for_group(&ab->ext_irq_grp[i]);
}
-static void ath12k_ahb_free_ext_napi(struct ath12k_base *ab)
+static void ath12k_ahb_free_config_irq(struct ath12k_base *ab)
{
+ if (ab->hw_params->hybrid_bus_type) {
+ ath12k_pcic_free_irq(ab);
+ return;
+ }
+
ath12k_ahb_free_napi(ab, ATH12K_EXT_IRQ_GRP_NUM_MAX);
}
@@ -719,6 +724,9 @@ static int ath12k_ahb_config_irq(struct ath12k_base *ab)
int irq, irq_idx, i;
int ret;
+ if (ab->hw_params->hybrid_bus_type)
+ return ath12k_pcic_config_irq(ab);
+
/* Configure CE irqs */
for (i = 0; i < ab->hw_params->ce_count; i++) {
struct ath12k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
@@ -1405,7 +1413,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
ret = ab_ahb->device_family_ops->arch_init(ab);
if (ret) {
ath12k_err(ab, "AHB arch_init failed %d\n", ret);
- goto err_free_ext_napi;
+ goto err_free_irq;
}
ret = ath12k_core_init(ab);
@@ -1419,8 +1427,8 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
err_deinit_arch:
ab_ahb->device_family_ops->arch_deinit(ab);
-err_free_ext_napi:
- ath12k_ahb_free_ext_napi(ab);
+err_free_irq:
+ ath12k_ahb_free_config_irq(ab);
err_rproc_deconfigure:
mutex_lock(&ath12k_rproc_info_lock);
@@ -1464,7 +1472,7 @@ static void ath12k_ahb_free_resources(struct ath12k_base *ab)
struct platform_device *pdev = ab->pdev;
struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
- ath12k_ahb_free_ext_napi(ab);
+ ath12k_ahb_free_config_irq(ab);
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
ath12k_ahb_resource_deinit(ab);
diff --git a/drivers/net/wireless/ath/ath12k/ce.h b/drivers/net/wireless/ath/ath12k/ce.h
index cd913a885470..c15ec0c32374 100644
--- a/drivers/net/wireless/ath/ath12k/ce.h
+++ b/drivers/net/wireless/ath/ath12k/ce.h
@@ -11,6 +11,9 @@
#define ATH12K_MSI_IRQ_CE0_OFFSET 3
+/* IRQ name buffer size for CE interrupts */
+#define ATH12K_CE_IRQ_NAME_LEN 32
+
/* Byte swap data words */
#define CE_ATTR_BYTE_SWAP_DATA 2
@@ -172,6 +175,7 @@ struct ath12k_ce_pipe {
struct ath12k_ce_ring *dest_ring;
struct ath12k_ce_ring *status_ring;
u64 timestamp;
+ char irq_name[ATH12K_CE_IRQ_NAME_LEN];
};
struct ath12k_ce {
diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h
index 293c7561b27a..21332aeb0c22 100644
--- a/drivers/net/wireless/ath/ath12k/core.h
+++ b/drivers/net/wireless/ath/ath12k/core.h
@@ -164,6 +164,7 @@ enum ath12k_hw_rev {
#define ATH12K_IRQ_NUM_MAX 57
#define ATH12K_EXT_IRQ_NUM_MAX 16
#define ATH12K_MAX_TCL_RING_NUM 3
+#define ATH12K_MAX_MSI_VECTOR 32
struct ath12k_ext_irq_grp {
struct ath12k_base *ab;
@@ -189,6 +190,12 @@ enum ath12k_smbios_cc_type {
enum ath12k_msi_supported_hw {
ATH12K_MSI_CONFIG_PCI,
+
+ /*
+ * IPCI (Integrated PCI) configuration is used by AHB devices that
+ * support platform MSI.
+ */
+ ATH12K_MSI_CONFIG_IPCI,
};
struct ath12k_smbios_bdf {
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index fe0939ca890c..a26fdb3c0ad2 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -51,6 +51,15 @@ const struct ath12k_msi_config ath12k_msi_config[] = {
{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
},
},
+ {
+ .total_vectors = 32,
+ .total_users = 3,
+ .users = (const struct ath12k_msi_user[]) {
+ { .name = "QDSS", .num_vectors = 1, .base_vector = 0 },
+ { .name = "CE", .num_vectors = 5, .base_vector = 1 },
+ { .name = "DP", .num_vectors = 15, .base_vector = 6 },
+ },
+ },
};
EXPORT_SYMBOL(ath12k_msi_config);
diff --git a/drivers/net/wireless/ath/ath12k/pcic.c b/drivers/net/wireless/ath/ath12k/pcic.c
index e3c8476af459..fea284c3707b 100644
--- a/drivers/net/wireless/ath/ath12k/pcic.c
+++ b/drivers/net/wireless/ath/ath12k/pcic.c
@@ -3,6 +3,7 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/module.h>
+#include <linux/msi.h>
#include "ahb.h"
#include "core.h"
#include "debug.h"
@@ -154,3 +155,157 @@ void ath12k_pcic_write32(struct ath12k_base *ab, u32 offset, u32 value)
window_start = ath12k_pcic_get_window_start(ab, offset);
writel_relaxed(value, ab->mem + window_start + (offset & WINDOW_RANGE_MASK));
}
+
+static void ath12k_pcic_ce_irq_disable(struct ath12k_base *ab, u16 ce_id)
+{
+ u32 irq_idx;
+
+ irq_idx = ATH12K_MSI_IRQ_CE0_OFFSET + ce_id;
+ disable_irq_nosync(ab->irq_num[irq_idx]);
+}
+
+static irqreturn_t ath12k_pcic_ce_interrupt_handler(int irq, void *arg)
+{
+ struct ath12k_ce_pipe *ce_pipe = arg;
+ struct ath12k_base *ab = ce_pipe->ab;
+
+ if (!test_bit(ATH12K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags))
+ return IRQ_HANDLED;
+
+ /* last interrupt received for this CE */
+ ce_pipe->timestamp = jiffies;
+
+ ath12k_pcic_ce_irq_disable(ab, ce_pipe->pipe_num);
+ queue_work(system_bh_wq, &ce_pipe->intr_wq);
+
+ return IRQ_HANDLED;
+}
+
+static int ath12k_pcic_ce_irq_config(struct ath12k_base *ab,
+ struct msi_desc **msi_desc, int num_msi)
+{
+ struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+ int irq_idx, ret, i, vec_idx = 0;
+ u8 userpd_id = ab_ahb->userpd_id;
+ struct ath12k_ce_pipe *ce_pipe;
+ bool msi_info_captured = false;
+ struct msi_desc *desc;
+
+ for (i = 0; i < ab->hw_params->ce_count; i++) {
+ if (ath12k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)
+ continue;
+
+ ce_pipe = &ab->ce.ce_pipe[i];
+ desc = msi_desc[vec_idx];
+ INIT_WORK(&ce_pipe->intr_wq, ath12k_pci_ce_workqueue);
+ irq_idx = ATH12K_MSI_IRQ_CE0_OFFSET + i;
+
+ scnprintf(ce_pipe->irq_name, sizeof(ce_pipe->irq_name),
+ "pcic%u_wlan_ce_%u", userpd_id, i);
+ ret = request_irq(desc->irq, ath12k_pcic_ce_interrupt_handler,
+ IRQF_SHARED, ce_pipe->irq_name, ce_pipe);
+ if (ret) {
+ ath12k_warn(ab, "failed to request irq %d: %d\n", irq_idx, ret);
+ ath12k_pci_free_ce_irq(ab, i);
+ return ret;
+ }
+
+ ab->irq_num[irq_idx] = desc->irq;
+ ath12k_pcic_ce_irq_disable(ab, i);
+ vec_idx = (vec_idx + 1) % num_msi;
+
+ if (!msi_info_captured) {
+ ab->msi.addr_lo = desc->msg.address_lo;
+ ab->msi.addr_hi = desc->msg.address_hi;
+ msi_info_captured = true;
+ }
+ }
+
+ return 0;
+}
+
+static void ath12k_msi_msg_handler(struct msi_desc *desc, struct msi_msg *msg)
+{
+ desc->msg.address_lo = msg->address_lo;
+ desc->msg.address_hi = msg->address_hi;
+ desc->msg.data = msg->data;
+}
+
+static int ath12k_pcic_request_msi_irqs(struct ath12k_base *ab, int base_vector,
+ int num_vectors,
+ int (*irq_config)(struct ath12k_base *ab,
+ struct msi_desc **msi_desc,
+ int num_msi))
+{
+ struct msi_desc *msi_vecs[ATH12K_MAX_MSI_VECTOR];
+ struct platform_device *pdev = ab->pdev;
+ struct msi_desc *msi_desc;
+ int num_msi = 0, ret;
+
+ guard(msi_descs_lock)(&pdev->dev);
+
+ msi_for_each_desc(msi_desc, &pdev->dev, MSI_DESC_ALL) {
+ if (msi_desc->msi_index < base_vector ||
+ msi_desc->msi_index >= (num_vectors + base_vector))
+ continue;
+
+ if (num_msi >= ATH12K_MAX_MSI_VECTOR)
+ return -EOVERFLOW;
+
+ msi_vecs[num_msi++] = msi_desc;
+ }
+
+ if (!num_msi)
+ return -EINVAL;
+
+ ret = irq_config(ab, msi_vecs, num_msi);
+ if (ret) {
+ ath12k_warn(ab, "failed to config irq %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int ath12k_pcic_config_irq(struct ath12k_base *ab)
+{
+ int user_base_data, base_vector, num_vectors;
+ struct platform_device *pdev = ab->pdev;
+ int ret;
+
+ ab->msi.config = &ath12k_msi_config[ATH12K_MSI_CONFIG_IPCI];
+
+ ret = platform_device_msi_init_and_alloc_irqs(&pdev->dev,
+ ab->msi.config->total_vectors,
+ ath12k_msi_msg_handler);
+ if (ret)
+ return ret;
+
+ ret = ath12k_pci_get_user_msi_assignment(ab, "CE", &num_vectors,
+ &user_base_data,
+ &base_vector);
+ if (ret)
+ goto free_msi;
+
+ ret = ath12k_pcic_request_msi_irqs(ab, base_vector, num_vectors,
+ ath12k_pcic_ce_irq_config);
+ if (ret) {
+ ath12k_err(ab, "failed to config CE irq\n");
+ goto free_msi;
+ }
+
+ set_bit(ATH12K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);
+ return 0;
+
+free_msi:
+ platform_device_msi_free_irqs_all(&pdev->dev);
+ return ret;
+}
+
+void ath12k_pcic_free_irq(struct ath12k_base *ab)
+{
+ struct platform_device *pdev = ab->pdev;
+
+ ath12k_pci_free_ce_irq(ab, ab->hw_params->ce_count);
+ platform_device_msi_free_irqs_all(&pdev->dev);
+}
diff --git a/drivers/net/wireless/ath/ath12k/pcic.h b/drivers/net/wireless/ath/ath12k/pcic.h
index f77091927039..7b6c55043618 100644
--- a/drivers/net/wireless/ath/ath12k/pcic.h
+++ b/drivers/net/wireless/ath/ath12k/pcic.h
@@ -19,4 +19,6 @@ int ath12k_pcic_cmem_write32(struct ath12k_base *ab, u32 addr,
u32 value);
int ath12k_pcic_cmem_read32(struct ath12k_base *ab, u32 addr, u32 *value);
void ath12k_pcic_config_static_window(struct ath12k_base *ab);
+int ath12k_pcic_config_irq(struct ath12k_base *ab);
+void ath12k_pcic_free_irq(struct ath12k_base *ab);
#endif /* _ATH12K_PCIC_H */
--
2.34.1
next prev parent reply other threads:[~2026-10-23 7:02 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-23 7:01 [PATCH ath-next v3 00/17] wifi: ath12k: Add support for QCN6432 Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 01/17] dt-bindings: net: wireless: Add QCN6432 Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 02/17] wifi: ath12k: Refactor PCI operations and MSI config structure Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 03/17] wifi: ath12k: Add hardware parameter for QCN6432 Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 04/17] wifi: ath12k: Add hardware ring mask " Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 05/17] wifi: ath12k: add hardware registers " Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 06/17] wifi: ath12k: move multi MSI vector flag to ath12k_dev_flags Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 07/17] wifi: ath12k: Add hybrid_bus_type in ath12k_hw_params Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 08/17] wifi: ath12k: Add hif operation support for QCN6432 Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 09/17] wifi: ath12k: add support for unified data-region memory allocation Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 10/17] wifi: ath12k: move MSI config to pci.c Aaradhana Sahu
2026-10-23 7:01 ` Aaradhana Sahu [this message]
2026-10-23 7:01 ` [PATCH ath-next v3 12/17] wifi: ath12k: Enable MSI interrupt support for DP interrupt Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 13/17] wifi: ath12k: use CMEM write for PPT on hybrid bus devices Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 14/17] wifi: ath12k: store and use MSI data per CE and DP interrupt group for QCN6432 Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 15/17] wifi: ath12k: Derive QMI service instance ID per protection domain Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 16/17] wifi: ath12k: Resolve userPD ID per device Aaradhana Sahu
2026-10-23 7:01 ` [PATCH ath-next v3 17/17] wifi: ath12k: Add QCN6432 AHB support Aaradhana Sahu
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=20261023-mpp-bringup-v3-11-19f3fcbf7b5f@oss.qualcomm.com \
--to=aaradhana.sahu@oss.qualcomm.com \
--cc=ath12k@lists.infradead.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=jjohnson@kernel.org \
--cc=johannes@sipsolutions.net \
--cc=krzk+dt@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-wireless@vger.kernel.org \
--cc=quic_ssreeela@quicinc.com \
--cc=robh@kernel.org \
/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®