Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions drivers/net/wireless/ath/ath12k/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
obj-$(CONFIG_ATH12K) += ath12k.o
ath12k-y += core.o \
hal.o \
hal_tx.o \
hal_rx.o \
wmi.o \
mac.o \
reg.o \
Expand All @@ -12,18 +10,22 @@ ath12k-y += core.o \
dp.o \
dp_tx.o \
dp_rx.o \
dp_htt.o \
dp_peer.o \
debug.o \
ce.o \
peer.o \
dbring.o \
hw.o \
mhi.o \
pci.o \
dp_mon.o \
fw.o \
p2p.o

ath12k-$(CONFIG_ATH12K_AHB) += ahb.o

obj-$(CONFIG_ATH12K) += wifi7/

ath12k-$(CONFIG_ATH12K_DEBUGFS) += debugfs.o debugfs_htt_stats.o debugfs_sta.o
ath12k-$(CONFIG_ACPI) += acpi.o
ath12k-$(CONFIG_ATH12K_TRACING) += trace.o
Expand Down
165 changes: 113 additions & 52 deletions drivers/net/wireless/ath/ath12k/ahb.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// 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.
*/

#include <linux/dma-mapping.h>
Expand All @@ -16,18 +16,11 @@
#include "debug.h"
#include "hif.h"

static const struct of_device_id ath12k_ahb_of_match[] = {
{ .compatible = "qcom,ipq5332-wifi",
.data = (void *)ATH12K_HW_IPQ5332_HW10,
},
{ }
};

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 struct ath12k_ahb_driver *ath12k_ahb_family_drivers[ATH12K_DEVICE_FAMILY_MAX];
static const char ath12k_userpd_irq[][9] = {"spawn",
"ready",
"stop-ack"};
Expand Down Expand Up @@ -130,15 +123,15 @@ enum ext_irq_num {

static u32 ath12k_ahb_read32(struct ath12k_base *ab, u32 offset)
{
if (ab->ce_remap && offset < HAL_SEQ_WCSS_CMEM_OFFSET)
if (ab->ce_remap && offset < ab->cmem_offset)
return ioread32(ab->mem_ce + offset);
return ioread32(ab->mem + offset);
}

static void ath12k_ahb_write32(struct ath12k_base *ab, u32 offset,
u32 value)
{
if (ab->ce_remap && offset < HAL_SEQ_WCSS_CMEM_OFFSET)
if (ab->ce_remap && offset < ab->cmem_offset)
iowrite32(value, ab->mem_ce + offset);
else
iowrite32(value, ab->mem + offset);
Expand Down Expand Up @@ -531,9 +524,10 @@ static int ath12k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)
struct ath12k_ext_irq_grp,
napi);
struct ath12k_base *ab = irq_grp->ab;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int work_done;

work_done = ath12k_dp_service_srng(ab, irq_grp, budget);
work_done = ath12k_dp_service_srng(dp, irq_grp, budget);
if (work_done < budget) {
napi_complete_done(napi, work_done);
ath12k_ahb_ext_grp_enable(irq_grp);
Expand Down Expand Up @@ -563,12 +557,10 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
{
const struct ath12k_hw_ring_mask *ring_mask;
struct ath12k_ext_irq_grp *irq_grp;
const struct hal_ops *hal_ops;
int i, j, irq, irq_idx, ret;
u32 num_irq;

ring_mask = ab->hw_params->ring_mask;
hal_ops = ab->hw_params->hal_ops;
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
irq_grp = &ab->ext_irq_grp[i];
num_irq = 0;
Expand All @@ -588,7 +580,7 @@ static int ath12k_ahb_config_ext_irq(struct ath12k_base *ab)
* tcl_to_wbm_rbm_map point to the same ring number.
*/
if (ring_mask->tx[i] &
BIT(hal_ops->tcl_to_wbm_rbm_map[j].wbm_ring_num)) {
BIT(ab->hal.tcl_to_wbm_rbm_map[j].wbm_ring_num)) {
irq_grp->irqs[num_irq++] =
wbm2host_tx_completions_ring1 - j;
}
Expand Down Expand Up @@ -698,7 +690,7 @@ static int ath12k_ahb_map_service_to_pipe(struct ath12k_base *ab, u16 service_id
return 0;
}

static const struct ath12k_hif_ops ath12k_ahb_hif_ops_ipq5332 = {
static const struct ath12k_hif_ops ath12k_ahb_hif_ops = {
.start = ath12k_ahb_start,
.stop = ath12k_ahb_stop,
.read32 = ath12k_ahb_read32,
Expand Down Expand Up @@ -935,7 +927,8 @@ static int ath12k_ahb_resource_init(struct ath12k_base *ab)
goto err_mem_unmap;
}
ab->ce_remap = true;
ab->ce_remap_base_addr = HAL_IPQ5332_CE_WFSS_REG_BASE;
ab->cmem_offset = ce_remap->cmem_offset;
ab->ce_remap_base_addr = ce_remap->base;
}

ab_ahb->xo_clk = devm_clk_get(ab->dev, "xo");
Expand Down Expand Up @@ -988,13 +981,34 @@ static void ath12k_ahb_resource_deinit(struct ath12k_base *ab)
ab_ahb->xo_clk = NULL;
}

static enum ath12k_device_family
ath12k_ahb_get_device_family(const struct platform_device *pdev)
{
enum ath12k_device_family device_family_id;
struct ath12k_ahb_driver *driver;
const struct of_device_id *of_id;

for (device_family_id = ATH12K_DEVICE_FAMILY_START;
device_family_id < ATH12K_DEVICE_FAMILY_MAX; device_family_id++) {
driver = ath12k_ahb_family_drivers[device_family_id];
if (driver) {
of_id = of_match_device(driver->id_table, &pdev->dev);
if (of_id) {
/* Found the driver */
return device_family_id;
}
}
}

return ATH12K_DEVICE_FAMILY_MAX;
}

static int ath12k_ahb_probe(struct platform_device *pdev)
{
struct ath12k_base *ab;
const struct ath12k_hif_ops *hif_ops;
enum ath12k_device_family device_id;
struct ath12k_ahb *ab_ahb;
enum ath12k_hw_rev hw_rev;
u32 addr, userpd_id;
struct ath12k_base *ab;
u32 addr;
int ret;

ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
Expand All @@ -1008,25 +1022,32 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
if (!ab)
return -ENOMEM;

hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
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;
ab_ahb = ath12k_ab_to_ahb(ab);
ab_ahb->ab = ab;
ab->hif.ops = &ath12k_ahb_hif_ops;
ab->pdev = pdev;
platform_set_drvdata(pdev, ab);

device_id = ath12k_ahb_get_device_family(pdev);
if (device_id >= ATH12K_DEVICE_FAMILY_MAX) {
ath12k_err(ab, "failed to get device family: %d\n", device_id);
ret = -EINVAL;
goto err_core_free;
}

ab->hif.ops = hif_ops;
ab->pdev = pdev;
ab->hw_rev = hw_rev;
ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
platform_set_drvdata(pdev, ab);
ab_ahb = ath12k_ab_to_ahb(ab);
ab_ahb->ab = ab;
ab_ahb->userpd_id = userpd_id;
ath12k_dbg(ab, ATH12K_DBG_AHB, "AHB device family id: %d\n", device_id);

ab_ahb->device_family_ops = &ath12k_ahb_family_drivers[device_id]->ops;

/* Call device specific probe. This is the callback that can
* be used to override any ops in future
* probe is validated for NULL during registration.
*/
ret = ab_ahb->device_family_ops->probe(pdev);
if (ret) {
ath12k_err(ab, "failed to probe device: %d\n", ret);
goto err_core_free;
}

/* 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
Expand Down Expand Up @@ -1065,14 +1086,26 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
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);

Expand Down Expand Up @@ -1111,11 +1144,13 @@ static void ath12k_ahb_remove_prepare(struct ath12k_base *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);
}
Expand All @@ -1136,21 +1171,47 @@ static void ath12k_ahb_remove(struct platform_device *pdev)
ath12k_ahb_free_resources(ab);
}

static struct platform_driver ath12k_ahb_driver = {
.driver = {
.name = "ath12k_ahb",
.of_match_table = ath12k_ahb_of_match,
},
.probe = ath12k_ahb_probe,
.remove = ath12k_ahb_remove,
};

int ath12k_ahb_init(void)
int ath12k_ahb_register_driver(const enum ath12k_device_family device_id,
struct ath12k_ahb_driver *driver)
{
return platform_driver_register(&ath12k_ahb_driver);
struct platform_driver *ahb_driver;

if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
return -EINVAL;

if (!driver || !driver->ops.probe ||
!driver->ops.arch_init || !driver->ops.arch_deinit)
return -EINVAL;

if (ath12k_ahb_family_drivers[device_id]) {
pr_err("Driver already registered for id %d\n", device_id);
return -EALREADY;
}

ath12k_ahb_family_drivers[device_id] = driver;

ahb_driver = &ath12k_ahb_family_drivers[device_id]->driver;
ahb_driver->driver.name = driver->name;
ahb_driver->driver.of_match_table = driver->id_table;
ahb_driver->probe = ath12k_ahb_probe;
ahb_driver->remove = ath12k_ahb_remove;

return platform_driver_register(ahb_driver);
}
EXPORT_SYMBOL(ath12k_ahb_register_driver);

void ath12k_ahb_exit(void)
void ath12k_ahb_unregister_driver(const enum ath12k_device_family device_id)
{
platform_driver_unregister(&ath12k_ahb_driver);
struct platform_driver *ahb_driver;

if (device_id >= ATH12K_DEVICE_FAMILY_MAX)
return;

if (!ath12k_ahb_family_drivers[device_id])
return;

ahb_driver = &ath12k_ahb_family_drivers[device_id]->driver;
platform_driver_unregister(ahb_driver);
ath12k_ahb_family_drivers[device_id] = NULL;
}
EXPORT_SYMBOL(ath12k_ahb_unregister_driver);
31 changes: 20 additions & 11 deletions drivers/net/wireless/ath/ath12k/ahb.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
/* 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

#include <linux/clk.h>
#include <linux/remoteproc/qcom_rproc.h>
#include <linux/platform_device.h>
#include "core.h"

#define ATH12K_AHB_RECOVERY_TIMEOUT (3 * HZ)
Expand Down Expand Up @@ -43,6 +44,12 @@ enum ath12k_ahb_userpd_irq {

struct ath12k_base;

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 {
struct ath12k_base *ab;
struct rproc *tgt_rproc;
Expand All @@ -59,22 +66,24 @@ struct ath12k_ahb {
u32 spawn_bit;
u32 stop_bit;
int userpd_irq_num[ATH12K_USERPD_MAX_IRQ];
const struct ath12k_ahb_ops *ahb_ops;
const struct ath12k_ahb_device_family_ops *device_family_ops;
};

struct ath12k_ahb_driver {
const char *name;
const struct of_device_id *id_table;
struct ath12k_ahb_device_family_ops ops;
struct platform_driver driver;
};

static inline struct ath12k_ahb *ath12k_ab_to_ahb(struct ath12k_base *ab)
{
return (struct ath12k_ahb *)ab->drv_priv;
}

#ifdef CONFIG_ATH12K_AHB
int ath12k_ahb_init(void);
void ath12k_ahb_exit(void);
#else
static inline int ath12k_ahb_init(void)
{
return 0;
}
int ath12k_ahb_register_driver(const enum ath12k_device_family device_id,
struct ath12k_ahb_driver *driver);
void ath12k_ahb_unregister_driver(const enum ath12k_device_family device_id);

static inline void ath12k_ahb_exit(void) {};
#endif
#endif
Loading