]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
wifi: ath12k: Register various userPD interrupts and save SMEM entries
authorSowmiya Sree Elavalagan <quic_ssreeela@quicinc.com>
Fri, 21 Mar 2025 10:52:47 +0000 (16:22 +0530)
committerJeff Johnson <jeff.johnson@oss.qualcomm.com>
Tue, 25 Mar 2025 14:55:44 +0000 (07:55 -0700)
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>
drivers/net/wireless/ath/ath12k/ahb.c
drivers/net/wireless/ath/ath12k/ahb.h
drivers/net/wireless/ath/ath12k/hw.h

index c08c2e6bc0d4a92b546189b0e5a2cc4738c50ea2..f55b0c00388311500e21fb8d7c636d6aa7ba0321 100644 (file)
@@ -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
index 1105473917ceeda294b5e073fff875331b7b1d8b..b17e7693b31acaca8271d838fcba6b14684f37b6 100644 (file)
@@ -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)
index a4332588b1173f3ec10009747bfa6cad93e2a429..d4a2e47169d97436a2c7ca88e0204085258df61e 100644 (file)
@@ -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,