Currently, the DP service SRNG handler is invoked directly from the NAPI poll handler, which prevents using different handlers for different architectures. To fix this, introduce a framework that allows registering architecture-specific service SRNG handlers. Also, add PCI and AHB hif_ops to manage IRQ setup and cleanup from DP. Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.4.1-00199-QCAHKSWPL_SILICONZ-1 Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.0.c5-00481-QCAHMTSWPL_V1.0_V2.0_SILICONZ-3 Signed-off-by: Ripan Deuri --- drivers/net/wireless/ath/ath12k/ahb.c | 16 +++++++----- drivers/net/wireless/ath/ath12k/core.h | 3 +++ drivers/net/wireless/ath/ath12k/hif.h | 30 +++++++++++++++++++++- drivers/net/wireless/ath/ath12k/pci.c | 23 +++++++++-------- drivers/net/wireless/ath/ath12k/wifi7/dp.c | 20 ++++++++++++--- drivers/net/wireless/ath/ath12k/wifi7/dp.h | 2 -- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/drivers/net/wireless/ath/ath12k/ahb.c b/drivers/net/wireless/ath/ath12k/ahb.c index c545bea18935..4bacdaa62f83 100644 --- a/drivers/net/wireless/ath/ath12k/ahb.c +++ b/drivers/net/wireless/ath/ath12k/ahb.c @@ -524,10 +524,9 @@ static int ath12k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget) struct ath12k_ext_irq_grp *irq_grp = container_of(napi, struct ath12k_ext_irq_grp, napi); - struct ath12k_base *ab = irq_grp->ab; int work_done; - work_done = ath12k_wifi7_dp_service_srng(ab, irq_grp, budget); + work_done = irq_grp->irq_handler(irq_grp->dp, irq_grp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); ath12k_ahb_ext_grp_enable(irq_grp); @@ -553,7 +552,12 @@ static irqreturn_t ath12k_ahb_ext_interrupt_handler(int irq, void *arg) return IRQ_HANDLED; } -static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab) +static int +ath12k_ahb_config_ext_irq(struct ath12k_base *ab, + int (*irq_handler)(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, + int budget), + struct ath12k_dp *dp) { const struct ath12k_hw_ring_mask *ring_mask; struct ath12k_ext_irq_grp *irq_grp; @@ -569,6 +573,8 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab) irq_grp->ab = ab; irq_grp->grp_id = i; + irq_grp->irq_handler = irq_handler; + irq_grp->dp = dp; irq_grp->napi_ndev = alloc_netdev_dummy(0); if (!irq_grp->napi_ndev) @@ -652,9 +658,6 @@ static int ath12k_ahb_config_irq(struct ath12k_base *ab) ab->irq_num[irq_idx] = irq; } - /* Configure external interrupts */ - ret = ath12k_ahb_config_ext_irq(ab); - return ret; } @@ -702,6 +705,7 @@ static const struct ath12k_hif_ops ath12k_ahb_hif_ops = { .map_service_to_pipe = ath12k_ahb_map_service_to_pipe, .power_up = ath12k_ahb_power_up, .power_down = ath12k_ahb_power_down, + .ext_irq_setup = ath12k_ahb_config_ext_irq, }; static irqreturn_t ath12k_userpd_irq_handler(int irq, void *data) diff --git a/drivers/net/wireless/ath/ath12k/core.h b/drivers/net/wireless/ath/ath12k/core.h index ff99d5ae6226..6a36dfdf5b17 100644 --- a/drivers/net/wireless/ath/ath12k/core.h +++ b/drivers/net/wireless/ath/ath12k/core.h @@ -166,6 +166,7 @@ enum ath12k_firmware_mode { #define ATH12K_MAX_TCL_RING_NUM 3 struct ath12k_ext_irq_grp { + struct ath12k_dp *dp; struct ath12k_base *ab; u32 irqs[ATH12K_EXT_IRQ_NUM_MAX]; u32 num_irq; @@ -174,6 +175,8 @@ struct ath12k_ext_irq_grp { bool napi_enabled; struct napi_struct napi; struct net_device *napi_ndev; + int (*irq_handler)(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, int budget); }; enum ath12k_smbios_cc_type { diff --git a/drivers/net/wireless/ath/ath12k/hif.h b/drivers/net/wireless/ath/ath12k/hif.h index e8840fab6061..1f9781f6d564 100644 --- a/drivers/net/wireless/ath/ath12k/hif.h +++ b/drivers/net/wireless/ath/ath12k/hif.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: BSD-3-Clause-Clear */ /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. - * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. */ #ifndef ATH12K_HIF_H @@ -32,6 +32,12 @@ 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 (*ext_irq_setup)(struct ath12k_base *ab, + int (*handler)(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, + int budget), + struct ath12k_dp *dp); + void (*ext_irq_cleanup)(struct ath12k_base *ab); }; static inline int ath12k_hif_map_service_to_pipe(struct ath12k_base *ab, u16 service_id, @@ -162,4 +168,26 @@ 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_ext_irq_setup(struct ath12k_base *ab, + int (*irq_handler)(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, + int budget), + struct ath12k_dp *dp) +{ + if (!ab->hif.ops->ext_irq_setup) + return -EOPNOTSUPP; + + return ab->hif.ops->ext_irq_setup(ab, irq_handler, dp); +} + +static inline void ath12k_hif_ext_irq_cleanup(struct ath12k_base *ab) +{ + if (!ab->hif.ops->ext_irq_cleanup) + return; + + ab->hif.ops->ext_irq_cleanup(ab); +} + #endif /* ATH12K_HIF_H */ diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c index 672cf2899681..a28bea5c1d40 100644 --- a/drivers/net/wireless/ath/ath12k/pci.c +++ b/drivers/net/wireless/ath/ath12k/pci.c @@ -319,8 +319,6 @@ static void ath12k_pci_free_irq(struct ath12k_base *ab) irq_idx = ATH12K_PCI_IRQ_CE0_OFFSET + i; free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); } - - ath12k_pci_free_ext_irq(ab); } static void ath12k_pci_ce_irq_enable(struct ath12k_base *ab, u16 ce_id) @@ -478,11 +476,10 @@ static int ath12k_pci_ext_grp_napi_poll(struct napi_struct *napi, int budget) struct ath12k_ext_irq_grp *irq_grp = container_of(napi, struct ath12k_ext_irq_grp, napi); - struct ath12k_base *ab = irq_grp->ab; int work_done; int i; - work_done = ath12k_wifi7_dp_service_srng(ab, irq_grp, budget); + work_done = irq_grp->irq_handler(irq_grp->dp, irq_grp, budget); if (work_done < budget) { napi_complete_done(napi, work_done); for (i = 0; i < irq_grp->num_irq; i++) @@ -517,7 +514,12 @@ static irqreturn_t ath12k_pci_ext_interrupt_handler(int irq, void *arg) return IRQ_HANDLED; } -static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) +static +int ath12k_pci_ext_irq_config(struct ath12k_base *ab, + int (*irq_handler)(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, + int budget), + struct ath12k_dp *dp) { struct ath12k_pci *ab_pci = ath12k_pci_priv(ab); int i, j, n, ret, num_vectors = 0; @@ -538,6 +540,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab) irq_grp->ab = ab; irq_grp->grp_id = i; + irq_grp->irq_handler = irq_handler; + irq_grp->dp = dp; irq_grp->napi_ndev = alloc_netdev_dummy(0); if (!irq_grp->napi_ndev) { ret = -ENOMEM; @@ -651,10 +655,6 @@ static int ath12k_pci_config_irq(struct ath12k_base *ab) ath12k_pci_ce_irq_disable(ab, i); } - ret = ath12k_pci_ext_irq_config(ab); - if (ret) - return ret; - return 0; } @@ -1483,6 +1483,8 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = { #ifdef CONFIG_ATH12K_COREDUMP .coredump_download = ath12k_pci_coredump_download, #endif + .ext_irq_setup = ath12k_pci_ext_irq_config, + .ext_irq_cleanup = ath12k_pci_free_ext_irq, }; static enum ath12k_device_family @@ -1691,6 +1693,7 @@ static void ath12k_pci_remove(struct pci_dev *pdev) ath12k_fw_unmap(ab); ath12k_mhi_unregister(ab_pci); + ab_pci->device_family_ops->arch_deinit(ab); ath12k_pci_free_irq(ab); ath12k_pci_msi_free(ab_pci); ath12k_pci_free_region(ab_pci); @@ -1698,8 +1701,6 @@ static void ath12k_pci_remove(struct pci_dev *pdev) ath12k_hal_srng_deinit(ab); ath12k_ce_free_pipes(ab); - ab_pci->device_family_ops->arch_deinit(ab); - ath12k_core_free(ab); } diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp.c b/drivers/net/wireless/ath/ath12k/wifi7/dp.c index adc3480b282b..df9696549d06 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp.c +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp.c @@ -10,13 +10,15 @@ #include "../dp_mon.h" #include "../dp_cmn.h" #include "dp_rx.h" +#include "../hif.h" #include "dp.h" #include "dp_tx.h" -int ath12k_wifi7_dp_service_srng(struct ath12k_base *ab, - struct ath12k_ext_irq_grp *irq_grp, - int budget) +static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp, + struct ath12k_ext_irq_grp *irq_grp, + int budget) { + struct ath12k_base *ab = dp->ab; struct napi_struct *napi = &irq_grp->napi; int grp_id = irq_grp->grp_id; int work_done = 0; @@ -138,6 +140,7 @@ int ath12k_wifi7_dp_service_srng(struct ath12k_base *ab, struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab) { struct ath12k_dp *dp; + int ret; /* TODO: align dp later if cache alignment becomes a bottleneck */ dp = kzalloc(sizeof(*dp), GFP_KERNEL); @@ -148,12 +151,23 @@ struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab) dp->dev = ab->dev; dp->hw_params = ab->hw_params; + ret = ath12k_hif_ext_irq_setup(dp->ab, ath12k_wifi7_dp_service_srng, dp); + if (ret) { + ath12k_err(ab, "failed to setup ext irq, ret %d", ret); + goto free_dp; + } + return dp; + +free_dp: + kfree(dp); + return NULL; } EXPORT_SYMBOL(ath12k_wifi7_dp_device_alloc); void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp) { + ath12k_hif_ext_irq_cleanup(dp->ab); kfree(dp); } EXPORT_SYMBOL(ath12k_wifi7_dp_device_free); diff --git a/drivers/net/wireless/ath/ath12k/wifi7/dp.h b/drivers/net/wireless/ath/ath12k/wifi7/dp.h index 2300fda65786..72fdfb368c99 100644 --- a/drivers/net/wireless/ath/ath12k/wifi7/dp.h +++ b/drivers/net/wireless/ath/ath12k/wifi7/dp.h @@ -13,8 +13,6 @@ struct ath12k_base; struct ath12k_dp; -int ath12k_wifi7_dp_service_srng(struct ath12k_base *ab, - struct ath12k_ext_irq_grp *irq_grp, int budget); struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab); void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp); -- 2.34.1