[PATCH ath12k-ng v2 5/6] wifi: ath12k: Add framework for hardware specific DP interrupt registration

Ripan Deuri quic_rdeuri at quicinc.com
Mon Sep 29 04:45:47 PDT 2025



On 9/26/2025 12:57 PM, Baochen Qiang wrote:
> 
> 
> On 9/26/2025 1:22 PM, Ripan Deuri wrote:
>> 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 <quic_rdeuri at quicinc.com>
>> ---
>>  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);
> 
> commit message says IRQ handler is architiecture specific, then why not put it in
> ath12k_dp_arch_ops? Replicating irq_handler in each irq_grp seems kind of waste.

Yes, it can be done via arch_ops too. Will use arch ops in the next
revision.

>>  };
>>  
>>  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);
>>  
> 




More information about the ath12k mailing list