summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>2025-03-21 16:22:47 +0530
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>2025-03-25 07:55:44 -0700
commitf73e089745a000b6eb99457f71b47dc862ab221a (patch)
treef2d3628e26076790c553361082103ec394e01789
parent10a355ba6238e13d196be2f226a59f7886d7b5bd (diff)
wifi: ath12k: Register various userPD interrupts and save SMEM entries
Q6 and ath12k driver communicates using SMEM and IRQs. Spawn interrupt is triggered once the userPD thread is spawned. Ready interrupts denotes userPD is completely powered up and ready. Stop-ack is to acknowledge the ath12k driver that userPD is stopped. Ath12k driver needs to set spawn bit in SMEM to instruct Q6 to spawn a userPD. Similarly stop bit is set when userPD needs to be stopped. Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.3.1-00130-QCAHKSWPL_SILICONZ-1 Signed-off-by: Sowmiya Sree Elavalagan <quic_ssreeela@quicinc.com> Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com> Signed-off-by: Raj Kumar Bhagat <quic_rajkbhag@quicinc.com> Link: https://patch.msgid.link/20250321-ath12k-ahb-v12-10-bb389ed76ae5@quicinc.com Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
-rw-r--r--drivers/net/wireless/ath/ath12k/ahb.c79
-rw-r--r--drivers/net/wireless/ath/ath12k/ahb.h16
-rw-r--r--drivers/net/wireless/ath/ath12k/hw.h1
3 files changed, 94 insertions, 2 deletions
diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c
index c08c2e6bc0d4..f55b0c003883 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.c
+++ b/drivers/net/wireless/ath/ath12k/ahb.c
@@ -9,6 +9,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
+#include <linux/soc/qcom/smem_state.h>
#include "ahb.h"
#include "debug.h"
#include "hif.h"
@@ -23,6 +24,11 @@ static const struct of_device_id ath12k_ahb_of_match[] = {
MODULE_DEVICE_TABLE(of, ath12k_ahb_of_match);
#define ATH12K_IRQ_CE0_OFFSET 4
+#define ATH12K_MAX_UPDS 1
+#define ATH12K_UPD_IRQ_WRD_LEN 18
+static const char ath12k_userpd_irq[][9] = {"spawn",
+ "ready",
+ "stop-ack"};
static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"misc-pulse1",
@@ -547,6 +553,72 @@ static const struct ath12k_hif_ops ath12k_ahb_hif_ops_ipq5332 = {
.map_service_to_pipe = ath12k_ahb_map_service_to_pipe,
};
+static irqreturn_t ath12k_userpd_irq_handler(int irq, void *data)
+{
+ struct ath12k_base *ab = data;
+ struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+
+ if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_SPAWN_IRQ]) {
+ complete(&ab_ahb->userpd_spawned);
+ } else if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_READY_IRQ]) {
+ complete(&ab_ahb->userpd_ready);
+ } else if (irq == ab_ahb->userpd_irq_num[ATH12K_USERPD_STOP_ACK_IRQ]) {
+ complete(&ab_ahb->userpd_stopped);
+ } else {
+ ath12k_err(ab, "Invalid userpd interrupt\n");
+ return IRQ_NONE;
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ath12k_ahb_config_rproc_irq(struct ath12k_base *ab)
+{
+ struct ath12k_ahb *ab_ahb = ath12k_ab_to_ahb(ab);
+ int i, ret;
+ char *upd_irq_name;
+
+ for (i = 0; i < ATH12K_USERPD_MAX_IRQ; i++) {
+ ab_ahb->userpd_irq_num[i] = platform_get_irq_byname(ab->pdev,
+ ath12k_userpd_irq[i]);
+ if (ab_ahb->userpd_irq_num[i] < 0)
+ return ab_ahb->userpd_irq_num[i];
+
+ upd_irq_name = devm_kzalloc(&ab->pdev->dev, ATH12K_UPD_IRQ_WRD_LEN,
+ GFP_KERNEL);
+ if (!upd_irq_name)
+ return -ENOMEM;
+
+ scnprintf(upd_irq_name, ATH12K_UPD_IRQ_WRD_LEN, "UserPD%u-%s",
+ ab_ahb->userpd_id, ath12k_userpd_irq[i]);
+ ret = devm_request_threaded_irq(&ab->pdev->dev, ab_ahb->userpd_irq_num[i],
+ NULL, ath12k_userpd_irq_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ upd_irq_name, ab);
+ if (ret)
+ return dev_err_probe(&ab->pdev->dev, ret,
+ "Request %s irq failed: %d\n",
+ ath12k_userpd_irq[i], ret);
+ }
+
+ ab_ahb->spawn_state = devm_qcom_smem_state_get(&ab->pdev->dev, "spawn",
+ &ab_ahb->spawn_bit);
+ if (IS_ERR(ab_ahb->spawn_state))
+ return dev_err_probe(&ab->pdev->dev, PTR_ERR(ab_ahb->spawn_state),
+ "Failed to acquire spawn state\n");
+
+ ab_ahb->stop_state = devm_qcom_smem_state_get(&ab->pdev->dev, "stop",
+ &ab_ahb->stop_bit);
+ if (IS_ERR(ab_ahb->stop_state))
+ return dev_err_probe(&ab->pdev->dev, PTR_ERR(ab_ahb->stop_state),
+ "Failed to acquire stop state\n");
+
+ init_completion(&ab_ahb->userpd_spawned);
+ init_completion(&ab_ahb->userpd_ready);
+ init_completion(&ab_ahb->userpd_stopped);
+ return 0;
+}
+
static int ath12k_ahb_root_pd_state_notifier(struct notifier_block *nb,
const unsigned long event, void *data)
{
@@ -659,7 +731,8 @@ static int ath12k_ahb_configure_rproc(struct ath12k_base *ab)
goto err_unreg_notifier;
}
}
- return 0;
+
+ return ath12k_ahb_config_rproc_irq(ab);
err_unreg_notifier:
ath12k_ahb_unregister_rproc_notifier(ab);
@@ -764,7 +837,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
const struct ath12k_hif_ops *hif_ops;
struct ath12k_ahb *ab_ahb;
enum ath12k_hw_rev hw_rev;
- u32 addr;
+ u32 addr, userpd_id;
int ret;
ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
@@ -782,6 +855,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
switch (hw_rev) {
case ATH12K_HW_IPQ5332_HW10:
hif_ops = &ath12k_ahb_hif_ops_ipq5332;
+ userpd_id = ATH12K_IPQ5332_USERPD_ID;
break;
default:
ret = -EOPNOTSUPP;
@@ -794,6 +868,7 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ab);
ab_ahb = ath12k_ab_to_ahb(ab);
ab_ahb->ab = ab;
+ ab_ahb->userpd_id = userpd_id;
/* Set fixed_mem_region to true for platforms that support fixed memory
* reservation from DT. If memory is reserved from DT for FW, ath12k driver
diff --git a/drivers/net/wireless/ath/ath12k/ahb.h b/drivers/net/wireless/ath/ath12k/ahb.h
index 1105473917ce..b17e7693b31a 100644
--- a/drivers/net/wireless/ath/ath12k/ahb.h
+++ b/drivers/net/wireless/ath/ath12k/ahb.h
@@ -25,6 +25,13 @@ enum ath12k_ahb_smp2p_msg_id {
ATH12K_AHB_POWER_SAVE_EXIT,
};
+enum ath12k_ahb_userpd_irq {
+ ATH12K_USERPD_SPAWN_IRQ,
+ ATH12K_USERPD_READY_IRQ,
+ ATH12K_USERPD_STOP_ACK_IRQ,
+ ATH12K_USERPD_MAX_IRQ,
+};
+
struct ath12k_base;
struct ath12k_ahb {
@@ -34,6 +41,15 @@ struct ath12k_ahb {
struct completion rootpd_ready;
struct notifier_block root_pd_nb;
void *root_pd_notifier;
+ struct qcom_smem_state *spawn_state;
+ struct qcom_smem_state *stop_state;
+ struct completion userpd_spawned;
+ struct completion userpd_ready;
+ struct completion userpd_stopped;
+ u32 userpd_id;
+ u32 spawn_bit;
+ u32 stop_bit;
+ int userpd_irq_num[ATH12K_USERPD_MAX_IRQ];
};
static inline struct ath12k_ahb *ath12k_ab_to_ahb(struct ath12k_base *ab)
diff --git a/drivers/net/wireless/ath/ath12k/hw.h b/drivers/net/wireless/ath/ath12k/hw.h
index a4332588b117..d4a2e47169d9 100644
--- a/drivers/net/wireless/ath/ath12k/hw.h
+++ b/drivers/net/wireless/ath/ath12k/hw.h
@@ -97,6 +97,7 @@
#define ATH12K_REGDB_FILE_NAME "regdb.bin"
#define ATH12K_PCIE_MAX_PAYLOAD_SIZE 128
+#define ATH12K_IPQ5332_USERPD_ID 1
enum ath12k_hw_rate_cck {
ATH12K_HW_RATE_CCK_LP_11M = 0,