Add arch_init() and arch_deinit() ops to the PCI and AHB family ops to
support allocation and cleanup of architecture-specific fields in
ath12k_base. Define shared ath12k_wifi7_arch_init() and
ath12k_wifi7_arch_deinit() functions to handle DP device allocation and
cleanup for Wi-Fi 7 across both PCI and AHB. Introduce a new header file
wifi7/core.h to declare functions defined in wifi7/core.c.
Currently, DP device allocation and cleanup are handled via arch_init()
and arch_deinit(), which can be extended to support additional
architecture-specific initialization in the future.
Define common ath12k_wifi7_arch_init() and
ath12k_wifi7_arch_deinit() functions to handle allocation and cleanup
for Wi-Fi 7. Add a new header file wifi7/core.h to declare common Wi-Fi 7
functions.
Add ath12k_wifi7_dp_device_alloc() and ath12k_wifi7_dp_device_free() to
handle allocation and deallocation of the DP device object for Wi-Fi 7.
Add ath12k_dp_cmn_device_init() and ath12k_dp_cmn_device_deinit() to
initialize and deinitialize common DP device fields. Introduce a new header
file dp_cmn.h to declare these functions, which can also be used to expose
new common DP functions that need to be invoked from non-DP code.
Rename existing DP allocation and cleanup functions to ath12k_dp_setup()
and ath12k_dp_cleanup() to better reflect their purpose in the updated
design.
Replicate device-related fields such as device and hw_params in the DP
device object to align with the new design, which limits per packet data
path object usage to DP specific objects.
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@quicinc.com>
Reviewed-by: Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Link: https://patch.msgid.link/20250930131005.2884253-3-quic_rdeuri@quicinc.com
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
goto err_rproc_deconfigure;
}
+ /* Invoke arch_init here so that arch-specific init operations
+ * can utilize already initialized ab fields, such as HAL SRNGs.
+ */
+ ret = ab_ahb->device_family_ops->arch_init(ab);
+ if (ret) {
+ ath12k_err(ab, "AHB arch_init failed %d\n", ret);
+ goto err_rproc_deconfigure;
+ }
+
ret = ath12k_core_init(ab);
if (ret) {
ath12k_err(ab, "failed to init core: %d\n", ret);
- goto err_rproc_deconfigure;
+ goto err_deinit_arch;
}
return 0;
+err_deinit_arch:
+ ab_ahb->device_family_ops->arch_deinit(ab);
+
err_rproc_deconfigure:
ath12k_ahb_deconfigure_rproc(ab);
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_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
ath12k_ahb_resource_deinit(ab);
ath12k_ahb_deconfigure_rproc(ab);
+ ab_ahb->device_family_ops->arch_deinit(ab);
ath12k_core_free(ab);
platform_set_drvdata(pdev, NULL);
}
if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
return -EINVAL;
- if (!driver || !driver->ops.probe)
+ if (!driver || !driver->ops.probe ||
+ !driver->ops.arch_init || !driver->ops.arch_deinit)
return -EINVAL;
if (ath12k_ahb_family_drivers[device_id]) {
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2025, Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_AHB_H
#define ATH12K_AHB_H
struct ath12k_ahb_device_family_ops {
int (*probe)(struct platform_device *pdev);
+ int (*arch_init)(struct ath12k_base *ab);
+ void (*arch_deinit)(struct ath12k_base *ab);
};
struct ath12k_ahb {
#include "hif.h"
#include "pci.h"
#include "wow.h"
+#include "dp_cmn.h"
unsigned int ath12k_debug_mask;
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
ath12k_dp_rx_pdev_reo_cleanup(ab);
ath12k_hif_stop(ab);
ath12k_wmi_detach(ab);
- ath12k_dp_free(ab);
+ ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
/* De-Init of components as needed */
}
goto err_firmware_stop;
}
- ret = ath12k_dp_alloc(ab);
+ ret = ath12k_dp_cmn_device_init(ath12k_ab_to_dp(ab));
if (ret) {
ath12k_err(ab, "failed to init DP: %d\n", ret);
goto err_firmware_stop;
ret = ath12k_core_start(ab);
if (ret) {
ath12k_err(ab, "failed to start core: %d\n", ret);
- goto err_dp_free;
+ goto err_deinit;
}
mutex_unlock(&ab->core_lock);
mutex_unlock(&ag->mutex);
goto exit;
-err_dp_free:
- ath12k_dp_free(ab);
+err_deinit:
+ ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
mutex_unlock(&ab->core_lock);
mutex_unlock(&ag->mutex);
ath12k_dp_rx_pdev_reo_cleanup(ab);
mutex_unlock(&ab->core_lock);
- ath12k_dp_free(ab);
+ ath12k_dp_cmn_device_deinit(ath12k_ab_to_dp(ab));
ath12k_hal_srng_deinit(ab);
total_vdev = ab->num_radios * TARGET_NUM_VDEVS(ab);
ab->free_vdev_map = (1LL << total_vdev) - 1;
#include "wifi7/dp_rx.h"
#include "peer.h"
#include "dp_mon.h"
+#include "dp_cmn.h"
enum ath12k_dp_desc_type {
ATH12K_DP_TX_DESC,
}
}
-void ath12k_dp_free(struct ath12k_base *ab)
+static void ath12k_dp_cleanup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i;
ath12k_dp_rx_free(ab);
/* Deinit any SOC level resource */
- kfree(ab->dp);
- ab->dp = NULL;
}
void ath12k_dp_cc_config(struct ath12k_base *ab)
}
}
-int ath12k_dp_alloc(struct ath12k_base *ab)
+static int ath12k_dp_setup(struct ath12k_base *ab)
{
struct ath12k_dp *dp;
struct hal_srng *srng = NULL;
int ret;
int i;
- /* TODO: align dp later if cache alignment becomes a bottleneck */
- dp = kzalloc(sizeof(*dp), GFP_KERNEL);
- if (!dp)
- return -ENOMEM;
-
- ab->dp = dp;
+ dp = ath12k_ab_to_dp(ab);
dp->ab = ab;
INIT_LIST_HEAD(&dp->reo_cmd_list);
ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc);
if (ret) {
ath12k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret);
- goto fail_dp_free;
+ return ret;
}
srng = &ab->hal.srng_list[dp->wbm_idle_ring.ring_id];
HAL_WBM_IDLE_LINK, srng, n_link_desc);
if (ret) {
ath12k_warn(ab, "failed to setup link desc: %d\n", ret);
- goto fail_dp_free;
+ return ret;
}
ret = ath12k_dp_cc_init(ab);
ath12k_dp_link_desc_cleanup(ab, dp->link_desc_banks,
HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring);
-fail_dp_free:
- kfree(ab->dp);
- ab->dp = NULL;
-
return ret;
}
+
+void ath12k_dp_cmn_device_deinit(struct ath12k_dp *dp)
+{
+ ath12k_dp_cleanup(dp->ab);
+}
+
+int ath12k_dp_cmn_device_init(struct ath12k_dp *dp)
+{
+ int ret;
+
+ ret = ath12k_dp_setup(dp->ab);
+ if (ret)
+ return ret;
+
+ return 0;
+}
struct dp_rxdma_mon_ring rx_mon_status_refill_ring[MAX_RXDMA_PER_PDEV];
struct ath12k_reo_q_addr_lut reoq_lut;
struct ath12k_reo_q_addr_lut ml_reoq_lut;
+ const struct ath12k_hw_params *hw_params;
+ struct device *dev;
};
static inline void ath12k_dp_get_mac_addr(u32 addr_l32, u16 addr_h16, u8 *addr)
}
void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif);
-void ath12k_dp_free(struct ath12k_base *ab);
-int ath12k_dp_alloc(struct ath12k_base *ab);
void ath12k_dp_cc_config(struct ath12k_base *ab);
void ath12k_dp_partner_cc_init(struct ath12k_base *ab);
int ath12k_dp_pdev_alloc(struct ath12k_base *ab);
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+
+#ifndef ATH12K_DP_CMN_H
+#define ATH12K_DP_CMN_H
+
+void ath12k_dp_cmn_device_deinit(struct ath12k_dp *dp);
+int ath12k_dp_cmn_device_init(struct ath12k_dp *dp);
+
+#endif
goto err_free_irq;
}
+ /* Invoke arch_init here so that arch-specific init operations
+ * can utilize already initialized ab fields, such as HAL SRNGs.
+ */
+ ret = ab_pci->device_family_ops->arch_init(ab);
+ if (ret) {
+ ath12k_err(ab, "PCI arch_init failed %d\n", ret);
+ goto err_pci_msi_free;
+ }
+
ret = ath12k_core_init(ab);
if (ret) {
ath12k_err(ab, "failed to init core: %d\n", ret);
- goto err_free_irq;
+ goto err_deinit_arch;
}
return 0;
+err_deinit_arch:
+ ab_pci->device_family_ops->arch_deinit(ab);
+
err_free_irq:
/* __free_irq() expects the caller to have cleared the affinity hint */
ath12k_pci_set_irq_affinity_hint(ab_pci, NULL);
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
+
+ ab_pci->device_family_ops->arch_deinit(ab);
+
ath12k_core_free(ab);
}
if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
return -EINVAL;
- if (!driver || !driver->ops.probe)
+ if (!driver || !driver->ops.probe ||
+ !driver->ops.arch_init || !driver->ops.arch_deinit)
return -EINVAL;
if (ath12k_pci_family_drivers[device_id]) {
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
- * Copyright (c) 2021-2025 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_PCI_H
#define ATH12K_PCI_H
struct ath12k_pci_device_family_ops {
int (*probe)(struct pci_dev *pdev, const struct pci_device_id *pci_dev);
+ int (*arch_init)(struct ath12k_base *ab);
+ void (*arch_deinit)(struct ath12k_base *ab);
};
struct ath12k_pci_reg_base {
#include "../debug.h"
#include "../hif.h"
#include "hw.h"
+#include "dp.h"
+#include "core.h"
static const struct of_device_id ath12k_wifi7_ahb_of_match[] = {
{ .compatible = "qcom,ipq5332-wifi",
.name = "ath12k_wifi7_ahb",
.id_table = ath12k_wifi7_ahb_of_match,
.ops.probe = ath12k_wifi7_ahb_probe,
+ .ops.arch_init = ath12k_wifi7_arch_init,
+ .ops.arch_deinit = ath12k_wifi7_arch_deinit,
};
int ath12k_wifi7_ahb_init(void)
#include "../pci.h"
#include "pci.h"
#include "ahb.h"
+#include "core.h"
+#include "dp.h"
+#include "../debug.h"
static int ahb_err, pci_err;
+int ath12k_wifi7_arch_init(struct ath12k_base *ab)
+{
+ struct ath12k_dp *dp;
+
+ dp = ath12k_wifi7_dp_device_alloc(ab);
+ if (!dp) {
+ ath12k_err(ab, "dp alloc failed");
+ return -EINVAL;
+ }
+
+ ab->dp = dp;
+
+ return 0;
+}
+
+void ath12k_wifi7_arch_deinit(struct ath12k_base *ab)
+{
+ ath12k_wifi7_dp_device_free(ab->dp);
+ ab->dp = NULL;
+}
+
static int ath12k_wifi7_init(void)
{
ahb_err = ath12k_wifi7_ahb_init();
--- /dev/null
+/* SPDX-License-Identifier: BSD-3-Clause-Clear */
+/*
+ * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
+ */
+#ifndef ATH12K_CORE_WIFI7_H
+#define ATH12K_CORE_WIFI7_H
+
+int ath12k_wifi7_arch_init(struct ath12k_base *ab);
+void ath12k_wifi7_arch_deinit(struct ath12k_base *ab);
+
+#endif
#include "../dp_rx.h"
#include "../dp_tx.h"
#include "../dp_mon.h"
+#include "../dp_cmn.h"
#include "dp_rx.h"
#include "dp.h"
#include "dp_tx.h"
done:
return tot_work_done;
}
+
+/* TODO: remove export once this file is built with wifi7 ko */
+struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab)
+{
+ struct ath12k_dp *dp;
+
+ /* TODO: align dp later if cache alignment becomes a bottleneck */
+ dp = kzalloc(sizeof(*dp), GFP_KERNEL);
+ if (!dp)
+ return NULL;
+
+ dp->ab = ab;
+ dp->dev = ab->dev;
+ dp->hw_params = ab->hw_params;
+
+ return dp;
+}
+EXPORT_SYMBOL(ath12k_wifi7_dp_device_alloc);
+
+void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp)
+{
+ kfree(dp);
+}
+EXPORT_SYMBOL(ath12k_wifi7_dp_device_free);
#ifndef ATH12K_DP_WIFI7_H
#define ATH12K_DP_WIFI7_H
+#include "../dp_cmn.h"
#include "hw.h"
+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);
+
#endif
#include "../mhi.h"
#include "hw.h"
#include "../hal.h"
+#include "dp.h"
+#include "core.h"
#define QCN9274_DEVICE_ID 0x1109
#define WCN7850_DEVICE_ID 0x1107
.id_table = ath12k_wifi7_pci_id_table,
.ops.probe = ath12k_wifi7_pci_probe,
.reg_base = &ath12k_wifi7_reg_base,
+ .ops.arch_init = ath12k_wifi7_arch_init,
+ .ops.arch_deinit = ath12k_wifi7_arch_deinit,
};
int ath12k_wifi7_pci_init(void)