Merge branch 'ath12k-ng' into ath-next

As originally proposed in [1], the ath12k driver was re-architected in
the ath12k-ng branch to separate the logic specific to 802.11be (Wi-Fi
7) from the core logic. This separation will allow ath12k to also
support 802.11bn (Wi-Fi 8) in the future. Now merge this into ath-next.

Many thanks to everyone who worked on this re-architecture. Special
thanks to Vasanthakumar Thiagarajan and Baochen Qiang who reviewed
every patch, and to Ripan Deuri for the ath12k-ng => ath-next merge
conflict resolution.

Link: https://lore.kernel.org/all/4a17d730-ede8-463e-98d8-9b0291d0ca45@oss.qualcomm.com/ # [1]
Signed-off-by: Jeff Johnson <jeff.johnson@oss.qualcomm.com>
master
Jeff Johnson 2025-12-15 08:55:21 -08:00
commit 631ee338f0
78 changed files with 20196 additions and 17407 deletions

View File

@ -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 \
@ -12,11 +10,12 @@ 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 \
@ -24,6 +23,9 @@ ath12k-y += core.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

View File

@ -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>
@ -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"};
@ -130,7 +123,7 @@ 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);
}
@ -138,7 +131,7 @@ static u32 ath12k_ahb_read32(struct ath12k_base *ab, u32 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);
@ -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);
@ -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;
@ -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;
}
@ -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,
@ -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");
@ -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));
@ -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
@ -1065,14 +1086,26 @@ static int ath12k_ahb_probe(struct platform_device *pdev)
goto err_rproc_deconfigure;
}
ret = ath12k_core_init(ab);
/* 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, "failed to init core: %d\n", 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_deinit_arch;
}
return 0;
err_deinit_arch:
ab_ahb->device_family_ops->arch_deinit(ab);
err_rproc_deconfigure:
ath12k_ahb_deconfigure_rproc(ab);
@ -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);
}
@ -1136,21 +1171,47 @@ qmi_fail:
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;
void ath12k_ahb_exit(void)
{
platform_driver_unregister(&ath12k_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_unregister_driver(const enum ath12k_device_family device_id)
{
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);

View File

@ -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)
@ -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;
@ -59,6 +66,15 @@ 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)
@ -66,15 +82,8 @@ 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

View File

@ -1,314 +1,13 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "dp_rx.h"
#include "debug.h"
#include "hif.h"
const struct ce_attr ath12k_host_ce_config_qcn9274[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI (mac0) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target->host pktlog */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_dp_htt_htc_t2h_msg_handler,
},
/* CE6: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: host->target WMI (mac1) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE8: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE9: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE10: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE11: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE12: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE13: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE14: target->host dbg log */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE15: reserved for future use */
{
.flags = (CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};
const struct ce_attr ath12k_host_ce_config_wcn7850[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 64,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI (mac0) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target->host pktlog */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE6: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: host->target WMI (mac1) */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE8: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};
const struct ce_attr ath12k_host_ce_config_ipq5332[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target -> host PKTLOG */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_dp_htt_htc_t2h_msg_handler,
},
/* CE6: Target autonomous HIF_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE8: Target HIF memcpy (Generic HIF memcypy) */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE9: WMI logging/CFR/Spectral/Radar */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
},
/* CE10: Unused */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE11: Unused */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};
static int ath12k_ce_rx_buf_enqueue_pipe(struct ath12k_ce_pipe *pipe,
struct sk_buff *skb, dma_addr_t paddr)
{
@ -341,7 +40,7 @@ static int ath12k_ce_rx_buf_enqueue_pipe(struct ath12k_ce_pipe *pipe,
goto exit;
}
ath12k_hal_ce_dst_set_desc(desc, paddr);
ath12k_hal_ce_dst_set_desc(&ab->hal, desc, paddr);
ring->skb[write_index] = skb;
write_index = CE_RING_IDX_INCR(nentries_mask, write_index);
@ -434,7 +133,7 @@ static int ath12k_ce_completed_recv_next(struct ath12k_ce_pipe *pipe,
goto err;
}
*nbytes = ath12k_hal_ce_dst_status_get_length(desc);
*nbytes = ath12k_hal_ce_dst_status_get_length(&ab->hal, desc);
*skb = pipe->dest_ring->skb[sw_index];
pipe->dest_ring->skb[sw_index] = NULL;
@ -666,6 +365,7 @@ ath12k_ce_alloc_ring(struct ath12k_base *ab, int nentries, int desc_sz)
static int ath12k_ce_alloc_pipe(struct ath12k_base *ab, int ce_id)
{
struct ath12k_hal *hal = &ab->hal;
struct ath12k_ce_pipe *pipe = &ab->ce.ce_pipe[ce_id];
const struct ce_attr *attr = &ab->hw_params->host_ce_config[ce_id];
struct ath12k_ce_ring *ring;
@ -677,7 +377,7 @@ static int ath12k_ce_alloc_pipe(struct ath12k_base *ab, int ce_id)
if (attr->src_nentries) {
pipe->send_cb = ath12k_ce_send_done_cb;
nentries = roundup_pow_of_two(attr->src_nentries);
desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
desc_sz = ath12k_hal_ce_get_desc_size(hal, HAL_CE_DESC_SRC);
ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
if (IS_ERR(ring))
return PTR_ERR(ring);
@ -687,13 +387,13 @@ static int ath12k_ce_alloc_pipe(struct ath12k_base *ab, int ce_id)
if (attr->dest_nentries) {
pipe->recv_cb = attr->recv_cb;
nentries = roundup_pow_of_two(attr->dest_nentries);
desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
desc_sz = ath12k_hal_ce_get_desc_size(hal, HAL_CE_DESC_DST);
ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
if (IS_ERR(ring))
return PTR_ERR(ring);
pipe->dest_ring = ring;
desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
desc_sz = ath12k_hal_ce_get_desc_size(hal, HAL_CE_DESC_DST_STATUS);
ring = ath12k_ce_alloc_ring(ab, nentries, desc_sz);
if (IS_ERR(ring))
return PTR_ERR(ring);
@ -786,7 +486,7 @@ int ath12k_ce_send(struct ath12k_base *ab, struct sk_buff *skb, u8 pipe_id,
if (pipe->attr_flags & CE_ATTR_BYTE_SWAP_DATA)
byte_swap_data = 1;
ath12k_hal_ce_src_set_desc(desc, ATH12K_SKB_CB(skb)->paddr,
ath12k_hal_ce_src_set_desc(&ab->hal, desc, ATH12K_SKB_CB(skb)->paddr,
skb->len, transfer_id, byte_swap_data);
pipe->src_ring->skb[write_index] = skb;
@ -972,6 +672,7 @@ int ath12k_ce_init_pipes(struct ath12k_base *ab)
void ath12k_ce_free_pipes(struct ath12k_base *ab)
{
struct ath12k_hal *hal = &ab->hal;
struct ath12k_ce_pipe *pipe;
int desc_sz;
int i;
@ -980,7 +681,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab)
pipe = &ab->ce.ce_pipe[i];
if (pipe->src_ring) {
desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_SRC);
desc_sz = ath12k_hal_ce_get_desc_size(hal,
HAL_CE_DESC_SRC);
dma_free_coherent(ab->dev,
pipe->src_ring->nentries * desc_sz +
CE_DESC_RING_ALIGN,
@ -991,7 +693,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab)
}
if (pipe->dest_ring) {
desc_sz = ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST);
desc_sz = ath12k_hal_ce_get_desc_size(hal,
HAL_CE_DESC_DST);
dma_free_coherent(ab->dev,
pipe->dest_ring->nentries * desc_sz +
CE_DESC_RING_ALIGN,
@ -1003,7 +706,8 @@ void ath12k_ce_free_pipes(struct ath12k_base *ab)
if (pipe->status_ring) {
desc_sz =
ath12k_hal_ce_get_desc_size(HAL_CE_DESC_DST_STATUS);
ath12k_hal_ce_get_desc_size(hal,
HAL_CE_DESC_DST_STATUS);
dma_free_coherent(ab->dev,
pipe->status_ring->nentries * desc_sz +
CE_DESC_RING_ALIGN,

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_CE_H
@ -85,6 +85,7 @@ struct ce_ie_addr {
struct ce_remap {
u32 base;
u32 size;
u32 cmem_offset;
};
struct ce_attr {
@ -173,10 +174,6 @@ struct ath12k_ce {
struct ath12k_hp_update_timer hp_timer[CE_COUNT_MAX];
};
extern const struct ce_attr ath12k_host_ce_config_qcn9274[];
extern const struct ce_attr ath12k_host_ce_config_wcn7850[];
extern const struct ce_attr ath12k_host_ce_config_ipq5332[];
void ath12k_ce_cleanup_pipes(struct ath12k_base *ab);
void ath12k_ce_rx_replenish_retry(struct timer_list *t);
void ath12k_ce_per_engine_service(struct ath12k_base *ab, u16 ce_id);

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_CMN_DEFS_H
#define ATH12K_CMN_DEFS_H
#include <net/mac80211.h>
#define MAX_RADIOS 2
#define ATH12K_MAX_DEVICES 3
#define ATH12K_GROUP_MAX_RADIO (ATH12K_MAX_DEVICES * MAX_RADIOS)
#define ATH12K_SCAN_MAX_LINKS ATH12K_GROUP_MAX_RADIO
/* Define 1 scan link for each radio for parallel scan purposes */
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + ATH12K_SCAN_MAX_LINKS)
#define MAX_MU_GROUP_ID 64
#endif

View File

@ -21,15 +21,18 @@
#include "hif.h"
#include "pci.h"
#include "wow.h"
#include "dp_cmn.h"
#include "peer.h"
static int ahb_err, pci_err;
unsigned int ath12k_debug_mask;
module_param_named(debug_mask, ath12k_debug_mask, uint, 0644);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
EXPORT_SYMBOL(ath12k_debug_mask);
bool ath12k_ftm_mode;
module_param_named(ftm_mode, ath12k_ftm_mode, bool, 0444);
MODULE_PARM_DESC(ftm_mode, "Boots up in factory test mode");
EXPORT_SYMBOL(ath12k_ftm_mode);
/* protected with ath12k_hw_group_mutex */
static struct list_head ath12k_hw_group_list = LIST_HEAD_INIT(ath12k_hw_group_list);
@ -632,6 +635,7 @@ u32 ath12k_core_get_max_peers_per_radio(struct ath12k_base *ab)
{
return ath12k_core_get_max_station_per_radio(ab) + TARGET_NUM_VDEVS(ab);
}
EXPORT_SYMBOL(ath12k_core_get_max_peers_per_radio);
struct reserved_mem *ath12k_core_get_reserved_mem(struct ath12k_base *ab,
int index)
@ -700,6 +704,8 @@ void ath12k_core_to_group_ref_put(struct ath12k_base *ab)
static void ath12k_core_stop(struct ath12k_base *ab)
{
ath12k_link_sta_rhash_tbl_destroy(ab);
ath12k_core_to_group_ref_put(ab);
if (!test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
@ -710,7 +716,7 @@ static void ath12k_core_stop(struct ath12k_base *ab)
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 */
}
@ -895,7 +901,7 @@ static int ath12k_core_start(struct ath12k_base *ab)
goto err_hif_stop;
}
ret = ath12k_dp_htt_connect(&ab->dp);
ret = ath12k_dp_htt_connect(ath12k_ab_to_dp(ab));
if (ret) {
ath12k_err(ab, "failed to connect to HTT: %d\n", ret);
goto err_hif_stop;
@ -920,7 +926,7 @@ static int ath12k_core_start(struct ath12k_base *ab)
goto err_hif_stop;
}
ath12k_dp_cc_config(ab);
ath12k_hal_cc_config(ab);
ret = ath12k_dp_rx_pdev_reo_setup(ab);
if (ret) {
@ -928,8 +934,6 @@ static int ath12k_core_start(struct ath12k_base *ab)
goto err_hif_stop;
}
ath12k_dp_hal_rx_desc_init(ab);
ret = ath12k_wmi_cmd_init(ab);
if (ret) {
ath12k_err(ab, "failed to send wmi init cmd: %d\n", ret);
@ -964,6 +968,12 @@ static int ath12k_core_start(struct ath12k_base *ab)
/* Indicate the core start in the appropriate group */
ath12k_core_to_group_ref_get(ab);
ret = ath12k_link_sta_rhash_tbl_init(ab);
if (ret) {
ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
goto err_reo_cleanup;
}
return 0;
err_reo_cleanup:
@ -1288,7 +1298,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
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;
@ -1300,7 +1310,7 @@ int ath12k_core_qmi_firmware_ready(struct ath12k_base *ab)
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);
@ -1333,8 +1343,8 @@ err_core_stop:
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);
@ -1350,13 +1360,14 @@ static int ath12k_core_reconfigure_on_crash(struct ath12k_base *ab)
int ret, total_vdev;
mutex_lock(&ab->core_lock);
ath12k_link_sta_rhash_tbl_destroy(ab);
ath12k_dp_pdev_free(ab);
ath12k_ce_cleanup_pipes(ab);
ath12k_wmi_detach(ab);
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;
@ -1565,6 +1576,7 @@ static void ath12k_core_post_reconfigure_recovery(struct ath12k_base *ab)
ath12k_core_halt(ar);
}
ath12k_mac_dp_peer_cleanup(ah);
break;
case ATH12K_HW_STATE_OFF:
ath12k_warn(ab,
@ -1739,17 +1751,11 @@ enum ath12k_qmi_mem_mode ath12k_core_get_memory_mode(struct ath12k_base *ab)
return ATH12K_QMI_MEMORY_MODE_DEFAULT;
}
EXPORT_SYMBOL(ath12k_core_get_memory_mode);
int ath12k_core_pre_init(struct ath12k_base *ab)
{
const struct ath12k_mem_profile_based_param *param;
int ret;
ret = ath12k_hw_init(ab);
if (ret) {
ath12k_err(ab, "failed to init hw params: %d\n", ret);
return ret;
}
param = &ath12k_mem_profile_based_param[ab->target_mem_mode];
ab->profile_param = param;
@ -1996,6 +2002,8 @@ exit:
ag->ab[ab->device_id] = ab;
ab->ag = ag;
ath12k_dp_cmn_hw_group_assign(ath12k_ab_to_dp(ab), ag);
ath12k_dbg(ab, ATH12K_DBG_BOOT, "wsi group-id %d num-devices %d index %d",
ag->id, ag->num_devices, wsi->index);
@ -2023,6 +2031,8 @@ void ath12k_core_hw_group_unassign(struct ath12k_base *ab)
return;
}
ath12k_dp_cmn_hw_group_unassign(ath12k_ab_to_dp(ab), ag);
ag->ab[device_id] = NULL;
ab->ag = NULL;
ab->device_id = ATH12K_INVALID_DEVICE_ID;
@ -2253,7 +2263,6 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
spin_lock_init(&ab->base_lock);
init_completion(&ab->reset_complete);
INIT_LIST_HEAD(&ab->peers);
init_waitqueue_head(&ab->peer_mapping_wq);
init_waitqueue_head(&ab->wmi_ab.tx_credits_wq);
INIT_WORK(&ab->restart_work, ath12k_core_restart);
@ -2291,31 +2300,5 @@ err_sc_free:
return NULL;
}
static int ath12k_init(void)
{
ahb_err = ath12k_ahb_init();
if (ahb_err)
pr_warn("Failed to initialize ath12k AHB device: %d\n", ahb_err);
pci_err = ath12k_pci_init();
if (pci_err)
pr_warn("Failed to initialize ath12k PCI device: %d\n", pci_err);
/* If both failed, return one of the failures (arbitrary) */
return ahb_err && pci_err ? ahb_err : 0;
}
static void ath12k_exit(void)
{
if (!pci_err)
ath12k_pci_exit();
if (!ahb_err)
ath12k_ahb_exit();
}
module_init(ath12k_init);
module_exit(ath12k_exit);
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN devices");
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -18,6 +18,7 @@
#include <linux/panic_notifier.h>
#include <linux/average.h>
#include <linux/of.h>
#include <linux/rhashtable.h>
#include "qmi.h"
#include "htc.h"
#include "wmi.h"
@ -26,7 +27,6 @@
#include "ce.h"
#include "mac.h"
#include "hw.h"
#include "hal_rx.h"
#include "reg.h"
#include "dbring.h"
#include "fw.h"
@ -34,6 +34,8 @@
#include "wow.h"
#include "debugfs_htt_stats.h"
#include "coredump.h"
#include "cmn_defs.h"
#include "dp_cmn.h"
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@ -64,8 +66,6 @@
#define ATH12K_RECONFIGURE_TIMEOUT_HZ (10 * HZ)
#define ATH12K_RECOVER_START_TIMEOUT_HZ (20 * HZ)
#define ATH12K_MAX_DEVICES 3
#define ATH12K_GROUP_MAX_RADIO (ATH12K_MAX_DEVICES * MAX_RADIOS)
#define ATH12K_INVALID_GROUP_ID 0xFF
#define ATH12K_INVALID_DEVICE_ID 0xFF
@ -310,16 +310,9 @@ struct ath12k_link_vif {
u32 vdev_id;
u32 beacon_interval;
u32 dtim_period;
u16 ast_hash;
u16 ast_idx;
u16 tcl_metadata;
u8 hal_addr_search_flags;
u8 search_type;
struct ath12k *ar;
int bank_id;
u8 vdev_id_check_en;
bool beacon_prot;
struct wmi_wmm_params_all_arg wmm_params;
@ -360,6 +353,8 @@ struct ath12k_link_vif {
};
struct ath12k_vif {
struct ath12k_dp_vif dp_vif;
enum wmi_vdev_type vdev_type;
enum wmi_vdev_subtype vdev_subtype;
struct ieee80211_vif *vif;
@ -383,10 +378,7 @@ struct ath12k_vif {
} u;
u32 aid;
u32 key_cipher;
u8 tx_encap_type;
bool ps;
atomic_t mcbc_gsn;
struct ath12k_link_vif deflink;
struct ath12k_link_vif __rcu *link[ATH12K_NUM_MAX_LINKS];
@ -407,51 +399,8 @@ struct ath12k_vif_iter {
struct ath12k_link_vif *arvif;
};
#define HAL_AST_IDX_INVALID 0xFFFF
#define HAL_RX_MAX_MCS 12
#define HAL_RX_MAX_MCS_HT 31
#define HAL_RX_MAX_MCS_VHT 9
#define HAL_RX_MAX_MCS_HE 11
#define HAL_RX_MAX_MCS_BE 15
#define HAL_RX_MAX_NSS 8
#define HAL_RX_MAX_NUM_LEGACY_RATES 12
#define ATH12K_SCAN_TIMEOUT_HZ (20 * HZ)
struct ath12k_rx_peer_rate_stats {
u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1];
u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1];
u64 he_mcs_count[HAL_RX_MAX_MCS_HE + 1];
u64 be_mcs_count[HAL_RX_MAX_MCS_BE + 1];
u64 nss_count[HAL_RX_MAX_NSS];
u64 bw_count[HAL_RX_BW_MAX];
u64 gi_count[HAL_RX_GI_MAX];
u64 legacy_count[HAL_RX_MAX_NUM_LEGACY_RATES];
u64 rx_rate[HAL_RX_BW_MAX][HAL_RX_GI_MAX][HAL_RX_MAX_NSS][HAL_RX_MAX_MCS_HT + 1];
};
struct ath12k_rx_peer_stats {
u64 num_msdu;
u64 num_mpdu_fcs_ok;
u64 num_mpdu_fcs_err;
u64 tcp_msdu_count;
u64 udp_msdu_count;
u64 other_msdu_count;
u64 ampdu_msdu_count;
u64 non_ampdu_msdu_count;
u64 stbc_count;
u64 beamformed_count;
u64 coding_count[HAL_RX_SU_MU_CODING_MAX];
u64 tid_count[IEEE80211_NUM_TIDS + 1];
u64 pream_cnt[HAL_RX_PREAMBLE_MAX];
u64 reception_type[HAL_RX_RECEPTION_TYPE_MAX];
u64 rx_duration;
u64 dcm_count;
u64 ru_alloc_cnt[HAL_RX_RU_ALLOC_TYPE_MAX];
struct ath12k_rx_peer_rate_stats pkt_stats;
struct ath12k_rx_peer_rate_stats byte_stats;
};
#define ATH12K_HE_MCS_NUM 12
#define ATH12K_VHT_MCS_NUM 10
#define ATH12K_BW_NUM 5
@ -533,12 +482,6 @@ struct ath12k_per_ppdu_tx_stats {
u32 retry_bytes;
};
struct ath12k_wbm_tx_stats {
u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX];
};
DECLARE_EWMA(avg_rssi, 10, 8)
struct ath12k_link_sta {
struct ath12k_link_vif *arvif;
struct ath12k_sta *ahsta;
@ -553,15 +496,7 @@ struct ath12k_link_sta {
u32 smps;
struct wiphy_work update_wk;
struct rate_info txrate;
struct rate_info last_txrate;
u64 rx_duration;
u64 tx_duration;
u8 rssi_comb;
struct ewma_avg_rssi avg_rssi;
u8 link_id;
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_wbm_tx_stats *wbm_tx_stats;
u32 bw_prev;
u32 peer_nss;
s8 rssi_beacon;
@ -572,14 +507,9 @@ struct ath12k_link_sta {
/* for firmware use only */
u8 link_idx;
u32 tx_retry_failed;
u32 tx_retry_count;
};
struct ath12k_reoq_buf {
void *vaddr;
dma_addr_t paddr_aligned;
u32 size;
/* peer addr based rhashtable list pointer */
struct rhash_head rhash_addr;
};
struct ath12k_sta {
@ -594,8 +524,6 @@ struct ath12k_sta {
u8 num_peer;
enum ieee80211_sta_state state;
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
};
#define ATH12K_HALF_20MHZ_BW 10
@ -667,23 +595,6 @@ struct ath12k_debug {
bool extd_rx_stats;
};
struct ath12k_per_peer_tx_stats {
u32 succ_bytes;
u32 retry_bytes;
u32 failed_bytes;
u32 duration;
u16 succ_pkts;
u16 retry_pkts;
u16 failed_pkts;
u16 ru_start;
u16 ru_tones;
u8 ba_fails;
u8 ppdu_type;
u32 mu_grpid;
u32 mu_pos;
bool is_ampdu;
};
struct ath12k_pdev_rssi_offsets {
s32 temp_offset;
s8 min_nf_dbm;
@ -809,9 +720,6 @@ struct ath12k {
struct ath12k_wow wow;
struct completion target_suspend;
bool target_suspend_ack;
struct ath12k_per_peer_tx_stats peer_tx_stats;
struct list_head ppdu_stats_info;
u32 ppdu_stat_list_depth;
struct ath12k_per_peer_tx_stats cached_stats;
u32 last_ppdu_id;
@ -866,8 +774,7 @@ struct ath12k_hw {
DECLARE_BITMAP(free_ml_peer_id_map, ATH12K_MAX_MLO_PEERS);
/* protected by wiphy_lock() */
struct list_head ml_peers;
struct ath12k_dp_hw dp_hw;
/* Keep last */
struct ath12k radio[] __aligned(sizeof(void *));
@ -941,32 +848,6 @@ struct ath12k_board_data {
size_t len;
};
struct ath12k_device_dp_tx_err_stats {
/* TCL Ring Descriptor unavailable */
u32 desc_na[DP_TCL_NUM_RING_MAX];
/* Other failures during dp_tx due to mem allocation failure
* idr unavailable etc.
*/
atomic_t misc_fail;
};
struct ath12k_device_dp_stats {
u32 err_ring_pkts;
u32 invalid_rbm;
u32 rxdma_error[HAL_REO_ENTR_RING_RXDMA_ECODE_MAX];
u32 reo_error[HAL_REO_DEST_RING_ERROR_CODE_MAX];
u32 hal_reo_error[DP_REO_DST_RING_MAX];
struct ath12k_device_dp_tx_err_stats tx_err;
u32 reo_rx[DP_REO_DST_RING_MAX][ATH12K_MAX_DEVICES];
u32 rx_wbm_rel_source[HAL_WBM_REL_SRC_MODULE_MAX][ATH12K_MAX_DEVICES];
u32 tqm_rel_reason[MAX_TQM_RELEASE_REASON];
u32 fw_tx_status[MAX_FW_TX_STATUS];
u32 tx_wbm_rel_source[HAL_WBM_REL_SRC_MODULE_MAX];
u32 tx_enqueued[DP_TCL_NUM_RING_MAX];
u32 tx_completed[DP_TCL_NUM_RING_MAX];
u32 reo_excep_msdu_buf_type;
};
struct ath12k_reg_freq {
u32 start_freq;
u32 end_freq;
@ -987,6 +868,11 @@ struct ath12k_hw_link {
* wiphy, protected with struct ath12k_hw_group::mutex.
*/
struct ath12k_hw_group {
/* Keep dp_hw_grp as the first member to allow efficient
* usage of cache lines for DP fields
*/
struct ath12k_dp_hw_group dp_hw_grp;
struct ath12k_hw_link hw_links[ATH12K_GROUP_MAX_RADIO];
struct list_head list;
u8 id;
u8 num_devices;
@ -1009,7 +895,6 @@ struct ath12k_hw_group {
bool mlo_capable;
struct device_node *wsi_node[ATH12K_MAX_DEVICES];
struct ath12k_mlo_memory mlo_mem;
struct ath12k_hw_link hw_links[ATH12K_GROUP_MAX_RADIO];
bool hw_link_id_init_done;
};
@ -1035,6 +920,12 @@ struct ath12k_mem_profile_based_param {
struct ath12k_dp_profile_params dp_params;
};
enum ath12k_device_family {
ATH12K_DEVICE_FAMILY_START,
ATH12K_DEVICE_FAMILY_WIFI7 = ATH12K_DEVICE_FAMILY_START,
ATH12K_DEVICE_FAMILY_MAX,
};
/* Master structure to hold the hw data which may be used in core module */
struct ath12k_base {
enum ath12k_hw_rev hw_rev;
@ -1054,13 +945,14 @@ struct ath12k_base {
struct ath12k_htc htc;
struct ath12k_dp dp;
struct ath12k_dp *dp;
void __iomem *mem;
unsigned long mem_len;
void __iomem *mem_ce;
u32 ce_remap_base_addr;
u32 cmem_offset;
bool ce_remap;
struct {
@ -1105,7 +997,6 @@ struct ath12k_base {
struct ath12k_wmi_hal_reg_capabilities_ext_arg hal_reg_cap[MAX_RADIOS];
unsigned long long free_vdev_map;
unsigned long long free_vdev_stats_id_map;
struct list_head peers;
wait_queue_head_t peer_mapping_wq;
u8 mac_addr[ETH_ALEN];
bool wmi_ready;
@ -1135,7 +1026,6 @@ struct ath12k_base {
/* Current DFS Regulatory */
enum ath12k_dfs_region dfs_region;
struct ath12k_device_dp_stats device_stats;
#ifdef CONFIG_ATH12K_DEBUGFS
struct dentry *debugfs_soc;
#endif
@ -1196,8 +1086,6 @@ struct ath12k_base {
bool fw_features_valid;
} fw;
const struct hal_rx_ops *hal_rx_ops;
struct completion restart_completed;
#ifdef CONFIG_ACPI
@ -1241,6 +1129,14 @@ struct ath12k_base {
const struct ath12k_mem_profile_based_param *profile_param;
enum ath12k_qmi_mem_mode target_mem_mode;
/* FIXME: Define this field in a ag equivalent object available
* during the initial phase of probe later.
*/
const struct ieee80211_ops *ath12k_ops;
struct rhashtable *rhead_sta_addr;
struct rhashtable_params rhash_sta_addr_param;
/* must be last */
u8 drv_priv[] __aligned(sizeof(void *));
};
@ -1516,4 +1412,18 @@ static inline s32 ath12k_pdev_get_noise_floor(struct ath12k *ar)
return ar->rssi_info.noise_floor;
}
/* The @ab->dp NULL check or assertion is intentionally omitted because
* @ab->dp is guaranteed to be non-NULL after a successful probe and
* remains valid until teardown. Invoking this before allocation or
* after teardown is considered invalid usage.
*/
static inline struct ath12k_dp *ath12k_ab_to_dp(struct ath12k_base *ab)
{
return ab->dp;
}
static inline struct ath12k *ath12k_pdev_dp_to_ar(struct ath12k_pdev_dp *dp)
{
return container_of(dp, struct ath12k, dp);
}
#endif /* _CORE_H_ */

View File

@ -1,12 +1,12 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2023 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "debug.h"
#include "hal.h"
static int ath12k_dbring_bufs_replenish(struct ath12k *ar,
struct ath12k_dbring *ring,
@ -55,7 +55,7 @@ static int ath12k_dbring_bufs_replenish(struct ath12k *ar,
cookie = u32_encode_bits(ar->pdev_idx, DP_RXDMA_BUF_COOKIE_PDEV_ID) |
u32_encode_bits(buf_id, DP_RXDMA_BUF_COOKIE_BUF_ID);
ath12k_hal_rx_buf_addr_info_set(desc, paddr, cookie, 0);
ath12k_hal_rx_buf_addr_info_set(&ab->hal, desc, paddr, cookie, 0);
ath12k_hal_srng_access_end(ab, srng);
@ -298,7 +298,7 @@ int ath12k_dbring_buffer_release_event(struct ath12k_base *ab,
num_buff_reaped++;
ath12k_hal_rx_buf_addr_info_get(&desc, &paddr, &cookie, &rbm);
ath12k_hal_rx_buf_addr_info_get(&ab->hal, &desc, &paddr, &cookie, &rbm);
buf_id = u32_get_bits(cookie, DP_RXDMA_BUF_COOKIE_BUF_ID);

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-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.
*
*/
#include <linux/vmalloc.h>
@ -21,6 +22,7 @@ void ath12k_info(struct ath12k_base *ab, const char *fmt, ...)
/* TODO: Trace the log */
va_end(args);
}
EXPORT_SYMBOL(ath12k_info);
void ath12k_err(struct ath12k_base *ab, const char *fmt, ...)
{
@ -35,6 +37,7 @@ void ath12k_err(struct ath12k_base *ab, const char *fmt, ...)
/* TODO: Trace the log */
va_end(args);
}
EXPORT_SYMBOL(ath12k_err);
void __ath12k_warn(struct device *dev, const char *fmt, ...)
{
@ -49,6 +52,7 @@ void __ath12k_warn(struct device *dev, const char *fmt, ...)
/* TODO: Trace the log */
va_end(args);
}
EXPORT_SYMBOL(__ath12k_warn);
#ifdef CONFIG_ATH12K_DEBUG
@ -72,6 +76,7 @@ void __ath12k_dbg(struct ath12k_base *ab, enum ath12k_debug_mask mask,
va_end(args);
}
EXPORT_SYMBOL(__ath12k_dbg);
void ath12k_dbg_dump(struct ath12k_base *ab,
enum ath12k_debug_mask mask,
@ -100,5 +105,6 @@ void ath12k_dbg_dump(struct ath12k_base *ab,
}
}
}
EXPORT_SYMBOL(ath12k_dbg_dump);
#endif /* CONFIG_ATH12K_DEBUG */

View File

@ -967,7 +967,7 @@ static int ath12k_open_link_stats(struct inode *inode, struct file *file)
"\nlink[%d] Tx Frame descriptor Encrypt Type = ",
link_id);
for (i = 0; i < HAL_ENCRYPT_TYPE_MAX; i++) {
for (i = 0; i < DP_ENCRYPT_TYPE_MAX; i++) {
len += scnprintf(buf + len, buf_len - len,
" %d:%d", i,
linkstat.tx_encrypt_type[i]);
@ -1020,13 +1020,15 @@ void ath12k_debugfs_op_vif_add(struct ieee80211_hw *hw,
debugfs_create_file("link_stats", 0400, vif->debugfs_dir, ahvif,
&ath12k_fops_link_stats);
}
EXPORT_SYMBOL(ath12k_debugfs_op_vif_add);
static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
char __user *user_buf,
size_t count, loff_t *ppos)
{
struct ath12k_base *ab = file->private_data;
struct ath12k_device_dp_stats *device_stats = &ab->device_stats;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_device_dp_stats *device_stats = &dp->device_stats;
int len = 0, i, j, ret;
struct ath12k *ar;
const int size = 4096;
@ -1155,6 +1157,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
len += scnprintf(buf + len, size - len, "\n");
rcu_read_lock();
for (i = 0; i < ab->num_radios; i++) {
ar = ath12k_mac_get_ar_by_pdev_id(ab, DP_SW2HW_MACID(i));
if (ar) {
@ -1163,6 +1166,7 @@ static ssize_t ath12k_debugfs_dump_device_dp_stats(struct file *file,
atomic_read(&ar->dp.num_tx_pending));
}
}
rcu_read_unlock();
len += scnprintf(buf + len, size - len, "\nREO Rx Received:\n");

View File

@ -1,12 +1,14 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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 DEBUG_HTT_STATS_H
#define DEBUG_HTT_STATS_H
#include "dp_htt.h"
#define ATH12K_HTT_STATS_BUF_SIZE (1024 * 512)
#define ATH12K_HTT_STATS_COOKIE_LSB GENMASK_ULL(31, 0)
#define ATH12K_HTT_STATS_COOKIE_MSB GENMASK_ULL(63, 32)

View File

@ -1,6 +1,6 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/vmalloc.h>
@ -11,6 +11,7 @@
#include "debug.h"
#include "debugfs_htt_stats.h"
#include "debugfs.h"
#include "dp_cmn.h"
static
u32 ath12k_dbg_sta_dump_rate_stats(u8 *buf, u32 offset, const int size,
@ -144,40 +145,40 @@ static ssize_t ath12k_dbg_sta_dump_rx_stats(struct file *file,
const int size = ATH12K_STA_RX_STATS_BUF_SIZE;
struct ath12k_hw *ah = ahsta->ahvif->ah;
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_dp_link_peer *link_peer;
struct ath12k_link_sta *arsta;
u8 link_id = link_sta->link_id;
int len = 0, i, ret = 0;
struct ath12k_dp *dp;
bool he_rates_avail;
struct ath12k *ar;
wiphy_lock(ah->hw->wiphy);
guard(wiphy)(ah->hw->wiphy);
if (!(BIT(link_id) & ahsta->links_map)) {
wiphy_unlock(ah->hw->wiphy);
if (!(BIT(link_id) & ahsta->links_map))
return -ENOENT;
}
arsta = wiphy_dereference(ah->hw->wiphy, ahsta->link[link_id]);
if (!arsta || !arsta->arvif->ar) {
wiphy_unlock(ah->hw->wiphy);
if (!arsta || !arsta->arvif->ar)
return -ENOENT;
}
ar = arsta->arvif->ar;
u8 *buf __free(kfree) = kzalloc(size, GFP_KERNEL);
if (!buf) {
ret = -ENOENT;
goto out;
}
if (!buf)
return -ENOMEM;
spin_lock_bh(&ar->ab->base_lock);
dp = ath12k_ab_to_dp(ar->ab);
rx_stats = arsta->rx_stats;
if (!rx_stats) {
ret = -ENOENT;
goto unlock;
}
guard(spinlock_bh)(&dp->dp_lock);
link_peer = ath12k_dp_link_peer_find_by_addr(dp, arsta->addr);
if (!link_peer)
return -ENOENT;
rx_stats = link_peer->peer_stats.rx_stats;
if (!rx_stats)
return -ENOENT;
len += scnprintf(buf + len, size - len, "RX peer stats:\n\n");
len += scnprintf(buf + len, size - len, "Num of MSDUs: %llu\n",
@ -237,13 +238,8 @@ static ssize_t ath12k_dbg_sta_dump_rx_stats(struct file *file,
len += ath12k_dbg_sta_dump_rate_stats(buf, len, size, he_rates_avail,
&rx_stats->byte_stats);
unlock:
spin_unlock_bh(&ar->ab->base_lock);
if (len)
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
out:
wiphy_unlock(ah->hw->wiphy);
return ret;
}
@ -261,10 +257,9 @@ static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file,
struct ieee80211_link_sta *link_sta = file->private_data;
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(link_sta->sta);
struct ath12k_hw *ah = ahsta->ahvif->ah;
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_link_sta *arsta;
u8 link_id = link_sta->link_id;
struct ath12k *ar;
struct ath12k_link_sta *arsta;
struct ath12k_dp *dp;
bool reset;
int ret;
@ -288,19 +283,9 @@ static ssize_t ath12k_dbg_sta_reset_rx_stats(struct file *file,
goto out;
}
ar = arsta->arvif->ar;
dp = ath12k_ab_to_dp(arsta->arvif->ar->ab);
spin_lock_bh(&ar->ab->base_lock);
rx_stats = arsta->rx_stats;
if (!rx_stats) {
spin_unlock_bh(&ar->ab->base_lock);
ret = -ENOENT;
goto out;
}
memset(rx_stats, 0, sizeof(*rx_stats));
spin_unlock_bh(&ar->ab->base_lock);
ath12k_dp_link_peer_reset_rx_stats(dp, arsta->addr);
ret = count;
out:
@ -335,3 +320,4 @@ void ath12k_debugfs_link_sta_op_add(struct ieee80211_hw *hw,
&fops_reset_rx_stats);
}
}
EXPORT_SYMBOL(ath12k_debugfs_link_sta_op_add);

View File

@ -1,63 +1,58 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-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.
*/
#include <crypto/hash.h>
#include "core.h"
#include "dp_tx.h"
#include "hal_tx.h"
#include "hif.h"
#include "hal.h"
#include "debug.h"
#include "dp_rx.h"
#include "peer.h"
#include "dp_mon.h"
#include "dp_cmn.h"
enum ath12k_dp_desc_type {
ATH12K_DP_TX_DESC,
ATH12K_DP_RX_DESC,
};
static void ath12k_dp_htt_htc_tx_complete(struct ath12k_base *ab,
struct sk_buff *skb)
{
dev_kfree_skb_any(skb);
}
void ath12k_dp_peer_cleanup(struct ath12k *ar, int vdev_id, const u8 *addr)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_peer *peer;
struct ath12k_dp_link_peer *peer;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
/* TODO: Any other peer specific DP cleanup */
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find(ab, vdev_id, addr);
if (!peer) {
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
if (!peer || !peer->dp_peer) {
ath12k_warn(ab, "failed to lookup peer %pM on vdev %d\n",
addr, vdev_id);
spin_unlock_bh(&ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return;
}
if (!peer->primary_link) {
spin_unlock_bh(&ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return;
}
ath12k_dp_rx_peer_tid_cleanup(ar, peer);
crypto_free_shash(peer->tfm_mmic);
peer->dp_setup_done = false;
spin_unlock_bh(&ab->base_lock);
crypto_free_shash(peer->dp_peer->tfm_mmic);
peer->dp_peer->dp_setup_done = false;
spin_unlock_bh(&dp->dp_lock);
}
int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_peer *peer;
struct ath12k_dp_link_peer *peer;
u32 reo_dest;
int ret = 0, tid;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
/* NOTE: reo_dest ring id starts from 1 unlike mac_id which starts from 0 */
reo_dest = ar->dp.mac_id + 1;
@ -92,19 +87,19 @@ int ath12k_dp_peer_setup(struct ath12k *ar, int vdev_id, const u8 *addr)
return 0;
peer_clean:
spin_lock_bh(&ab->base_lock);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_peer_find(ab, vdev_id, addr);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
if (!peer) {
ath12k_warn(ab, "failed to find the peer to del rx tid\n");
spin_unlock_bh(&ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return -ENOENT;
}
for (tid--; tid >= 0; tid--)
ath12k_dp_rx_peer_tid_delete(ar, peer, tid);
ath12k_dp_arch_rx_peer_tid_delete(dp, peer, tid);
spin_unlock_bh(&ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return ret;
}
@ -147,7 +142,7 @@ static int ath12k_dp_srng_calculate_msi_group(struct ath12k_base *ab,
grp_mask = &ab->hw_params->ring_mask->rx_wbm_rel[0];
ring_num = 0;
} else {
map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map;
map = ab->hal.tcl_to_wbm_rbm_map;
for (i = 0; i < ab->hw_params->max_tx_ring; i++) {
if (ring_num == map[i].wbm_ring_num) {
ring_num = i;
@ -338,50 +333,6 @@ int ath12k_dp_srng_setup(struct ath12k_base *ab, struct dp_srng *ring,
return 0;
}
static
u32 ath12k_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
struct ath12k_link_vif *arvif)
{
u32 bank_config = 0;
struct ath12k_vif *ahvif = arvif->ahvif;
/* Only valid for raw frames with HW crypto enabled.
* With SW crypto, mac80211 sets key per packet
*/
if (ahvif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
bank_config |=
u32_encode_bits(ath12k_dp_tx_get_encrypt_type(ahvif->key_cipher),
HAL_TX_BANK_CONFIG_ENCRYPT_TYPE);
bank_config |= u32_encode_bits(ahvif->tx_encap_type,
HAL_TX_BANK_CONFIG_ENCAP_TYPE);
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) |
u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) |
u32_encode_bits(0, HAL_TX_BANK_CONFIG_EPD);
/* only valid if idx_lookup_override is not set in tcl_data_cmd */
if (ahvif->vdev_type == WMI_VDEV_TYPE_STA)
bank_config |= u32_encode_bits(1, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN);
else
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN);
bank_config |= u32_encode_bits(arvif->hal_addr_search_flags & HAL_TX_ADDRX_EN,
HAL_TX_BANK_CONFIG_ADDRX_EN) |
u32_encode_bits(!!(arvif->hal_addr_search_flags &
HAL_TX_ADDRY_EN),
HAL_TX_BANK_CONFIG_ADDRY_EN);
bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0,
HAL_TX_BANK_CONFIG_MESH_EN) |
u32_encode_bits(arvif->vdev_id_check_en,
HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN);
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_DSCP_TIP_MAP_ID);
return bank_config;
}
static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab,
struct ath12k_link_vif *arvif,
struct ath12k_dp *dp)
@ -392,7 +343,7 @@ static int ath12k_dp_tx_get_bank_profile(struct ath12k_base *ab,
bool configure_register = false;
/* convert vdev params into hal_tx_bank_config */
bank_config = ath12k_dp_tx_get_vdev_bank_config(ab, arvif);
bank_config = ath12k_dp_arch_tx_get_vdev_bank_config(dp, arvif);
spin_lock_bh(&dp->tx_bank_lock);
/* TODO: implement using idr kernel framework*/
@ -424,7 +375,8 @@ inc_ref_and_return:
spin_unlock_bh(&dp->tx_bank_lock);
if (configure_register)
ath12k_hal_tx_configure_bank_register(ab, bank_config, bank_id);
ath12k_hal_tx_configure_bank_register(ab,
bank_config, bank_id);
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "dp_htt tcl bank_id %d input 0x%x match 0x%x num_users %u",
bank_id, bank_config, dp->bank_profiles[bank_id].bank_config,
@ -442,7 +394,7 @@ void ath12k_dp_tx_put_bank_profile(struct ath12k_dp *dp, u8 bank_id)
static void ath12k_dp_deinit_bank_profiles(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
kfree(dp->bank_profiles);
dp->bank_profiles = NULL;
@ -450,7 +402,7 @@ static void ath12k_dp_deinit_bank_profiles(struct ath12k_base *ab)
static int ath12k_dp_init_bank_profiles(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
u32 num_tcl_banks = ab->hw_params->num_tcl_banks;
int i;
@ -473,7 +425,7 @@ static int ath12k_dp_init_bank_profiles(struct ath12k_base *ab)
static void ath12k_dp_srng_common_cleanup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i;
ath12k_dp_srng_cleanup(ab, &dp->reo_status_ring);
@ -490,7 +442,7 @@ static void ath12k_dp_srng_common_cleanup(struct ath12k_base *ab)
static int ath12k_dp_srng_common_setup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
const struct ath12k_hal_tcl_to_wbm_rbm_map *map;
struct hal_srng *srng;
int i, ret, tx_comp_ring_num;
@ -506,7 +458,7 @@ static int ath12k_dp_srng_common_setup(struct ath12k_base *ab)
}
for (i = 0; i < ab->hw_params->max_tx_ring; i++) {
map = ab->hw_params->hal_ops->tcl_to_wbm_rbm_map;
map = ab->hal.tcl_to_wbm_rbm_map;
tx_comp_ring_num = map[i].wbm_ring_num;
ret = ath12k_dp_srng_setup(ab, &dp->tx_ring[i].tcl_data_ring,
@ -596,7 +548,7 @@ err:
static void ath12k_dp_scatter_idle_link_desc_cleanup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct hal_wbm_idle_scatter_list *slist = dp->scatter_list;
int i;
@ -616,7 +568,7 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab,
u32 n_link_desc,
u32 last_bank_sz)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct dp_link_desc_bank *link_desc_banks = dp->link_desc_banks;
struct hal_wbm_idle_scatter_list *slist = dp->scatter_list;
u32 n_entries_per_buf;
@ -659,7 +611,7 @@ static int ath12k_dp_scatter_idle_link_desc_setup(struct ath12k_base *ab,
paddr = link_desc_banks[i].paddr;
while (n_entries) {
cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i);
ath12k_hal_set_link_desc_addr(scatter_buf, cookie,
ath12k_hal_set_link_desc_addr(dp->hal, scatter_buf, cookie,
paddr, rbm);
n_entries--;
paddr += HAL_LINK_DESC_SIZE;
@ -710,7 +662,7 @@ static int ath12k_dp_link_desc_bank_alloc(struct ath12k_base *ab,
int n_link_desc_bank,
int last_bank_sz)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i;
int ret = 0;
int desc_sz = DP_LINK_DESC_ALLOC_SIZE_THRESH;
@ -758,7 +710,7 @@ void ath12k_dp_link_desc_cleanup(struct ath12k_base *ab,
static int ath12k_wbm_idle_ring_setup(struct ath12k_base *ab, u32 *n_link_desc)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
u32 n_mpdu_link_desc, n_mpdu_queue_desc;
u32 n_tx_msdu_link_desc, n_rx_msdu_link_desc;
int ret = 0;
@ -797,6 +749,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab,
u32 ring_type, struct hal_srng *srng,
u32 n_link_desc)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
u32 tot_mem_sz;
u32 n_link_desc_bank, last_bank_sz;
u32 entry_sz, align_bytes, n_entries;
@ -804,7 +757,7 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab,
u32 paddr;
int i, ret;
u32 cookie;
enum hal_rx_buf_return_buf_manager rbm = ab->dp.idle_link_rbm;
enum hal_rx_buf_return_buf_manager rbm = dp->idle_link_rbm;
tot_mem_sz = n_link_desc * HAL_LINK_DESC_SIZE;
tot_mem_sz += HAL_LINK_DESC_ALIGN;
@ -865,7 +818,8 @@ int ath12k_dp_link_desc_setup(struct ath12k_base *ab,
while (n_entries &&
(desc = ath12k_hal_srng_src_get_next_entry(ab, srng))) {
cookie = DP_LINK_DESC_COOKIE_SET(n_entries, i);
ath12k_hal_set_link_desc_addr(desc, cookie, paddr, rbm);
ath12k_hal_set_link_desc_addr(dp->hal, desc, cookie, paddr,
rbm);
n_entries--;
paddr += HAL_LINK_DESC_SIZE;
}
@ -883,134 +837,19 @@ fail_desc_bank_free:
return ret;
}
int ath12k_dp_service_srng(struct ath12k_base *ab,
struct ath12k_ext_irq_grp *irq_grp,
int budget)
{
struct napi_struct *napi = &irq_grp->napi;
int grp_id = irq_grp->grp_id;
int work_done = 0;
int i = 0, j;
int tot_work_done = 0;
enum dp_monitor_mode monitor_mode;
u8 ring_mask;
if (ab->hw_params->ring_mask->tx[grp_id]) {
i = fls(ab->hw_params->ring_mask->tx[grp_id]) - 1;
ath12k_dp_tx_completion_handler(ab, i);
}
if (ab->hw_params->ring_mask->rx_err[grp_id]) {
work_done = ath12k_dp_rx_process_err(ab, napi, budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (ab->hw_params->ring_mask->rx_wbm_rel[grp_id]) {
work_done = ath12k_dp_rx_process_wbm_err(ab,
napi,
budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (ab->hw_params->ring_mask->rx[grp_id]) {
i = fls(ab->hw_params->ring_mask->rx[grp_id]) - 1;
work_done = ath12k_dp_rx_process(ab, i, napi,
budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (ab->hw_params->ring_mask->rx_mon_status[grp_id]) {
ring_mask = ab->hw_params->ring_mask->rx_mon_status[grp_id];
for (i = 0; i < ab->num_radios; i++) {
for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) {
int id = i * ab->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_dp_mon_process_ring(ab, id, napi, budget,
0);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (ab->hw_params->ring_mask->rx_mon_dest[grp_id]) {
monitor_mode = ATH12K_DP_RX_MONITOR_MODE;
ring_mask = ab->hw_params->ring_mask->rx_mon_dest[grp_id];
for (i = 0; i < ab->num_radios; i++) {
for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) {
int id = i * ab->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_dp_mon_process_ring(ab, id, napi, budget,
monitor_mode);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (ab->hw_params->ring_mask->tx_mon_dest[grp_id]) {
monitor_mode = ATH12K_DP_TX_MONITOR_MODE;
ring_mask = ab->hw_params->ring_mask->tx_mon_dest[grp_id];
for (i = 0; i < ab->num_radios; i++) {
for (j = 0; j < ab->hw_params->num_rxdma_per_pdev; j++) {
int id = i * ab->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_dp_mon_process_ring(ab, id, napi, budget,
monitor_mode);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (ab->hw_params->ring_mask->reo_status[grp_id])
ath12k_dp_rx_process_reo_status(ab);
if (ab->hw_params->ring_mask->host2rxdma[grp_id]) {
struct ath12k_dp *dp = &ab->dp;
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
LIST_HEAD(list);
ath12k_dp_rx_bufs_replenish(ab, rx_ring, &list, 0);
}
/* TODO: Implement handler for other interrupts */
done:
return tot_work_done;
}
void ath12k_dp_pdev_free(struct ath12k_base *ab)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k *ar;
int i;
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
rcu_assign_pointer(dp->dp_pdevs[ar->pdev_idx], NULL);
}
synchronize_rcu();
for (i = 0; i < ab->num_radios; i++)
ath12k_dp_rx_pdev_free(ab, i);
}
@ -1025,31 +864,10 @@ void ath12k_dp_pdev_pre_alloc(struct ath12k *ar)
/* TODO: Add any RXDMA setup required per pdev */
}
bool ath12k_dp_wmask_compaction_rx_tlv_supported(struct ath12k_base *ab)
{
if (test_bit(WMI_TLV_SERVICE_WMSK_COMPACTION_RX_TLVS, ab->wmi_ab.svc_map) &&
ab->hw_params->hal_ops->rxdma_ring_wmask_rx_mpdu_start &&
ab->hw_params->hal_ops->rxdma_ring_wmask_rx_msdu_end &&
ab->hw_params->hal_ops->get_hal_rx_compact_ops) {
return true;
}
return false;
}
void ath12k_dp_hal_rx_desc_init(struct ath12k_base *ab)
{
if (ath12k_dp_wmask_compaction_rx_tlv_supported(ab)) {
/* RX TLVS compaction is supported, hence change the hal_rx_ops
* to compact hal_rx_ops.
*/
ab->hal_rx_ops = ab->hw_params->hal_ops->get_hal_rx_compact_ops();
}
ab->hal.hal_desc_sz =
ab->hal_rx_ops->rx_desc_get_desc_size();
}
int ath12k_dp_pdev_alloc(struct ath12k_base *ab)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_pdev_dp *dp_pdev;
struct ath12k *ar;
int ret;
int i;
@ -1061,6 +879,14 @@ int ath12k_dp_pdev_alloc(struct ath12k_base *ab)
/* TODO: Per-pdev rx ring unlike tx ring which is mapped to different AC's */
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
dp_pdev = &ar->dp;
dp_pdev->hw = ar->ah->hw;
dp_pdev->dp = dp;
dp_pdev->hw_link_id = ar->hw_link_id;
dp_pdev->dp_hw = &ar->ah->dp_hw;
ret = ath12k_dp_rx_pdev_alloc(ab, i);
if (ret) {
ath12k_warn(ab, "failed to allocate pdev rx for pdev_id :%d\n",
@ -1074,6 +900,11 @@ int ath12k_dp_pdev_alloc(struct ath12k_base *ab)
}
}
for (i = 0; i < ab->num_radios; i++) {
ar = ab->pdevs[i].ar;
rcu_assign_pointer(dp->dp_pdevs[ar->pdev_idx], &ar->dp);
}
return 0;
err:
ath12k_dp_pdev_free(ab);
@ -1081,40 +912,23 @@ out:
return ret;
}
int ath12k_dp_htt_connect(struct ath12k_dp *dp)
{
struct ath12k_htc_svc_conn_req conn_req = {};
struct ath12k_htc_svc_conn_resp conn_resp = {};
int status;
conn_req.ep_ops.ep_tx_complete = ath12k_dp_htt_htc_tx_complete;
conn_req.ep_ops.ep_rx_complete = ath12k_dp_htt_htc_t2h_msg_handler;
/* connect to control service */
conn_req.service_id = ATH12K_HTC_SVC_ID_HTT_DATA_MSG;
status = ath12k_htc_connect_service(&dp->ab->htc, &conn_req,
&conn_resp);
if (status)
return status;
dp->eid = conn_resp.eid;
return 0;
}
static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif)
{
u8 link_id = arvif->link_id;
struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k_dp_link_vif *dp_link_vif;
dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, link_id);
switch (arvif->ahvif->vdev_type) {
case WMI_VDEV_TYPE_STA:
arvif->hal_addr_search_flags = HAL_TX_ADDRY_EN;
arvif->search_type = HAL_TX_ADDR_SEARCH_INDEX;
dp_link_vif->hal_addr_search_flags = HAL_TX_ADDRY_EN;
dp_link_vif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT;
break;
case WMI_VDEV_TYPE_AP:
case WMI_VDEV_TYPE_IBSS:
arvif->hal_addr_search_flags = HAL_TX_ADDRX_EN;
arvif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT;
dp_link_vif->hal_addr_search_flags = HAL_TX_ADDRX_EN;
dp_link_vif->search_type = HAL_TX_ADDR_SEARCH_DEFAULT;
break;
case WMI_VDEV_TYPE_MONITOR:
default:
@ -1125,22 +939,29 @@ static void ath12k_dp_update_vdev_search(struct ath12k_link_vif *arvif)
void ath12k_dp_vdev_tx_attach(struct ath12k *ar, struct ath12k_link_vif *arvif)
{
struct ath12k_base *ab = ar->ab;
struct ath12k_vif *ahvif = arvif->ahvif;
u8 link_id = arvif->link_id;
int bank_id;
struct ath12k_dp_link_vif *dp_link_vif;
arvif->tcl_metadata |= u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) |
u32_encode_bits(arvif->vdev_id,
HTT_TCL_META_DATA_VDEV_ID) |
u32_encode_bits(ar->pdev->pdev_id,
HTT_TCL_META_DATA_PDEV_ID);
dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, link_id);
dp_link_vif->tcl_metadata |= u32_encode_bits(1, HTT_TCL_META_DATA_TYPE) |
u32_encode_bits(arvif->vdev_id,
HTT_TCL_META_DATA_VDEV_ID) |
u32_encode_bits(ar->pdev->pdev_id,
HTT_TCL_META_DATA_PDEV_ID);
/* set HTT extension valid bit to 0 by default */
arvif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
dp_link_vif->tcl_metadata &= ~HTT_TCL_META_DATA_VALID_HTT;
ath12k_dp_update_vdev_search(arvif);
arvif->vdev_id_check_en = true;
arvif->bank_id = ath12k_dp_tx_get_bank_profile(ab, arvif, &ab->dp);
dp_link_vif->vdev_id_check_en = true;
bank_id = ath12k_dp_tx_get_bank_profile(ab, arvif, ath12k_ab_to_dp(ab));
dp_link_vif->bank_id = bank_id;
/* TODO: error path for bank id failure */
if (arvif->bank_id == DP_INVALID_BANK_ID) {
if (bank_id == DP_INVALID_BANK_ID) {
ath12k_err(ar->ab, "Failed to initialize DP TX Banks");
return;
}
@ -1150,7 +971,7 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
{
struct ath12k_rx_desc_info *desc_info;
struct ath12k_tx_desc_info *tx_desc_info, *tmp1;
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_skb_cb *skb_cb;
struct sk_buff *skb;
struct ath12k *ar;
@ -1273,15 +1094,13 @@ static void ath12k_dp_cc_cleanup(struct ath12k_base *ab)
static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
if (!ab->hw_params->reoq_lut_support)
return;
if (dp->reoq_lut.vaddr_unaligned) {
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_LUT_BASE0(ab), 0);
ath12k_hal_write_reoq_lut_addr(ab, 0);
dma_free_coherent(ab->dev, dp->reoq_lut.size,
dp->reoq_lut.vaddr_unaligned,
dp->reoq_lut.paddr_unaligned);
@ -1289,9 +1108,7 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
}
if (dp->ml_reoq_lut.vaddr_unaligned) {
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_LUT_BASE1(ab), 0);
ath12k_hal_write_ml_reoq_lut_addr(ab, 0);
dma_free_coherent(ab->dev, dp->ml_reoq_lut.size,
dp->ml_reoq_lut.vaddr_unaligned,
dp->ml_reoq_lut.paddr_unaligned);
@ -1299,11 +1116,13 @@ static void ath12k_dp_reoq_lut_cleanup(struct ath12k_base *ab)
}
}
void ath12k_dp_free(struct ath12k_base *ab)
static void ath12k_dp_cleanup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i;
ath12k_dp_link_peer_rhash_tbl_destroy(dp);
if (!dp->ab)
return;
@ -1324,60 +1143,6 @@ void ath12k_dp_free(struct ath12k_base *ab)
ath12k_dp_rx_free(ab);
/* Deinit any SOC level resource */
dp->ab = NULL;
}
void ath12k_dp_cc_config(struct ath12k_base *ab)
{
u32 cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start;
u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
u32 wbm_base = HAL_SEQ_WCSS_UMAC_WBM_REG;
u32 val = 0;
if (ath12k_ftm_mode)
return;
ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG0(ab), cmem_base);
val |= u32_encode_bits(ATH12K_CMEM_ADDR_MSB,
HAL_REO1_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB) |
u32_encode_bits(ATH12K_CC_PPT_MSB,
HAL_REO1_SW_COOKIE_CFG_COOKIE_PPT_MSB) |
u32_encode_bits(ATH12K_CC_SPT_MSB,
HAL_REO1_SW_COOKIE_CFG_COOKIE_SPT_MSB) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_ALIGN) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_ENABLE) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_GLOBAL_ENABLE);
ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG1(ab), val);
/* Enable HW CC for WBM */
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG0, cmem_base);
val = u32_encode_bits(ATH12K_CMEM_ADDR_MSB,
HAL_WBM_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB) |
u32_encode_bits(ATH12K_CC_PPT_MSB,
HAL_WBM_SW_COOKIE_CFG_COOKIE_PPT_MSB) |
u32_encode_bits(ATH12K_CC_SPT_MSB,
HAL_WBM_SW_COOKIE_CFG_COOKIE_SPT_MSB) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_ALIGN);
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG1, val);
/* Enable conversion complete indication */
val = ath12k_hif_read32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG2);
val |= u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_RELEASE_PATH_EN) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_ERR_PATH_EN) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_CONV_IND_EN);
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG2, val);
/* Enable Cookie conversion for WBM2SW Rings */
val = ath12k_hif_read32(ab, wbm_base + HAL_WBM_SW_COOKIE_CONVERT_CFG);
val |= u32_encode_bits(1, HAL_WBM_SW_COOKIE_CONV_CFG_GLOBAL_EN) |
ab->hw_params->hal_params->wbm2sw_cc_enable;
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CONVERT_CFG, val);
}
static u32 ath12k_dp_cc_cookie_gen(u16 ppt_idx, u16 spt_idx)
@ -1385,26 +1150,23 @@ static u32 ath12k_dp_cc_cookie_gen(u16 ppt_idx, u16 spt_idx)
return (u32)ppt_idx << ATH12K_CC_PPT_SHIFT | spt_idx;
}
static inline void *ath12k_dp_cc_get_desc_addr_ptr(struct ath12k_base *ab,
u16 ppt_idx, u16 spt_idx)
static void *ath12k_dp_cc_get_desc_addr_ptr(struct ath12k_dp *dp,
u16 ppt_idx, u16 spt_idx)
{
struct ath12k_dp *dp = &ab->dp;
return dp->spt_info[ppt_idx].vaddr + spt_idx;
}
struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab,
struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_dp *dp,
u32 cookie)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_rx_desc_info **desc_addr_ptr;
u16 start_ppt_idx, end_ppt_idx, ppt_idx, spt_idx;
ppt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_PPT);
spt_idx = u32_get_bits(cookie, ATH12K_DP_CC_COOKIE_SPT);
start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET(ab);
end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES(ab);
start_ppt_idx = dp->rx_ppt_base + ATH12K_RX_SPT_PAGE_OFFSET(dp->ab);
end_ppt_idx = start_ppt_idx + ATH12K_NUM_RX_SPT_PAGES(dp->ab);
if (ppt_idx < start_ppt_idx ||
ppt_idx >= end_ppt_idx ||
@ -1412,12 +1174,13 @@ struct ath12k_rx_desc_info *ath12k_dp_get_rx_desc(struct ath12k_base *ab,
return NULL;
ppt_idx = ppt_idx - dp->rx_ppt_base;
desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, spt_idx);
desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, spt_idx);
return *desc_addr_ptr;
}
EXPORT_SYMBOL(ath12k_dp_get_rx_desc);
struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab,
struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_dp *dp,
u32 cookie)
{
struct ath12k_tx_desc_info **desc_addr_ptr;
@ -1428,21 +1191,22 @@ struct ath12k_tx_desc_info *ath12k_dp_get_tx_desc(struct ath12k_base *ab,
start_ppt_idx = ATH12K_TX_SPT_PAGE_OFFSET;
end_ppt_idx = start_ppt_idx +
(ATH12K_TX_SPT_PAGES_PER_POOL(ab) * ATH12K_HW_MAX_QUEUES);
(ATH12K_TX_SPT_PAGES_PER_POOL(dp->ab) * ATH12K_HW_MAX_QUEUES);
if (ppt_idx < start_ppt_idx ||
ppt_idx >= end_ppt_idx ||
spt_idx > ATH12K_MAX_SPT_ENTRIES)
return NULL;
desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, spt_idx);
desc_addr_ptr = ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, spt_idx);
return *desc_addr_ptr;
}
EXPORT_SYMBOL(ath12k_dp_get_tx_desc);
static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_rx_desc_info *rx_descs, **rx_desc_addr;
struct ath12k_tx_desc_info *tx_descs, **tx_desc_addr;
u32 num_rx_spt_pages = ATH12K_NUM_RX_SPT_PAGES(ab);
@ -1482,7 +1246,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
list_add_tail(&rx_descs[j].list, &dp->rx_desc_free_list);
/* Update descriptor VA in SPT */
rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, j);
rx_desc_addr = ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, j);
*rx_desc_addr = &rx_descs[j];
}
}
@ -1521,7 +1285,7 @@ static int ath12k_dp_cc_desc_init(struct ath12k_base *ab)
/* Update descriptor VA in SPT */
tx_desc_addr =
ath12k_dp_cc_get_desc_addr_ptr(ab, ppt_idx, j);
ath12k_dp_cc_get_desc_addr_ptr(dp, ppt_idx, j);
*tx_desc_addr = &tx_descs[j];
}
}
@ -1571,7 +1335,7 @@ void ath12k_dp_partner_cc_init(struct ath12k_base *ab)
if (ag->ab[i] == ab)
continue;
ath12k_dp_cmem_init(ab, &ag->ab[i]->dp, ATH12K_DP_RX_DESC);
ath12k_dp_cmem_init(ab, ath12k_ab_to_dp(ag->ab[i]), ATH12K_DP_RX_DESC);
}
}
@ -1582,7 +1346,7 @@ static u32 ath12k_dp_get_num_spt_pages(struct ath12k_base *ab)
static int ath12k_dp_cc_init(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int i, ret = 0;
INIT_LIST_HEAD(&dp->rx_desc_free_list);
@ -1668,8 +1432,7 @@ static int ath12k_dp_alloc_reoq_lut(struct ath12k_base *ab,
static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
u32 val;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
int ret;
if (!ab->hw_params->reoq_lut_support)
@ -1697,50 +1460,24 @@ static int ath12k_dp_reoq_lut_setup(struct ath12k_base *ab)
* register only
*/
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE0(ab),
dp->reoq_lut.paddr >> 8);
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_LUT_BASE1(ab),
dp->ml_reoq_lut.paddr >> 8);
val = ath12k_hif_read32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab));
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(ab),
val | HAL_REO_QDESC_ADDR_READ_LUT_ENABLE);
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_MAX_PEERID(ab),
HAL_REO_QDESC_MAX_PEERID);
ath12k_hal_write_reoq_lut_addr(ab, dp->reoq_lut.paddr >> 8);
ath12k_hal_write_ml_reoq_lut_addr(ab, dp->ml_reoq_lut.paddr >> 8);
ath12k_hal_reoq_lut_addr_read_enable(ab);
ath12k_hal_reoq_lut_set_max_peerid(ab);
return 0;
}
static enum hal_rx_buf_return_buf_manager
ath12k_dp_get_idle_link_rbm(struct ath12k_base *ab)
static int ath12k_dp_setup(struct ath12k_base *ab)
{
switch (ab->device_id) {
case 0:
return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST;
case 1:
return HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST;
case 2:
return HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST;
default:
ath12k_warn(ab, "invalid %d device id, so choose default rbm\n",
ab->device_id);
WARN_ON(1);
return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST;
}
}
int ath12k_dp_alloc(struct ath12k_base *ab)
{
struct ath12k_dp *dp = &ab->dp;
struct ath12k_dp *dp;
struct hal_srng *srng = NULL;
size_t size = 0;
u32 n_link_desc = 0;
int ret;
int i;
dp = ath12k_ab_to_dp(ab);
dp->ab = ab;
INIT_LIST_HEAD(&dp->reo_cmd_list);
@ -1749,13 +1486,25 @@ int ath12k_dp_alloc(struct ath12k_base *ab)
spin_lock_init(&dp->reo_cmd_lock);
spin_lock_init(&dp->reo_rxq_flush_lock);
spin_lock_init(&dp->dp_lock);
INIT_LIST_HEAD(&dp->peers);
mutex_init(&dp->link_peer_rhash_tbl_lock);
dp->reo_cmd_cache_flush_count = 0;
dp->idle_link_rbm = ath12k_dp_get_idle_link_rbm(ab);
dp->idle_link_rbm =
ath12k_hal_get_idle_link_rbm(&ab->hal, ab->device_id);
ret = ath12k_dp_link_peer_rhash_tbl_init(dp);
if (ret) {
ath12k_warn(ab, "failed to init link_peer rhash table: %d\n", ret);
return ret;
}
ret = ath12k_wbm_idle_ring_setup(ab, &n_link_desc);
if (ret) {
ath12k_warn(ab, "failed to setup wbm_idle_ring: %d\n", ret);
return ret;
goto rhash_destroy;
}
srng = &ab->hal.srng_list[dp->wbm_idle_ring.ring_id];
@ -1783,7 +1532,7 @@ int ath12k_dp_alloc(struct ath12k_base *ab)
if (ret)
goto fail_dp_bank_profiles_cleanup;
size = sizeof(struct hal_wbm_release_ring_tx) *
size = ab->hal.hal_wbm_release_ring_tx_size *
DP_TX_COMP_RING_SIZE(ab);
ret = ath12k_dp_reoq_lut_setup(ab);
@ -1836,6 +1585,48 @@ fail_hw_cc_cleanup:
fail_link_desc_cleanup:
ath12k_dp_link_desc_cleanup(ab, dp->link_desc_banks,
HAL_WBM_IDLE_LINK, &dp->wbm_idle_ring);
rhash_destroy:
ath12k_dp_link_peer_rhash_tbl_destroy(dp);
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;
}
void ath12k_dp_cmn_hw_group_unassign(struct ath12k_dp *dp,
struct ath12k_hw_group *ag)
{
struct ath12k_dp_hw_group *dp_hw_grp = &ag->dp_hw_grp;
lockdep_assert_held(&ag->mutex);
dp_hw_grp->dp[dp->device_id] = NULL;
dp->ag = NULL;
dp->device_id = ATH12K_INVALID_DEVICE_ID;
}
void ath12k_dp_cmn_hw_group_assign(struct ath12k_dp *dp,
struct ath12k_hw_group *ag)
{
struct ath12k_base *ab = dp->ab;
struct ath12k_dp_hw_group *dp_hw_grp = &ag->dp_hw_grp;
dp->ag = ag;
dp->device_id = ab->device_id;
dp_hw_grp->dp[dp->device_id] = dp;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,106 @@
/* 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
#include "cmn_defs.h"
struct ath12k_hw_group;
/*
* ML Peer IDs start from 8192, assuming max SLO clients count 1536,
* then max peer id shall be 9728, therefore rounding the peer table size
* to the nearest next power of 2 i.e 16384.
*/
#define MAX_DP_PEER_LIST_SIZE 16384
struct ath12k_dp_hw {
struct ath12k_dp_peer __rcu *dp_peers[MAX_DP_PEER_LIST_SIZE];
/* Lock for protection of dp_peer_list and peers */
spinlock_t peer_lock;
struct list_head dp_peers_list;
};
struct ath12k_dp_hw_group {
struct ath12k_dp *dp[ATH12K_MAX_DEVICES];
};
struct ath12k_dp_link_vif {
u32 vdev_id;
u8 search_type;
u8 hal_addr_search_flags;
u8 pdev_idx;
u8 lmac_id;
u16 ast_idx;
u16 ast_hash;
u16 tcl_metadata;
u8 vdev_id_check_en;
int bank_id;
};
struct ath12k_dp_vif {
u8 tx_encap_type;
u32 key_cipher;
atomic_t mcbc_gsn;
struct ath12k_dp_link_vif dp_link_vif[ATH12K_NUM_MAX_LINKS];
};
/* TODO: Move this to a separate dp_stats file */
struct ath12k_per_peer_tx_stats {
u32 succ_bytes;
u32 retry_bytes;
u32 failed_bytes;
u32 duration;
u16 succ_pkts;
u16 retry_pkts;
u16 failed_pkts;
u16 ru_start;
u16 ru_tones;
u8 ba_fails;
u8 ppdu_type;
u32 mu_grpid;
u32 mu_pos;
bool is_ampdu;
};
struct ath12k_dp_peer_create_params {
struct ieee80211_sta *sta;
bool is_mlo;
u16 peer_id;
bool ucast_ra_only;
};
struct ath12k_dp_link_peer_rate_info {
struct rate_info txrate;
u64 rx_duration;
u64 tx_duration;
u8 rssi_comb;
s8 signal_avg;
};
static inline struct ath12k_dp_link_vif *
ath12k_dp_vif_to_dp_link_vif(struct ath12k_dp_vif *dp_vif, u8 link_id)
{
return &dp_vif->dp_link_vif[link_id];
}
void ath12k_dp_cmn_device_deinit(struct ath12k_dp *dp);
int ath12k_dp_cmn_device_init(struct ath12k_dp *dp);
void ath12k_dp_cmn_hw_group_unassign(struct ath12k_dp *dp,
struct ath12k_hw_group *ag);
void ath12k_dp_cmn_hw_group_assign(struct ath12k_dp *dp,
struct ath12k_hw_group *ag);
int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
u8 vdev_id, struct ieee80211_sta *sta, u8 *addr,
u8 link_id, u32 hw_link_id);
void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
u8 vdev_id, u8 *addr, u32 hw_link_id);
void
ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr,
struct ath12k_dp_link_peer_rate_info *info);
void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* 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_DP_MON_H
@ -12,6 +12,12 @@
#define ATH12K_MON_RX_DOT11_OFFSET 5
#define ATH12K_MON_RX_PKT_OFFSET 8
#define ATH12K_LE32_DEC_ENC(value, dec_bits, enc_bits) \
u32_encode_bits(le32_get_bits(value, dec_bits), enc_bits)
#define ATH12K_LE64_DEC_ENC(value, dec_bits, enc_bits) \
u32_encode_bits(le64_get_bits(value, dec_bits), enc_bits)
enum dp_monitor_mode {
ATH12K_DP_TX_MONITOR_MODE,
ATH12K_DP_RX_MONITOR_MODE
@ -77,31 +83,41 @@ struct dp_mon_tx_ppdu_info {
struct dp_mon_mpdu *tx_mon_mpdu;
};
enum hal_rx_mon_status
ath12k_dp_mon_rx_parse_mon_status(struct ath12k *ar,
struct ath12k_mon_data *pmon,
struct sk_buff *skb,
struct napi_struct *napi);
int ath12k_dp_mon_buf_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *buf_ring,
int req_entries);
int ath12k_dp_mon_status_bufs_replenish(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *rx_ring,
int req_entries);
int ath12k_dp_mon_process_ring(struct ath12k_base *ab, int mac_id,
struct napi_struct *napi, int budget,
enum dp_monitor_mode monitor_mode);
struct sk_buff *ath12k_dp_mon_tx_alloc_skb(void);
enum dp_mon_tx_tlv_status
ath12k_dp_mon_tx_status_get_num_user(u16 tlv_tag,
struct hal_tlv_hdr *tx_tlv,
u8 *num_users);
enum hal_rx_mon_status
ath12k_dp_mon_tx_parse_mon_status(struct ath12k *ar,
struct ath12k_mon_data *pmon,
struct sk_buff *skb,
struct napi_struct *napi,
u32 ppdu_id);
void ath12k_dp_mon_rx_process_ulofdma(struct hal_rx_mon_ppdu_info *ppdu_info);
int ath12k_dp_mon_srng_process(struct ath12k *ar, int *budget, struct napi_struct *napi);
void
ath12k_dp_mon_rx_update_peer_mu_stats(struct ath12k_base *ab,
struct hal_rx_mon_ppdu_info *ppdu_info);
void ath12k_dp_mon_rx_update_peer_su_stats(struct ath12k_dp_link_peer *peer,
struct hal_rx_mon_ppdu_info *ppdu_info);
int ath12k_dp_pkt_set_pktlen(struct sk_buff *skb, u32 len);
struct sk_buff
*ath12k_dp_rx_alloc_mon_status_buf(struct ath12k_base *ab,
struct dp_rxdma_mon_ring *rx_ring,
int *buf_id);
u32 ath12k_dp_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id);
int
ath12k_dp_mon_parse_status_buf(struct ath12k_pdev_dp *dp_pdev,
struct ath12k_mon_data *pmon,
const struct dp_mon_packet_info *packet_info);
void ath12k_dp_mon_update_radiotap(struct ath12k_pdev_dp *dp_pdev,
struct hal_rx_mon_ppdu_info *ppduinfo,
struct sk_buff *mon_skb,
struct ieee80211_rx_status *rxs);
void ath12k_dp_mon_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev,
struct napi_struct *napi,
struct sk_buff *msdu,
const struct hal_rx_mon_ppdu_info *ppduinfo,
struct ieee80211_rx_status *status,
u8 decap);
struct sk_buff *
ath12k_dp_mon_rx_merg_msdus(struct ath12k_pdev_dp *dp_pdev,
struct dp_mon_mpdu *mon_mpdu,
struct hal_rx_mon_ppdu_info *ppdu_info,
struct ieee80211_rx_status *rxs);
#endif

View File

@ -0,0 +1,690 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "dp_peer.h"
#include "debug.h"
#include "debugfs.h"
void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer)
{
list_del(&peer->list);
kfree(peer->peer_stats.rx_stats);
kfree(peer);
}
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp *dp,
int vdev_id, const u8 *addr)
{
struct ath12k_dp_link_peer *peer;
lockdep_assert_held(&dp->dp_lock);
list_for_each_entry(peer, &dp->peers, list) {
if (peer->vdev_id != vdev_id)
continue;
if (!ether_addr_equal(peer->addr, addr))
continue;
return peer;
}
return NULL;
}
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx,
const u8 *addr)
{
struct ath12k_dp_link_peer *peer;
lockdep_assert_held(&dp->dp_lock);
list_for_each_entry(peer, &dp->peers, list) {
if (peer->pdev_idx != pdev_idx)
continue;
if (!ether_addr_equal(peer->addr, addr))
continue;
return peer;
}
return NULL;
}
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr)
{
lockdep_assert_held(&dp->dp_lock);
return rhashtable_lookup_fast(dp->rhead_peer_addr, addr,
dp->rhash_peer_addr_param);
}
EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_addr);
static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ml_id(struct ath12k_dp *dp, int ml_peer_id)
{
struct ath12k_dp_link_peer *peer;
lockdep_assert_held(&dp->dp_lock);
list_for_each_entry(peer, &dp->peers, list)
if (ml_peer_id == peer->ml_id)
return peer;
return NULL;
}
static struct ath12k_dp_link_peer *
ath12k_dp_link_peer_search_by_id(struct ath12k_dp *dp, int peer_id)
{
struct ath12k_dp_link_peer *peer;
lockdep_assert_held(&dp->dp_lock);
if (peer_id == HAL_INVALID_PEERID)
return NULL;
if (peer_id & ATH12K_PEER_ML_ID_VALID)
return ath12k_dp_link_peer_find_by_ml_id(dp, peer_id);
list_for_each_entry(peer, &dp->peers, list)
if (peer_id == peer->peer_id)
return peer;
return NULL;
}
bool ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp *dp, int vdev_id)
{
struct ath12k_dp_link_peer *peer;
spin_lock_bh(&dp->dp_lock);
list_for_each_entry(peer, &dp->peers, list) {
if (vdev_id == peer->vdev_id) {
spin_unlock_bh(&dp->dp_lock);
return true;
}
}
spin_unlock_bh(&dp->dp_lock);
return false;
}
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ast(struct ath12k_dp *dp, int ast_hash)
{
struct ath12k_dp_link_peer *peer;
lockdep_assert_held(&dp->dp_lock);
list_for_each_entry(peer, &dp->peers, list)
if (ast_hash == peer->ast_hash)
return peer;
return NULL;
}
void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id)
{
struct ath12k_dp_link_peer *peer;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_search_by_id(dp, peer_id);
if (!peer) {
ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
peer_id);
goto exit;
}
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
peer->vdev_id, peer->addr, peer_id);
ath12k_dp_link_peer_free(peer);
wake_up(&ab->peer_mapping_wq);
exit:
spin_unlock_bh(&dp->dp_lock);
}
void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
{
struct ath12k_dp_link_peer *peer;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k *ar;
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, mac_addr);
if (!peer) {
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
if (!peer)
goto exit;
peer->vdev_id = vdev_id;
peer->peer_id = peer_id;
peer->ast_hash = ast_hash;
peer->hw_peer_id = hw_peer_id;
ether_addr_copy(peer->addr, mac_addr);
rcu_read_lock();
ar = ath12k_mac_get_ar_by_vdev_id(ab, vdev_id);
if (ar && ath12k_debugfs_is_extd_rx_stats_enabled(ar) &&
!peer->peer_stats.rx_stats) {
peer->peer_stats.rx_stats =
kzalloc(sizeof(*peer->peer_stats.rx_stats), GFP_ATOMIC);
}
rcu_read_unlock();
list_add(&peer->list, &dp->peers);
wake_up(&ab->peer_mapping_wq);
ewma_avg_rssi_init(&peer->avg_rssi);
}
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
vdev_id, mac_addr, peer_id);
exit:
spin_unlock_bh(&dp->dp_lock);
}
struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab,
struct ath12k_dp_link_peer *peer)
{
struct ath12k_sta *ahsta;
struct ath12k_link_sta *arsta;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k_dp_link_peer to ath12k_link_sta called without rcu lock");
if (!peer->sta)
return NULL;
ahsta = ath12k_sta_to_ahsta(peer->sta);
if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) {
if (!(ahsta->links_map & BIT(peer->link_id))) {
ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n",
peer->addr, peer->peer_id, peer->link_id,
ahsta->links_map);
return NULL;
}
arsta = rcu_dereference(ahsta->link[peer->link_id]);
if (!arsta)
return NULL;
} else {
arsta = &ahsta->deflink;
}
return arsta;
}
static int ath12k_dp_link_peer_rhash_addr_tbl_init(struct ath12k_dp *dp)
{
struct ath12k_base *ab = dp->ab;
struct rhashtable_params *param;
struct rhashtable *rhash_addr_tbl;
int ret;
lockdep_assert_held(&dp->link_peer_rhash_tbl_lock);
rhash_addr_tbl = kzalloc(sizeof(*dp->rhead_peer_addr), GFP_KERNEL);
if (!rhash_addr_tbl)
return -ENOMEM;
param = &dp->rhash_peer_addr_param;
param->key_offset = offsetof(struct ath12k_dp_link_peer, addr);
param->head_offset = offsetof(struct ath12k_dp_link_peer, rhash_addr);
param->key_len = sizeof_field(struct ath12k_dp_link_peer, addr);
param->automatic_shrinking = true;
param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab);
ret = rhashtable_init(rhash_addr_tbl, param);
if (ret) {
ath12k_warn(ab, "failed to init peer addr rhash table %d\n", ret);
goto err_free;
}
dp->rhead_peer_addr = rhash_addr_tbl;
return 0;
err_free:
kfree(rhash_addr_tbl);
return ret;
}
int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp)
{
int ret;
mutex_lock(&dp->link_peer_rhash_tbl_lock);
ret = ath12k_dp_link_peer_rhash_addr_tbl_init(dp);
mutex_unlock(&dp->link_peer_rhash_tbl_lock);
return ret;
}
void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp)
{
mutex_lock(&dp->link_peer_rhash_tbl_lock);
rhashtable_destroy(dp->rhead_peer_addr);
kfree(dp->rhead_peer_addr);
dp->rhead_peer_addr = NULL;
mutex_unlock(&dp->link_peer_rhash_tbl_lock);
}
static int ath12k_dp_link_peer_rhash_insert(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer)
{
struct ath12k_dp_link_peer *tmp;
lockdep_assert_held(&dp->dp_lock);
tmp = rhashtable_lookup_get_insert_fast(dp->rhead_peer_addr, &peer->rhash_addr,
dp->rhash_peer_addr_param);
if (!tmp)
return 0;
else if (IS_ERR(tmp))
return PTR_ERR(tmp);
else
return -EEXIST;
}
static int ath12k_dp_link_peer_rhash_remove(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer)
{
int ret;
lockdep_assert_held(&dp->dp_lock);
ret = rhashtable_remove_fast(dp->rhead_peer_addr, &peer->rhash_addr,
dp->rhash_peer_addr_param);
if (ret && ret != -ENOENT)
return ret;
return 0;
}
int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer)
{
int ret;
lockdep_assert_held(&dp->dp_lock);
ret = ath12k_dp_link_peer_rhash_insert(dp, peer);
if (ret)
ath12k_warn(dp, "failed to add peer %pM with id %d in rhash_addr ret %d\n",
peer->addr, peer->peer_id, ret);
return ret;
}
void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer)
{
/* No failure handling and hence return type is void */
int ret;
lockdep_assert_held(&dp->dp_lock);
ret = ath12k_dp_link_peer_rhash_remove(dp, peer);
if (ret)
ath12k_warn(dp, "failed to remove peer %pM with id %d in rhash_addr ret %d\n",
peer->addr, peer->peer_id, ret);
}
struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw *dp_hw, u8 *addr)
{
struct ath12k_dp_peer *peer;
lockdep_assert_held(&dp_hw->peer_lock);
list_for_each_entry(peer, &dp_hw->dp_peers_list, list) {
if (ether_addr_equal(peer->addr, addr))
return peer;
}
return NULL;
}
EXPORT_SYMBOL(ath12k_dp_peer_find_by_addr);
struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw *dp_hw,
u8 *addr,
struct ieee80211_sta *sta)
{
struct ath12k_dp_peer *dp_peer;
lockdep_assert_held(&dp_hw->peer_lock);
list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
if (ether_addr_equal(dp_peer->addr, addr) && (dp_peer->sta == sta))
return dp_peer;
}
return NULL;
}
static struct ath12k_dp_peer *ath12k_dp_peer_create_find(struct ath12k_dp_hw *dp_hw,
u8 *addr,
struct ieee80211_sta *sta,
bool mlo_peer)
{
struct ath12k_dp_peer *dp_peer;
lockdep_assert_held(&dp_hw->peer_lock);
list_for_each_entry(dp_peer, &dp_hw->dp_peers_list, list) {
if (ether_addr_equal(dp_peer->addr, addr)) {
if (!sta || mlo_peer || dp_peer->is_mlo ||
dp_peer->sta == sta)
return dp_peer;
}
}
return NULL;
}
/*
* Index of ath12k_dp_peer for MLO client is same as peer id of ath12k_dp_peer,
* while for ath12k_dp_link_peer(mlo and non-mlo) and ath12k_dp_peer for
* Non-MLO client it is derived as ((DEVICE_ID << 10) | (10 bits of peer id)).
*
* This is done because ml_peer_id and peer_id_table are at hw granularity,
* while link_peer_id is at device granularity, hence in order to avoid
* conflict this approach is followed.
*/
#define ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT 10
u16 ath12k_dp_peer_get_peerid_index(struct ath12k_dp *dp, u16 peer_id)
{
return (peer_id & ATH12K_PEER_ML_ID_VALID) ? peer_id :
((dp->device_id << ATH12K_DP_PEER_TABLE_DEVICE_ID_SHIFT) | peer_id);
}
struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev,
u16 peer_id)
{
u16 index;
struct ath12k_dp *dp = dp_pdev->dp;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k dp peer find by peerid index called without rcu lock");
if (!peer_id || peer_id >= ATH12K_DP_PEER_ID_INVALID)
return NULL;
index = ath12k_dp_peer_get_peerid_index(dp, peer_id);
return rcu_dereference(dp_pdev->dp_hw->dp_peers[index]);
}
EXPORT_SYMBOL(ath12k_dp_peer_find_by_peerid);
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id)
{
struct ath12k_dp_peer *dp_peer = NULL;
u8 link_id;
RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
"ath12k dp link peer find by peerid index called without rcu lock");
if (dp_pdev->hw_link_id >= ATH12K_GROUP_MAX_RADIO)
return NULL;
dp_peer = ath12k_dp_peer_find_by_peerid(dp_pdev, peer_id);
if (!dp_peer)
return NULL;
link_id = dp_peer->hw_links[dp_pdev->hw_link_id];
return rcu_dereference(dp_peer->link_peers[link_id]);
}
EXPORT_SYMBOL(ath12k_dp_link_peer_find_by_peerid);
int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
struct ath12k_dp_peer_create_params *params)
{
struct ath12k_dp_peer *dp_peer;
spin_lock_bh(&dp_hw->peer_lock);
dp_peer = ath12k_dp_peer_create_find(dp_hw, addr, params->sta, params->is_mlo);
if (dp_peer) {
spin_unlock_bh(&dp_hw->peer_lock);
return -EEXIST;
}
spin_unlock_bh(&dp_hw->peer_lock);
dp_peer = kzalloc(sizeof(*dp_peer), GFP_ATOMIC);
if (!dp_peer)
return -ENOMEM;
ether_addr_copy(dp_peer->addr, addr);
dp_peer->sta = params->sta;
dp_peer->is_mlo = params->is_mlo;
/*
* For MLO client, the host assigns the ML peer ID, so set peer_id in dp_peer
* For non-MLO client, host gets link peer ID from firmware and will be
* assigned at the time of link peer creation
*/
dp_peer->peer_id = params->is_mlo ? params->peer_id : ATH12K_DP_PEER_ID_INVALID;
dp_peer->ucast_ra_only = params->ucast_ra_only;
dp_peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
dp_peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
dp_peer->ucast_ra_only = params->ucast_ra_only;
spin_lock_bh(&dp_hw->peer_lock);
list_add(&dp_peer->list, &dp_hw->dp_peers_list);
/*
* For MLO client, the peer_id for ath12k_dp_peer is allocated by host
* and that peer_id is known at this point, and hence this ath12k_dp_peer
* can be added to the RCU table using the peer_id.
* For non-MLO client, this addition to RCU table shall be done at the
* time of assignment of ath12k_dp_link_peer to ath12k_dp_peer.
*/
if (dp_peer->is_mlo)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], dp_peer);
spin_unlock_bh(&dp_hw->peer_lock);
return 0;
}
void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
struct ieee80211_sta *sta)
{
struct ath12k_dp_peer *dp_peer;
spin_lock_bh(&dp_hw->peer_lock);
dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, addr, sta);
if (!dp_peer) {
spin_unlock_bh(&dp_hw->peer_lock);
return;
}
if (dp_peer->is_mlo)
rcu_assign_pointer(dp_hw->dp_peers[dp_peer->peer_id], NULL);
list_del(&dp_peer->list);
spin_unlock_bh(&dp_hw->peer_lock);
synchronize_rcu();
kfree(dp_peer);
}
int ath12k_dp_link_peer_assign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
u8 vdev_id, struct ieee80211_sta *sta, u8 *addr,
u8 link_id, u32 hw_link_id)
{
struct ath12k_dp_peer *dp_peer;
struct ath12k_dp_link_peer *peer, *temp_peer;
u16 peerid_index;
int ret = -EINVAL;
u8 *dp_peer_mac = !sta ? addr : sta->addr;
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
if (!peer) {
ath12k_warn(dp, "failed to find dp_link_peer with mac %pM on vdev %u\n",
addr, vdev_id);
ret = -ENOENT;
goto err_peer;
}
spin_lock_bh(&dp_hw->peer_lock);
dp_peer = ath12k_dp_peer_find_by_addr_and_sta(dp_hw, dp_peer_mac, sta);
if (!dp_peer) {
ath12k_warn(dp, "failed to find dp_peer with mac %pM\n", dp_peer_mac);
ret = -ENOENT;
goto err_dp_peer;
}
/*
* Set peer_id in dp_peer for non-mlo client, peer_id for mlo client is
* set during dp_peer create
*/
if (!dp_peer->is_mlo)
dp_peer->peer_id = peer->peer_id;
peer->dp_peer = dp_peer;
peer->hw_link_id = hw_link_id;
dp_peer->hw_links[peer->hw_link_id] = link_id;
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], peer);
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], dp_peer);
spin_unlock_bh(&dp_hw->peer_lock);
/*
* In case of Split PHY and roaming scenario, pdev idx
* might differ but both the pdev will share same rhash
* table. In that case update the rhash table if link_peer is
* already present
*/
temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
if (temp_peer && temp_peer->hw_link_id != hw_link_id)
ath12k_dp_link_peer_rhash_delete(dp, temp_peer);
ret = ath12k_dp_link_peer_rhash_add(dp, peer);
if (ret) {
/*
* If new entry addition failed, add back old entry
* If old entry addition also fails, then nothing
* can be done, simply proceed
*/
if (temp_peer)
ath12k_dp_link_peer_rhash_add(dp, temp_peer);
}
spin_unlock_bh(&dp->dp_lock);
return ret;
err_dp_peer:
spin_unlock_bh(&dp_hw->peer_lock);
err_peer:
spin_unlock_bh(&dp->dp_lock);
return ret;
}
void ath12k_dp_link_peer_unassign(struct ath12k_dp *dp, struct ath12k_dp_hw *dp_hw,
u8 vdev_id, u8 *addr, u32 hw_link_id)
{
struct ath12k_dp_peer *dp_peer;
struct ath12k_dp_link_peer *peer, *temp_peer;
u16 peerid_index;
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, vdev_id, addr);
if (!peer || !peer->dp_peer) {
spin_unlock_bh(&dp->dp_lock);
return;
}
spin_lock_bh(&dp_hw->peer_lock);
dp_peer = peer->dp_peer;
dp_peer->hw_links[peer->hw_link_id] = 0;
peerid_index = ath12k_dp_peer_get_peerid_index(dp, peer->peer_id);
rcu_assign_pointer(dp_peer->link_peers[peer->link_id], NULL);
rcu_assign_pointer(dp_hw->dp_peers[peerid_index], NULL);
spin_unlock_bh(&dp_hw->peer_lock);
/* To handle roaming and split phy scenario */
temp_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
if (temp_peer && temp_peer->hw_link_id == hw_link_id)
ath12k_dp_link_peer_rhash_delete(dp, peer);
spin_unlock_bh(&dp->dp_lock);
synchronize_rcu();
}
void
ath12k_dp_link_peer_get_sta_rate_info_stats(struct ath12k_dp *dp, const u8 *addr,
struct ath12k_dp_link_peer_rate_info *info)
{
struct ath12k_dp_link_peer *link_peer;
guard(spinlock_bh)(&dp->dp_lock);
link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
if (!link_peer)
return;
info->rx_duration = link_peer->rx_duration;
info->tx_duration = link_peer->tx_duration;
info->txrate.legacy = link_peer->txrate.legacy;
info->txrate.mcs = link_peer->txrate.mcs;
info->txrate.nss = link_peer->txrate.nss;
info->txrate.bw = link_peer->txrate.bw;
info->txrate.he_gi = link_peer->txrate.he_gi;
info->txrate.he_dcm = link_peer->txrate.he_dcm;
info->txrate.he_ru_alloc = link_peer->txrate.he_ru_alloc;
info->txrate.flags = link_peer->txrate.flags;
info->rssi_comb = link_peer->rssi_comb;
info->signal_avg = ewma_avg_rssi_read(&link_peer->avg_rssi);
}
void ath12k_dp_link_peer_reset_rx_stats(struct ath12k_dp *dp, const u8 *addr)
{
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_dp_link_peer *link_peer;
guard(spinlock_bh)(&dp->dp_lock);
link_peer = ath12k_dp_link_peer_find_by_addr(dp, addr);
if (!link_peer || !link_peer->peer_stats.rx_stats)
return;
rx_stats = link_peer->peer_stats.rx_stats;
if (rx_stats)
memset(rx_stats, 0, sizeof(*rx_stats));
}

View File

@ -0,0 +1,182 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_PEER_H
#define ATH12K_DP_PEER_H
#include "dp_rx.h"
#define ATH12K_DP_PEER_ID_INVALID 0x3FFF
struct ppdu_user_delayba {
u16 sw_peer_id;
u32 info0;
u16 ru_end;
u16 ru_start;
u32 info1;
u32 rate_flags;
u32 resp_rate_flags;
};
#define ATH12K_PEER_ML_ID_VALID BIT(13)
struct ath12k_rx_peer_rate_stats {
u64 ht_mcs_count[HAL_RX_MAX_MCS_HT + 1];
u64 vht_mcs_count[HAL_RX_MAX_MCS_VHT + 1];
u64 he_mcs_count[HAL_RX_MAX_MCS_HE + 1];
u64 be_mcs_count[HAL_RX_MAX_MCS_BE + 1];
u64 nss_count[HAL_RX_MAX_NSS];
u64 bw_count[HAL_RX_BW_MAX];
u64 gi_count[HAL_RX_GI_MAX];
u64 legacy_count[HAL_RX_MAX_NUM_LEGACY_RATES];
u64 rx_rate[HAL_RX_BW_MAX][HAL_RX_GI_MAX][HAL_RX_MAX_NSS][HAL_RX_MAX_MCS_HT + 1];
};
struct ath12k_rx_peer_stats {
u64 num_msdu;
u64 num_mpdu_fcs_ok;
u64 num_mpdu_fcs_err;
u64 tcp_msdu_count;
u64 udp_msdu_count;
u64 other_msdu_count;
u64 ampdu_msdu_count;
u64 non_ampdu_msdu_count;
u64 stbc_count;
u64 beamformed_count;
u64 coding_count[HAL_RX_SU_MU_CODING_MAX];
u64 tid_count[IEEE80211_NUM_TIDS + 1];
u64 pream_cnt[HAL_RX_PREAMBLE_MAX];
u64 reception_type[HAL_RX_RECEPTION_TYPE_MAX];
u64 rx_duration;
u64 dcm_count;
u64 ru_alloc_cnt[HAL_RX_RU_ALLOC_TYPE_MAX];
struct ath12k_rx_peer_rate_stats pkt_stats;
struct ath12k_rx_peer_rate_stats byte_stats;
};
struct ath12k_wbm_tx_stats {
u64 wbm_tx_comp_stats[HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX];
};
struct ath12k_dp_peer_stats {
struct ath12k_rx_peer_stats *rx_stats;
struct ath12k_wbm_tx_stats *wbm_tx_stats;
};
DECLARE_EWMA(avg_rssi, 10, 8)
struct ath12k_dp_link_peer {
struct list_head list;
struct ieee80211_sta *sta;
struct ath12k_dp_peer *dp_peer;
int vdev_id;
u8 addr[ETH_ALEN];
int peer_id;
u16 ast_hash;
u8 pdev_idx;
u16 hw_peer_id;
struct ppdu_user_delayba ppdu_stats_delayba;
bool delayba_flag;
bool is_authorized;
bool mlo;
/* protected by ab->data_lock */
u16 ml_id;
/* any other ML info common for all partners can be added
* here and would be same for all partner peers.
*/
u8 ml_addr[ETH_ALEN];
/* To ensure only certain work related to dp is done once */
bool primary_link;
/* for reference to ath12k_link_sta */
u8 link_id;
/* peer addr based rhashtable list pointer */
struct rhash_head rhash_addr;
u8 hw_link_id;
u32 rx_tid_active_bitmask;
/* link stats */
struct rate_info txrate;
struct rate_info last_txrate;
u64 rx_duration;
u64 tx_duration;
u8 rssi_comb;
struct ewma_avg_rssi avg_rssi;
struct ath12k_dp_peer_stats peer_stats;
u32 tx_retry_failed;
u32 tx_retry_count;
};
void ath12k_dp_link_peer_unmap_event(struct ath12k_base *ab, u16 peer_id);
void ath12k_dp_link_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id);
struct ath12k_dp_peer {
struct list_head list;
bool is_mlo;
bool dp_setup_done;
u8 ucast_keyidx;
u8 addr[ETH_ALEN];
u8 mcast_keyidx;
bool ucast_ra_only;
int peer_id;
struct ieee80211_sta *sta;
u8 hw_links[ATH12K_GROUP_MAX_RADIO];
u16 sec_type_grp;
u16 sec_type;
/* Info used in MMIC verification of * RX fragments */
struct crypto_shash *tfm_mmic;
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
struct ath12k_dp_link_peer __rcu *link_peers[ATH12K_NUM_MAX_LINKS];
struct ath12k_reoq_buf reoq_bufs[IEEE80211_NUM_TIDS + 1];
struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
};
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_vdev_and_addr(struct ath12k_dp *dp,
int vdev_id, const u8 *addr);
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_addr(struct ath12k_dp *dp, const u8 *addr);
bool ath12k_dp_link_peer_exist_by_vdev_id(struct ath12k_dp *dp, int vdev_id);
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_ast(struct ath12k_dp *dp, int ast_hash);
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_pdev_and_addr(struct ath12k_dp *dp, u8 pdev_idx,
const u8 *addr);
struct ath12k_link_sta *ath12k_dp_link_peer_to_link_sta(struct ath12k_base *ab,
struct ath12k_dp_link_peer *peer);
int ath12k_dp_link_peer_rhash_tbl_init(struct ath12k_dp *dp);
void ath12k_dp_link_peer_rhash_tbl_destroy(struct ath12k_dp *dp);
int ath12k_dp_link_peer_rhash_add(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer);
void ath12k_dp_link_peer_rhash_delete(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer);
int ath12k_dp_peer_create(struct ath12k_dp_hw *dp_hw, u8 *addr,
struct ath12k_dp_peer_create_params *params);
void ath12k_dp_peer_delete(struct ath12k_dp_hw *dp_hw, u8 *addr,
struct ieee80211_sta *sta);
struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr(struct ath12k_dp_hw *dp_hw, u8 *addr);
struct ath12k_dp_peer *ath12k_dp_peer_find_by_addr_and_sta(struct ath12k_dp_hw *dp_hw,
u8 *addr,
struct ieee80211_sta *sta);
u16 ath12k_dp_peer_get_peerid_index(struct ath12k_dp *dp, u16 peer_id);
struct ath12k_dp_peer *ath12k_dp_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev,
u16 peer_id);
struct ath12k_dp_link_peer *
ath12k_dp_link_peer_find_by_peerid(struct ath12k_pdev_dp *dp_pdev, u16 peer_id);
void ath12k_dp_link_peer_free(struct ath12k_dp_link_peer *peer);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,21 +1,26 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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_DP_RX_H
#define ATH12K_DP_RX_H
#include <crypto/hash.h>
#include "core.h"
#include "rx_desc.h"
#include "debug.h"
#define DP_MAX_NWIFI_HDR_LEN 30
struct ath12k_reoq_buf {
void *vaddr;
dma_addr_t paddr_aligned;
u32 size;
};
struct ath12k_dp_rx_tid {
u8 tid;
u32 ba_win_sz;
bool active;
struct ath12k_reoq_buf qbuf;
/* Info related to rx fragments */
@ -28,7 +33,7 @@ struct ath12k_dp_rx_tid {
/* Timer info related to fragments */
struct timer_list frag_timer;
struct ath12k_base *ab;
struct ath12k_dp *dp;
};
struct ath12k_dp_rx_tid_rxq {
@ -59,6 +64,8 @@ struct ath12k_dp_rx_reo_cmd {
enum hal_reo_cmd_status status);
};
#define ATH12K_DP_RX_FRAGMENT_TIMEOUT_MS (2 * HZ)
#define ATH12K_DP_RX_REO_DESC_FREE_THRES 64
#define ATH12K_DP_RX_REO_DESC_FREE_TIMEOUT_MS 1000
@ -77,24 +84,6 @@ struct ath12k_dp_rx_rfc1042_hdr {
__be16 snap_type;
} __packed;
struct ath12k_dp_rx_info {
struct ieee80211_rx_status *rx_status;
u32 phy_meta_data;
u16 peer_id;
u8 decap_type;
u8 pkt_type;
u8 sgi;
u8 rate_mcs;
u8 bw;
u8 nss;
u8 addr2[ETH_ALEN];
u8 tid;
bool ip_csum_fail;
bool l4_csum_fail;
bool is_mcbc;
bool addr2_present;
};
static inline u32 ath12k_he_gi_to_nl80211_he_gi(u8 sgi)
{
u32 ret = 0;
@ -117,6 +106,109 @@ static inline u32 ath12k_he_gi_to_nl80211_he_gi(u8 sgi)
return ret;
}
static inline bool ath12k_dp_rx_h_more_frags(struct ath12k_hal *hal,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)(skb->data + hal->hal_desc_sz);
return ieee80211_has_morefrags(hdr->frame_control);
}
static inline u16 ath12k_dp_rx_h_frag_no(struct ath12k_hal *hal,
struct sk_buff *skb)
{
struct ieee80211_hdr *hdr;
hdr = (struct ieee80211_hdr *)(skb->data + hal->hal_desc_sz);
return le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG;
}
static inline u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab,
struct hal_rx_desc *desc)
{
return ab->hal.ops->rx_desc_get_l3_pad_bytes(desc);
}
static inline void ath12k_dp_rx_desc_end_tlv_copy(struct ath12k_hal *hal,
struct hal_rx_desc *fdesc,
struct hal_rx_desc *ldesc)
{
hal->ops->rx_desc_copy_end_tlv(fdesc, ldesc);
}
static inline void ath12k_dp_rxdesc_set_msdu_len(struct ath12k_hal *hal,
struct hal_rx_desc *desc,
u16 len)
{
hal->ops->rx_desc_set_msdu_len(desc, len);
}
static inline u32 ath12k_dp_rxdesc_get_ppduid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc)
{
return ab->hal.ops->rx_desc_get_mpdu_ppdu_id(rx_desc);
}
static inline void ath12k_dp_rx_desc_get_dot11_hdr(struct ath12k_hal *hal,
struct hal_rx_desc *desc,
struct ieee80211_hdr *hdr)
{
hal->ops->rx_desc_get_dot11_hdr(desc, hdr);
}
static inline void ath12k_dp_rx_desc_get_crypto_header(struct ath12k_hal *hal,
struct hal_rx_desc *desc,
u8 *crypto_hdr,
enum hal_encrypt_type enctype)
{
hal->ops->rx_desc_get_crypto_header(desc, crypto_hdr, enctype);
}
static inline u8 ath12k_dp_rx_get_msdu_src_link(struct ath12k_hal *hal,
struct hal_rx_desc *desc)
{
return hal->ops->rx_desc_get_msdu_src_link_id(desc);
}
static inline void ath12k_dp_clean_up_skb_list(struct sk_buff_head *skb_list)
{
struct sk_buff *skb;
while ((skb = __skb_dequeue(skb_list)))
dev_kfree_skb_any(skb);
}
static inline
void ath12k_dp_extract_rx_desc_data(struct ath12k_hal *hal,
struct hal_rx_desc_data *rx_info,
struct hal_rx_desc *rx_desc,
struct hal_rx_desc *ldesc)
{
hal->ops->extract_rx_desc_data(rx_info, rx_desc, ldesc);
}
void ath12k_dp_rx_h_undecap(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
struct hal_rx_desc *rx_desc,
enum hal_encrypt_type enctype,
bool decrypted,
struct hal_rx_desc_data *rx_info);
void ath12k_dp_rx_deliver_msdu(struct ath12k_pdev_dp *dp_pdev, struct napi_struct *napi,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info);
bool ath12k_dp_rx_check_nwifi_hdr_len_valid(struct ath12k_dp *dp,
struct hal_rx_desc *rx_desc,
struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info);
u64 ath12k_dp_rx_h_get_pn(struct ath12k_dp *dp, struct sk_buff *skb);
void ath12k_dp_rx_h_sort_frags(struct ath12k_hal *hal,
struct sk_buff_head *frag_list,
struct sk_buff *cur_frag);
void ath12k_dp_rx_h_undecap_frag(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
enum hal_encrypt_type enctype, u32 flags);
int ath12k_dp_rx_h_michael_mic(struct crypto_shash *tfm, u8 *key,
struct ieee80211_hdr *hdr, u8 *data,
size_t data_len, u8 *mic);
int ath12k_dp_rx_ampdu_start(struct ath12k *ar,
struct ieee80211_ampdu_params *params,
u8 link_id);
@ -127,14 +219,12 @@ int ath12k_dp_rx_peer_pn_replay_config(struct ath12k_link_vif *arvif,
const u8 *peer_addr,
enum set_key_cmd key_cmd,
struct ieee80211_key_conf *key);
void ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_peer *peer);
void ath12k_dp_rx_peer_tid_cleanup(struct ath12k *ar, struct ath12k_dp_link_peer *peer);
void ath12k_dp_rx_peer_tid_delete(struct ath12k *ar,
struct ath12k_peer *peer, u8 tid);
struct ath12k_dp_link_peer *peer, u8 tid);
int ath12k_dp_rx_peer_tid_setup(struct ath12k *ar, const u8 *peer_mac, int vdev_id,
u8 tid, u32 ba_win_sz, u16 ssn,
enum hal_pn_type pn_type);
void ath12k_dp_htt_htc_t2h_msg_handler(struct ath12k_base *ab,
struct sk_buff *skb);
int ath12k_dp_rx_pdev_reo_setup(struct ath12k_base *ab);
void ath12k_dp_rx_pdev_reo_cleanup(struct ath12k_base *ab);
int ath12k_dp_rx_htt_setup(struct ath12k_base *ab);
@ -143,15 +233,7 @@ void ath12k_dp_rx_free(struct ath12k_base *ab);
int ath12k_dp_rx_pdev_alloc(struct ath12k_base *ab, int pdev_idx);
void ath12k_dp_rx_pdev_free(struct ath12k_base *ab, int pdev_idx);
void ath12k_dp_rx_reo_cmd_list_cleanup(struct ath12k_base *ab);
void ath12k_dp_rx_process_reo_status(struct ath12k_base *ab);
int ath12k_dp_rx_process_wbm_err(struct ath12k_base *ab,
struct napi_struct *napi, int budget);
int ath12k_dp_rx_process_err(struct ath12k_base *ab, struct napi_struct *napi,
int budget);
int ath12k_dp_rx_process(struct ath12k_base *ab, int mac_id,
struct napi_struct *napi,
int budget);
int ath12k_dp_rx_bufs_replenish(struct ath12k_base *ab,
int ath12k_dp_rx_bufs_replenish(struct ath12k_dp *dp,
struct dp_rxdma_ring *rx_ring,
struct list_head *used_list,
int req_entries);
@ -160,32 +242,27 @@ int ath12k_dp_rx_peer_frag_setup(struct ath12k *ar, const u8 *peer_mac, int vdev
u8 ath12k_dp_rx_h_l3pad(struct ath12k_base *ab,
struct hal_rx_desc *desc);
struct ath12k_peer *
ath12k_dp_rx_h_find_peer(struct ath12k_base *ab, struct sk_buff *msdu,
struct ath12k_dp_rx_info *rx_info);
struct ath12k_dp_link_peer *
ath12k_dp_rx_h_find_link_peer(struct ath12k_pdev_dp *dp_pdev, struct sk_buff *msdu,
struct hal_rx_desc_data *rx_info);
u8 ath12k_dp_rx_h_decap_type(struct ath12k_base *ab,
struct hal_rx_desc *desc);
u32 ath12k_dp_rx_h_mpdu_err(struct ath12k_base *ab,
struct hal_rx_desc *desc);
void ath12k_dp_rx_h_ppdu(struct ath12k *ar, struct ath12k_dp_rx_info *rx_info);
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
int ath12k_dp_htt_tlv_iter(struct ath12k_base *ab, const void *ptr, size_t len,
int (*iter)(struct ath12k_base *ar, u16 tag, u16 len,
const void *ptr, void *data),
void *data);
void ath12k_dp_rx_h_fetch_info(struct ath12k_base *ab, struct hal_rx_desc *rx_desc,
struct ath12k_dp_rx_info *rx_info);
int ath12k_dp_rx_crypto_mic_len(struct ath12k *ar, enum hal_encrypt_type enctype);
int ath12k_dp_rx_crypto_mic_len(struct ath12k_dp *dp, enum hal_encrypt_type enctype);
u32 ath12k_dp_rxdesc_get_ppduid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
bool ath12k_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
int ath12k_dp_rx_link_desc_return(struct ath12k_base *ab,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action);
bool ath12k_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
void ath12k_dp_rx_h_ppdu(struct ath12k_pdev_dp *dp_pdev,
struct hal_rx_desc_data *rx_info);
struct sk_buff *ath12k_dp_rx_get_msdu_last_buf(struct sk_buff_head *msdu_list,
struct sk_buff *first);
void ath12k_dp_reo_cmd_free(struct ath12k_dp *dp, void *ctx,
enum hal_reo_cmd_status status);
void ath12k_dp_rx_tid_del_func(struct ath12k_dp *dp, void *ctx,
enum hal_reo_cmd_status status);
void ath12k_dp_rx_process_reo_cmd_update_rx_queue_list(struct ath12k_dp *dp);
void ath12k_dp_init_rx_tid_rxq(struct ath12k_dp_rx_tid_rxq *rx_tid_rxq,
struct ath12k_dp_rx_tid *rx_tid,
bool active);
void ath12k_dp_mark_tid_as_inactive(struct ath12k_dp *dp, int peer_id, u8 tid);
#endif /* ATH12K_DP_RX_H */

File diff suppressed because it is too large Load Diff

View File

@ -1,41 +1,32 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_TX_H
#define ATH12K_DP_TX_H
#include "core.h"
#include "hal_tx.h"
struct ath12k_dp_htt_wbm_tx_status {
bool acked;
s8 ack_rssi;
};
int ath12k_dp_tx_htt_h2t_ver_req_msg(struct ath12k_base *ab);
int ath12k_dp_tx(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
bool is_mcast);
void ath12k_dp_tx_completion_handler(struct ath12k_base *ab, int ring_id);
int ath12k_dp_tx_htt_h2t_ppdu_stats_req(struct ath12k *ar, u32 mask);
int
ath12k_dp_tx_htt_h2t_ext_stats_req(struct ath12k *ar, u8 type,
struct htt_ext_stats_cfg_params *cfg_params,
u64 cookie);
int ath12k_dp_tx_htt_rx_monitor_mode_ring_config(struct ath12k *ar, bool reset);
int ath12k_dp_tx_htt_rx_filter_setup(struct ath12k_base *ab, u32 ring_id,
int mac_id, enum hal_ring_type ring_type,
int rx_buf_size,
struct htt_rx_ring_tlv_filter *tlv_filter);
void ath12k_dp_tx_put_bank_profile(struct ath12k_dp *dp, u8 bank_id);
int ath12k_dp_tx_htt_tx_filter_setup(struct ath12k_base *ab, u32 ring_id,
int mac_id, enum hal_ring_type ring_type,
int tx_buf_size,
struct htt_tx_ring_tlv_filter *htt_tlv_filter);
int ath12k_dp_tx_htt_monitor_mode_ring_config(struct ath12k *ar, bool reset);
enum hal_tcl_encap_type
ath12k_dp_tx_get_encap_type(struct ath12k_base *ab, struct sk_buff *skb);
void ath12k_dp_tx_encap_nwifi(struct sk_buff *skb);
u8 ath12k_dp_tx_get_tid(struct sk_buff *skb);
void *ath12k_dp_metadata_align_skb(struct sk_buff *skb, u8 tail_len);
int ath12k_dp_tx_align_payload(struct ath12k_dp *dp, struct sk_buff **pskb);
void ath12k_dp_tx_release_txbuf(struct ath12k_dp *dp,
struct ath12k_tx_desc_info *tx_desc,
u8 pool_id);
struct ath12k_tx_desc_info *ath12k_dp_tx_assign_buffer(struct ath12k_dp *dp,
u8 pool_id);
void ath12k_dp_tx_free_txbuf(struct ath12k_dp *dp,
struct dp_tx_ring *tx_ring,
struct ath12k_tx_desc_params *desc_params);
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/skbuff.h>
#include <linux/ctype.h>
@ -376,6 +376,7 @@ void ath12k_htc_rx_completion_handler(struct ath12k_base *ab,
out:
kfree_skb(skb);
}
EXPORT_SYMBOL(ath12k_htc_rx_completion_handler);
static void ath12k_htc_control_rx_complete(struct ath12k_base *ab,
struct sk_buff *skb)

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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_HW_H
@ -128,11 +128,6 @@ struct ath12k_hw_ring_mask {
u8 tx_mon_dest[ATH12K_EXT_IRQ_GRP_NUM_MAX];
};
struct ath12k_hw_hal_params {
enum hal_rx_buf_return_buf_manager rx_buf_rbm;
u32 wbm2sw_cc_enable;
};
enum ath12k_m3_fw_loaders {
ath12k_m3_fw_loader_driver,
ath12k_m3_fw_loader_remoteproc,
@ -156,7 +151,6 @@ struct ath12k_hw_params {
const struct ath12k_hw_ops *hw_ops;
const struct ath12k_hw_ring_mask *ring_mask;
const struct ath12k_hw_regs *regs;
const struct ce_attr *host_ce_config;
u32 ce_count;
@ -165,8 +159,6 @@ struct ath12k_hw_params {
const struct service_to_pipe *svc_to_ce_map;
u32 svc_to_ce_map_len;
const struct ath12k_hw_hal_params *hal_params;
bool rxdma1_enable:1;
int num_rxdma_per_pdev;
int num_rxdma_dst_ring;
@ -193,8 +185,6 @@ struct ath12k_hw_params {
void (*wmi_init)(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
const struct hal_ops *hal_ops;
u64 qmi_cnss_feature_bitmap;
u32 rfkill_pin;
@ -285,86 +275,6 @@ enum ath12k_bd_ie_type {
ATH12K_BD_IE_REGDB = 1,
};
struct ath12k_hw_regs {
u32 hal_tcl1_ring_id;
u32 hal_tcl1_ring_misc;
u32 hal_tcl1_ring_tp_addr_lsb;
u32 hal_tcl1_ring_tp_addr_msb;
u32 hal_tcl1_ring_consumer_int_setup_ix0;
u32 hal_tcl1_ring_consumer_int_setup_ix1;
u32 hal_tcl1_ring_msi1_base_lsb;
u32 hal_tcl1_ring_msi1_base_msb;
u32 hal_tcl1_ring_msi1_data;
u32 hal_tcl_ring_base_lsb;
u32 hal_tcl1_ring_base_lsb;
u32 hal_tcl1_ring_base_msb;
u32 hal_tcl2_ring_base_lsb;
u32 hal_tcl_status_ring_base_lsb;
u32 hal_reo1_qdesc_addr;
u32 hal_reo1_qdesc_max_peerid;
u32 hal_wbm_idle_ring_base_lsb;
u32 hal_wbm_idle_ring_misc_addr;
u32 hal_wbm_r0_idle_list_cntl_addr;
u32 hal_wbm_r0_idle_list_size_addr;
u32 hal_wbm_scattered_ring_base_lsb;
u32 hal_wbm_scattered_ring_base_msb;
u32 hal_wbm_scattered_desc_head_info_ix0;
u32 hal_wbm_scattered_desc_head_info_ix1;
u32 hal_wbm_scattered_desc_tail_info_ix0;
u32 hal_wbm_scattered_desc_tail_info_ix1;
u32 hal_wbm_scattered_desc_ptr_hp_addr;
u32 hal_wbm_sw_release_ring_base_lsb;
u32 hal_wbm_sw1_release_ring_base_lsb;
u32 hal_wbm0_release_ring_base_lsb;
u32 hal_wbm1_release_ring_base_lsb;
u32 pcie_qserdes_sysclk_en_sel;
u32 pcie_pcs_osc_dtct_config_base;
u32 hal_umac_ce0_src_reg_base;
u32 hal_umac_ce0_dest_reg_base;
u32 hal_umac_ce1_src_reg_base;
u32 hal_umac_ce1_dest_reg_base;
u32 hal_ppe_rel_ring_base;
u32 hal_reo2_ring_base;
u32 hal_reo1_misc_ctrl_addr;
u32 hal_reo1_sw_cookie_cfg0;
u32 hal_reo1_sw_cookie_cfg1;
u32 hal_reo1_qdesc_lut_base0;
u32 hal_reo1_qdesc_lut_base1;
u32 hal_reo1_ring_base_lsb;
u32 hal_reo1_ring_base_msb;
u32 hal_reo1_ring_id;
u32 hal_reo1_ring_misc;
u32 hal_reo1_ring_hp_addr_lsb;
u32 hal_reo1_ring_hp_addr_msb;
u32 hal_reo1_ring_producer_int_setup;
u32 hal_reo1_ring_msi1_base_lsb;
u32 hal_reo1_ring_msi1_base_msb;
u32 hal_reo1_ring_msi1_data;
u32 hal_reo1_aging_thres_ix0;
u32 hal_reo1_aging_thres_ix1;
u32 hal_reo1_aging_thres_ix2;
u32 hal_reo1_aging_thres_ix3;
u32 hal_reo2_sw0_ring_base;
u32 hal_sw2reo_ring_base;
u32 hal_sw2reo1_ring_base;
u32 hal_reo_cmd_ring_base;
u32 hal_reo_status_ring_base;
u32 gcc_gcc_pcie_hot_rst;
};
static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type)
{
switch (type) {
@ -377,6 +287,4 @@ static inline const char *ath12k_bd_ie_type_str(enum ath12k_bd_ie_type type)
return "unknown";
}
int ath12k_hw_init(struct ath12k_base *ab);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -54,9 +54,6 @@ struct ath12k_generic_iter {
* for driver usage purpose.
*/
#define ATH12K_FIRST_SCAN_LINK IEEE80211_MLD_MAX_NUM_LINKS
#define ATH12K_SCAN_MAX_LINKS ATH12K_GROUP_MAX_RADIO
/* Define 1 scan link for each radio for parallel scan purposes */
#define ATH12K_NUM_MAX_LINKS (IEEE80211_MLD_MAX_NUM_LINKS + ATH12K_SCAN_MAX_LINKS)
#define ATH12K_SCAN_LINKS_MASK GENMASK(ATH12K_NUM_MAX_LINKS, IEEE80211_MLD_MAX_NUM_LINKS)
#define ATH12K_NUM_MAX_ACTIVE_LINKS_PER_DEVICE 2
@ -172,6 +169,7 @@ struct ath12k *ath12k_mac_get_ar_by_pdev_id(struct ath12k_base *ab, u32 pdev_id)
void ath12k_mac_drain_tx(struct ath12k *ar);
void ath12k_mac_peer_cleanup_all(struct ath12k *ar);
void ath12k_mac_dp_peer_cleanup(struct ath12k_hw *ah);
int ath12k_mac_tx_mgmt_pending_free(int buf_id, void *skb, void *ctx);
enum rate_info_bw ath12k_mac_bw_to_mac80211_bw(enum ath12k_supported_bw bw);
enum ath12k_supported_bw ath12k_mac_mac80211_bw_to_ath12k_bw(enum rate_info_bw bw);
@ -206,4 +204,139 @@ void ath12k_mac_update_freq_range(struct ath12k *ar,
void ath12k_mac_fill_reg_tpc_info(struct ath12k *ar,
struct ath12k_link_vif *arvif,
struct ieee80211_chanctx_conf *ctx);
int ath12k_mac_op_start(struct ieee80211_hw *hw);
void ath12k_mac_op_stop(struct ieee80211_hw *hw, bool suspend);
void
ath12k_mac_op_reconfig_complete(struct ieee80211_hw *hw,
enum ieee80211_reconfig_type reconfig_type);
int ath12k_mac_op_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void ath12k_mac_op_remove_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
void ath12k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int ath12k_mac_op_config(struct ieee80211_hw *hw, int radio_idx, u32 changed);
void ath12k_mac_op_link_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *info,
u64 changed);
void ath12k_mac_op_vif_cfg_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u64 changed);
int
ath12k_mac_op_change_vif_links
(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u16 old_links, u16 new_links,
struct ieee80211_bss_conf *ol[IEEE80211_MLD_MAX_NUM_LINKS]);
void ath12k_mac_op_configure_filter(struct ieee80211_hw *hw,
unsigned int changed_flags,
unsigned int *total_flags,
u64 multicast);
int ath12k_mac_op_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_scan_request *hw_req);
void ath12k_mac_op_cancel_hw_scan(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int ath12k_mac_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct ieee80211_vif *vif, struct ieee80211_sta *sta,
struct ieee80211_key_conf *key);
void ath12k_mac_op_set_rekey_data(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct cfg80211_gtk_rekey_data *data);
int ath12k_mac_op_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
enum ieee80211_sta_state old_state,
enum ieee80211_sta_state new_state);
int ath12k_mac_op_sta_set_txpwr(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta);
void ath12k_mac_op_link_sta_rc_update(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
u32 changed);
int ath12k_mac_op_conf_tx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int link_id, u16 ac,
const struct ieee80211_tx_queue_params *params);
int ath12k_mac_op_set_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 tx_ant, u32 rx_ant);
int ath12k_mac_op_get_antenna(struct ieee80211_hw *hw, int radio_idx,
u32 *tx_ant, u32 *rx_ant);
int ath12k_mac_op_ampdu_action(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_ampdu_params *params);
int ath12k_mac_op_add_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void ath12k_mac_op_remove_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx);
void ath12k_mac_op_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed);
int
ath12k_mac_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx);
void
ath12k_mac_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct ieee80211_chanctx_conf *ctx);
int
ath12k_mac_op_switch_vif_chanctx(struct ieee80211_hw *hw,
struct ieee80211_vif_chanctx_switch *vifs,
int n_vifs,
enum ieee80211_chanctx_switch_mode mode);
int ath12k_mac_op_set_rts_threshold(struct ieee80211_hw *hw,
int radio_idx, u32 value);
int ath12k_mac_op_set_frag_threshold(struct ieee80211_hw *hw,
int radio_idx, u32 value);
int
ath12k_mac_op_set_bitrate_mask(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
const struct cfg80211_bitrate_mask *mask);
int ath12k_mac_op_get_survey(struct ieee80211_hw *hw, int idx,
struct survey_info *survey);
void ath12k_mac_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop);
void ath12k_mac_op_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
struct station_info *sinfo);
void ath12k_mac_op_link_sta_statistics(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_link_sta *link_sta,
struct link_station_info *link_sinfo);
int ath12k_mac_op_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_channel *chan,
int duration,
enum ieee80211_roc_type type);
int ath12k_mac_op_cancel_remain_on_channel(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int ath12k_mac_op_change_sta_links(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
u16 old_links, u16 new_links);
bool ath12k_mac_op_can_activate_links(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
u16 active_links);
int ath12k_mac_op_get_txpower(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
unsigned int link_id,
int *dbm);
int ath12k_mac_mgmt_tx(struct ath12k *ar, struct sk_buff *skb,
bool is_prb_rsp);
void ath12k_mac_add_p2p_noa_ie(struct ath12k *ar,
struct ieee80211_vif *vif,
struct sk_buff *skb,
bool is_prb_rsp);
u8 ath12k_mac_get_tx_link(struct ieee80211_sta *sta, struct ieee80211_vif *vif,
u8 link, struct sk_buff *skb, u32 info_flags);
void ath12k_mlo_mcast_update_tx_link_address(struct ieee80211_vif *vif,
u8 link_id, struct sk_buff *skb,
u32 info_flags);
#endif

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020-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.
*/
#include <linux/msi.h>
@ -18,136 +18,6 @@
#define OTP_VALID_DUALMAC_BOARD_ID_MASK 0x1000
#define MHI_CB_INVALID 0xff
static const struct mhi_channel_config ath12k_mhi_channels_qcn9274[] = {
{
.num = 20,
.name = "IPCR",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
.name = "IPCR",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
static struct mhi_event_config ath12k_mhi_events_qcn9274[] = {
{
.num_elements = 32,
.irq_moderation_ms = 0,
.irq = 1,
.data_type = MHI_ER_CTRL,
.mode = MHI_DB_BRST_DISABLE,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
{
.num_elements = 256,
.irq_moderation_ms = 1,
.irq = 2,
.mode = MHI_DB_BRST_DISABLE,
.priority = 1,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
};
const struct mhi_controller_config ath12k_mhi_config_qcn9274 = {
.max_channels = 30,
.timeout_ms = 10000,
.use_bounce_buf = false,
.buf_len = 0,
.num_channels = ARRAY_SIZE(ath12k_mhi_channels_qcn9274),
.ch_cfg = ath12k_mhi_channels_qcn9274,
.num_events = ARRAY_SIZE(ath12k_mhi_events_qcn9274),
.event_cfg = ath12k_mhi_events_qcn9274,
};
static const struct mhi_channel_config ath12k_mhi_channels_wcn7850[] = {
{
.num = 20,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
static struct mhi_event_config ath12k_mhi_events_wcn7850[] = {
{
.num_elements = 32,
.irq_moderation_ms = 0,
.irq = 1,
.mode = MHI_DB_BRST_DISABLE,
.data_type = MHI_ER_CTRL,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
{
.num_elements = 256,
.irq_moderation_ms = 1,
.irq = 2,
.mode = MHI_DB_BRST_DISABLE,
.priority = 1,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
};
const struct mhi_controller_config ath12k_mhi_config_wcn7850 = {
.max_channels = 128,
.timeout_ms = 2000,
.use_bounce_buf = false,
.buf_len = 8192,
.num_channels = ARRAY_SIZE(ath12k_mhi_channels_wcn7850),
.ch_cfg = ath12k_mhi_channels_wcn7850,
.num_events = ARRAY_SIZE(ath12k_mhi_events_wcn7850),
.event_cfg = ath12k_mhi_events_wcn7850,
};
void ath12k_mhi_set_mhictrl_reset(struct ath12k_base *ab)
{
u32 val;

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef _ATH12K_MHI_H
#define _ATH12K_MHI_H
@ -31,9 +31,6 @@ enum ath12k_mhi_state {
ATH12K_MHI_RDDM_DONE,
};
extern const struct mhi_controller_config ath12k_mhi_config_qcn9274;
extern const struct mhi_controller_config ath12k_mhi_config_wcn7850;
int ath12k_mhi_start(struct ath12k_pci *ar_pci);
void ath12k_mhi_stop(struct ath12k_pci *ar_pci, bool is_suspend);
int ath12k_mhi_register(struct ath12k_pci *ar_pci);

View File

@ -15,6 +15,7 @@
#include "hif.h"
#include "mhi.h"
#include "debug.h"
#include "hal.h"
#define ATH12K_PCI_BAR_NUM 0
#define ATH12K_PCI_DMA_MASK 36
@ -28,44 +29,17 @@
#define WINDOW_RANGE_MASK GENMASK(18, 0)
#define WINDOW_STATIC_MASK GENMASK(31, 6)
#define TCSR_SOC_HW_VERSION 0x1B00000
#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)
#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 4)
/* BAR0 + 4k is always accessible, and no
* need to force wakeup.
* 4K - 32 = 0xFE0
*/
#define ACCESS_ALWAYS_OFF 0xFE0
#define QCN9274_DEVICE_ID 0x1109
#define WCN7850_DEVICE_ID 0x1107
#define PCIE_LOCAL_REG_QRTR_NODE_ID 0x1E03164
#define DOMAIN_NUMBER_MASK GENMASK(7, 4)
#define BUS_NUMBER_MASK GENMASK(3, 0)
static const struct pci_device_id ath12k_pci_id_table[] = {
{ PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) },
{ PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) },
{}
};
MODULE_DEVICE_TABLE(pci, ath12k_pci_id_table);
/* TODO: revisit IRQ mapping for new SRNG's */
static const struct ath12k_msi_config ath12k_msi_config[] = {
{
.total_vectors = 16,
.total_users = 3,
.users = (struct ath12k_msi_user[]) {
{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
},
},
};
static struct ath12k_pci_driver *ath12k_pci_family_drivers[ATH12K_DEVICE_FAMILY_MAX];
static const struct ath12k_msi_config msi_config_one_msi = {
.total_vectors = 1,
.total_users = 4,
@ -136,30 +110,6 @@ static const char *irq_name[ATH12K_IRQ_NUM_MAX] = {
"tcl2host-status-ring",
};
static int ath12k_pci_bus_wake_up(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
}
static void ath12k_pci_bus_release(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
}
static const struct ath12k_pci_ops ath12k_pci_ops_qcn9274 = {
.wakeup = NULL,
.release = NULL,
};
static const struct ath12k_pci_ops ath12k_pci_ops_wcn7850 = {
.wakeup = ath12k_pci_bus_wake_up,
.release = ath12k_pci_bus_release,
};
static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)
{
struct ath12k_base *ab = ab_pci->ab;
@ -183,10 +133,12 @@ static void ath12k_pci_select_window(struct ath12k_pci *ab_pci, u32 offset)
static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci)
{
u32 umac_window = u32_get_bits(HAL_SEQ_WCSS_UMAC_OFFSET, WINDOW_VALUE_MASK);
u32 ce_window = u32_get_bits(HAL_CE_WFSS_CE_REG_BASE, WINDOW_VALUE_MASK);
u32 umac_window;
u32 ce_window;
u32 window;
umac_window = u32_get_bits(ab_pci->reg_base->umac_base, WINDOW_VALUE_MASK);
ce_window = u32_get_bits(ab_pci->reg_base->ce_reg_base, WINDOW_VALUE_MASK);
window = (umac_window << 12) | (ce_window << 6);
spin_lock_bh(&ab_pci->window_lock);
@ -199,13 +151,14 @@ static void ath12k_pci_select_static_window(struct ath12k_pci *ab_pci)
static u32 ath12k_pci_get_window_start(struct ath12k_base *ab,
u32 offset)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
u32 window_start;
/* If offset lies within DP register range, use 3rd window */
if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < WINDOW_RANGE_MASK)
if ((offset ^ ab_pci->reg_base->umac_base) < WINDOW_RANGE_MASK)
window_start = 3 * WINDOW_START;
/* If offset lies within CE register range, use 2nd window */
else if ((offset ^ HAL_CE_WFSS_CE_REG_BASE) < WINDOW_RANGE_MASK)
else if ((offset ^ ab_pci->reg_base->ce_reg_base) < WINDOW_RANGE_MASK)
window_start = 2 * WINDOW_START;
else
window_start = WINDOW_START;
@ -544,10 +497,11 @@ static int ath12k_pci_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;
int i;
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);
for (i = 0; i < irq_grp->num_irq; i++)
@ -1244,6 +1198,7 @@ u32 ath12k_pci_read32(struct ath12k_base *ab, u32 offset)
ab_pci->pci_ops->release(ab);
return val;
}
EXPORT_SYMBOL(ath12k_pci_read32);
void ath12k_pci_write32(struct ath12k_base *ab, u32 offset, u32 value)
{
@ -1549,28 +1504,34 @@ static const struct ath12k_hif_ops ath12k_pci_hif_ops = {
#endif
};
static
void ath12k_pci_read_hw_version(struct ath12k_base *ab, u32 *major, u32 *minor)
static enum ath12k_device_family
ath12k_get_device_family(const struct pci_device_id *pci_dev)
{
u32 soc_hw_version;
enum ath12k_device_family device_family_id;
const struct pci_device_id *id;
soc_hw_version = ath12k_pci_read32(ab, TCSR_SOC_HW_VERSION);
*major = FIELD_GET(TCSR_SOC_HW_VERSION_MAJOR_MASK,
soc_hw_version);
*minor = FIELD_GET(TCSR_SOC_HW_VERSION_MINOR_MASK,
soc_hw_version);
for (device_family_id = ATH12K_DEVICE_FAMILY_START;
device_family_id < ATH12K_DEVICE_FAMILY_MAX; device_family_id++) {
if (!ath12k_pci_family_drivers[device_family_id])
continue;
ath12k_dbg(ab, ATH12K_DBG_PCI,
"pci tcsr_soc_hw_version major %d minor %d\n",
*major, *minor);
id = ath12k_pci_family_drivers[device_family_id]->id_table;
while (id->device) {
if (id->device == pci_dev->device)
return device_family_id;
id += 1;
}
}
return ATH12K_DEVICE_FAMILY_MAX;
}
static int ath12k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev)
{
struct ath12k_base *ab;
enum ath12k_device_family device_id;
struct ath12k_pci *ab_pci;
u32 soc_hw_version_major, soc_hw_version_minor;
struct ath12k_base *ab;
int ret;
ab = ath12k_core_alloc(&pdev->dev, sizeof(*ab_pci), ATH12K_BUS_PCI);
@ -1605,56 +1566,25 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
ab->id.subsystem_vendor = pdev->subsystem_vendor;
ab->id.subsystem_device = pdev->subsystem_device;
switch (pci_dev->device) {
case QCN9274_DEVICE_ID:
ab_pci->msi_config = &ath12k_msi_config[0];
ab->static_window_map = true;
ab_pci->pci_ops = &ath12k_pci_ops_qcn9274;
ab->hal_rx_ops = &hal_rx_qcn9274_ops;
ath12k_pci_read_hw_version(ab, &soc_hw_version_major,
&soc_hw_version_minor);
ab->target_mem_mode = ath12k_core_get_memory_mode(ab);
switch (soc_hw_version_major) {
case ATH12K_PCI_SOC_HW_VERSION_2:
ab->hw_rev = ATH12K_HW_QCN9274_HW20;
break;
case ATH12K_PCI_SOC_HW_VERSION_1:
ab->hw_rev = ATH12K_HW_QCN9274_HW10;
break;
default:
dev_err(&pdev->dev,
"Unknown hardware version found for QCN9274: 0x%x\n",
soc_hw_version_major);
ret = -EOPNOTSUPP;
goto err_pci_free_region;
}
break;
case WCN7850_DEVICE_ID:
ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD;
ab_pci->msi_config = &ath12k_msi_config[0];
ab->static_window_map = false;
ab_pci->pci_ops = &ath12k_pci_ops_wcn7850;
ab->hal_rx_ops = &hal_rx_wcn7850_ops;
ath12k_pci_read_hw_version(ab, &soc_hw_version_major,
&soc_hw_version_minor);
ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
switch (soc_hw_version_major) {
case ATH12K_PCI_SOC_HW_VERSION_2:
ab->hw_rev = ATH12K_HW_WCN7850_HW20;
break;
default:
dev_err(&pdev->dev,
"Unknown hardware version found for WCN7850: 0x%x\n",
soc_hw_version_major);
ret = -EOPNOTSUPP;
goto err_pci_free_region;
}
break;
device_id = ath12k_get_device_family(pci_dev);
if (device_id >= ATH12K_DEVICE_FAMILY_MAX) {
ath12k_err(ab, "failed to get device family id\n");
ret = -EINVAL;
goto err_pci_free_region;
}
default:
dev_err(&pdev->dev, "Unknown PCI device found: 0x%x\n",
pci_dev->device);
ret = -EOPNOTSUPP;
ath12k_dbg(ab, ATH12K_DBG_PCI, "PCI device family id: %d\n", device_id);
ab_pci->device_family_ops = &ath12k_pci_family_drivers[device_id]->ops;
ab_pci->reg_base = ath12k_pci_family_drivers[device_id]->reg_base;
/* 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_pci->device_family_ops->probe(pdev, pci_dev);
if (ret) {
ath12k_err(ab, "failed to probe device: %d\n", ret);
goto err_pci_free_region;
}
@ -1709,13 +1639,25 @@ static int ath12k_pci_probe(struct pci_dev *pdev,
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);
@ -1774,6 +1716,9 @@ qmi_fail:
ath12k_hal_srng_deinit(ab);
ath12k_ce_free_pipes(ab);
ab_pci->device_family_ops->arch_deinit(ab);
ath12k_core_free(ab);
}
@ -1862,33 +1807,47 @@ static const struct dev_pm_ops __maybe_unused ath12k_pci_pm_ops = {
ath12k_pci_pm_resume_early)
};
static struct pci_driver ath12k_pci_driver = {
.name = "ath12k_pci",
.id_table = ath12k_pci_id_table,
.probe = ath12k_pci_probe,
.remove = ath12k_pci_remove,
.shutdown = ath12k_pci_shutdown,
.driver.pm = &ath12k_pci_pm_ops,
};
int ath12k_pci_init(void)
int ath12k_pci_register_driver(const enum ath12k_device_family device_id,
struct ath12k_pci_driver *driver)
{
int ret;
struct pci_driver *pci_driver;
ret = pci_register_driver(&ath12k_pci_driver);
if (ret) {
pr_err("failed to register ath12k pci driver: %d\n",
ret);
return ret;
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_pci_family_drivers[device_id]) {
pr_err("Driver already registered for %d\n", device_id);
return -EALREADY;
}
return 0;
}
ath12k_pci_family_drivers[device_id] = driver;
void ath12k_pci_exit(void)
{
pci_unregister_driver(&ath12k_pci_driver);
pci_driver = &ath12k_pci_family_drivers[device_id]->driver;
pci_driver->name = driver->name;
pci_driver->id_table = driver->id_table;
pci_driver->probe = ath12k_pci_probe;
pci_driver->remove = ath12k_pci_remove;
pci_driver->shutdown = ath12k_pci_shutdown;
pci_driver->driver.pm = &ath12k_pci_pm_ops;
return pci_register_driver(pci_driver);
}
EXPORT_SYMBOL(ath12k_pci_register_driver);
void ath12k_pci_unregister_driver(const enum ath12k_device_family device_id)
{
if (device_id >= ATH12K_DEVICE_FAMILY_MAX ||
!ath12k_pci_family_drivers[device_id])
return;
pci_unregister_driver(&ath12k_pci_family_drivers[device_id]->driver);
ath12k_pci_family_drivers[device_id] = NULL;
}
EXPORT_SYMBOL(ath12k_pci_unregister_driver);
/* firmware files */
MODULE_FIRMWARE(ATH12K_FW_DIR "/QCN9274/hw2.0/*");

View File

@ -1,12 +1,13 @@
/* 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
#include <linux/mhi.h>
#include <linux/pci.h>
#include "core.h"
@ -29,7 +30,7 @@
#define PARM_LTSSM_VALUE 0x111
#define GCC_GCC_PCIE_HOT_RST(ab) \
((ab)->hw_params->regs->gcc_gcc_pcie_hot_rst)
((ab)->hal.regs->gcc_gcc_pcie_hot_rst)
#define GCC_GCC_PCIE_HOT_RST_VAL 0x10
@ -38,17 +39,17 @@
#define PCIE_INT_CLEAR_ALL 0xffffffff
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_REG(ab) \
((ab)->hw_params->regs->pcie_qserdes_sysclk_en_sel)
((ab)->hal.regs->pcie_qserdes_sysclk_en_sel)
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_VAL 0x10
#define PCIE_QSERDES_COM_SYSCLK_EN_SEL_MSK 0xffffffff
#define PCIE_PCS_OSC_DTCT_CONFIG1_REG(ab) \
((ab)->hw_params->regs->pcie_pcs_osc_dtct_config_base)
((ab)->hal.regs->pcie_pcs_osc_dtct_config_base)
#define PCIE_PCS_OSC_DTCT_CONFIG1_VAL 0x02
#define PCIE_PCS_OSC_DTCT_CONFIG2_REG(ab) \
((ab)->hw_params->regs->pcie_pcs_osc_dtct_config_base + 0x4)
((ab)->hal.regs->pcie_pcs_osc_dtct_config_base + 0x4)
#define PCIE_PCS_OSC_DTCT_CONFIG2_VAL 0x52
#define PCIE_PCS_OSC_DTCT_CONFIG4_REG(ab) \
((ab)->hw_params->regs->pcie_pcs_osc_dtct_config_base + 0xc)
((ab)->hal.regs->pcie_pcs_osc_dtct_config_base + 0xc)
#define PCIE_PCS_OSC_DTCT_CONFIG4_VAL 0xff
#define PCIE_PCS_OSC_DTCT_CONFIG_MSK 0x000000ff
@ -70,9 +71,6 @@
#define QRTR_PCI_DOMAIN_NR_MASK GENMASK(7, 4)
#define QRTR_PCI_BUS_NUMBER_MASK GENMASK(3, 0)
#define ATH12K_PCI_SOC_HW_VERSION_1 1
#define ATH12K_PCI_SOC_HW_VERSION_2 2
struct ath12k_msi_user {
const char *name;
int num_vectors;
@ -97,6 +95,17 @@ struct ath12k_pci_ops {
void (*release)(struct ath12k_base *ab);
};
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 {
u32 umac_base;
u32 ce_reg_base;
};
struct ath12k_pci {
struct pci_dev *pdev;
struct ath12k_base *ab;
@ -119,6 +128,16 @@ struct ath12k_pci {
const struct ath12k_pci_ops *pci_ops;
u32 qmi_instance;
u64 dma_mask;
const struct ath12k_pci_device_family_ops *device_family_ops;
const struct ath12k_pci_reg_base *reg_base;
};
struct ath12k_pci_driver {
const char *name;
const struct pci_device_id *id_table;
struct ath12k_pci_device_family_ops ops;
struct pci_driver driver;
const struct ath12k_pci_reg_base *reg_base;
};
static inline struct ath12k_pci *ath12k_pci_priv(struct ath12k_base *ab)
@ -148,6 +167,7 @@ void ath12k_pci_stop(struct ath12k_base *ab);
int ath12k_pci_start(struct ath12k_base *ab);
int ath12k_pci_power_up(struct ath12k_base *ab);
void ath12k_pci_power_down(struct ath12k_base *ab, bool is_suspend);
int ath12k_pci_init(void);
void ath12k_pci_exit(void);
int ath12k_pci_register_driver(const enum ath12k_device_family device_id,
struct ath12k_pci_driver *driver);
void ath12k_pci_unregister_driver(const enum ath12k_device_family device_id);
#endif /* ATH12K_PCI_H */

View File

@ -1,211 +1,28 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "peer.h"
#include "debug.h"
#include "debugfs.h"
struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah, const u8 *addr)
{
struct ath12k_ml_peer *ml_peer;
lockdep_assert_wiphy(ah->hw->wiphy);
list_for_each_entry(ml_peer, &ah->ml_peers, list) {
if (!ether_addr_equal(ml_peer->addr, addr))
continue;
return ml_peer;
}
return NULL;
}
struct ath12k_peer *ath12k_peer_find(struct ath12k_base *ab, int vdev_id,
const u8 *addr)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list) {
if (peer->vdev_id != vdev_id)
continue;
if (!ether_addr_equal(peer->addr, addr))
continue;
return peer;
}
return NULL;
}
static struct ath12k_peer *ath12k_peer_find_by_pdev_idx(struct ath12k_base *ab,
u8 pdev_idx, const u8 *addr)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list) {
if (peer->pdev_idx != pdev_idx)
continue;
if (!ether_addr_equal(peer->addr, addr))
continue;
return peer;
}
return NULL;
}
struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab,
const u8 *addr)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list) {
if (!ether_addr_equal(peer->addr, addr))
continue;
return peer;
}
return NULL;
}
static struct ath12k_peer *ath12k_peer_find_by_ml_id(struct ath12k_base *ab,
int ml_peer_id)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list)
if (ml_peer_id == peer->ml_id)
return peer;
return NULL;
}
struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab,
int peer_id)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
if (peer_id == HAL_INVALID_PEERID)
return NULL;
if (peer_id & ATH12K_PEER_ML_ID_VALID)
return ath12k_peer_find_by_ml_id(ab, peer_id);
list_for_each_entry(peer, &ab->peers, list)
if (peer_id == peer->peer_id)
return peer;
return NULL;
}
bool ath12k_peer_exist_by_vdev_id(struct ath12k_base *ab, int vdev_id)
{
struct ath12k_peer *peer;
spin_lock_bh(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list) {
if (vdev_id == peer->vdev_id) {
spin_unlock_bh(&ab->base_lock);
return true;
}
}
spin_unlock_bh(&ab->base_lock);
return false;
}
struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab,
int ast_hash)
{
struct ath12k_peer *peer;
lockdep_assert_held(&ab->base_lock);
list_for_each_entry(peer, &ab->peers, list)
if (ast_hash == peer->ast_hash)
return peer;
return NULL;
}
void ath12k_peer_unmap_event(struct ath12k_base *ab, u16 peer_id)
{
struct ath12k_peer *peer;
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find_by_id(ab, peer_id);
if (!peer) {
ath12k_warn(ab, "peer-unmap-event: unknown peer id %d\n",
peer_id);
goto exit;
}
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
peer->vdev_id, peer->addr, peer_id);
list_del(&peer->list);
kfree(peer);
wake_up(&ab->peer_mapping_wq);
exit:
spin_unlock_bh(&ab->base_lock);
}
void ath12k_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id)
{
struct ath12k_peer *peer;
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find(ab, vdev_id, mac_addr);
if (!peer) {
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
if (!peer)
goto exit;
peer->vdev_id = vdev_id;
peer->peer_id = peer_id;
peer->ast_hash = ast_hash;
peer->hw_peer_id = hw_peer_id;
ether_addr_copy(peer->addr, mac_addr);
list_add(&peer->list, &ab->peers);
wake_up(&ab->peer_mapping_wq);
}
ath12k_dbg(ab, ATH12K_DBG_DP_HTT, "htt peer map vdev %d peer %pM id %d\n",
vdev_id, mac_addr, peer_id);
exit:
spin_unlock_bh(&ab->base_lock);
}
static int ath12k_wait_for_peer_common(struct ath12k_base *ab, int vdev_id,
const u8 *addr, bool expect_mapped)
static int ath12k_wait_for_dp_link_peer_common(struct ath12k_base *ab, int vdev_id,
const u8 *addr, bool expect_mapped)
{
int ret;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
ret = wait_event_timeout(ab->peer_mapping_wq, ({
bool mapped;
spin_lock_bh(&ab->base_lock);
mapped = !!ath12k_peer_find(ab, vdev_id, addr);
spin_unlock_bh(&ab->base_lock);
spin_lock_bh(&dp->dp_lock);
mapped = !!ath12k_dp_link_peer_find_by_vdev_and_addr(dp,
vdev_id,
addr);
spin_unlock_bh(&dp->dp_lock);
(mapped == expect_mapped ||
test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags));
@ -219,30 +36,30 @@ static int ath12k_wait_for_peer_common(struct ath12k_base *ab, int vdev_id,
void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id)
{
struct ath12k_peer *peer, *tmp;
struct ath12k_dp_link_peer *peer, *tmp;
struct ath12k_base *ab = ar->ab;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
spin_lock_bh(&ab->base_lock);
list_for_each_entry_safe(peer, tmp, &ab->peers, list) {
spin_lock_bh(&dp->dp_lock);
list_for_each_entry_safe(peer, tmp, &dp->peers, list) {
if (peer->vdev_id != vdev_id)
continue;
ath12k_warn(ab, "removing stale peer %pM from vdev_id %d\n",
peer->addr, vdev_id);
list_del(&peer->list);
kfree(peer);
ath12k_dp_link_peer_free(peer);
ar->num_peers--;
}
spin_unlock_bh(&ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
}
static int ath12k_wait_for_peer_deleted(struct ath12k *ar, int vdev_id, const u8 *addr)
{
return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, false);
return ath12k_wait_for_dp_link_peer_common(ar->ab, vdev_id, addr, false);
}
int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
@ -293,6 +110,10 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
ath12k_dp_link_peer_unassign(ath12k_ab_to_dp(ar->ab),
&(ath12k_ar_to_ah(ar)->dp_hw), vdev_id,
addr, ar->hw_link_id);
ret = ath12k_peer_delete_send(ar, vdev_id, addr);
if (ret)
return ret;
@ -308,7 +129,7 @@ int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr)
static int ath12k_wait_for_peer_created(struct ath12k *ar, int vdev_id, const u8 *addr)
{
return ath12k_wait_for_peer_common(ar->ab, vdev_id, addr, true);
return ath12k_wait_for_dp_link_peer_common(ar->ab, vdev_id, addr, true);
}
int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
@ -316,28 +137,34 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct ath12k_wmi_peer_create_arg *arg)
{
struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k_dp_link_vif *dp_link_vif;
struct ath12k_link_sta *arsta;
u8 link_id = arvif->link_id;
struct ath12k_peer *peer;
struct ath12k_dp_link_peer *peer;
struct ath12k_sta *ahsta;
u16 ml_peer_id;
int ret;
struct ath12k_dp *dp = ath12k_ab_to_dp(ar->ab);
lockdep_assert_wiphy(ath12k_ar_to_hw(ar)->wiphy);
dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, link_id);
if (ar->num_peers > (ar->max_num_peers - 1)) {
ath12k_warn(ar->ab,
"failed to create peer due to insufficient peer entry resource in firmware\n");
return -ENOBUFS;
}
spin_lock_bh(&ar->ab->base_lock);
peer = ath12k_peer_find_by_pdev_idx(ar->ab, ar->pdev_idx, arg->peer_addr);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_pdev_and_addr(dp, ar->pdev_idx,
arg->peer_addr);
if (peer) {
spin_unlock_bh(&ar->ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return -EINVAL;
}
spin_unlock_bh(&ar->ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
ret = ath12k_wmi_send_peer_create_cmd(ar, arg);
if (ret) {
@ -352,11 +179,12 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
if (ret)
return ret;
spin_lock_bh(&ar->ab->base_lock);
spin_lock_bh(&dp->dp_lock);
peer = ath12k_peer_find(ar->ab, arg->vdev_id, arg->peer_addr);
peer = ath12k_dp_link_peer_find_by_vdev_and_addr(dp, arg->vdev_id,
arg->peer_addr);
if (!peer) {
spin_unlock_bh(&ar->ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
ath12k_warn(ar->ab, "failed to find peer %pM on vdev %i after creation\n",
arg->peer_addr, arg->vdev_id);
@ -382,13 +210,10 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
peer->sta = sta;
if (vif->type == NL80211_IFTYPE_STATION) {
arvif->ast_hash = peer->ast_hash;
arvif->ast_idx = peer->hw_peer_id;
dp_link_vif->ast_hash = peer->ast_hash;
dp_link_vif->ast_idx = peer->hw_peer_id;
}
if (vif->type == NL80211_IFTYPE_AP)
peer->ucast_ra_only = true;
if (sta) {
ahsta = ath12k_sta_to_ahsta(sta);
arsta = wiphy_dereference(ath12k_ar_to_hw(ar)->wiphy,
@ -412,17 +237,22 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
}
}
peer->sec_type = HAL_ENCRYPT_TYPE_OPEN;
peer->sec_type_grp = HAL_ENCRYPT_TYPE_OPEN;
ar->num_peers++;
spin_unlock_bh(&ar->ab->base_lock);
spin_unlock_bh(&dp->dp_lock);
return 0;
if (arvif->link_id < IEEE80211_MLD_MAX_NUM_LINKS) {
ret = ath12k_dp_link_peer_assign(ath12k_ab_to_dp(ar->ab),
&(ath12k_ar_to_ah(ar)->dp_hw),
arvif->vdev_id, sta,
(u8 *)arg->peer_addr, link_id,
ar->hw_link_id);
}
return ret;
}
static u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
{
u16 ml_peer_id;
@ -442,68 +272,6 @@ static u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah)
return ml_peer_id;
}
int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta)
{
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
struct ath12k_ml_peer *ml_peer;
lockdep_assert_wiphy(ah->hw->wiphy);
if (!sta->mlo)
return -EINVAL;
ml_peer = ath12k_peer_ml_find(ah, sta->addr);
if (ml_peer) {
ath12k_hw_warn(ah, "ML peer %d exists already, unable to add new entry for %pM",
ml_peer->id, sta->addr);
return -EEXIST;
}
ml_peer = kzalloc(sizeof(*ml_peer), GFP_ATOMIC);
if (!ml_peer)
return -ENOMEM;
ahsta->ml_peer_id = ath12k_peer_ml_alloc(ah);
if (ahsta->ml_peer_id == ATH12K_MLO_PEER_ID_INVALID) {
ath12k_hw_warn(ah, "unable to allocate ML peer id for sta %pM",
sta->addr);
kfree(ml_peer);
return -ENOMEM;
}
ether_addr_copy(ml_peer->addr, sta->addr);
ml_peer->id = ahsta->ml_peer_id;
list_add(&ml_peer->list, &ah->ml_peers);
return 0;
}
int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta)
{
struct ath12k_sta *ahsta = ath12k_sta_to_ahsta(sta);
struct ath12k_ml_peer *ml_peer;
lockdep_assert_wiphy(ah->hw->wiphy);
if (!sta->mlo)
return -EINVAL;
clear_bit(ahsta->ml_peer_id, ah->free_ml_peer_id_map);
ahsta->ml_peer_id = ATH12K_MLO_PEER_ID_INVALID;
ml_peer = ath12k_peer_ml_find(ah, sta->addr);
if (!ml_peer) {
ath12k_hw_warn(ah, "ML peer for %pM not found", sta->addr);
return -EINVAL;
}
list_del(&ml_peer->list);
kfree(ml_peer);
return 0;
}
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta)
{
struct ieee80211_sta *sta = ath12k_ahsta_to_sta(ahsta);
@ -536,6 +304,11 @@ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_st
ath12k_dp_peer_cleanup(ar, arvif->vdev_id, arsta->addr);
ath12k_dp_link_peer_unassign(ath12k_ab_to_dp(ar->ab),
&(ath12k_ar_to_ah(ar)->dp_hw),
arvif->vdev_id, arsta->addr,
ar->hw_link_id);
ret = ath12k_peer_delete_send(ar, arvif->vdev_id, arsta->addr);
if (ret) {
ath12k_warn(ar->ab,
@ -568,3 +341,119 @@ int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_st
return err_ret;
}
static int ath12k_link_sta_rhash_insert(struct ath12k_base *ab,
struct ath12k_link_sta *arsta)
{
struct ath12k_link_sta *tmp;
lockdep_assert_held(&ab->base_lock);
tmp = rhashtable_lookup_get_insert_fast(ab->rhead_sta_addr, &arsta->rhash_addr,
ab->rhash_sta_addr_param);
if (!tmp)
return 0;
else if (IS_ERR(tmp))
return PTR_ERR(tmp);
else
return -EEXIST;
}
static int ath12k_link_sta_rhash_remove(struct ath12k_base *ab,
struct ath12k_link_sta *arsta)
{
int ret;
lockdep_assert_held(&ab->base_lock);
ret = rhashtable_remove_fast(ab->rhead_sta_addr, &arsta->rhash_addr,
ab->rhash_sta_addr_param);
if (ret && ret != -ENOENT)
return ret;
return 0;
}
int ath12k_link_sta_rhash_add(struct ath12k_base *ab,
struct ath12k_link_sta *arsta)
{
int ret;
lockdep_assert_held(&ab->base_lock);
ret = ath12k_link_sta_rhash_insert(ab, arsta);
if (ret)
ath12k_warn(ab, "failed to add arsta %pM in rhash_addr ret %d\n",
arsta->addr, ret);
return ret;
}
void ath12k_link_sta_rhash_delete(struct ath12k_base *ab,
struct ath12k_link_sta *arsta)
{
/*
* Return type of this function is void since there is nothing to be
* done in failure case
*/
int ret;
lockdep_assert_held(&ab->base_lock);
ret = ath12k_link_sta_rhash_remove(ab, arsta);
if (ret)
ath12k_warn(ab,
"failed to remove arsta %pM in rhash_addr ret %d\n",
arsta->addr, ret);
}
int ath12k_link_sta_rhash_tbl_init(struct ath12k_base *ab)
{
struct rhashtable_params *param;
struct rhashtable *rhash_addr_tbl;
int ret;
rhash_addr_tbl = kzalloc(sizeof(*ab->rhead_sta_addr), GFP_KERNEL);
if (!rhash_addr_tbl)
return -ENOMEM;
param = &ab->rhash_sta_addr_param;
param->key_offset = offsetof(struct ath12k_link_sta, addr);
param->head_offset = offsetof(struct ath12k_link_sta, rhash_addr);
param->key_len = sizeof_field(struct ath12k_link_sta, addr);
param->automatic_shrinking = true;
param->nelem_hint = ab->num_radios * ath12k_core_get_max_peers_per_radio(ab);
ret = rhashtable_init(rhash_addr_tbl, param);
if (ret) {
ath12k_warn(ab, "failed to init peer addr rhash table %d\n",
ret);
goto err_free;
}
ab->rhead_sta_addr = rhash_addr_tbl;
return 0;
err_free:
kfree(rhash_addr_tbl);
return ret;
}
void ath12k_link_sta_rhash_tbl_destroy(struct ath12k_base *ab)
{
rhashtable_destroy(ab->rhead_sta_addr);
kfree(ab->rhead_sta_addr);
ab->rhead_sta_addr = NULL;
}
struct ath12k_link_sta *ath12k_link_sta_find_by_addr(struct ath12k_base *ab,
const u8 *addr)
{
lockdep_assert_held(&ab->base_lock);
return rhashtable_lookup_fast(ab->rhead_sta_addr, addr,
ab->rhash_sta_addr_param);
}

View File

@ -1,84 +1,14 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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_PEER_H
#define ATH12K_PEER_H
#include "dp_rx.h"
#include "dp_peer.h"
struct ppdu_user_delayba {
u16 sw_peer_id;
u32 info0;
u16 ru_end;
u16 ru_start;
u32 info1;
u32 rate_flags;
u32 resp_rate_flags;
};
#define ATH12K_PEER_ML_ID_VALID BIT(13)
struct ath12k_peer {
struct list_head list;
struct ieee80211_sta *sta;
int vdev_id;
u8 addr[ETH_ALEN];
int peer_id;
u16 ast_hash;
u8 pdev_idx;
u16 hw_peer_id;
/* protected by ab->data_lock */
struct ieee80211_key_conf *keys[WMI_MAX_KEY_INDEX + 1];
struct ath12k_dp_rx_tid rx_tid[IEEE80211_NUM_TIDS + 1];
/* Info used in MMIC verification of
* RX fragments
*/
struct crypto_shash *tfm_mmic;
u8 mcast_keyidx;
u8 ucast_keyidx;
u16 sec_type;
u16 sec_type_grp;
struct ppdu_user_delayba ppdu_stats_delayba;
bool delayba_flag;
bool is_authorized;
bool mlo;
/* protected by ab->data_lock */
bool dp_setup_done;
u16 ml_id;
/* any other ML info common for all partners can be added
* here and would be same for all partner peers.
*/
u8 ml_addr[ETH_ALEN];
/* To ensure only certain work related to dp is done once */
bool primary_link;
/* for reference to ath12k_link_sta */
u8 link_id;
bool ucast_ra_only;
};
struct ath12k_ml_peer {
struct list_head list;
u8 addr[ETH_ALEN];
u16 id;
};
void ath12k_peer_unmap_event(struct ath12k_base *ab, u16 peer_id);
void ath12k_peer_map_event(struct ath12k_base *ab, u8 vdev_id, u16 peer_id,
u8 *mac_addr, u16 ast_hash, u16 hw_peer_id);
struct ath12k_peer *ath12k_peer_find(struct ath12k_base *ab, int vdev_id,
const u8 *addr);
struct ath12k_peer *ath12k_peer_find_by_addr(struct ath12k_base *ab,
const u8 *addr);
struct ath12k_peer *ath12k_peer_find_by_id(struct ath12k_base *ab, int peer_id);
void ath12k_peer_cleanup(struct ath12k *ar, u32 vdev_id);
int ath12k_peer_delete(struct ath12k *ar, u32 vdev_id, u8 *addr);
int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
@ -86,38 +16,14 @@ int ath12k_peer_create(struct ath12k *ar, struct ath12k_link_vif *arvif,
struct ath12k_wmi_peer_create_arg *arg);
int ath12k_wait_for_peer_delete_done(struct ath12k *ar, u32 vdev_id,
const u8 *addr);
bool ath12k_peer_exist_by_vdev_id(struct ath12k_base *ab, int vdev_id);
struct ath12k_peer *ath12k_peer_find_by_ast(struct ath12k_base *ab, int ast_hash);
int ath12k_peer_ml_create(struct ath12k_hw *ah, struct ieee80211_sta *sta);
int ath12k_peer_ml_delete(struct ath12k_hw *ah, struct ieee80211_sta *sta);
int ath12k_peer_mlo_link_peers_delete(struct ath12k_vif *ahvif, struct ath12k_sta *ahsta);
struct ath12k_ml_peer *ath12k_peer_ml_find(struct ath12k_hw *ah,
const u8 *addr);
static inline
struct ath12k_link_sta *ath12k_peer_get_link_sta(struct ath12k_base *ab,
struct ath12k_peer *peer)
{
struct ath12k_sta *ahsta;
struct ath12k_link_sta *arsta;
if (!peer->sta)
return NULL;
ahsta = ath12k_sta_to_ahsta(peer->sta);
if (peer->ml_id & ATH12K_PEER_ML_ID_VALID) {
if (!(ahsta->links_map & BIT(peer->link_id))) {
ath12k_warn(ab, "peer %pM id %d link_id %d can't found in STA link_map 0x%x\n",
peer->addr, peer->peer_id, peer->link_id,
ahsta->links_map);
return NULL;
}
arsta = rcu_dereference(ahsta->link[peer->link_id]);
if (!arsta)
return NULL;
} else {
arsta = &ahsta->deflink;
}
return arsta;
}
int ath12k_link_sta_rhash_tbl_init(struct ath12k_base *ab);
void ath12k_link_sta_rhash_tbl_destroy(struct ath12k_base *ab);
void ath12k_link_sta_rhash_delete(struct ath12k_base *ab, struct ath12k_link_sta *arsta);
int ath12k_link_sta_rhash_add(struct ath12k_base *ab, struct ath12k_link_sta *arsta);
struct ath12k_link_sta *ath12k_link_sta_find_by_addr(struct ath12k_base *ab,
const u8 *addr);
u16 ath12k_peer_ml_alloc(struct ath12k_hw *ah);
#endif /* _PEER_H_ */

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-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.
*/
#include "testmode.h"
@ -393,3 +393,4 @@ int ath12k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return -EOPNOTSUPP;
}
}
EXPORT_SYMBOL(ath12k_tm_cmd);

View File

@ -0,0 +1,19 @@
# SPDX-License-Identifier: BSD-3-Clause-Clear
obj-$(CONFIG_ATH12K) += ath12k_wifi7.o
ath12k_wifi7-y += core.o \
pci.o \
wmi.o \
mhi.o \
ce.o \
hw.o \
hal_tx.o \
hal_rx.o \
dp_rx.o \
dp_tx.o \
dp.o \
dp_mon.o \
hal.o \
hal_qcn9274.o \
hal_wcn7850.o
ath12k_wifi7-$(CONFIG_ATH12K_AHB) += ahb.o

View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/soc/qcom/mdt_loader.h>
#include "../ahb.h"
#include "ahb.h"
#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",
.data = (void *)ATH12K_HW_IPQ5332_HW10,
},
{ }
};
MODULE_DEVICE_TABLE(of, ath12k_wifi7_ahb_of_match);
static int ath12k_wifi7_ahb_probe(struct platform_device *pdev)
{
struct ath12k_ahb *ab_ahb;
enum ath12k_hw_rev hw_rev;
struct ath12k_base *ab;
int ret;
ab = platform_get_drvdata(pdev);
ab_ahb = ath12k_ab_to_ahb(ab);
hw_rev = (enum ath12k_hw_rev)(kernel_ulong_t)of_device_get_match_data(&pdev->dev);
switch (hw_rev) {
case ATH12K_HW_IPQ5332_HW10:
ab_ahb->userpd_id = ATH12K_IPQ5332_USERPD_ID;
break;
default:
return -EOPNOTSUPP;
}
ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
ab->hw_rev = hw_rev;
ret = ath12k_wifi7_hw_init(ab);
if (ret) {
ath12k_err(ab, "WiFi-7 hw_init for AHB failed: %d\n", ret);
return ret;
}
return 0;
}
static struct ath12k_ahb_driver ath12k_wifi7_ahb_driver = {
.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)
{
return ath12k_ahb_register_driver(ATH12K_DEVICE_FAMILY_WIFI7,
&ath12k_wifi7_ahb_driver);
}
void ath12k_wifi7_ahb_exit(void)
{
ath12k_ahb_unregister_driver(ATH12K_DEVICE_FAMILY_WIFI7);
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_AHB_WIFI7_H
#define ATH12K_AHB_WIFI7_H
#ifdef CONFIG_ATH12K_AHB
int ath12k_wifi7_ahb_init(void);
void ath12k_wifi7_ahb_exit(void);
#else
static inline int ath12k_wifi7_ahb_init(void)
{
return 0;
}
static inline void ath12k_wifi7_ahb_exit(void) {}
#endif
#endif /* ATH12K_AHB_WIFI7_H */

View File

@ -0,0 +1,973 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include "../core.h"
#include "../ce.h"
#include "ce.h"
#include "../dp_rx.h"
/* Copy Engine (CE) configs for QCN9274 */
/* Target firmware's Copy Engine configuration. */
const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_qcn9274[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT + HTC control */
{
.pipenum = __cpu_to_le32(1),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI */
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI (mac0) */
{
.pipenum = __cpu_to_le32(3),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
.pipenum = __cpu_to_le32(4),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(256),
.nbytes_max = __cpu_to_le32(256),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE5: target->host Pktlog */
{
.pipenum = __cpu_to_le32(5),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous hif_memcpy */
{
.pipenum = __cpu_to_le32(6),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE7: host->target WMI (mac1) */
{
.pipenum = __cpu_to_le32(7),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE8: Reserved for target autonomous hif_memcpy */
{
.pipenum = __cpu_to_le32(8),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE9, 10 and 11: Reserved for MHI */
/* CE12: Target CV prefetch */
{
.pipenum = __cpu_to_le32(12),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE13: Target CV prefetch */
{
.pipenum = __cpu_to_le32(13),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE14: WMI logging/CFR/Spectral/Radar */
{
.pipenum = __cpu_to_le32(14),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE15: Reserved */
};
/* Map from service/endpoint to Copy Engine.
* This table is derived from the CE_PCI TABLE, above.
* It is passed to the Target at startup for use by firmware.
* Pipe direction:
* PIPEDIR_OUT = UL = host -> target
* PIPEDIR_IN = DL = target -> host
*/
const struct service_to_pipe
ath12k_wifi7_target_service_to_ce_map_wlan_qcn9274[] = {
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(0),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_TEST_RAW_STREAMS),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(0),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_TEST_RAW_STREAMS),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(4),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(7),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL_MAC1),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_PKT_LOG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(5),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL_DIAG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(14),
},
/* (Additions here) */
{ /* must be last */
__cpu_to_le32(0),
__cpu_to_le32(0),
__cpu_to_le32(0),
},
};
const struct ce_attr ath12k_wifi7_host_ce_config_qcn9274[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI (mac0) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target->host pktlog */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_dp_htt_htc_t2h_msg_handler,
},
/* CE6: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: host->target WMI (mac1) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE8: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE9: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE10: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE11: MHI */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE12: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE13: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE14: target->host dbg log */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE15: reserved for future use */
{
.flags = (CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};
/* Copy Engine (CE) configs for WCN7850 */
/* Target firmware's Copy Engine configuration. */
const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_wcn7850[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT + HTC control */
{
.pipenum = __cpu_to_le32(1),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI */
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI */
{
.pipenum = __cpu_to_le32(3),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
.pipenum = __cpu_to_le32(4),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(256),
.nbytes_max = __cpu_to_le32(256),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE5: target->host Pktlog */
{
.pipenum = __cpu_to_le32(5),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous hif_memcpy */
{
.pipenum = __cpu_to_le32(6),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE7 used only by Host */
{
.pipenum = __cpu_to_le32(7),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT_H2H),
.nentries = __cpu_to_le32(0),
.nbytes_max = __cpu_to_le32(0),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE8 target->host used only by IPA */
{
.pipenum = __cpu_to_le32(8),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE 9, 10, 11 are used by MHI driver */
};
const struct service_to_pipe
ath12k_wifi7_target_service_to_ce_map_wlan_wcn7850[] = {
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(0),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(4),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
/* (Additions here) */
{ /* must be last */
__cpu_to_le32(0),
__cpu_to_le32(0),
__cpu_to_le32(0),
},
};
const struct ce_attr ath12k_wifi7_host_ce_config_wcn7850[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 64,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI (mac0) */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target->host pktlog */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE6: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: host->target WMI (mac1) */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE8: target autonomous hif_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};
/* Copy Engine (CE) configs for IPQ5332 */
/* Target firmware's Copy Engine configuration. */
const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_ipq5332[] = {
/* CE0: host->target HTC control and raw streams */
{
.pipenum = __cpu_to_le32(0),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE1: target->host HTT */
{
.pipenum = __cpu_to_le32(1),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE2: target->host WMI + HTC control */
{
.pipenum = __cpu_to_le32(2),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE3: host->target WMI */
{
.pipenum = __cpu_to_le32(3),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE4: host->target HTT */
{
.pipenum = __cpu_to_le32(4),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(256),
.nbytes_max = __cpu_to_le32(256),
.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),
.reserved = __cpu_to_le32(0),
},
/* CE5: Target -> host PKTLOG */
{
.pipenum = __cpu_to_le32(5),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE6: Reserved for target autonomous HIF_memcpy */
{
.pipenum = __cpu_to_le32(6),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE7: Reserved for CV Prefetch */
{
.pipenum = __cpu_to_le32(7),
.pipedir = __cpu_to_le32(PIPEDIR_OUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE8: Reserved for target generic HIF memcpy */
{
.pipenum = __cpu_to_le32(8),
.pipedir = __cpu_to_le32(PIPEDIR_INOUT),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(16384),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE9: WMI logging/CFR/Spectral/Radar/ */
{
.pipenum = __cpu_to_le32(9),
.pipedir = __cpu_to_le32(PIPEDIR_IN),
.nentries = __cpu_to_le32(32),
.nbytes_max = __cpu_to_le32(2048),
.flags = __cpu_to_le32(CE_ATTR_FLAGS),
.reserved = __cpu_to_le32(0),
},
/* CE10: Unused TBD */
{
.pipenum = __cpu_to_le32(10),
.pipedir = __cpu_to_le32(PIPEDIR_NONE),
.nentries = __cpu_to_le32(0),
.nbytes_max = __cpu_to_le32(0),
.flags = __cpu_to_le32(0),
.reserved = __cpu_to_le32(0),
},
/* CE11: Unused TBD */
{
.pipenum = __cpu_to_le32(11),
.pipedir = __cpu_to_le32(PIPEDIR_NONE),
.nentries = __cpu_to_le32(0),
.nbytes_max = __cpu_to_le32(0),
.flags = __cpu_to_le32(0),
.reserved = __cpu_to_le32(0),
},
};
const struct service_to_pipe
ath12k_wifi7_target_service_to_ce_map_wlan_ipq5332[] = {
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VO),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BK),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_BE),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_DATA_VI),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(3),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(2),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(0),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_RSVD_CTRL),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_TEST_RAW_STREAMS),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(0),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_TEST_RAW_STREAMS),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_OUT),
__cpu_to_le32(4),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_HTT_DATA_MSG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(1),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_PKT_LOG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(5),
},
{
__cpu_to_le32(ATH12K_HTC_SVC_ID_WMI_CONTROL_DIAG),
__cpu_to_le32(PIPEDIR_IN),
__cpu_to_le32(9),
},
/* (Additions here) */
{ /* must be last */
__cpu_to_le32(0),
__cpu_to_le32(0),
__cpu_to_le32(0),
},
};
const struct ce_attr ath12k_wifi7_host_ce_config_ipq5332[] = {
/* CE0: host->target HTC control and raw streams */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 16,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE1: target->host HTT + HTC control */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE2: target->host WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
.recv_cb = ath12k_htc_rx_completion_handler,
},
/* CE3: host->target WMI */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 32,
.src_sz_max = 2048,
.dest_nentries = 0,
},
/* CE4: host->target HTT */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 2048,
.src_sz_max = 256,
.dest_nentries = 0,
},
/* CE5: target -> host PKTLOG */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 512,
.recv_cb = ath12k_dp_htt_htc_t2h_msg_handler,
},
/* CE6: Target autonomous HIF_memcpy */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE7: CV Prefetch */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE8: Target HIF memcpy (Generic HIF memcypy) */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE9: WMI logging/CFR/Spectral/Radar */
{
.flags = CE_ATTR_FLAGS,
.src_nentries = 0,
.src_sz_max = 2048,
.dest_nentries = 128,
},
/* CE10: Unused */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
/* CE11: Unused */
{
.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,
.src_nentries = 0,
.src_sz_max = 0,
.dest_nentries = 0,
},
};

View File

@ -0,0 +1,22 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_WIFI7_CE_H
#define ATH12K_WIFI7_CE_H
extern const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_qcn9274[];
extern const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_wcn7850[];
extern const struct ce_pipe_config ath12k_wifi7_target_ce_config_wlan_ipq5332[];
extern const struct service_to_pipe ath12k_wifi7_target_service_to_ce_map_wlan_qcn9274[];
extern const struct service_to_pipe ath12k_wifi7_target_service_to_ce_map_wlan_wcn7850[];
extern const struct service_to_pipe ath12k_wifi7_target_service_to_ce_map_wlan_ipq5332[];
extern const struct ce_attr ath12k_wifi7_host_ce_config_qcn9274[];
extern const struct ce_attr ath12k_wifi7_host_ce_config_wcn7850[];
extern const struct ce_attr ath12k_wifi7_host_ce_config_ipq5332[];
#endif /* ATH12K_WIFI7_CE_H */

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/module.h>
#include "../ahb.h"
#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();
if (ahb_err)
pr_warn("Failed to initialize ath12k Wi-Fi 7 AHB device: %d\n",
ahb_err);
pci_err = ath12k_wifi7_pci_init();
if (pci_err)
pr_warn("Failed to initialize ath12k Wi-Fi 7 PCI device: %d\n",
pci_err);
/* If both failed, return one of the failures (arbitrary) */
return ahb_err && pci_err ? ahb_err : 0;
}
static void ath12k_wifi7_exit(void)
{
if (!pci_err)
ath12k_wifi7_pci_exit();
if (!ahb_err)
ath12k_wifi7_ahb_exit();
}
module_init(ath12k_wifi7_init);
module_exit(ath12k_wifi7_exit);
MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11be WLAN devices");
MODULE_LICENSE("Dual BSD/GPL");

View File

@ -0,0 +1,11 @@
/* 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

View File

@ -0,0 +1,181 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "../core.h"
#include "../debug.h"
#include "../dp_rx.h"
#include "../dp_tx.h"
#include "hal_desc.h"
#include "../dp_mon.h"
#include "dp_mon.h"
#include "../dp_cmn.h"
#include "dp_rx.h"
#include "dp.h"
#include "dp_tx.h"
#include "hal.h"
static int ath12k_wifi7_dp_service_srng(struct ath12k_dp *dp,
struct ath12k_ext_irq_grp *irq_grp,
int budget)
{
struct napi_struct *napi = &irq_grp->napi;
int grp_id = irq_grp->grp_id;
int work_done = 0;
int i = 0, j;
int tot_work_done = 0;
enum dp_monitor_mode monitor_mode;
u8 ring_mask;
if (dp->hw_params->ring_mask->tx[grp_id]) {
i = fls(dp->hw_params->ring_mask->tx[grp_id]) - 1;
ath12k_wifi7_dp_tx_completion_handler(dp, i);
}
if (dp->hw_params->ring_mask->rx_err[grp_id]) {
work_done = ath12k_wifi7_dp_rx_process_err(dp, napi, budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (dp->hw_params->ring_mask->rx_wbm_rel[grp_id]) {
work_done = ath12k_wifi7_dp_rx_process_wbm_err(dp, napi, budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (dp->hw_params->ring_mask->rx[grp_id]) {
i = fls(dp->hw_params->ring_mask->rx[grp_id]) - 1;
work_done = ath12k_wifi7_dp_rx_process(dp, i, napi, budget);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
if (dp->hw_params->ring_mask->rx_mon_status[grp_id]) {
ring_mask = dp->hw_params->ring_mask->rx_mon_status[grp_id];
for (i = 0; i < dp->ab->num_radios; i++) {
for (j = 0; j < dp->hw_params->num_rxdma_per_pdev; j++) {
int id = i * dp->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_wifi7_dp_mon_process_ring(dp, id, napi,
budget,
0);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (dp->hw_params->ring_mask->rx_mon_dest[grp_id]) {
monitor_mode = ATH12K_DP_RX_MONITOR_MODE;
ring_mask = dp->hw_params->ring_mask->rx_mon_dest[grp_id];
for (i = 0; i < dp->ab->num_radios; i++) {
for (j = 0; j < dp->hw_params->num_rxdma_per_pdev; j++) {
int id = i * dp->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_wifi7_dp_mon_process_ring(dp, id, napi,
budget,
monitor_mode);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (dp->hw_params->ring_mask->tx_mon_dest[grp_id]) {
monitor_mode = ATH12K_DP_TX_MONITOR_MODE;
ring_mask = dp->hw_params->ring_mask->tx_mon_dest[grp_id];
for (i = 0; i < dp->ab->num_radios; i++) {
for (j = 0; j < dp->hw_params->num_rxdma_per_pdev; j++) {
int id = i * dp->hw_params->num_rxdma_per_pdev + j;
if (ring_mask & BIT(id)) {
work_done =
ath12k_wifi7_dp_mon_process_ring(dp, id,
napi, budget,
monitor_mode);
budget -= work_done;
tot_work_done += work_done;
if (budget <= 0)
goto done;
}
}
}
}
if (dp->hw_params->ring_mask->reo_status[grp_id])
ath12k_wifi7_dp_rx_process_reo_status(dp);
if (dp->hw_params->ring_mask->host2rxdma[grp_id]) {
struct dp_rxdma_ring *rx_ring = &dp->rx_refill_buf_ring;
LIST_HEAD(list);
ath12k_dp_rx_bufs_replenish(dp, rx_ring, &list, 0);
}
/* TODO: Implement handler for other interrupts */
done:
return tot_work_done;
}
static struct ath12k_dp_arch_ops ath12k_wifi7_dp_arch_ops = {
.service_srng = ath12k_wifi7_dp_service_srng,
.tx_get_vdev_bank_config = ath12k_wifi7_dp_tx_get_vdev_bank_config,
.reo_cmd_send = ath12k_wifi7_dp_reo_cmd_send,
.setup_pn_check_reo_cmd = ath12k_wifi7_dp_setup_pn_check_reo_cmd,
.rx_peer_tid_delete = ath12k_wifi7_dp_rx_peer_tid_delete,
.reo_cache_flush = ath12k_wifi7_dp_reo_cache_flush,
.rx_link_desc_return = ath12k_wifi7_dp_rx_link_desc_return,
.rx_frags_cleanup = ath12k_wifi7_dp_rx_frags_cleanup,
.peer_rx_tid_reo_update = ath12k_wifi7_peer_rx_tid_reo_update,
.rx_assign_reoq = ath12k_wifi7_dp_rx_assign_reoq,
.peer_rx_tid_qref_setup = ath12k_wifi7_peer_rx_tid_qref_setup,
.peer_rx_tid_qref_reset = ath12k_wifi7_peer_rx_tid_qref_reset,
.rx_tid_delete_handler = ath12k_wifi7_dp_rx_tid_delete_handler,
};
/* 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;
dp->hal = &ab->hal;
dp->ops = &ath12k_wifi7_dp_arch_ops;
return dp;
}
void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp)
{
kfree(dp);
}

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_WIFI7_H
#define ATH12K_DP_WIFI7_H
#include "../dp_cmn.h"
#include "hw.h"
struct ath12k_base;
struct ath12k_dp;
enum dp_monitor_mode;
struct ath12k_dp *ath12k_wifi7_dp_device_alloc(struct ath12k_base *ab);
void ath12k_wifi7_dp_device_free(struct ath12k_dp *dp);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_MON_WIFI7_H
#define ATH12K_DP_MON_WIFI7_H
#include "hw.h"
enum dp_monitor_mode;
int ath12k_wifi7_dp_mon_process_ring(struct ath12k_dp *dp, int mac_id,
struct napi_struct *napi, int budget,
enum dp_monitor_mode monitor_mode);
enum hal_rx_mon_status
ath12k_wifi7_dp_mon_tx_parse_mon_status(struct ath12k_pdev_dp *dp_pdev,
struct ath12k_mon_data *pmon,
struct sk_buff *skb,
struct napi_struct *napi,
u32 ppdu_id);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,59 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_RX_WIFI7_H
#define ATH12K_DP_RX_WIFI7_H
#include "../core.h"
#include "../dp_rx.h"
#include "hal_rx_desc.h"
struct ath12k_hal_reo_cmd;
int ath12k_wifi7_dp_rx_process_wbm_err(struct ath12k_dp *dp,
struct napi_struct *napi, int budget);
int ath12k_wifi7_dp_rx_process_err(struct ath12k_dp *dp, struct napi_struct *napi,
int budget);
int ath12k_wifi7_dp_rx_process(struct ath12k_dp *dp, int mac_id,
struct napi_struct *napi,
int budget);
void ath12k_wifi7_dp_rx_process_reo_status(struct ath12k_dp *dp);
int ath12k_dp_rxdma_ring_sel_config_qcn9274(struct ath12k_base *ab);
int ath12k_dp_rxdma_ring_sel_config_wcn7850(struct ath12k_base *ab);
void ath12k_wifi7_dp_setup_pn_check_reo_cmd(struct ath12k_hal_reo_cmd *cmd,
struct ath12k_dp_rx_tid *rx_tid,
u32 cipher, enum set_key_cmd key_cmd);
int ath12k_wifi7_dp_rx_assign_reoq(struct ath12k_base *ab, struct ath12k_dp_peer *dp_peer,
struct ath12k_dp_rx_tid *rx_tid,
u16 ssn, enum hal_pn_type pn_type);
int ath12k_wifi7_dp_rx_link_desc_return(struct ath12k_dp *dp,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action);
void ath12k_wifi7_dp_rx_frags_cleanup(struct ath12k_dp_rx_tid *rx_tid,
bool rel_link_desc);
void ath12k_wifi7_peer_rx_tid_qref_setup(struct ath12k_base *ab, u16 peer_id, u16 tid,
dma_addr_t paddr);
void ath12k_wifi7_dp_rx_peer_tid_delete(struct ath12k_base *ab,
struct ath12k_dp_link_peer *peer, u8 tid);
int ath12k_wifi7_dp_reo_cmd_send(struct ath12k_base *ab,
struct ath12k_dp_rx_tid_rxq *rx_tid,
enum hal_reo_cmd_type type,
struct ath12k_hal_reo_cmd *cmd,
void (*cb)(struct ath12k_dp *dp, void *ctx,
enum hal_reo_cmd_status status));
int ath12k_wifi7_dp_reo_cache_flush(struct ath12k_base *ab,
struct ath12k_dp_rx_tid_rxq *rx_tid);
int ath12k_wifi7_peer_rx_tid_reo_update(struct ath12k_dp *dp,
struct ath12k_dp_link_peer *peer,
struct ath12k_dp_rx_tid *rx_tid,
u32 ba_win_sz, u16 ssn,
bool update_ssn);
void ath12k_wifi7_peer_rx_tid_qref_reset(struct ath12k_base *ab, u16 peer_id, u16 tid);
bool
ath12k_wifi7_dp_rxdesc_mpdu_valid(struct ath12k_base *ab,
struct hal_rx_desc *rx_desc);
int ath12k_wifi7_dp_rx_tid_delete_handler(struct ath12k_base *ab,
struct ath12k_dp_rx_tid_rxq *rx_tid);
#endif

View File

@ -0,0 +1,978 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "../core.h"
#include "../debug.h"
#include "../dp_tx.h"
#include "../peer.h"
#include "dp_tx.h"
#include "hal_desc.h"
#include "hal.h"
#include "hal_tx.h"
static void
ath12k_wifi7_hal_tx_cmd_ext_desc_setup(struct ath12k_base *ab,
struct hal_tx_msdu_ext_desc *tcl_ext_cmd,
struct hal_tx_info *ti)
{
tcl_ext_cmd->info0 = le32_encode_bits(ti->paddr,
HAL_TX_MSDU_EXT_INFO0_BUF_PTR_LO);
tcl_ext_cmd->info1 = le32_encode_bits(0x0,
HAL_TX_MSDU_EXT_INFO1_BUF_PTR_HI) |
le32_encode_bits(ti->data_len,
HAL_TX_MSDU_EXT_INFO1_BUF_LEN);
tcl_ext_cmd->info1 |= le32_encode_bits(1, HAL_TX_MSDU_EXT_INFO1_EXTN_OVERRIDE) |
le32_encode_bits(ti->encap_type,
HAL_TX_MSDU_EXT_INFO1_ENCAP_TYPE) |
le32_encode_bits(ti->encrypt_type,
HAL_TX_MSDU_EXT_INFO1_ENCRYPT_TYPE);
}
#define HTT_META_DATA_ALIGNMENT 0x8
/* Preparing HTT Metadata when utilized with ext MSDU */
static int ath12k_wifi7_dp_prepare_htt_metadata(struct sk_buff *skb)
{
struct hal_tx_msdu_metadata *desc_ext;
u8 htt_desc_size;
/* Size rounded of multiple of 8 bytes */
u8 htt_desc_size_aligned;
htt_desc_size = sizeof(struct hal_tx_msdu_metadata);
htt_desc_size_aligned = ALIGN(htt_desc_size, HTT_META_DATA_ALIGNMENT);
desc_ext = ath12k_dp_metadata_align_skb(skb, htt_desc_size_aligned);
if (!desc_ext)
return -ENOMEM;
desc_ext->info0 = le32_encode_bits(1, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_FLAG) |
le32_encode_bits(0, HAL_TX_MSDU_METADATA_INFO0_ENCRYPT_TYPE) |
le32_encode_bits(1,
HAL_TX_MSDU_METADATA_INFO0_HOST_TX_DESC_POOL);
return 0;
}
/* TODO: Remove the export once this file is built with wifi7 ko */
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
bool is_mcast)
{
struct ath12k_dp *dp = dp_pdev->dp;
struct ath12k_hal *hal = dp->hal;
struct ath12k_base *ab = dp->ab;
struct hal_tx_info ti = {};
struct ath12k_tx_desc_info *tx_desc;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
struct hal_tcl_data_cmd *hal_tcl_desc;
struct hal_tx_msdu_ext_desc *msg;
struct sk_buff *skb_ext_desc = NULL;
struct hal_srng *tcl_ring;
struct ieee80211_hdr *hdr = (void *)skb->data;
struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k_dp_vif *dp_vif = &ahvif->dp_vif;
struct ath12k_dp_link_vif *dp_link_vif;
struct dp_tx_ring *tx_ring;
u8 pool_id;
u8 hal_ring_id;
int ret;
u8 ring_selector, ring_map = 0;
bool tcl_ring_retry;
bool msdu_ext_desc = false;
bool add_htt_metadata = false;
u32 iova_mask = dp->hw_params->iova_mask;
bool is_diff_encap = false;
bool is_null_frame = false;
if (test_bit(ATH12K_FLAG_CRASH_FLUSH, &ab->dev_flags))
return -ESHUTDOWN;
if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
!ieee80211_is_data(hdr->frame_control))
return -EOPNOTSUPP;
pool_id = skb_get_queue_mapping(skb) & (ATH12K_HW_MAX_QUEUES - 1);
/* Let the default ring selection be based on current processor
* number, where one of the 3 tcl rings are selected based on
* the smp_processor_id(). In case that ring
* is full/busy, we resort to other available rings.
* If all rings are full, we drop the packet.
* TODO: Add throttling logic when all rings are full
*/
ring_selector = dp->hw_params->hw_ops->get_ring_selector(skb);
tcl_ring_sel:
tcl_ring_retry = false;
ti.ring_id = ring_selector % dp->hw_params->max_tx_ring;
ring_map |= BIT(ti.ring_id);
ti.rbm_id = hal->tcl_to_wbm_rbm_map[ti.ring_id].rbm_id;
tx_ring = &dp->tx_ring[ti.ring_id];
tx_desc = ath12k_dp_tx_assign_buffer(dp, pool_id);
if (!tx_desc)
return -ENOMEM;
dp_link_vif = ath12k_dp_vif_to_dp_link_vif(&ahvif->dp_vif, arvif->link_id);
ti.bank_id = dp_link_vif->bank_id;
ti.meta_data_flags = dp_link_vif->tcl_metadata;
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags)) {
if (skb_cb->flags & ATH12K_SKB_CIPHER_SET) {
ti.encrypt_type =
ath12k_dp_tx_get_encrypt_type(skb_cb->cipher);
if (ieee80211_has_protected(hdr->frame_control))
skb_put(skb, IEEE80211_CCMP_MIC_LEN);
} else {
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
}
msdu_ext_desc = true;
}
if (gsn_valid) {
/* Reset and Initialize meta_data_flags with Global Sequence
* Number (GSN) info.
*/
ti.meta_data_flags =
u32_encode_bits(HTT_TCL_META_DATA_TYPE_GLOBAL_SEQ_NUM,
HTT_TCL_META_DATA_TYPE) |
u32_encode_bits(mcbc_gsn, HTT_TCL_META_DATA_GLOBAL_SEQ_NUM);
}
ti.encap_type = ath12k_dp_tx_get_encap_type(ab, skb);
ti.addr_search_flags = dp_link_vif->hal_addr_search_flags;
ti.search_type = dp_link_vif->search_type;
ti.type = HAL_TCL_DESC_TYPE_BUFFER;
ti.pkt_offset = 0;
ti.lmac_id = dp_link_vif->lmac_id;
ti.vdev_id = dp_link_vif->vdev_id;
if (gsn_valid)
ti.vdev_id += HTT_TX_MLO_MCAST_HOST_REINJECT_BASE_VDEV_ID;
ti.bss_ast_hash = dp_link_vif->ast_hash;
ti.bss_ast_idx = dp_link_vif->ast_idx;
ti.dscp_tid_tbl_idx = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL &&
ti.encap_type != HAL_TCL_ENCAP_TYPE_RAW) {
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_IP4_CKSUM_EN) |
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP4_CKSUM_EN) |
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_UDP6_CKSUM_EN) |
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP4_CKSUM_EN) |
u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TCP6_CKSUM_EN);
}
ti.flags1 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO3_TID_OVERWRITE);
ti.tid = ath12k_dp_tx_get_tid(skb);
switch (ti.encap_type) {
case HAL_TCL_ENCAP_TYPE_NATIVE_WIFI:
is_null_frame = ieee80211_is_nullfunc(hdr->frame_control);
if (ahvif->vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED) {
if (skb->protocol == cpu_to_be16(ETH_P_PAE) || is_null_frame)
is_diff_encap = true;
/* Firmware expects msdu ext descriptor for nwifi/raw packets
* received in ETH mode. Without this, observed tx fail for
* Multicast packets in ETH mode.
*/
msdu_ext_desc = true;
} else {
ath12k_dp_tx_encap_nwifi(skb);
}
break;
case HAL_TCL_ENCAP_TYPE_RAW:
if (!test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags)) {
ret = -EINVAL;
goto fail_remove_tx_buf;
}
break;
case HAL_TCL_ENCAP_TYPE_ETHERNET:
/* no need to encap */
break;
case HAL_TCL_ENCAP_TYPE_802_3:
default:
/* TODO: Take care of other encap modes as well */
ret = -EINVAL;
atomic_inc(&dp->device_stats.tx_err.misc_fail);
goto fail_remove_tx_buf;
}
if (iova_mask &&
(unsigned long)skb->data & iova_mask) {
ret = ath12k_dp_tx_align_payload(dp, &skb);
if (ret) {
ath12k_warn(ab, "failed to align TX buffer %d\n", ret);
/* don't bail out, give original buffer
* a chance even unaligned.
*/
goto map;
}
/* hdr is pointing to a wrong place after alignment,
* so refresh it for later use.
*/
hdr = (void *)skb->data;
}
map:
ti.paddr = dma_map_single(dp->dev, skb->data, skb->len, DMA_TO_DEVICE);
if (dma_mapping_error(dp->dev, ti.paddr)) {
atomic_inc(&dp->device_stats.tx_err.misc_fail);
ath12k_warn(ab, "failed to DMA map data Tx buffer\n");
ret = -ENOMEM;
goto fail_remove_tx_buf;
}
if ((!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags) &&
!(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) &&
!(skb_cb->flags & ATH12K_SKB_CIPHER_SET) &&
ieee80211_has_protected(hdr->frame_control)) ||
is_diff_encap) {
/* Firmware is not expecting meta data for qos null
* nwifi packet received in ETH encap mode.
*/
if (is_null_frame && msdu_ext_desc)
goto skip_htt_meta;
/* Add metadata for sw encrypted vlan group traffic
* and EAPOL nwifi packet received in ETH encap mode.
*/
add_htt_metadata = true;
msdu_ext_desc = true;
ti.meta_data_flags |= HTT_TCL_META_DATA_VALID_HTT;
skip_htt_meta:
ti.flags0 |= u32_encode_bits(1, HAL_TCL_DATA_CMD_INFO2_TO_FW);
ti.encap_type = HAL_TCL_ENCAP_TYPE_RAW;
ti.encrypt_type = HAL_ENCRYPT_TYPE_OPEN;
}
tx_desc->skb = skb;
tx_desc->mac_id = dp_link_vif->pdev_idx;
ti.desc_id = tx_desc->desc_id;
ti.data_len = skb->len;
skb_cb->paddr = ti.paddr;
if (msdu_ext_desc) {
skb_ext_desc = dev_alloc_skb(sizeof(struct hal_tx_msdu_ext_desc));
if (!skb_ext_desc) {
ret = -ENOMEM;
goto fail_unmap_dma;
}
skb_put(skb_ext_desc, sizeof(struct hal_tx_msdu_ext_desc));
memset(skb_ext_desc->data, 0, skb_ext_desc->len);
msg = (struct hal_tx_msdu_ext_desc *)skb_ext_desc->data;
ath12k_wifi7_hal_tx_cmd_ext_desc_setup(ab, msg, &ti);
if (add_htt_metadata) {
ret = ath12k_wifi7_dp_prepare_htt_metadata(skb_ext_desc);
if (ret < 0) {
ath12k_dbg(ab, ATH12K_DBG_DP_TX,
"Failed to add HTT meta data, dropping packet\n");
goto fail_free_ext_skb;
}
}
ti.paddr = dma_map_single(dp->dev, skb_ext_desc->data,
skb_ext_desc->len, DMA_TO_DEVICE);
ret = dma_mapping_error(dp->dev, ti.paddr);
if (ret)
goto fail_free_ext_skb;
ti.data_len = skb_ext_desc->len;
ti.type = HAL_TCL_DESC_TYPE_EXT_DESC;
skb_cb->paddr_ext_desc = ti.paddr;
tx_desc->skb_ext_desc = skb_ext_desc;
}
hal_ring_id = tx_ring->tcl_data_ring.ring_id;
tcl_ring = &hal->srng_list[hal_ring_id];
spin_lock_bh(&tcl_ring->lock);
ath12k_hal_srng_access_begin(ab, tcl_ring);
hal_tcl_desc = ath12k_hal_srng_src_get_next_entry(ab, tcl_ring);
if (!hal_tcl_desc) {
/* NOTE: It is highly unlikely we'll be running out of tcl_ring
* desc because the desc is directly enqueued onto hw queue.
*/
ath12k_hal_srng_access_end(ab, tcl_ring);
dp->device_stats.tx_err.desc_na[ti.ring_id]++;
spin_unlock_bh(&tcl_ring->lock);
ret = -ENOMEM;
/* Checking for available tcl descriptors in another ring in
* case of failure due to full tcl ring now, is better than
* checking this ring earlier for each pkt tx.
* Restart ring selection if some rings are not checked yet.
*/
if (ring_map != (BIT(dp->hw_params->max_tx_ring) - 1) &&
dp->hw_params->tcl_ring_retry) {
tcl_ring_retry = true;
ring_selector++;
}
goto fail_unmap_dma_ext;
}
spin_lock_bh(&arvif->link_stats_lock);
arvif->link_stats.tx_encap_type[ti.encap_type]++;
arvif->link_stats.tx_encrypt_type[ti.encrypt_type]++;
arvif->link_stats.tx_desc_type[ti.type]++;
if (is_mcast)
arvif->link_stats.tx_bcast_mcast++;
else
arvif->link_stats.tx_enqueued++;
spin_unlock_bh(&arvif->link_stats_lock);
dp->device_stats.tx_enqueued[ti.ring_id]++;
ath12k_wifi7_hal_tx_cmd_desc_setup(ab, hal_tcl_desc, &ti);
ath12k_hal_srng_access_end(ab, tcl_ring);
spin_unlock_bh(&tcl_ring->lock);
ath12k_dbg_dump(ab, ATH12K_DBG_DP_TX, NULL, "dp tx msdu: ",
skb->data, skb->len);
atomic_inc(&dp_pdev->num_tx_pending);
return 0;
fail_unmap_dma_ext:
if (skb_cb->paddr_ext_desc)
dma_unmap_single(dp->dev, skb_cb->paddr_ext_desc,
skb_ext_desc->len,
DMA_TO_DEVICE);
fail_free_ext_skb:
kfree_skb(skb_ext_desc);
fail_unmap_dma:
dma_unmap_single(dp->dev, ti.paddr, ti.data_len, DMA_TO_DEVICE);
fail_remove_tx_buf:
ath12k_dp_tx_release_txbuf(dp, tx_desc, pool_id);
spin_lock_bh(&arvif->link_stats_lock);
arvif->link_stats.tx_dropped++;
spin_unlock_bh(&arvif->link_stats_lock);
if (tcl_ring_retry)
goto tcl_ring_sel;
return ret;
}
static void
ath12k_dp_tx_htt_tx_complete_buf(struct ath12k_dp *dp,
struct ath12k_tx_desc_params *desc_params,
struct dp_tx_ring *tx_ring,
struct ath12k_dp_htt_wbm_tx_status *ts,
u16 peer_id)
{
struct ath12k_base *ab = dp->ab;
struct ieee80211_tx_info *info;
struct ath12k_link_vif *arvif;
struct ath12k_skb_cb *skb_cb;
struct ieee80211_vif *vif;
struct ath12k_vif *ahvif;
struct sk_buff *msdu = desc_params->skb;
s32 noise_floor;
struct ieee80211_tx_status status = {};
struct ath12k_dp_link_peer *peer;
struct ath12k_pdev_dp *dp_pdev;
u8 pdev_id;
skb_cb = ATH12K_SKB_CB(msdu);
info = IEEE80211_SKB_CB(msdu);
pdev_id = ath12k_hw_mac_id_to_pdev_id(dp->hw_params, desc_params->mac_id);
rcu_read_lock();
dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_id);
if (!dp_pdev) {
rcu_read_unlock();
return;
}
dp->device_stats.tx_completed[tx_ring->tcl_data_ring_id]++;
if (atomic_dec_and_test(&dp_pdev->num_tx_pending))
wake_up(&dp_pdev->tx_empty_waitq);
dma_unmap_single(dp->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
if (skb_cb->paddr_ext_desc) {
dma_unmap_single(dp->dev, skb_cb->paddr_ext_desc,
desc_params->skb_ext_desc->len, DMA_TO_DEVICE);
dev_kfree_skb_any(desc_params->skb_ext_desc);
}
vif = skb_cb->vif;
if (vif) {
ahvif = ath12k_vif_to_ahvif(vif);
arvif = rcu_dereference(ahvif->link[skb_cb->link_id]);
if (arvif) {
spin_lock_bh(&arvif->link_stats_lock);
arvif->link_stats.tx_completed++;
spin_unlock_bh(&arvif->link_stats_lock);
}
}
memset(&info->status, 0, sizeof(info->status));
if (ts->acked) {
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts->ack_rssi;
if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,
ab->wmi_ab.svc_map)) {
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
spin_lock_bh(&ar->data_lock);
noise_floor = ath12k_pdev_get_noise_floor(ar);
spin_unlock_bh(&ar->data_lock);
info->status.ack_signal += noise_floor;
}
info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID;
} else {
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
}
}
peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, peer_id);
if (!peer || !peer->sta) {
ath12k_dbg(ab, ATH12K_DBG_DATA,
"dp_tx: failed to find the peer with peer_id %d\n", peer_id);
ieee80211_free_txskb(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
goto exit;
} else {
status.sta = peer->sta;
}
status.info = info;
status.skb = msdu;
ieee80211_tx_status_ext(ath12k_pdev_dp_to_hw(dp_pdev), &status);
exit:
rcu_read_unlock();
}
static void
ath12k_dp_tx_process_htt_tx_complete(struct ath12k_dp *dp, void *desc,
struct dp_tx_ring *tx_ring,
struct ath12k_tx_desc_params *desc_params)
{
struct htt_tx_wbm_completion *status_desc;
struct ath12k_dp_htt_wbm_tx_status ts = {};
enum hal_wbm_htt_tx_comp_status wbm_status;
u16 peer_id;
status_desc = desc;
wbm_status = le32_get_bits(status_desc->info0,
HTT_TX_WBM_COMP_INFO0_STATUS);
dp->device_stats.fw_tx_status[wbm_status]++;
switch (wbm_status) {
case HAL_WBM_REL_HTT_TX_COMP_STATUS_OK:
ts.acked = (wbm_status == HAL_WBM_REL_HTT_TX_COMP_STATUS_OK);
ts.ack_rssi = le32_get_bits(status_desc->info2,
HTT_TX_WBM_COMP_INFO2_ACK_RSSI);
peer_id = le32_get_bits(((struct hal_wbm_completion_ring_tx *)desc)->
info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID);
ath12k_dp_tx_htt_tx_complete_buf(dp, desc_params, tx_ring, &ts, peer_id);
break;
case HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP:
case HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL:
case HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ:
case HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT:
case HAL_WBM_REL_HTT_TX_COMP_STATUS_VDEVID_MISMATCH:
ath12k_dp_tx_free_txbuf(dp, tx_ring, desc_params);
break;
case HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY:
/* This event is to be handled only when the driver decides to
* use WDS offload functionality.
*/
break;
default:
ath12k_warn(dp->ab, "Unknown htt wbm tx status %d\n", wbm_status);
break;
}
}
static void ath12k_wifi7_dp_tx_update_txcompl(struct ath12k_pdev_dp *dp_pdev,
struct hal_tx_status *ts)
{
struct ath12k_dp *dp = dp_pdev->dp;
struct ath12k_dp_link_peer *peer;
struct ath12k_link_sta *arsta;
struct rate_info txrate = {};
struct ieee80211_sta *sta;
struct ath12k_sta *ahsta;
u16 rate, ru_tones;
u8 rate_idx = 0;
int ret;
peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, ts->peer_id);
if (!peer || !peer->sta) {
ath12k_dbg(dp->ab, ATH12K_DBG_DP_TX,
"failed to find the peer by id %u\n", ts->peer_id);
return;
}
spin_lock_bh(&dp->dp_lock);
sta = peer->sta;
ahsta = ath12k_sta_to_ahsta(sta);
arsta = &ahsta->deflink;
spin_unlock_bh(&dp->dp_lock);
/* This is to prefer choose the real NSS value arsta->last_txrate.nss,
* if it is invalid, then choose the NSS value while assoc.
*/
if (peer->last_txrate.nss)
txrate.nss = peer->last_txrate.nss;
else
txrate.nss = arsta->peer_nss;
switch (ts->pkt_type) {
case HAL_TX_RATE_STATS_PKT_TYPE_11A:
case HAL_TX_RATE_STATS_PKT_TYPE_11B:
ret = ath12k_mac_hw_ratecode_to_legacy_rate(ts->mcs,
ts->pkt_type,
&rate_idx,
&rate);
if (ret < 0) {
ath12k_warn(dp->ab, "Invalid tx legacy rate %d\n", ret);
return;
}
txrate.legacy = rate;
break;
case HAL_TX_RATE_STATS_PKT_TYPE_11N:
if (ts->mcs > ATH12K_HT_MCS_MAX) {
ath12k_warn(dp->ab, "Invalid HT mcs index %d\n", ts->mcs);
return;
}
if (txrate.nss != 0)
txrate.mcs = ts->mcs + 8 * (txrate.nss - 1);
txrate.flags = RATE_INFO_FLAGS_MCS;
if (ts->sgi)
txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case HAL_TX_RATE_STATS_PKT_TYPE_11AC:
if (ts->mcs > ATH12K_VHT_MCS_MAX) {
ath12k_warn(dp->ab, "Invalid VHT mcs index %d\n", ts->mcs);
return;
}
txrate.mcs = ts->mcs;
txrate.flags = RATE_INFO_FLAGS_VHT_MCS;
if (ts->sgi)
txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
break;
case HAL_TX_RATE_STATS_PKT_TYPE_11AX:
if (ts->mcs > ATH12K_HE_MCS_MAX) {
ath12k_warn(dp->ab, "Invalid HE mcs index %d\n", ts->mcs);
return;
}
txrate.mcs = ts->mcs;
txrate.flags = RATE_INFO_FLAGS_HE_MCS;
txrate.he_gi = ath12k_he_gi_to_nl80211_he_gi(ts->sgi);
break;
case HAL_TX_RATE_STATS_PKT_TYPE_11BE:
if (ts->mcs > ATH12K_EHT_MCS_MAX) {
ath12k_warn(dp->ab, "Invalid EHT mcs index %d\n", ts->mcs);
return;
}
txrate.mcs = ts->mcs;
txrate.flags = RATE_INFO_FLAGS_EHT_MCS;
txrate.eht_gi = ath12k_mac_eht_gi_to_nl80211_eht_gi(ts->sgi);
break;
default:
ath12k_warn(dp->ab, "Invalid tx pkt type: %d\n", ts->pkt_type);
return;
}
txrate.bw = ath12k_mac_bw_to_mac80211_bw(ts->bw);
if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11AX) {
txrate.bw = RATE_INFO_BW_HE_RU;
ru_tones = ath12k_mac_he_convert_tones_to_ru_tones(ts->tones);
txrate.he_ru_alloc =
ath12k_he_ru_tones_to_nl80211_he_ru_alloc(ru_tones);
}
if (ts->ofdma && ts->pkt_type == HAL_TX_RATE_STATS_PKT_TYPE_11BE) {
txrate.bw = RATE_INFO_BW_EHT_RU;
txrate.eht_ru_alloc =
ath12k_mac_eht_ru_tones_to_nl80211_eht_ru_alloc(ts->tones);
}
spin_lock_bh(&dp->dp_lock);
peer->txrate = txrate;
spin_unlock_bh(&dp->dp_lock);
}
static void ath12k_wifi7_dp_tx_complete_msdu(struct ath12k_pdev_dp *dp_pdev,
struct ath12k_tx_desc_params *desc_params,
struct hal_tx_status *ts,
int ring)
{
struct ath12k_dp *dp = dp_pdev->dp;
struct ath12k_base *ab = dp->ab;
struct ieee80211_tx_info *info;
struct ath12k_link_vif *arvif;
struct ath12k_skb_cb *skb_cb;
struct ieee80211_vif *vif;
struct ath12k_vif *ahvif;
struct sk_buff *msdu = desc_params->skb;
s32 noise_floor;
struct ieee80211_tx_status status = {};
struct ieee80211_rate_status status_rate = {};
struct ath12k_dp_link_peer *peer;
struct rate_info rate;
if (WARN_ON_ONCE(ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)) {
/* Must not happen */
return;
}
skb_cb = ATH12K_SKB_CB(msdu);
dp->device_stats.tx_completed[ring]++;
dma_unmap_single(dp->dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
if (skb_cb->paddr_ext_desc) {
dma_unmap_single(dp->dev, skb_cb->paddr_ext_desc,
desc_params->skb_ext_desc->len, DMA_TO_DEVICE);
dev_kfree_skb_any(desc_params->skb_ext_desc);
}
rcu_read_lock();
if (!rcu_dereference(ab->pdevs_active[dp_pdev->mac_id])) {
ieee80211_free_txskb(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
goto exit;
}
if (!skb_cb->vif) {
ieee80211_free_txskb(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
goto exit;
}
vif = skb_cb->vif;
if (vif) {
ahvif = ath12k_vif_to_ahvif(vif);
arvif = rcu_dereference(ahvif->link[skb_cb->link_id]);
if (arvif) {
spin_lock_bh(&arvif->link_stats_lock);
arvif->link_stats.tx_completed++;
spin_unlock_bh(&arvif->link_stats_lock);
}
}
info = IEEE80211_SKB_CB(msdu);
memset(&info->status, 0, sizeof(info->status));
/* skip tx rate update from ieee80211_status*/
info->status.rates[0].idx = -1;
switch (ts->status) {
case HAL_WBM_TQM_REL_REASON_FRAME_ACKED:
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) {
info->flags |= IEEE80211_TX_STAT_ACK;
info->status.ack_signal = ts->ack_rssi;
if (!test_bit(WMI_TLV_SERVICE_HW_DB2DBM_CONVERSION_SUPPORT,
ab->wmi_ab.svc_map)) {
struct ath12k *ar = ath12k_pdev_dp_to_ar(dp_pdev);
spin_lock_bh(&ar->data_lock);
noise_floor = ath12k_pdev_get_noise_floor(ar);
spin_unlock_bh(&ar->data_lock);
info->status.ack_signal += noise_floor;
}
info->status.flags = IEEE80211_TX_STATUS_ACK_SIGNAL_VALID;
}
break;
case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_TX:
if (info->flags & IEEE80211_TX_CTL_NO_ACK) {
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
break;
}
fallthrough;
case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_MPDU:
case HAL_WBM_TQM_REL_REASON_DROP_THRESHOLD:
case HAL_WBM_TQM_REL_REASON_CMD_REMOVE_AGED_FRAMES:
/* The failure status is due to internal firmware tx failure
* hence drop the frame; do not update the status of frame to
* the upper layer
*/
ieee80211_free_txskb(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
goto exit;
default:
ath12k_dbg(ab, ATH12K_DBG_DP_TX, "tx frame is not acked status %d\n",
ts->status);
break;
}
/* NOTE: Tx rate status reporting. Tx completion status does not have
* necessary information (for example nss) to build the tx rate.
* Might end up reporting it out-of-band from HTT stats.
*/
ath12k_wifi7_dp_tx_update_txcompl(dp_pdev, ts);
peer = ath12k_dp_link_peer_find_by_peerid(dp_pdev, ts->peer_id);
if (!peer || !peer->sta) {
ath12k_err(ab,
"dp_tx: failed to find the peer with peer_id %d\n",
ts->peer_id);
ieee80211_free_txskb(ath12k_pdev_dp_to_hw(dp_pdev), msdu);
goto exit;
}
status.sta = peer->sta;
status.info = info;
status.skb = msdu;
rate = peer->last_txrate;
status_rate.rate_idx = rate;
status_rate.try_count = 1;
status.rates = &status_rate;
status.n_rates = 1;
ieee80211_tx_status_ext(ath12k_pdev_dp_to_hw(dp_pdev), &status);
exit:
rcu_read_unlock();
}
static void
ath12k_wifi7_dp_tx_status_parse(struct ath12k_dp *dp,
struct hal_wbm_completion_ring_tx *desc,
struct hal_tx_status *ts)
{
u32 info0 = le32_to_cpu(desc->rate_stats.info0);
ts->buf_rel_source =
le32_get_bits(desc->info0, HAL_WBM_COMPL_TX_INFO0_REL_SRC_MODULE);
if (ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_FW &&
ts->buf_rel_source != HAL_WBM_REL_SRC_MODULE_TQM)
return;
if (ts->buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW)
return;
ts->status = le32_get_bits(desc->info0,
HAL_WBM_COMPL_TX_INFO0_TQM_RELEASE_REASON);
ts->ppdu_id = le32_get_bits(desc->info1,
HAL_WBM_COMPL_TX_INFO1_TQM_STATUS_NUMBER);
ts->peer_id = le32_get_bits(desc->info3, HAL_WBM_COMPL_TX_INFO3_PEER_ID);
ts->ack_rssi = le32_get_bits(desc->info2,
HAL_WBM_COMPL_TX_INFO2_ACK_FRAME_RSSI);
if (info0 & HAL_TX_RATE_STATS_INFO0_VALID) {
ts->pkt_type = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_PKT_TYPE);
ts->mcs = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_MCS);
ts->sgi = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_SGI);
ts->bw = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_BW);
ts->tones = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_TONES_IN_RU);
ts->ofdma = u32_get_bits(info0, HAL_TX_RATE_STATS_INFO0_OFDMA_TX);
}
}
void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id)
{
struct ath12k_base *ab = dp->ab;
struct ath12k_pdev_dp *dp_pdev;
int hal_ring_id = dp->tx_ring[ring_id].tcl_comp_ring.ring_id;
struct hal_srng *status_ring = &dp->hal->srng_list[hal_ring_id];
struct ath12k_tx_desc_info *tx_desc = NULL;
struct hal_tx_status ts = {};
struct ath12k_tx_desc_params desc_params;
struct dp_tx_ring *tx_ring = &dp->tx_ring[ring_id];
struct hal_wbm_release_ring *desc;
u8 pdev_idx;
u64 desc_va;
enum hal_wbm_rel_src_module buf_rel_source;
enum hal_wbm_tqm_rel_reason rel_status;
spin_lock_bh(&status_ring->lock);
ath12k_hal_srng_access_begin(ab, status_ring);
while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) !=
tx_ring->tx_status_tail) {
desc = ath12k_hal_srng_dst_get_next_entry(ab, status_ring);
if (!desc)
break;
memcpy(&tx_ring->tx_status[tx_ring->tx_status_head],
desc, sizeof(*desc));
tx_ring->tx_status_head =
ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head);
}
if (ath12k_hal_srng_dst_peek(ab, status_ring) &&
(ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_head) ==
tx_ring->tx_status_tail)) {
/* TODO: Process pending tx_status messages when kfifo_is_full() */
ath12k_warn(ab, "Unable to process some of the tx_status ring desc because status_fifo is full\n");
}
ath12k_hal_srng_access_end(ab, status_ring);
spin_unlock_bh(&status_ring->lock);
while (ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail) !=
tx_ring->tx_status_head) {
struct hal_wbm_completion_ring_tx *tx_status;
u32 desc_id;
tx_ring->tx_status_tail =
ATH12K_TX_COMPL_NEXT(ab, tx_ring->tx_status_tail);
tx_status = &tx_ring->tx_status[tx_ring->tx_status_tail];
ath12k_wifi7_dp_tx_status_parse(dp, tx_status, &ts);
if (le32_get_bits(tx_status->info0, HAL_WBM_COMPL_TX_INFO0_CC_DONE)) {
/* HW done cookie conversion */
desc_va = ((u64)le32_to_cpu(tx_status->buf_va_hi) << 32 |
le32_to_cpu(tx_status->buf_va_lo));
tx_desc = (struct ath12k_tx_desc_info *)((unsigned long)desc_va);
} else {
/* SW does cookie conversion to VA */
desc_id = le32_get_bits(tx_status->buf_va_hi,
BUFFER_ADDR_INFO1_SW_COOKIE);
tx_desc = ath12k_dp_get_tx_desc(dp, desc_id);
}
if (!tx_desc) {
ath12k_warn(ab, "unable to retrieve tx_desc!");
continue;
}
desc_params.mac_id = tx_desc->mac_id;
desc_params.skb = tx_desc->skb;
desc_params.skb_ext_desc = tx_desc->skb_ext_desc;
/* Find the HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE value */
buf_rel_source = le32_get_bits(tx_status->info0,
HAL_WBM_RELEASE_INFO0_REL_SRC_MODULE);
dp->device_stats.tx_wbm_rel_source[buf_rel_source]++;
rel_status = le32_get_bits(tx_status->info0,
HAL_WBM_COMPL_TX_INFO0_TQM_RELEASE_REASON);
dp->device_stats.tqm_rel_reason[rel_status]++;
/* Release descriptor as soon as extracting necessary info
* to reduce contention
*/
ath12k_dp_tx_release_txbuf(dp, tx_desc, tx_desc->pool_id);
if (ts.buf_rel_source == HAL_WBM_REL_SRC_MODULE_FW) {
ath12k_dp_tx_process_htt_tx_complete(dp, (void *)tx_status,
tx_ring, &desc_params);
continue;
}
pdev_idx = ath12k_hw_mac_id_to_pdev_id(dp->hw_params, desc_params.mac_id);
rcu_read_lock();
dp_pdev = ath12k_dp_to_pdev_dp(dp, pdev_idx);
if (!dp_pdev) {
rcu_read_unlock();
continue;
}
if (atomic_dec_and_test(&dp_pdev->num_tx_pending))
wake_up(&dp_pdev->tx_empty_waitq);
ath12k_wifi7_dp_tx_complete_msdu(dp_pdev, &desc_params, &ts,
tx_ring->tcl_data_ring_id);
rcu_read_unlock();
}
}
u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
struct ath12k_link_vif *arvif)
{
u32 bank_config = 0;
u8 link_id = arvif->link_id;
struct ath12k_vif *ahvif = arvif->ahvif;
struct ath12k_dp_vif *dp_vif = &ahvif->dp_vif;
struct ath12k_dp_link_vif *dp_link_vif;
dp_link_vif = ath12k_dp_vif_to_dp_link_vif(dp_vif, link_id);
/* Only valid for raw frames with HW crypto enabled.
* With SW crypto, mac80211 sets key per packet
*/
if (dp_vif->tx_encap_type == HAL_TCL_ENCAP_TYPE_RAW &&
test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ab->dev_flags))
bank_config |=
u32_encode_bits(ath12k_dp_tx_get_encrypt_type(dp_vif->key_cipher),
HAL_TX_BANK_CONFIG_ENCRYPT_TYPE);
bank_config |= u32_encode_bits(dp_vif->tx_encap_type,
HAL_TX_BANK_CONFIG_ENCAP_TYPE);
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_SRC_BUFFER_SWAP) |
u32_encode_bits(0, HAL_TX_BANK_CONFIG_LINK_META_SWAP) |
u32_encode_bits(0, HAL_TX_BANK_CONFIG_EPD);
/* only valid if idx_lookup_override is not set in tcl_data_cmd */
if (ahvif->vdev_type == WMI_VDEV_TYPE_STA)
bank_config |= u32_encode_bits(1, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN);
else
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_INDEX_LOOKUP_EN);
bank_config |= u32_encode_bits(dp_link_vif->hal_addr_search_flags &
HAL_TX_ADDRX_EN,
HAL_TX_BANK_CONFIG_ADDRX_EN) |
u32_encode_bits(!!(dp_link_vif->hal_addr_search_flags &
HAL_TX_ADDRY_EN),
HAL_TX_BANK_CONFIG_ADDRY_EN);
bank_config |= u32_encode_bits(ieee80211_vif_is_mesh(ahvif->vif) ? 3 : 0,
HAL_TX_BANK_CONFIG_MESH_EN) |
u32_encode_bits(dp_link_vif->vdev_id_check_en,
HAL_TX_BANK_CONFIG_VDEV_ID_CHECK_EN);
bank_config |= u32_encode_bits(0, HAL_TX_BANK_CONFIG_DSCP_TIP_MAP_ID);
return bank_config;
}

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_DP_TX_WIFI7_H
#define ATH12K_DP_TX_WIFI7_H
int ath12k_wifi7_dp_tx(struct ath12k_pdev_dp *dp_pdev, struct ath12k_link_vif *arvif,
struct sk_buff *skb, bool gsn_valid, int mcbc_gsn,
bool is_mcast);
void ath12k_wifi7_dp_tx_completion_handler(struct ath12k_dp *dp, int ring_id);
u32 ath12k_wifi7_dp_tx_get_vdev_bank_config(struct ath12k_base *ab,
struct ath12k_link_vif *arvif);
#endif

View File

@ -0,0 +1,705 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "hw.h"
#include "hal_desc.h"
#include "../hal.h"
#include "hal.h"
#include "hal_tx.h"
#include "../debug.h"
#include "../hif.h"
#include "hal_qcn9274.h"
#include "hal_wcn7850.h"
static const struct ath12k_hw_version_map ath12k_wifi7_hw_ver_map[] = {
[ATH12K_HW_QCN9274_HW10] = {
.hal_ops = &hal_qcn9274_ops,
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274_compact),
.tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_qcn9274,
.hal_params = &ath12k_hw_hal_params_qcn9274,
.hw_regs = &qcn9274_v1_regs,
},
[ATH12K_HW_QCN9274_HW20] = {
.hal_ops = &hal_qcn9274_ops,
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274_compact),
.tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_qcn9274,
.hal_params = &ath12k_hw_hal_params_qcn9274,
.hw_regs = &qcn9274_v2_regs,
},
[ATH12K_HW_WCN7850_HW20] = {
.hal_ops = &hal_wcn7850_ops,
.hal_desc_sz = sizeof(struct hal_rx_desc_wcn7850),
.tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_wcn7850,
.hal_params = &ath12k_hw_hal_params_wcn7850,
.hw_regs = &wcn7850_regs,
},
[ATH12K_HW_IPQ5332_HW10] = {
.hal_ops = &hal_qcn9274_ops,
.hal_desc_sz = sizeof(struct hal_rx_desc_qcn9274_compact),
.tcl_to_wbm_rbm_map = ath12k_hal_tcl_to_wbm_rbm_map_qcn9274,
.hal_params = &ath12k_hw_hal_params_ipq5332,
.hw_regs = &ipq5332_regs,
},
};
int ath12k_wifi7_hal_init(struct ath12k_base *ab)
{
struct ath12k_hal *hal = &ab->hal;
memset(hal, 0, sizeof(*hal));
hal->ops = ath12k_wifi7_hw_ver_map[ab->hw_rev].hal_ops;
hal->hal_desc_sz = ath12k_wifi7_hw_ver_map[ab->hw_rev].hal_desc_sz;
hal->tcl_to_wbm_rbm_map = ath12k_wifi7_hw_ver_map[ab->hw_rev].tcl_to_wbm_rbm_map;
hal->regs = ath12k_wifi7_hw_ver_map[ab->hw_rev].hw_regs;
hal->hal_params = ath12k_wifi7_hw_ver_map[ab->hw_rev].hal_params;
hal->hal_wbm_release_ring_tx_size = sizeof(struct hal_wbm_release_ring_tx);
return 0;
}
static unsigned int ath12k_wifi7_hal_reo1_ring_id_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_ID(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned
int ath12k_wifi7_hal_reo1_ring_msi1_base_lsb_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_MSI1_BASE_LSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned
int ath12k_wifi7_hal_reo1_ring_msi1_base_msb_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_MSI1_BASE_MSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned int ath12k_wifi7_hal_reo1_ring_msi1_data_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_MSI1_DATA(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned int ath12k_wifi7_hal_reo1_ring_base_msb_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_BASE_MSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned
int ath12k_wifi7_hal_reo1_ring_producer_int_setup_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_PRODUCER_INT_SETUP(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned int ath12k_wifi7_hal_reo1_ring_hp_addr_lsb_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_HP_ADDR_LSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned int ath12k_wifi7_hal_reo1_ring_hp_addr_msb_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_HP_ADDR_MSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
static unsigned int ath12k_wifi7_hal_reo1_ring_misc_offset(struct ath12k_hal *hal)
{
return HAL_REO1_RING_MISC(hal) - HAL_REO1_RING_BASE_LSB(hal);
}
void ath12k_wifi7_hal_ce_dst_setup(struct ath12k_base *ab,
struct hal_srng *srng, int ring_num)
{
struct hal_srng_config *srng_config = &ab->hal.srng_config[HAL_CE_DST];
u32 addr;
u32 val;
addr = HAL_CE_DST_RING_CTRL +
srng_config->reg_start[HAL_SRNG_REG_GRP_R0] +
ring_num * srng_config->reg_size[HAL_SRNG_REG_GRP_R0];
val = ath12k_hif_read32(ab, addr);
val &= ~HAL_CE_DST_R0_DEST_CTRL_MAX_LEN;
val |= u32_encode_bits(srng->u.dst_ring.max_buffer_length,
HAL_CE_DST_R0_DEST_CTRL_MAX_LEN);
ath12k_hif_write32(ab, addr, val);
}
void ath12k_wifi7_hal_srng_dst_hw_init(struct ath12k_base *ab,
struct hal_srng *srng)
{
struct ath12k_hal *hal = &ab->hal;
u32 val;
u64 hp_addr;
u32 reg_base;
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {
ath12k_hif_write32(ab, reg_base +
ath12k_wifi7_hal_reo1_ring_msi1_base_lsb_offset(hal),
srng->msi_addr);
val = u32_encode_bits(((u64)srng->msi_addr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_REO1_RING_MSI1_BASE_MSB_ADDR) |
HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE;
ath12k_hif_write32(ab, reg_base +
ath12k_wifi7_hal_reo1_ring_msi1_base_msb_offset(hal),
val);
ath12k_hif_write32(ab,
reg_base +
ath12k_wifi7_hal_reo1_ring_msi1_data_offset(hal),
srng->msi_data);
}
ath12k_hif_write32(ab, reg_base, srng->ring_base_paddr);
val = u32_encode_bits(((u64)srng->ring_base_paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB) |
u32_encode_bits((srng->entry_size * srng->num_entries),
HAL_REO1_RING_BASE_MSB_RING_SIZE);
ath12k_hif_write32(ab, reg_base + ath12k_wifi7_hal_reo1_ring_base_msb_offset(hal),
val);
val = u32_encode_bits(srng->ring_id, HAL_REO1_RING_ID_RING_ID) |
u32_encode_bits(srng->entry_size, HAL_REO1_RING_ID_ENTRY_SIZE);
ath12k_hif_write32(ab, reg_base + ath12k_wifi7_hal_reo1_ring_id_offset(hal), val);
/* interrupt setup */
val = u32_encode_bits((srng->intr_timer_thres_us >> 3),
HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD);
val |= u32_encode_bits((srng->intr_batch_cntr_thres_entries * srng->entry_size),
HAL_REO1_RING_PRDR_INT_SETUP_BATCH_COUNTER_THOLD);
ath12k_hif_write32(ab,
reg_base +
ath12k_wifi7_hal_reo1_ring_producer_int_setup_offset(hal),
val);
hp_addr = hal->rdp.paddr +
((unsigned long)srng->u.dst_ring.hp_addr -
(unsigned long)hal->rdp.vaddr);
ath12k_hif_write32(ab, reg_base +
ath12k_wifi7_hal_reo1_ring_hp_addr_lsb_offset(hal),
hp_addr & HAL_ADDR_LSB_REG_MASK);
ath12k_hif_write32(ab, reg_base +
ath12k_wifi7_hal_reo1_ring_hp_addr_msb_offset(hal),
hp_addr >> HAL_ADDR_MSB_REG_SHIFT);
/* Initialize head and tail pointers to indicate ring is empty */
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
ath12k_hif_write32(ab, reg_base, 0);
ath12k_hif_write32(ab, reg_base + HAL_REO1_RING_TP_OFFSET, 0);
*srng->u.dst_ring.hp_addr = 0;
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
val = 0;
if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)
val |= HAL_REO1_RING_MISC_DATA_TLV_SWAP;
if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)
val |= HAL_REO1_RING_MISC_HOST_FW_SWAP;
if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)
val |= HAL_REO1_RING_MISC_MSI_SWAP;
val |= HAL_REO1_RING_MISC_SRNG_ENABLE;
ath12k_hif_write32(ab, reg_base + ath12k_wifi7_hal_reo1_ring_misc_offset(hal),
val);
}
void ath12k_wifi7_hal_srng_src_hw_init(struct ath12k_base *ab,
struct hal_srng *srng)
{
struct ath12k_hal *hal = &ab->hal;
u32 val;
u64 tp_addr;
u32 reg_base;
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
if (srng->flags & HAL_SRNG_FLAGS_MSI_INTR) {
ath12k_hif_write32(ab, reg_base +
HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(hal),
srng->msi_addr);
val = u32_encode_bits(((u64)srng->msi_addr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_TCL1_RING_MSI1_BASE_MSB_ADDR) |
HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE;
ath12k_hif_write32(ab, reg_base +
HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(hal),
val);
ath12k_hif_write32(ab, reg_base +
HAL_TCL1_RING_MSI1_DATA_OFFSET(hal),
srng->msi_data);
}
ath12k_hif_write32(ab, reg_base, srng->ring_base_paddr);
val = u32_encode_bits(((u64)srng->ring_base_paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB) |
u32_encode_bits((srng->entry_size * srng->num_entries),
HAL_TCL1_RING_BASE_MSB_RING_SIZE);
ath12k_hif_write32(ab, reg_base + HAL_TCL1_RING_BASE_MSB_OFFSET(hal), val);
val = u32_encode_bits(srng->entry_size, HAL_REO1_RING_ID_ENTRY_SIZE);
ath12k_hif_write32(ab, reg_base + HAL_TCL1_RING_ID_OFFSET(hal), val);
val = u32_encode_bits(srng->intr_timer_thres_us,
HAL_TCL1_RING_CONSR_INT_SETUP_IX0_INTR_TMR_THOLD);
val |= u32_encode_bits((srng->intr_batch_cntr_thres_entries * srng->entry_size),
HAL_TCL1_RING_CONSR_INT_SETUP_IX0_BATCH_COUNTER_THOLD);
ath12k_hif_write32(ab,
reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(hal),
val);
val = 0;
if (srng->flags & HAL_SRNG_FLAGS_LOW_THRESH_INTR_EN) {
val |= u32_encode_bits(srng->u.src_ring.low_threshold,
HAL_TCL1_RING_CONSR_INT_SETUP_IX1_LOW_THOLD);
}
ath12k_hif_write32(ab,
reg_base + HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(hal),
val);
if (srng->ring_id != HAL_SRNG_RING_ID_WBM_IDLE_LINK) {
tp_addr = hal->rdp.paddr +
((unsigned long)srng->u.src_ring.tp_addr -
(unsigned long)hal->rdp.vaddr);
ath12k_hif_write32(ab,
reg_base + HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(hal),
tp_addr & HAL_ADDR_LSB_REG_MASK);
ath12k_hif_write32(ab,
reg_base + HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(hal),
tp_addr >> HAL_ADDR_MSB_REG_SHIFT);
}
/* Initialize head and tail pointers to indicate ring is empty */
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
ath12k_hif_write32(ab, reg_base, 0);
ath12k_hif_write32(ab, reg_base + HAL_TCL1_RING_TP_OFFSET, 0);
*srng->u.src_ring.tp_addr = 0;
reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R0];
val = 0;
if (srng->flags & HAL_SRNG_FLAGS_DATA_TLV_SWAP)
val |= HAL_TCL1_RING_MISC_DATA_TLV_SWAP;
if (srng->flags & HAL_SRNG_FLAGS_RING_PTR_SWAP)
val |= HAL_TCL1_RING_MISC_HOST_FW_SWAP;
if (srng->flags & HAL_SRNG_FLAGS_MSI_SWAP)
val |= HAL_TCL1_RING_MISC_MSI_SWAP;
/* Loop count is not used for SRC rings */
val |= HAL_TCL1_RING_MISC_MSI_LOOPCNT_DISABLE;
val |= HAL_TCL1_RING_MISC_SRNG_ENABLE;
if (srng->ring_id == HAL_SRNG_RING_ID_WBM_IDLE_LINK)
val |= HAL_TCL1_RING_MISC_MSI_RING_ID_DISABLE;
ath12k_hif_write32(ab, reg_base + HAL_TCL1_RING_MISC_OFFSET(hal), val);
}
void ath12k_wifi7_hal_set_umac_srng_ptr_addr(struct ath12k_base *ab,
struct hal_srng *srng)
{
u32 reg_base = srng->hwreg_base[HAL_SRNG_REG_GRP_R2];
if (srng->ring_dir == HAL_SRNG_DIR_SRC) {
if (!ab->hw_params->supports_shadow_regs) {
srng->u.src_ring.hp_addr =
(u32 *)((unsigned long)ab->mem + reg_base);
} else {
ath12k_dbg(ab, ATH12K_DBG_HAL,
"hal reg_base 0x%x shadow 0x%lx\n",
reg_base,
(unsigned long)srng->u.src_ring.hp_addr -
(unsigned long)ab->mem);
}
} else {
if (!ab->hw_params->supports_shadow_regs) {
srng->u.dst_ring.tp_addr =
(u32 *)((unsigned long)ab->mem + reg_base +
(HAL_REO1_RING_TP - HAL_REO1_RING_HP));
} else {
ath12k_dbg(ab, ATH12K_DBG_HAL,
"target_reg 0x%x shadow 0x%lx\n",
reg_base + HAL_REO1_RING_TP - HAL_REO1_RING_HP,
(unsigned long)srng->u.dst_ring.tp_addr -
(unsigned long)ab->mem);
}
}
}
int ath12k_wifi7_hal_srng_get_ring_id(struct ath12k_hal *hal,
enum hal_ring_type type,
int ring_num, int mac_id)
{
struct hal_srng_config *srng_config = &hal->srng_config[type];
int ring_id;
if (ring_num >= srng_config->max_rings) {
ath12k_warn(hal, "invalid ring number :%d\n", ring_num);
return -EINVAL;
}
ring_id = srng_config->start_ring_id + ring_num;
if (srng_config->mac_type == ATH12K_HAL_SRNG_PMAC)
ring_id += mac_id * HAL_SRNG_RINGS_PER_PMAC;
if (WARN_ON(ring_id >= HAL_SRNG_RING_ID_MAX))
return -EINVAL;
return ring_id;
}
static
void ath12k_wifi7_hal_srng_update_hp_tp_addr(struct ath12k_base *ab,
int shadow_cfg_idx,
enum hal_ring_type ring_type,
int ring_num)
{
struct hal_srng *srng;
struct ath12k_hal *hal = &ab->hal;
int ring_id;
struct hal_srng_config *srng_config = &hal->srng_config[ring_type];
ring_id = ath12k_wifi7_hal_srng_get_ring_id(hal, ring_type, ring_num,
0);
if (ring_id < 0)
return;
srng = &hal->srng_list[ring_id];
if (srng_config->ring_dir == HAL_SRNG_DIR_DST)
srng->u.dst_ring.tp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
(unsigned long)ab->mem);
else
srng->u.src_ring.hp_addr = (u32 *)(HAL_SHADOW_REG(shadow_cfg_idx) +
(unsigned long)ab->mem);
}
u32 ath12k_wifi7_hal_ce_get_desc_size(enum hal_ce_desc type)
{
switch (type) {
case HAL_CE_DESC_SRC:
return sizeof(struct hal_ce_srng_src_desc);
case HAL_CE_DESC_DST:
return sizeof(struct hal_ce_srng_dest_desc);
case HAL_CE_DESC_DST_STATUS:
return sizeof(struct hal_ce_srng_dst_status_desc);
}
return 0;
}
int ath12k_wifi7_hal_srng_update_shadow_config(struct ath12k_base *ab,
enum hal_ring_type ring_type,
int ring_num)
{
struct ath12k_hal *hal = &ab->hal;
struct hal_srng_config *srng_config = &hal->srng_config[ring_type];
int shadow_cfg_idx = hal->num_shadow_reg_configured;
u32 target_reg;
if (shadow_cfg_idx >= HAL_SHADOW_NUM_REGS_MAX)
return -EINVAL;
hal->num_shadow_reg_configured++;
target_reg = srng_config->reg_start[HAL_HP_OFFSET_IN_REG_START];
target_reg += srng_config->reg_size[HAL_HP_OFFSET_IN_REG_START] *
ring_num;
/* For destination ring, shadow the TP */
if (srng_config->ring_dir == HAL_SRNG_DIR_DST)
target_reg += HAL_OFFSET_FROM_HP_TO_TP;
hal->shadow_reg_addr[shadow_cfg_idx] = target_reg;
/* update hp/tp addr to hal structure*/
ath12k_wifi7_hal_srng_update_hp_tp_addr(ab, shadow_cfg_idx, ring_type,
ring_num);
ath12k_dbg(ab, ATH12K_DBG_HAL,
"target_reg %x, shadow reg 0x%x shadow_idx 0x%x, ring_type %d, ring num %d",
target_reg,
HAL_SHADOW_REG(shadow_cfg_idx),
shadow_cfg_idx,
ring_type, ring_num);
return 0;
}
void ath12k_wifi7_hal_ce_src_set_desc(struct hal_ce_srng_src_desc *desc,
dma_addr_t paddr,
u32 len, u32 id, u8 byte_swap_data)
{
desc->buffer_addr_low = cpu_to_le32(paddr & HAL_ADDR_LSB_REG_MASK);
desc->buffer_addr_info =
le32_encode_bits(((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_CE_SRC_DESC_ADDR_INFO_ADDR_HI) |
le32_encode_bits(byte_swap_data,
HAL_CE_SRC_DESC_ADDR_INFO_BYTE_SWAP) |
le32_encode_bits(0, HAL_CE_SRC_DESC_ADDR_INFO_GATHER) |
le32_encode_bits(len, HAL_CE_SRC_DESC_ADDR_INFO_LEN);
desc->meta_info = le32_encode_bits(id, HAL_CE_SRC_DESC_META_INFO_DATA);
}
void ath12k_wifi7_hal_ce_dst_set_desc(struct hal_ce_srng_dest_desc *desc,
dma_addr_t paddr)
{
desc->buffer_addr_low = cpu_to_le32(paddr & HAL_ADDR_LSB_REG_MASK);
desc->buffer_addr_info =
le32_encode_bits(((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_CE_DEST_DESC_ADDR_INFO_ADDR_HI);
}
void ath12k_wifi7_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc,
u32 cookie, dma_addr_t paddr,
enum hal_rx_buf_return_buf_manager rbm)
{
desc->buf_addr_info.info0 = le32_encode_bits((paddr & HAL_ADDR_LSB_REG_MASK),
BUFFER_ADDR_INFO0_ADDR);
desc->buf_addr_info.info1 =
le32_encode_bits(((u64)paddr >> HAL_ADDR_MSB_REG_SHIFT),
BUFFER_ADDR_INFO1_ADDR) |
le32_encode_bits(rbm, BUFFER_ADDR_INFO1_RET_BUF_MGR) |
le32_encode_bits(cookie, BUFFER_ADDR_INFO1_SW_COOKIE);
}
u32 ath12k_wifi7_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc)
{
u32 len;
len = le32_get_bits(READ_ONCE(desc->flags), HAL_CE_DST_STATUS_DESC_FLAGS_LEN);
desc->flags &= ~cpu_to_le32(HAL_CE_DST_STATUS_DESC_FLAGS_LEN);
return len;
}
void
ath12k_wifi7_hal_setup_link_idle_list(struct ath12k_base *ab,
struct hal_wbm_idle_scatter_list *sbuf,
u32 nsbufs, u32 tot_link_desc,
u32 end_offset)
{
struct ath12k_hal *hal = &ab->hal;
struct ath12k_buffer_addr *link_addr;
int i;
u32 reg_scatter_buf_sz = HAL_WBM_IDLE_SCATTER_BUF_SIZE / 64;
u32 val;
link_addr = (void *)sbuf[0].vaddr + HAL_WBM_IDLE_SCATTER_BUF_SIZE;
for (i = 1; i < nsbufs; i++) {
link_addr->info0 = cpu_to_le32(sbuf[i].paddr & HAL_ADDR_LSB_REG_MASK);
link_addr->info1 =
le32_encode_bits((u64)sbuf[i].paddr >> HAL_ADDR_MSB_REG_SHIFT,
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32) |
le32_encode_bits(BASE_ADDR_MATCH_TAG_VAL,
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG);
link_addr = (void *)sbuf[i].vaddr +
HAL_WBM_IDLE_SCATTER_BUF_SIZE;
}
val = u32_encode_bits(reg_scatter_buf_sz, HAL_WBM_SCATTER_BUFFER_SIZE) |
u32_encode_bits(0x1, HAL_WBM_LINK_DESC_IDLE_LIST_MODE);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR(hal),
val);
val = u32_encode_bits(reg_scatter_buf_sz * nsbufs,
HAL_WBM_SCATTER_RING_SIZE_OF_IDLE_LINK_DESC_LIST);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_R0_IDLE_LIST_SIZE_ADDR(hal),
val);
val = u32_encode_bits(sbuf[0].paddr & HAL_ADDR_LSB_REG_MASK,
BUFFER_ADDR_INFO0_ADDR);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_RING_BASE_LSB(hal),
val);
val = u32_encode_bits(BASE_ADDR_MATCH_TAG_VAL,
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG) |
u32_encode_bits((u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT,
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_RING_BASE_MSB(hal),
val);
/* Setup head and tail pointers for the idle list */
val = u32_encode_bits(sbuf[nsbufs - 1].paddr, BUFFER_ADDR_INFO0_ADDR);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0(hal),
val);
val = u32_encode_bits(((u64)sbuf[nsbufs - 1].paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32) |
u32_encode_bits((end_offset >> 2),
HAL_WBM_SCATTERED_DESC_HEAD_P_OFFSET_IX1);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX1(hal),
val);
val = u32_encode_bits(sbuf[0].paddr, BUFFER_ADDR_INFO0_ADDR);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0(hal),
val);
val = u32_encode_bits(sbuf[0].paddr, BUFFER_ADDR_INFO0_ADDR);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX0(hal),
val);
val = u32_encode_bits(((u64)sbuf[0].paddr >> HAL_ADDR_MSB_REG_SHIFT),
HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32) |
u32_encode_bits(0, HAL_WBM_SCATTERED_DESC_TAIL_P_OFFSET_IX1);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX1(hal),
val);
val = 2 * tot_link_desc;
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SCATTERED_DESC_PTR_HP_ADDR(hal),
val);
/* Enable the SRNG */
val = u32_encode_bits(1, HAL_WBM_IDLE_LINK_RING_MISC_SRNG_ENABLE) |
u32_encode_bits(1, HAL_WBM_IDLE_LINK_RING_MISC_RIND_ID_DISABLE);
ath12k_hif_write32(ab,
HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_IDLE_LINK_RING_MISC_ADDR(hal),
val);
}
void ath12k_wifi7_hal_tx_configure_bank_register(struct ath12k_base *ab,
u32 bank_config,
u8 bank_id)
{
ath12k_hif_write32(ab, HAL_TCL_SW_CONFIG_BANK_ADDR + 4 * bank_id,
bank_config);
}
void ath12k_wifi7_hal_reoq_lut_addr_read_enable(struct ath12k_base *ab)
{
struct ath12k_hal *hal = &ab->hal;
u32 val = ath12k_hif_read32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_ADDR(hal));
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_ADDR(hal),
val | HAL_REO_QDESC_ADDR_READ_LUT_ENABLE);
}
void ath12k_wifi7_hal_reoq_lut_set_max_peerid(struct ath12k_base *ab)
{
struct ath12k_hal *hal = &ab->hal;
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_QDESC_MAX_PEERID(hal),
HAL_REO_QDESC_MAX_PEERID);
}
void ath12k_wifi7_hal_write_reoq_lut_addr(struct ath12k_base *ab,
dma_addr_t paddr)
{
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_LUT_BASE0(&ab->hal), paddr);
}
void ath12k_wifi7_hal_write_ml_reoq_lut_addr(struct ath12k_base *ab,
dma_addr_t paddr)
{
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_LUT_BASE1(&ab->hal), paddr);
}
void ath12k_wifi7_hal_cc_config(struct ath12k_base *ab)
{
u32 cmem_base = ab->qmi.dev_mem[ATH12K_QMI_DEVMEM_CMEM_INDEX].start;
u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
u32 wbm_base = HAL_SEQ_WCSS_UMAC_WBM_REG;
u32 val = 0;
struct ath12k_hal *hal = &ab->hal;
if (ath12k_ftm_mode)
return;
ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG0(hal), cmem_base);
val |= u32_encode_bits(ATH12K_CMEM_ADDR_MSB,
HAL_REO1_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB) |
u32_encode_bits(ATH12K_CC_PPT_MSB,
HAL_REO1_SW_COOKIE_CFG_COOKIE_PPT_MSB) |
u32_encode_bits(ATH12K_CC_SPT_MSB,
HAL_REO1_SW_COOKIE_CFG_COOKIE_SPT_MSB) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_ALIGN) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_ENABLE) |
u32_encode_bits(1, HAL_REO1_SW_COOKIE_CFG_GLOBAL_ENABLE);
ath12k_hif_write32(ab, reo_base + HAL_REO1_SW_COOKIE_CFG1(hal), val);
/* Enable HW CC for WBM */
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG0, cmem_base);
val = u32_encode_bits(ATH12K_CMEM_ADDR_MSB,
HAL_WBM_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB) |
u32_encode_bits(ATH12K_CC_PPT_MSB,
HAL_WBM_SW_COOKIE_CFG_COOKIE_PPT_MSB) |
u32_encode_bits(ATH12K_CC_SPT_MSB,
HAL_WBM_SW_COOKIE_CFG_COOKIE_SPT_MSB) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_ALIGN);
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG1, val);
/* Enable conversion complete indication */
val = ath12k_hif_read32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG2);
val |= u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_RELEASE_PATH_EN) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_ERR_PATH_EN) |
u32_encode_bits(1, HAL_WBM_SW_COOKIE_CFG_CONV_IND_EN);
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CFG2, val);
/* Enable Cookie conversion for WBM2SW Rings */
val = ath12k_hif_read32(ab, wbm_base + HAL_WBM_SW_COOKIE_CONVERT_CFG);
val |= u32_encode_bits(1, HAL_WBM_SW_COOKIE_CONV_CFG_GLOBAL_EN) |
hal->hal_params->wbm2sw_cc_enable;
ath12k_hif_write32(ab, wbm_base + HAL_WBM_SW_COOKIE_CONVERT_CFG, val);
}
enum hal_rx_buf_return_buf_manager
ath12k_wifi7_hal_get_idle_link_rbm(struct ath12k_hal *hal, u8 device_id)
{
switch (device_id) {
case 0:
return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST;
case 1:
return HAL_RX_BUF_RBM_WBM_DEV1_IDLE_DESC_LIST;
case 2:
return HAL_RX_BUF_RBM_WBM_DEV2_IDLE_DESC_LIST;
default:
ath12k_warn(hal,
"invalid %d device id, so choose default rbm\n",
device_id);
WARN_ON(1);
return HAL_RX_BUF_RBM_WBM_DEV0_IDLE_DESC_LIST;
}
}

View File

@ -0,0 +1,564 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_HAL_WIFI7_H
#define ATH12K_HAL_WIFI7_H
#include "../core.h"
#include "../hal.h"
#include "hal_desc.h"
#include "hal_tx.h"
#include "hal_rx.h"
#include "hal_rx_desc.h"
/* calculate the register address from bar0 of shadow register x */
#define HAL_SHADOW_BASE_ADDR 0x000008fc
#define HAL_SHADOW_NUM_REGS 40
#define HAL_HP_OFFSET_IN_REG_START 1
#define HAL_OFFSET_FROM_HP_TO_TP 4
#define HAL_SHADOW_REG(x) (HAL_SHADOW_BASE_ADDR + (4 * (x)))
#define HAL_REO_QDESC_MAX_PEERID 8191
/* WCSS Relative address */
#define HAL_SEQ_WCSS_CMEM_OFFSET 0x00100000
#define HAL_SEQ_WCSS_UMAC_OFFSET 0x00a00000
#define HAL_SEQ_WCSS_UMAC_REO_REG 0x00a38000
#define HAL_SEQ_WCSS_UMAC_TCL_REG 0x00a44000
#define HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(hal) \
((hal)->regs->umac_ce0_src_reg_base)
#define HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal) \
((hal)->regs->umac_ce0_dest_reg_base)
#define HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(hal) \
((hal)->regs->umac_ce1_src_reg_base)
#define HAL_SEQ_WCSS_UMAC_CE1_DST_REG(hal) \
((hal)->regs->umac_ce1_dest_reg_base)
#define HAL_SEQ_WCSS_UMAC_WBM_REG 0x00a34000
#define HAL_CE_WFSS_CE_REG_BASE 0x01b80000
#define HAL_TCL_SW_CONFIG_BANK_ADDR 0x00a4408c
/* SW2TCL(x) R0 ring configuration address */
#define HAL_TCL1_RING_CMN_CTRL_REG 0x00000020
#define HAL_TCL1_RING_DSCP_TID_MAP 0x00000240
#define HAL_TCL1_RING_BASE_LSB(hal) \
((hal)->regs->tcl1_ring_base_lsb)
#define HAL_TCL1_RING_BASE_MSB(hal) \
((hal)->regs->tcl1_ring_base_msb)
#define HAL_TCL1_RING_ID(hal) ((hal)->regs->tcl1_ring_id)
#define HAL_TCL1_RING_MISC(hal) \
((hal)->regs->tcl1_ring_misc)
#define HAL_TCL1_RING_TP_ADDR_LSB(hal) \
((hal)->regs->tcl1_ring_tp_addr_lsb)
#define HAL_TCL1_RING_TP_ADDR_MSB(hal) \
((hal)->regs->tcl1_ring_tp_addr_msb)
#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(hal) \
((hal)->regs->tcl1_ring_consumer_int_setup_ix0)
#define HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(hal) \
((hal)->regs->tcl1_ring_consumer_int_setup_ix1)
#define HAL_TCL1_RING_MSI1_BASE_LSB(hal) \
((hal)->regs->tcl1_ring_msi1_base_lsb)
#define HAL_TCL1_RING_MSI1_BASE_MSB(hal) \
((hal)->regs->tcl1_ring_msi1_base_msb)
#define HAL_TCL1_RING_MSI1_DATA(hal) \
((hal)->regs->tcl1_ring_msi1_data)
#define HAL_TCL2_RING_BASE_LSB(hal) \
((hal)->regs->tcl2_ring_base_lsb)
#define HAL_TCL_RING_BASE_LSB(hal) \
((hal)->regs->tcl_ring_base_lsb)
#define HAL_TCL1_RING_MSI1_BASE_LSB_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_MSI1_BASE_LSB(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_MSI1_BASE_MSB_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_MSI1_BASE_MSB(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_MSI1_DATA_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_MSI1_DATA(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_BASE_MSB_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_BASE_MSB(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_ID_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_ID(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX0(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_CONSUMER_INT_SETUP_IX1(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_TP_ADDR_LSB_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_TP_ADDR_LSB(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_TP_ADDR_MSB_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_TP_ADDR_MSB(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
#define HAL_TCL1_RING_MISC_OFFSET(hal) ({ typeof(hal) _hal = (hal); \
(HAL_TCL1_RING_MISC(_hal) - HAL_TCL1_RING_BASE_LSB(_hal)); })
/* SW2TCL(x) R2 ring pointers (head/tail) address */
#define HAL_TCL1_RING_HP 0x00002000
#define HAL_TCL1_RING_TP 0x00002004
#define HAL_TCL2_RING_HP 0x00002008
#define HAL_TCL_RING_HP 0x00002028
#define HAL_TCL1_RING_TP_OFFSET \
(HAL_TCL1_RING_TP - HAL_TCL1_RING_HP)
/* TCL STATUS ring address */
#define HAL_TCL_STATUS_RING_BASE_LSB(hal) \
((hal)->regs->tcl_status_ring_base_lsb)
#define HAL_TCL_STATUS_RING_HP 0x00002048
/* PPE2TCL1 Ring address */
#define HAL_TCL_PPE2TCL1_RING_BASE_LSB 0x00000c48
#define HAL_TCL_PPE2TCL1_RING_HP 0x00002038
/* WBM PPE Release Ring address */
#define HAL_WBM_PPE_RELEASE_RING_BASE_LSB(hal) \
((hal)->regs->ppe_rel_ring_base)
#define HAL_WBM_PPE_RELEASE_RING_HP 0x00003020
/* REO2SW(x) R0 ring configuration address */
#define HAL_REO1_GEN_ENABLE 0x00000000
#define HAL_REO1_MISC_CTRL_ADDR(hal) \
((hal)->regs->reo1_misc_ctrl_addr)
#define HAL_REO1_DEST_RING_CTRL_IX_0 0x00000004
#define HAL_REO1_DEST_RING_CTRL_IX_1 0x00000008
#define HAL_REO1_DEST_RING_CTRL_IX_2 0x0000000c
#define HAL_REO1_DEST_RING_CTRL_IX_3 0x00000010
#define HAL_REO1_QDESC_ADDR(hal) ((hal)->regs->reo1_qdesc_addr)
#define HAL_REO1_QDESC_MAX_PEERID(hal) ((hal)->regs->reo1_qdesc_max_peerid)
#define HAL_REO1_SW_COOKIE_CFG0(hal) ((hal)->regs->reo1_sw_cookie_cfg0)
#define HAL_REO1_SW_COOKIE_CFG1(hal) ((hal)->regs->reo1_sw_cookie_cfg1)
#define HAL_REO1_QDESC_LUT_BASE0(hal) ((hal)->regs->reo1_qdesc_lut_base0)
#define HAL_REO1_QDESC_LUT_BASE1(hal) ((hal)->regs->reo1_qdesc_lut_base1)
#define HAL_REO1_RING_BASE_LSB(hal) ((hal)->regs->reo1_ring_base_lsb)
#define HAL_REO1_RING_BASE_MSB(hal) ((hal)->regs->reo1_ring_base_msb)
#define HAL_REO1_RING_ID(hal) ((hal)->regs->reo1_ring_id)
#define HAL_REO1_RING_MISC(hal) ((hal)->regs->reo1_ring_misc)
#define HAL_REO1_RING_HP_ADDR_LSB(hal) ((hal)->regs->reo1_ring_hp_addr_lsb)
#define HAL_REO1_RING_HP_ADDR_MSB(hal) ((hal)->regs->reo1_ring_hp_addr_msb)
#define HAL_REO1_RING_PRODUCER_INT_SETUP(hal) \
((hal)->regs->reo1_ring_producer_int_setup)
#define HAL_REO1_RING_MSI1_BASE_LSB(hal) \
((hal)->regs->reo1_ring_msi1_base_lsb)
#define HAL_REO1_RING_MSI1_BASE_MSB(hal) \
((hal)->regs->reo1_ring_msi1_base_msb)
#define HAL_REO1_RING_MSI1_DATA(hal) ((hal)->regs->reo1_ring_msi1_data)
#define HAL_REO2_RING_BASE_LSB(hal) ((hal)->regs->reo2_ring_base)
#define HAL_REO1_AGING_THRESH_IX_0(hal) ((hal)->regs->reo1_aging_thres_ix0)
#define HAL_REO1_AGING_THRESH_IX_1(hal) ((hal)->regs->reo1_aging_thres_ix1)
#define HAL_REO1_AGING_THRESH_IX_2(hal) ((hal)->regs->reo1_aging_thres_ix2)
#define HAL_REO1_AGING_THRESH_IX_3(hal) ((hal)->regs->reo1_aging_thres_ix3)
/* REO2SW(x) R2 ring pointers (head/tail) address */
#define HAL_REO1_RING_HP 0x00003048
#define HAL_REO1_RING_TP 0x0000304c
#define HAL_REO2_RING_HP 0x00003050
#define HAL_REO1_RING_TP_OFFSET (HAL_REO1_RING_TP - HAL_REO1_RING_HP)
/* REO2SW0 ring configuration address */
#define HAL_REO_SW0_RING_BASE_LSB(hal) \
((hal)->regs->reo2_sw0_ring_base)
/* REO2SW0 R2 ring pointer (head/tail) address */
#define HAL_REO_SW0_RING_HP 0x00003088
/* REO CMD R0 address */
#define HAL_REO_CMD_RING_BASE_LSB(hal) \
((hal)->regs->reo_cmd_ring_base)
/* REO CMD R2 address */
#define HAL_REO_CMD_HP 0x00003020
/* SW2REO R0 address */
#define HAL_SW2REO_RING_BASE_LSB(hal) \
((hal)->regs->sw2reo_ring_base)
#define HAL_SW2REO1_RING_BASE_LSB(hal) \
((hal)->regs->sw2reo1_ring_base)
/* SW2REO R2 address */
#define HAL_SW2REO_RING_HP 0x00003028
#define HAL_SW2REO1_RING_HP 0x00003030
/* CE ring R0 address */
#define HAL_CE_SRC_RING_BASE_LSB 0x00000000
#define HAL_CE_DST_RING_BASE_LSB 0x00000000
#define HAL_CE_DST_STATUS_RING_BASE_LSB 0x00000058
#define HAL_CE_DST_RING_CTRL 0x000000b0
/* CE ring R2 address */
#define HAL_CE_DST_RING_HP 0x00000400
#define HAL_CE_DST_STATUS_RING_HP 0x00000408
/* REO status address */
#define HAL_REO_STATUS_RING_BASE_LSB(hal) \
((hal)->regs->reo_status_ring_base)
#define HAL_REO_STATUS_HP 0x000030a8
/* WBM Idle R0 address */
#define HAL_WBM_IDLE_LINK_RING_BASE_LSB(hal) \
((hal)->regs->wbm_idle_ring_base_lsb)
#define HAL_WBM_IDLE_LINK_RING_MISC_ADDR(hal) \
((hal)->regs->wbm_idle_ring_misc_addr)
#define HAL_WBM_R0_IDLE_LIST_CONTROL_ADDR(hal) \
((hal)->regs->wbm_r0_idle_list_cntl_addr)
#define HAL_WBM_R0_IDLE_LIST_SIZE_ADDR(hal) \
((hal)->regs->wbm_r0_idle_list_size_addr)
#define HAL_WBM_SCATTERED_RING_BASE_LSB(hal) \
((hal)->regs->wbm_scattered_ring_base_lsb)
#define HAL_WBM_SCATTERED_RING_BASE_MSB(hal) \
((hal)->regs->wbm_scattered_ring_base_msb)
#define HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX0(hal) \
((hal)->regs->wbm_scattered_desc_head_info_ix0)
#define HAL_WBM_SCATTERED_DESC_PTR_HEAD_INFO_IX1(hal) \
((hal)->regs->wbm_scattered_desc_head_info_ix1)
#define HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX0(hal) \
((hal)->regs->wbm_scattered_desc_tail_info_ix0)
#define HAL_WBM_SCATTERED_DESC_PTR_TAIL_INFO_IX1(hal) \
((hal)->regs->wbm_scattered_desc_tail_info_ix1)
#define HAL_WBM_SCATTERED_DESC_PTR_HP_ADDR(hal) \
((hal)->regs->wbm_scattered_desc_ptr_hp_addr)
/* WBM Idle R2 address */
#define HAL_WBM_IDLE_LINK_RING_HP 0x000030b8
/* SW2WBM R0 release address */
#define HAL_WBM_SW_RELEASE_RING_BASE_LSB(hal) \
((hal)->regs->wbm_sw_release_ring_base_lsb)
#define HAL_WBM_SW1_RELEASE_RING_BASE_LSB(hal) \
((hal)->regs->wbm_sw1_release_ring_base_lsb)
/* SW2WBM R2 release address */
#define HAL_WBM_SW_RELEASE_RING_HP 0x00003010
#define HAL_WBM_SW1_RELEASE_RING_HP 0x00003018
/* WBM2SW R0 release address */
#define HAL_WBM0_RELEASE_RING_BASE_LSB(hal) \
((hal)->regs->wbm0_release_ring_base_lsb)
#define HAL_WBM1_RELEASE_RING_BASE_LSB(hal) \
((hal)->regs->wbm1_release_ring_base_lsb)
/* WBM2SW R2 release address */
#define HAL_WBM0_RELEASE_RING_HP 0x000030c8
#define HAL_WBM1_RELEASE_RING_HP 0x000030d0
/* WBM cookie config address and mask */
#define HAL_WBM_SW_COOKIE_CFG0 0x00000040
#define HAL_WBM_SW_COOKIE_CFG1 0x00000044
#define HAL_WBM_SW_COOKIE_CFG2 0x00000090
#define HAL_WBM_SW_COOKIE_CONVERT_CFG 0x00000094
#define HAL_WBM_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_WBM_SW_COOKIE_CFG_COOKIE_PPT_MSB GENMASK(12, 8)
#define HAL_WBM_SW_COOKIE_CFG_COOKIE_SPT_MSB GENMASK(17, 13)
#define HAL_WBM_SW_COOKIE_CFG_ALIGN BIT(18)
#define HAL_WBM_SW_COOKIE_CFG_RELEASE_PATH_EN BIT(0)
#define HAL_WBM_SW_COOKIE_CFG_ERR_PATH_EN BIT(1)
#define HAL_WBM_SW_COOKIE_CFG_CONV_IND_EN BIT(3)
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW0_EN BIT(1)
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW1_EN BIT(2)
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW2_EN BIT(3)
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW3_EN BIT(4)
#define HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW4_EN BIT(5)
#define HAL_WBM_SW_COOKIE_CONV_CFG_GLOBAL_EN BIT(8)
/* TCL ring field mask and offset */
#define HAL_TCL1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_TCL1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_TCL1_RING_ID_ENTRY_SIZE GENMASK(7, 0)
#define HAL_TCL1_RING_MISC_MSI_RING_ID_DISABLE BIT(0)
#define HAL_TCL1_RING_MISC_MSI_LOOPCNT_DISABLE BIT(1)
#define HAL_TCL1_RING_MISC_MSI_SWAP BIT(3)
#define HAL_TCL1_RING_MISC_HOST_FW_SWAP BIT(4)
#define HAL_TCL1_RING_MISC_DATA_TLV_SWAP BIT(5)
#define HAL_TCL1_RING_MISC_SRNG_ENABLE BIT(6)
#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_INTR_TMR_THOLD GENMASK(31, 16)
#define HAL_TCL1_RING_CONSR_INT_SETUP_IX0_BATCH_COUNTER_THOLD GENMASK(14, 0)
#define HAL_TCL1_RING_CONSR_INT_SETUP_IX1_LOW_THOLD GENMASK(15, 0)
#define HAL_TCL1_RING_MSI1_BASE_MSB_MSI1_ENABLE BIT(8)
#define HAL_TCL1_RING_MSI1_BASE_MSB_ADDR GENMASK(7, 0)
#define HAL_TCL1_RING_CMN_CTRL_DSCP_TID_MAP_PROG_EN BIT(23)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP GENMASK(31, 0)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP0 GENMASK(2, 0)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP1 GENMASK(5, 3)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP2 GENMASK(8, 6)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP3 GENMASK(11, 9)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP4 GENMASK(14, 12)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP5 GENMASK(17, 15)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP6 GENMASK(20, 18)
#define HAL_TCL1_RING_FIELD_DSCP_TID_MAP7 GENMASK(23, 21)
/* REO ring field mask and offset */
#define HAL_REO1_RING_BASE_MSB_RING_SIZE GENMASK(27, 8)
#define HAL_REO1_RING_BASE_MSB_RING_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_REO1_RING_ID_RING_ID GENMASK(15, 8)
#define HAL_REO1_RING_ID_ENTRY_SIZE GENMASK(7, 0)
#define HAL_REO1_RING_MISC_MSI_SWAP BIT(3)
#define HAL_REO1_RING_MISC_HOST_FW_SWAP BIT(4)
#define HAL_REO1_RING_MISC_DATA_TLV_SWAP BIT(5)
#define HAL_REO1_RING_MISC_SRNG_ENABLE BIT(6)
#define HAL_REO1_RING_PRDR_INT_SETUP_INTR_TMR_THOLD GENMASK(31, 16)
#define HAL_REO1_RING_PRDR_INT_SETUP_BATCH_COUNTER_THOLD GENMASK(14, 0)
#define HAL_REO1_RING_MSI1_BASE_MSB_MSI1_ENABLE BIT(8)
#define HAL_REO1_RING_MSI1_BASE_MSB_ADDR GENMASK(7, 0)
#define HAL_REO1_MISC_CTL_FRAG_DST_RING GENMASK(20, 17)
#define HAL_REO1_MISC_CTL_BAR_DST_RING GENMASK(24, 21)
#define HAL_REO1_GEN_ENABLE_AGING_LIST_ENABLE BIT(2)
#define HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE BIT(3)
#define HAL_REO1_SW_COOKIE_CFG_CMEM_BASE_ADDR_MSB GENMASK(7, 0)
#define HAL_REO1_SW_COOKIE_CFG_COOKIE_PPT_MSB GENMASK(12, 8)
#define HAL_REO1_SW_COOKIE_CFG_COOKIE_SPT_MSB GENMASK(17, 13)
#define HAL_REO1_SW_COOKIE_CFG_ALIGN BIT(18)
#define HAL_REO1_SW_COOKIE_CFG_ENABLE BIT(19)
#define HAL_REO1_SW_COOKIE_CFG_GLOBAL_ENABLE BIT(20)
#define HAL_REO_QDESC_ADDR_READ_LUT_ENABLE BIT(7)
#define HAL_REO_QDESC_ADDR_READ_CLEAR_QDESC_ARRAY BIT(6)
/* CE ring bit field mask and shift */
#define HAL_CE_DST_R0_DEST_CTRL_MAX_LEN GENMASK(15, 0)
#define HAL_ADDR_LSB_REG_MASK 0xffffffff
#define HAL_ADDR_MSB_REG_SHIFT 32
/* WBM ring bit field mask and shift */
#define HAL_WBM_LINK_DESC_IDLE_LIST_MODE BIT(1)
#define HAL_WBM_SCATTER_BUFFER_SIZE GENMASK(10, 2)
#define HAL_WBM_SCATTER_RING_SIZE_OF_IDLE_LINK_DESC_LIST GENMASK(31, 16)
#define HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_39_32 GENMASK(7, 0)
#define HAL_WBM_SCATTERED_DESC_MSB_BASE_ADDR_MATCH_TAG GENMASK(31, 8)
#define HAL_WBM_SCATTERED_DESC_HEAD_P_OFFSET_IX1 GENMASK(20, 8)
#define HAL_WBM_SCATTERED_DESC_TAIL_P_OFFSET_IX1 GENMASK(20, 8)
#define HAL_WBM_IDLE_LINK_RING_MISC_SRNG_ENABLE BIT(6)
#define HAL_WBM_IDLE_LINK_RING_MISC_RIND_ID_DISABLE BIT(0)
#define BASE_ADDR_MATCH_TAG_VAL 0x5
#define HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_REO_REO2SW0_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_REO_CMD_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_CE_SRC_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_CE_DST_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE 0x0000ffff
#define HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_RXDMA_RING_MAX_SIZE 0x0000ffff
#define HAL_RXDMA_RING_MAX_SIZE_BE 0x000fffff
#define HAL_WBM2PPE_RELEASE_RING_BASE_MSB_RING_SIZE 0x000fffff
#define HAL_WBM2SW_REL_ERR_RING_NUM 3
/* Add any other errors here and return them in
* ath12k_hal_rx_desc_get_err().
*/
#define HAL_IPQ5332_CE_WFSS_REG_BASE 0x740000
#define HAL_IPQ5332_CE_SIZE 0x100000
#define HAL_RX_MAX_BA_WINDOW 256
#define HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC (100 * 1000)
#define HAL_DEFAULT_VO_REO_TIMEOUT_USEC (40 * 1000)
#define HAL_SRNG_TLV_HDR_TAG GENMASK(9, 1)
#define HAL_SRNG_TLV_HDR_LEN GENMASK(25, 10)
#define HAL_SRNG_DESC_LOOP_CNT 0xf0000000
#define HAL_REO_CMD_FLG_NEED_STATUS BIT(0)
#define HAL_REO_CMD_FLG_STATS_CLEAR BIT(1)
#define HAL_REO_CMD_FLG_FLUSH_BLOCK_LATER BIT(2)
#define HAL_REO_CMD_FLG_FLUSH_RELEASE_BLOCKING BIT(3)
#define HAL_REO_CMD_FLG_FLUSH_NO_INVAL BIT(4)
#define HAL_REO_CMD_FLG_FLUSH_FWD_ALL_MPDUS BIT(5)
#define HAL_REO_CMD_FLG_FLUSH_ALL BIT(6)
#define HAL_REO_CMD_FLG_UNBLK_RESOURCE BIT(7)
#define HAL_REO_CMD_FLG_UNBLK_CACHE BIT(8)
#define HAL_REO_CMD_FLG_FLUSH_QUEUE_1K_DESC BIT(9)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO0_UPD_* fields */
#define HAL_REO_CMD_UPD0_RX_QUEUE_NUM BIT(8)
#define HAL_REO_CMD_UPD0_VLD BIT(9)
#define HAL_REO_CMD_UPD0_ALDC BIT(10)
#define HAL_REO_CMD_UPD0_DIS_DUP_DETECTION BIT(11)
#define HAL_REO_CMD_UPD0_SOFT_REORDER_EN BIT(12)
#define HAL_REO_CMD_UPD0_AC BIT(13)
#define HAL_REO_CMD_UPD0_BAR BIT(14)
#define HAL_REO_CMD_UPD0_RETRY BIT(15)
#define HAL_REO_CMD_UPD0_CHECK_2K_MODE BIT(16)
#define HAL_REO_CMD_UPD0_OOR_MODE BIT(17)
#define HAL_REO_CMD_UPD0_BA_WINDOW_SIZE BIT(18)
#define HAL_REO_CMD_UPD0_PN_CHECK BIT(19)
#define HAL_REO_CMD_UPD0_EVEN_PN BIT(20)
#define HAL_REO_CMD_UPD0_UNEVEN_PN BIT(21)
#define HAL_REO_CMD_UPD0_PN_HANDLE_ENABLE BIT(22)
#define HAL_REO_CMD_UPD0_PN_SIZE BIT(23)
#define HAL_REO_CMD_UPD0_IGNORE_AMPDU_FLG BIT(24)
#define HAL_REO_CMD_UPD0_SVLD BIT(25)
#define HAL_REO_CMD_UPD0_SSN BIT(26)
#define HAL_REO_CMD_UPD0_SEQ_2K_ERR BIT(27)
#define HAL_REO_CMD_UPD0_PN_ERR BIT(28)
#define HAL_REO_CMD_UPD0_PN_VALID BIT(29)
#define HAL_REO_CMD_UPD0_PN BIT(30)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO1_* fields */
#define HAL_REO_CMD_UPD1_VLD BIT(16)
#define HAL_REO_CMD_UPD1_ALDC GENMASK(18, 17)
#define HAL_REO_CMD_UPD1_DIS_DUP_DETECTION BIT(19)
#define HAL_REO_CMD_UPD1_SOFT_REORDER_EN BIT(20)
#define HAL_REO_CMD_UPD1_AC GENMASK(22, 21)
#define HAL_REO_CMD_UPD1_BAR BIT(23)
#define HAL_REO_CMD_UPD1_RETRY BIT(24)
#define HAL_REO_CMD_UPD1_CHECK_2K_MODE BIT(25)
#define HAL_REO_CMD_UPD1_OOR_MODE BIT(26)
#define HAL_REO_CMD_UPD1_PN_CHECK BIT(27)
#define HAL_REO_CMD_UPD1_EVEN_PN BIT(28)
#define HAL_REO_CMD_UPD1_UNEVEN_PN BIT(29)
#define HAL_REO_CMD_UPD1_PN_HANDLE_ENABLE BIT(30)
#define HAL_REO_CMD_UPD1_IGNORE_AMPDU_FLG BIT(31)
/* Should be matching with HAL_REO_UPD_RX_QUEUE_INFO2_* fields */
#define HAL_REO_CMD_UPD2_SVLD BIT(10)
#define HAL_REO_CMD_UPD2_SSN GENMASK(22, 11)
#define HAL_REO_CMD_UPD2_SEQ_2K_ERR BIT(23)
#define HAL_REO_CMD_UPD2_PN_ERR BIT(24)
struct hal_reo_status_queue_stats {
u16 ssn;
u16 curr_idx;
u32 pn[4];
u32 last_rx_queue_ts;
u32 last_rx_dequeue_ts;
u32 rx_bitmap[8]; /* Bitmap from 0-255 */
u32 curr_mpdu_cnt;
u32 curr_msdu_cnt;
u16 fwd_due_to_bar_cnt;
u16 dup_cnt;
u32 frames_in_order_cnt;
u32 num_mpdu_processed_cnt;
u32 num_msdu_processed_cnt;
u32 total_num_processed_byte_cnt;
u32 late_rx_mpdu_cnt;
u32 reorder_hole_cnt;
u8 timeout_cnt;
u8 bar_rx_cnt;
u8 num_window_2k_jump_cnt;
};
struct hal_reo_status_flush_queue {
bool err_detected;
};
enum hal_reo_status_flush_cache_err_code {
HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_SUCCESS,
HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_IN_USE,
HAL_REO_STATUS_FLUSH_CACHE_ERR_CODE_NOT_FOUND,
};
struct hal_reo_status_flush_cache {
bool err_detected;
enum hal_reo_status_flush_cache_err_code err_code;
bool cache_controller_flush_status_hit;
u8 cache_controller_flush_status_desc_type;
u8 cache_controller_flush_status_client_id;
u8 cache_controller_flush_status_err;
u8 cache_controller_flush_status_cnt;
};
enum hal_reo_status_unblock_cache_type {
HAL_REO_STATUS_UNBLOCK_BLOCKING_RESOURCE,
HAL_REO_STATUS_UNBLOCK_ENTIRE_CACHE_USAGE,
};
struct hal_reo_status_unblock_cache {
bool err_detected;
enum hal_reo_status_unblock_cache_type unblock_type;
};
struct hal_reo_status_flush_timeout_list {
bool err_detected;
bool list_empty;
u16 release_desc_cnt;
u16 fwd_buf_cnt;
};
enum hal_reo_threshold_idx {
HAL_REO_THRESHOLD_IDX_DESC_COUNTER0,
HAL_REO_THRESHOLD_IDX_DESC_COUNTER1,
HAL_REO_THRESHOLD_IDX_DESC_COUNTER2,
HAL_REO_THRESHOLD_IDX_DESC_COUNTER_SUM,
};
struct hal_reo_status_desc_thresh_reached {
enum hal_reo_threshold_idx threshold_idx;
u32 link_desc_counter0;
u32 link_desc_counter1;
u32 link_desc_counter2;
u32 link_desc_counter_sum;
};
struct hal_reo_status {
struct hal_reo_status_header uniform_hdr;
u8 loop_cnt;
union {
struct hal_reo_status_queue_stats queue_stats;
struct hal_reo_status_flush_queue flush_queue;
struct hal_reo_status_flush_cache flush_cache;
struct hal_reo_status_unblock_cache unblock_cache;
struct hal_reo_status_flush_timeout_list timeout_list;
struct hal_reo_status_desc_thresh_reached desc_thresh_reached;
} u;
};
int ath12k_wifi7_hal_init(struct ath12k_base *ab);
void ath12k_wifi7_hal_ce_dst_setup(struct ath12k_base *ab,
struct hal_srng *srng, int ring_num);
void ath12k_wifi7_hal_srng_dst_hw_init(struct ath12k_base *ab,
struct hal_srng *srng);
void ath12k_wifi7_hal_srng_src_hw_init(struct ath12k_base *ab,
struct hal_srng *srng);
void ath12k_wifi7_hal_set_umac_srng_ptr_addr(struct ath12k_base *ab,
struct hal_srng *srng);
int ath12k_wifi7_hal_srng_update_shadow_config(struct ath12k_base *ab,
enum hal_ring_type ring_type,
int ring_num);
int ath12k_wifi7_hal_srng_get_ring_id(struct ath12k_hal *hal,
enum hal_ring_type type,
int ring_num, int mac_id);
u32 ath12k_wifi7_hal_ce_get_desc_size(enum hal_ce_desc type);
void ath12k_wifi7_hal_cc_config(struct ath12k_base *ab);
enum hal_rx_buf_return_buf_manager
ath12k_wifi7_hal_get_idle_link_rbm(struct ath12k_hal *hal, u8 device_id);
void ath12k_wifi7_hal_ce_src_set_desc(struct hal_ce_srng_src_desc *desc,
dma_addr_t paddr,
u32 len, u32 id, u8 byte_swap_data);
void ath12k_wifi7_hal_ce_dst_set_desc(struct hal_ce_srng_dest_desc *desc,
dma_addr_t paddr);
void
ath12k_wifi7_hal_set_link_desc_addr(struct hal_wbm_link_desc *desc,
u32 cookie, dma_addr_t paddr,
enum hal_rx_buf_return_buf_manager rbm);
u32
ath12k_wifi7_hal_ce_dst_status_get_length(struct hal_ce_srng_dst_status_desc *desc);
void
ath12k_wifi7_hal_setup_link_idle_list(struct ath12k_base *ab,
struct hal_wbm_idle_scatter_list *sbuf,
u32 nsbufs, u32 tot_link_desc,
u32 end_offset);
void ath12k_wifi7_hal_reoq_lut_addr_read_enable(struct ath12k_base *ab);
void ath12k_wifi7_hal_reoq_lut_set_max_peerid(struct ath12k_base *ab);
void ath12k_wifi7_hal_write_reoq_lut_addr(struct ath12k_base *ab,
dma_addr_t paddr);
void ath12k_wifi7_hal_write_ml_reoq_lut_addr(struct ath12k_base *ab,
dma_addr_t paddr);
u32 ath12k_wifi7_hal_reo_qdesc_size(u32 ba_window_size, u8 tid);
#endif

View File

@ -1,92 +1,13 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "core.h"
#include "../core.h"
#ifndef ATH12K_HAL_DESC_H
#define ATH12K_HAL_DESC_H
#define BUFFER_ADDR_INFO0_ADDR GENMASK(31, 0)
#define BUFFER_ADDR_INFO1_ADDR GENMASK(7, 0)
#define BUFFER_ADDR_INFO1_RET_BUF_MGR GENMASK(11, 8)
#define BUFFER_ADDR_INFO1_SW_COOKIE GENMASK(31, 12)
struct ath12k_buffer_addr {
__le32 info0;
__le32 info1;
} __packed;
/* ath12k_buffer_addr
*
* buffer_addr_31_0
* Address (lower 32 bits) of the MSDU buffer or MSDU_EXTENSION
* descriptor or Link descriptor
*
* buffer_addr_39_32
* Address (upper 8 bits) of the MSDU buffer or MSDU_EXTENSION
* descriptor or Link descriptor
*
* return_buffer_manager (RBM)
* Consumer: WBM
* Producer: SW/FW
* Indicates to which buffer manager the buffer or MSDU_EXTENSION
* descriptor or link descriptor that is being pointed to shall be
* returned after the frame has been processed. It is used by WBM
* for routing purposes.
*
* Values are defined in enum %HAL_RX_BUF_RBM_
*
* sw_buffer_cookie
* Cookie field exclusively used by SW. HW ignores the contents,
* accept that it passes the programmed value on to other
* descriptors together with the physical address.
*
* Field can be used by SW to for example associate the buffers
* physical address with the virtual address.
*
* NOTE1:
* The three most significant bits can have a special meaning
* in case this struct is embedded in a TX_MPDU_DETAILS STRUCT,
* and field transmit_bw_restriction is set
*
* In case of NON punctured transmission:
* Sw_buffer_cookie[19:17] = 3'b000: 20 MHz TX only
* Sw_buffer_cookie[19:17] = 3'b001: 40 MHz TX only
* Sw_buffer_cookie[19:17] = 3'b010: 80 MHz TX only
* Sw_buffer_cookie[19:17] = 3'b011: 160 MHz TX only
* Sw_buffer_cookie[19:17] = 3'b101: 240 MHz TX only
* Sw_buffer_cookie[19:17] = 3'b100: 320 MHz TX only
* Sw_buffer_cookie[19:18] = 2'b11: reserved
*
* In case of punctured transmission:
* Sw_buffer_cookie[19:16] = 4'b0000: pattern 0 only
* Sw_buffer_cookie[19:16] = 4'b0001: pattern 1 only
* Sw_buffer_cookie[19:16] = 4'b0010: pattern 2 only
* Sw_buffer_cookie[19:16] = 4'b0011: pattern 3 only
* Sw_buffer_cookie[19:16] = 4'b0100: pattern 4 only
* Sw_buffer_cookie[19:16] = 4'b0101: pattern 5 only
* Sw_buffer_cookie[19:16] = 4'b0110: pattern 6 only
* Sw_buffer_cookie[19:16] = 4'b0111: pattern 7 only
* Sw_buffer_cookie[19:16] = 4'b1000: pattern 8 only
* Sw_buffer_cookie[19:16] = 4'b1001: pattern 9 only
* Sw_buffer_cookie[19:16] = 4'b1010: pattern 10 only
* Sw_buffer_cookie[19:16] = 4'b1011: pattern 11 only
* Sw_buffer_cookie[19:18] = 2'b11: reserved
*
* Note: a punctured transmission is indicated by the presence
* of TLV TX_PUNCTURE_SETUP embedded in the scheduler TLV
*
* Sw_buffer_cookie[20:17]: Tid: The TID field in the QoS control
* field
*
* Sw_buffer_cookie[16]: Mpdu_qos_control_valid: This field
* indicates MPDUs with a QoS control field.
*
*/
enum hal_tlv_tag {
HAL_MACTX_CBF_START = 0 /* 0x0 */,
HAL_PHYRX_DATA = 1 /* 0x1 */,
@ -820,35 +741,6 @@ struct rx_msdu_ext_desc {
* Set to the link ID of the PMAC that received the frame
*/
enum hal_reo_dest_ring_buffer_type {
HAL_REO_DEST_RING_BUFFER_TYPE_MSDU,
HAL_REO_DEST_RING_BUFFER_TYPE_LINK_DESC,
};
enum hal_reo_dest_ring_push_reason {
HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED,
HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION,
};
enum hal_reo_dest_ring_error_code {
HAL_REO_DEST_RING_ERROR_CODE_DESC_ADDR_ZERO,
HAL_REO_DEST_RING_ERROR_CODE_DESC_INVALID,
HAL_REO_DEST_RING_ERROR_CODE_AMPDU_IN_NON_BA,
HAL_REO_DEST_RING_ERROR_CODE_NON_BA_DUPLICATE,
HAL_REO_DEST_RING_ERROR_CODE_BA_DUPLICATE,
HAL_REO_DEST_RING_ERROR_CODE_FRAME_2K_JUMP,
HAL_REO_DEST_RING_ERROR_CODE_BAR_2K_JUMP,
HAL_REO_DEST_RING_ERROR_CODE_FRAME_OOR,
HAL_REO_DEST_RING_ERROR_CODE_BAR_OOR,
HAL_REO_DEST_RING_ERROR_CODE_NO_BA_SESSION,
HAL_REO_DEST_RING_ERROR_CODE_FRAME_SN_EQUALS_SSN,
HAL_REO_DEST_RING_ERROR_CODE_PN_CHECK_FAILED,
HAL_REO_DEST_RING_ERROR_CODE_2K_ERR_FLAG_SET,
HAL_REO_DEST_RING_ERROR_CODE_PN_ERR_FLAG_SET,
HAL_REO_DEST_RING_ERROR_CODE_DESC_BLOCKED,
HAL_REO_DEST_RING_ERROR_CODE_MAX,
};
#define HAL_REO_DEST_RING_INFO0_BUFFER_TYPE BIT(0)
#define HAL_REO_DEST_RING_INFO0_PUSH_REASON GENMASK(2, 1)
#define HAL_REO_DEST_RING_INFO0_ERROR_CODE GENMASK(7, 3)
@ -986,35 +878,6 @@ struct hal_reo_to_ppe_ring {
* More Segments followed
*/
enum hal_reo_entr_rxdma_push_reason {
HAL_REO_ENTR_RING_RXDMA_PUSH_REASON_ERR_DETECTED,
HAL_REO_ENTR_RING_RXDMA_PUSH_REASON_ROUTING_INSTRUCTION,
HAL_REO_ENTR_RING_RXDMA_PUSH_REASON_RX_FLUSH,
};
enum hal_reo_entr_rxdma_ecode {
HAL_REO_ENTR_RING_RXDMA_ECODE_OVERFLOW_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_MPDU_LEN_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_FCS_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_DECRYPT_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_TKIP_MIC_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_UNECRYPTED_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LEN_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_MSDU_LIMIT_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_WIFI_PARSE_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_PARSE_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_SA_TIMEOUT_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_DA_TIMEOUT_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_FLOW_TIMEOUT_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_FLUSH_REQUEST_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_FRAG_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_MULTICAST_ECHO_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_AMSDU_MISMATCH_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_UNAUTH_WDS_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_GRPCAST_AMSDU_WDS_ERR,
HAL_REO_ENTR_RING_RXDMA_ECODE_MAX,
};
enum hal_rx_reo_dest_ring {
HAL_RX_REO_DEST_RING_TCL,
HAL_RX_REO_DEST_RING_SW1,
@ -1269,46 +1132,6 @@ struct hal_reo_flush_cache {
#define HAL_TCL_DATA_CMD_INFO5_RING_ID GENMASK(27, 20)
#define HAL_TCL_DATA_CMD_INFO5_LOOPING_COUNT GENMASK(31, 28)
enum hal_encrypt_type {
HAL_ENCRYPT_TYPE_WEP_40,
HAL_ENCRYPT_TYPE_WEP_104,
HAL_ENCRYPT_TYPE_TKIP_NO_MIC,
HAL_ENCRYPT_TYPE_WEP_128,
HAL_ENCRYPT_TYPE_TKIP_MIC,
HAL_ENCRYPT_TYPE_WAPI,
HAL_ENCRYPT_TYPE_CCMP_128,
HAL_ENCRYPT_TYPE_OPEN,
HAL_ENCRYPT_TYPE_CCMP_256,
HAL_ENCRYPT_TYPE_GCMP_128,
HAL_ENCRYPT_TYPE_AES_GCMP_256,
HAL_ENCRYPT_TYPE_WAPI_GCM_SM4,
};
enum hal_tcl_encap_type {
HAL_TCL_ENCAP_TYPE_RAW,
HAL_TCL_ENCAP_TYPE_NATIVE_WIFI,
HAL_TCL_ENCAP_TYPE_ETHERNET,
HAL_TCL_ENCAP_TYPE_802_3 = 3,
HAL_TCL_ENCAP_TYPE_MAX
};
enum hal_tcl_desc_type {
HAL_TCL_DESC_TYPE_BUFFER,
HAL_TCL_DESC_TYPE_EXT_DESC,
HAL_TCL_DESC_TYPE_MAX,
};
enum hal_wbm_htt_tx_comp_status {
HAL_WBM_REL_HTT_TX_COMP_STATUS_OK,
HAL_WBM_REL_HTT_TX_COMP_STATUS_DROP,
HAL_WBM_REL_HTT_TX_COMP_STATUS_TTL,
HAL_WBM_REL_HTT_TX_COMP_STATUS_REINJ,
HAL_WBM_REL_HTT_TX_COMP_STATUS_INSPECT,
HAL_WBM_REL_HTT_TX_COMP_STATUS_MEC_NOTIFY,
HAL_WBM_REL_HTT_TX_COMP_STATUS_VDEVID_MISMATCH,
HAL_WBM_REL_HTT_TX_COMP_STATUS_MAX,
};
struct hal_tcl_data_cmd {
struct ath12k_buffer_addr buf_addr_info;
__le32 info0;
@ -1765,107 +1588,11 @@ struct hal_ce_srng_dst_status_desc {
#define HAL_TX_RATE_STATS_INFO0_OFDMA_TX BIT(16)
#define HAL_TX_RATE_STATS_INFO0_TONES_IN_RU GENMASK(28, 17)
enum hal_tx_rate_stats_bw {
HAL_TX_RATE_STATS_BW_20,
HAL_TX_RATE_STATS_BW_40,
HAL_TX_RATE_STATS_BW_80,
HAL_TX_RATE_STATS_BW_160,
};
enum hal_tx_rate_stats_pkt_type {
HAL_TX_RATE_STATS_PKT_TYPE_11A,
HAL_TX_RATE_STATS_PKT_TYPE_11B,
HAL_TX_RATE_STATS_PKT_TYPE_11N,
HAL_TX_RATE_STATS_PKT_TYPE_11AC,
HAL_TX_RATE_STATS_PKT_TYPE_11AX,
HAL_TX_RATE_STATS_PKT_TYPE_11BA,
HAL_TX_RATE_STATS_PKT_TYPE_11BE,
};
enum hal_tx_rate_stats_sgi {
HAL_TX_RATE_STATS_SGI_08US,
HAL_TX_RATE_STATS_SGI_04US,
HAL_TX_RATE_STATS_SGI_16US,
HAL_TX_RATE_STATS_SGI_32US,
};
struct hal_tx_rate_stats {
__le32 info0;
__le32 tsf;
} __packed;
struct hal_wbm_link_desc {
struct ath12k_buffer_addr buf_addr_info;
} __packed;
/* hal_wbm_link_desc
*
* Producer: WBM
* Consumer: WBM
*
* buf_addr_info
* Details of the physical address of a buffer or MSDU
* link descriptor.
*/
enum hal_wbm_rel_src_module {
HAL_WBM_REL_SRC_MODULE_TQM,
HAL_WBM_REL_SRC_MODULE_RXDMA,
HAL_WBM_REL_SRC_MODULE_REO,
HAL_WBM_REL_SRC_MODULE_FW,
HAL_WBM_REL_SRC_MODULE_SW,
HAL_WBM_REL_SRC_MODULE_MAX,
};
enum hal_wbm_rel_desc_type {
HAL_WBM_REL_DESC_TYPE_REL_MSDU,
HAL_WBM_REL_DESC_TYPE_MSDU_LINK,
HAL_WBM_REL_DESC_TYPE_MPDU_LINK,
HAL_WBM_REL_DESC_TYPE_MSDU_EXT,
HAL_WBM_REL_DESC_TYPE_QUEUE_EXT,
};
/* hal_wbm_rel_desc_type
*
* msdu_buffer
* The address points to an MSDU buffer
*
* msdu_link_descriptor
* The address points to an Tx MSDU link descriptor
*
* mpdu_link_descriptor
* The address points to an MPDU link descriptor
*
* msdu_ext_descriptor
* The address points to an MSDU extension descriptor
*
* queue_ext_descriptor
* The address points to an TQM queue extension descriptor. WBM should
* treat this is the same way as a link descriptor.
*/
enum hal_wbm_rel_bm_act {
HAL_WBM_REL_BM_ACT_PUT_IN_IDLE,
HAL_WBM_REL_BM_ACT_REL_MSDU,
};
/* hal_wbm_rel_bm_act
*
* put_in_idle_list
* Put the buffer or descriptor back in the idle list. In case of MSDU or
* MDPU link descriptor, BM does not need to check to release any
* individual MSDU buffers.
*
* release_msdu_list
* This BM action can only be used in combination with desc_type being
* msdu_link_descriptor. Field first_msdu_index points out which MSDU
* pointer in the MSDU link descriptor is the first of an MPDU that is
* released. BM shall release all the MSDU buffers linked to this first
* MSDU buffer pointer. All related MSDU buffer pointer entries shall be
* set to value 0, which represents the 'NULL' pointer. When all MSDU
* buffer pointers in the MSDU link descriptor are 'NULL', the MSDU link
* descriptor itself shall also be released.
*/
#define HAL_WBM_COMPL_RX_INFO0_REL_SRC_MODULE GENMASK(2, 0)
#define HAL_WBM_COMPL_RX_INFO0_BM_ACTION GENMASK(5, 3)
#define HAL_WBM_COMPL_RX_INFO0_DESC_TYPE GENMASK(8, 6)
@ -2007,7 +1734,6 @@ struct hal_wbm_release_ring_cc_rx {
#define HAL_WBM_RELEASE_INFO3_CONTINUATION BIT(2)
#define HAL_WBM_RELEASE_INFO5_LOOPING_COUNT GENMASK(31, 28)
#define HAL_ENCRYPT_TYPE_MAX 12
struct hal_wbm_release_ring {
struct ath12k_buffer_addr buf_addr_info;
@ -2331,7 +2057,6 @@ enum hal_desc_buf_type {
#define HAL_DESC_REO_OWNED 4
#define HAL_DESC_REO_QUEUE_DESC 8
#define HAL_DESC_REO_QUEUE_EXT_DESC 9
#define HAL_DESC_REO_NON_QOS_TID 16
#define HAL_DESC_HDR_INFO0_OWNER GENMASK(3, 0)
#define HAL_DESC_HDR_INFO0_BUF_TYPE GENMASK(7, 4)
@ -2957,25 +2682,6 @@ struct hal_tcl_entrance_from_ppe_ring {
__le32 info0;
} __packed;
struct hal_mon_buf_ring {
__le32 paddr_lo;
__le32 paddr_hi;
__le64 cookie;
};
/* hal_mon_buf_ring
* Producer : SW
* Consumer : Monitor
*
* paddr_lo
* Lower 32-bit physical address of the buffer pointer from the source ring.
* paddr_hi
* bit range 7-0 : upper 8 bit of the physical address.
* bit range 31-8 : reserved.
* cookie
* Consumer: RxMon/TxMon 64 bit cookie of the buffers.
*/
#define HAL_MON_DEST_COOKIE_BUF_ID GENMASK(17, 0)
#define HAL_MON_DEST_INFO0_END_OFFSET GENMASK(11, 0)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear*/
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_HAL_QCN9274_H
#define ATH12K_HAL_QCN9274_H
#include <linux/ieee80211.h>
#include <linux/etherdevice.h>
#include "../hal.h"
#include "hal_rx.h"
#include "hal.h"
extern const struct hal_ops hal_qcn9274_ops;
extern const struct ath12k_hw_regs qcn9274_v1_regs;
extern const struct ath12k_hw_regs qcn9274_v2_regs;
extern const struct ath12k_hw_regs ipq5332_regs;
extern const struct ath12k_hal_tcl_to_wbm_rbm_map
ath12k_hal_tcl_to_wbm_rbm_map_qcn9274[DP_TCL_NUM_RING_MAX];
extern const struct ath12k_hw_hal_params ath12k_hw_hal_params_qcn9274;
extern const struct ath12k_hw_hal_params ath12k_hw_hal_params_ipq5332;
u8 ath12k_hal_rx_desc_get_l3_pad_bytes_qcn9274(struct hal_rx_desc *desc);
void ath12k_hal_rx_desc_copy_end_tlv_qcn9274(struct hal_rx_desc *fdesc,
struct hal_rx_desc *ldesc);
u32 ath12k_hal_rx_desc_get_mpdu_ppdu_id_qcn9274(struct hal_rx_desc *desc);
void ath12k_hal_rx_desc_set_msdu_len_qcn9274(struct hal_rx_desc *desc, u16 len);
u8 *ath12k_hal_rx_desc_get_msdu_payload_qcn9274(struct hal_rx_desc *desc);
u32 ath12k_hal_rx_desc_get_mpdu_start_offset_qcn9274(void);
u32 ath12k_hal_rx_desc_get_msdu_end_offset_qcn9274(void);
u32 ath12k_hal_get_rx_desc_size_qcn9274(void);
u8 ath12k_hal_rx_desc_get_msdu_src_link_qcn9274(struct hal_rx_desc *desc);
u16 ath12k_hal_rx_mpdu_start_wmask_get_qcn9274(void);
u32 ath12k_hal_rx_msdu_end_wmask_get_qcn9274(void);
void ath12k_hal_rx_desc_get_crypto_hdr_qcn9274(struct hal_rx_desc *desc,
u8 *crypto_hdr,
enum hal_encrypt_type enctype);
void ath12k_hal_rx_desc_get_dot11_hdr_qcn9274(struct hal_rx_desc *desc,
struct ieee80211_hdr *hdr);
void ath12k_hal_extract_rx_desc_data_qcn9274(struct hal_rx_desc_data *rx_desc_data,
struct hal_rx_desc *rx_desc,
struct hal_rx_desc *ldesc);
#endif

View File

@ -4,15 +4,17 @@
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "debug.h"
#include "hal.h"
#include "../debug.h"
#include "../hal.h"
#include "../hif.h"
#include "hal_tx.h"
#include "hal_rx.h"
#include "hal_desc.h"
#include "hif.h"
#include "hal.h"
static void ath12k_hal_reo_set_desc_hdr(struct hal_desc_header *hdr,
u8 owner, u8 buffer_type, u32 magic)
static
void ath12k_wifi7_hal_reo_set_desc_hdr(struct hal_desc_header *hdr,
u8 owner, u8 buffer_type, u32 magic)
{
hdr->info0 = le32_encode_bits(owner, HAL_DESC_HDR_INFO0_OWNER) |
le32_encode_bits(buffer_type, HAL_DESC_HDR_INFO0_BUF_TYPE);
@ -21,8 +23,8 @@ static void ath12k_hal_reo_set_desc_hdr(struct hal_desc_header *hdr,
hdr->info0 |= le32_encode_bits(magic, HAL_DESC_HDR_INFO0_DBG_RESERVED);
}
static int ath12k_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
static int ath12k_wifi7_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_get_queue_stats *desc;
@ -45,9 +47,9 @@ static int ath12k_hal_reo_cmd_queue_stats(struct hal_tlv_64_hdr *tlv,
return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER);
}
static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal,
struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
static int ath12k_wifi7_hal_reo_cmd_flush_cache(struct ath12k_hal *hal,
struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_flush_cache *desc;
u8 avail_slot = ffz(hal->avail_blk_resource);
@ -95,8 +97,9 @@ static int ath12k_hal_reo_cmd_flush_cache(struct ath12k_hal *hal,
return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER);
}
static int ath12k_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
static int
ath12k_wifi7_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_reo_update_rx_queue *desc;
@ -220,9 +223,9 @@ static int ath12k_hal_reo_cmd_update_rx_queue(struct hal_tlv_64_hdr *tlv,
return le32_get_bits(desc->cmd.info0, HAL_REO_CMD_HDR_INFO0_CMD_NUMBER);
}
int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
enum hal_reo_cmd_type type,
struct ath12k_hal_reo_cmd *cmd)
int ath12k_wifi7_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
enum hal_reo_cmd_type type,
struct ath12k_hal_reo_cmd *cmd)
{
struct hal_tlv_64_hdr *reo_desc;
int ret;
@ -238,13 +241,14 @@ int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
switch (type) {
case HAL_REO_CMD_GET_QUEUE_STATS:
ret = ath12k_hal_reo_cmd_queue_stats(reo_desc, cmd);
ret = ath12k_wifi7_hal_reo_cmd_queue_stats(reo_desc, cmd);
break;
case HAL_REO_CMD_FLUSH_CACHE:
ret = ath12k_hal_reo_cmd_flush_cache(&ab->hal, reo_desc, cmd);
ret = ath12k_wifi7_hal_reo_cmd_flush_cache(&ab->hal, reo_desc,
cmd);
break;
case HAL_REO_CMD_UPDATE_RX_QUEUE:
ret = ath12k_hal_reo_cmd_update_rx_queue(reo_desc, cmd);
ret = ath12k_wifi7_hal_reo_cmd_update_rx_queue(reo_desc, cmd);
break;
case HAL_REO_CMD_FLUSH_QUEUE:
case HAL_REO_CMD_UNBLOCK_CACHE:
@ -265,8 +269,9 @@ out:
return ret;
}
void ath12k_hal_rx_buf_addr_info_set(struct ath12k_buffer_addr *binfo,
dma_addr_t paddr, u32 cookie, u8 manager)
void ath12k_wifi7_hal_rx_buf_addr_info_set(struct ath12k_buffer_addr *binfo,
dma_addr_t paddr, u32 cookie,
u8 manager)
{
u32 paddr_lo, paddr_hi;
@ -278,9 +283,9 @@ void ath12k_hal_rx_buf_addr_info_set(struct ath12k_buffer_addr *binfo,
le32_encode_bits(manager, BUFFER_ADDR_INFO1_RET_BUF_MGR);
}
void ath12k_hal_rx_buf_addr_info_get(struct ath12k_buffer_addr *binfo,
dma_addr_t *paddr,
u32 *cookie, u8 *rbm)
void ath12k_wifi7_hal_rx_buf_addr_info_get(struct ath12k_buffer_addr *binfo,
dma_addr_t *paddr,
u32 *cookie, u8 *rbm)
{
*paddr = (((u64)le32_get_bits(binfo->info1, BUFFER_ADDR_INFO1_ADDR)) << 32) |
le32_get_bits(binfo->info0, BUFFER_ADDR_INFO0_ADDR);
@ -288,9 +293,10 @@ void ath12k_hal_rx_buf_addr_info_get(struct ath12k_buffer_addr *binfo,
*rbm = le32_get_bits(binfo->info1, BUFFER_ADDR_INFO1_RET_BUF_MGR);
}
void ath12k_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link, u32 *num_msdus,
u32 *msdu_cookies,
enum hal_rx_buf_return_buf_manager *rbm)
void
ath12k_wifi7_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link,
u32 *num_msdus, u32 *msdu_cookies,
enum hal_rx_buf_return_buf_manager *rbm)
{
struct hal_rx_msdu_details *msdu;
u32 val;
@ -317,10 +323,11 @@ void ath12k_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link, u32 *num_ms
}
}
int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
struct hal_reo_dest_ring *desc,
dma_addr_t *paddr, u32 *desc_bank)
int ath12k_wifi7_hal_desc_reo_parse_err(struct ath12k_dp *dp,
struct hal_reo_dest_ring *desc,
dma_addr_t *paddr, u32 *desc_bank)
{
struct ath12k_base *ab = dp->ab;
enum hal_reo_dest_ring_push_reason push_reason;
enum hal_reo_dest_ring_error_code err_code;
u32 cookie;
@ -329,7 +336,7 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
HAL_REO_DEST_RING_INFO0_PUSH_REASON);
err_code = le32_get_bits(desc->info0,
HAL_REO_DEST_RING_INFO0_ERROR_CODE);
ab->device_stats.reo_error[err_code]++;
dp->device_stats.reo_error[err_code]++;
if (push_reason != HAL_REO_DEST_RING_PUSH_REASON_ERR_DETECTED &&
push_reason != HAL_REO_DEST_RING_PUSH_REASON_ROUTING_INSTRUCTION) {
@ -338,14 +345,15 @@ int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
return -EINVAL;
}
ath12k_hal_rx_reo_ent_paddr_get(ab, &desc->buf_addr_info, paddr, &cookie);
ath12k_wifi7_hal_rx_reo_ent_paddr_get(&desc->buf_addr_info, paddr,
&cookie);
*desc_bank = u32_get_bits(cookie, DP_LINK_DESC_BANK_MASK);
return 0;
}
int ath12k_hal_wbm_desc_parse_err(struct ath12k_base *ab, void *desc,
struct hal_rx_wbm_rel_info *rel_info)
int ath12k_wifi7_hal_wbm_desc_parse_err(struct ath12k_dp *dp, void *desc,
struct hal_rx_wbm_rel_info *rel_info)
{
struct hal_wbm_release_ring *wbm_desc = desc;
struct hal_wbm_release_ring_cc_rx *wbm_cc_desc = desc;
@ -378,7 +386,7 @@ int ath12k_hal_wbm_desc_parse_err(struct ath12k_base *ab, void *desc,
val = le32_get_bits(wbm_desc->buf_addr_info.info1,
BUFFER_ADDR_INFO1_RET_BUF_MGR);
if (val != HAL_RX_BUF_RBM_SW3_BM) {
ab->device_stats.invalid_rbm++;
dp->device_stats.invalid_rbm++;
return -EINVAL;
}
@ -390,7 +398,7 @@ int ath12k_hal_wbm_desc_parse_err(struct ath12k_base *ab, void *desc,
val = le32_get_bits(wbm_cc_desc->info0,
HAL_WBM_RELEASE_RX_CC_INFO0_RBM);
if (val != HAL_RX_BUF_RBM_SW3_BM) {
ab->device_stats.invalid_rbm++;
dp->device_stats.invalid_rbm++;
return -EINVAL;
}
@ -429,12 +437,13 @@ int ath12k_hal_wbm_desc_parse_err(struct ath12k_base *ab, void *desc,
HAL_WBM_RELEASE_INFO0_RXDMA_ERROR_CODE);
}
rel_info->peer_metadata = wbm_desc->info2;
return 0;
}
void ath12k_hal_rx_reo_ent_paddr_get(struct ath12k_base *ab,
struct ath12k_buffer_addr *buff_addr,
dma_addr_t *paddr, u32 *cookie)
void ath12k_wifi7_hal_rx_reo_ent_paddr_get(struct ath12k_buffer_addr *buff_addr,
dma_addr_t *paddr, u32 *cookie)
{
*paddr = ((u64)(le32_get_bits(buff_addr->info1,
BUFFER_ADDR_INFO1_ADDR)) << 32) |
@ -443,10 +452,10 @@ void ath12k_hal_rx_reo_ent_paddr_get(struct ath12k_base *ab,
*cookie = le32_get_bits(buff_addr->info1, BUFFER_ADDR_INFO1_SW_COOKIE);
}
void ath12k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
u32 *sw_cookie,
struct ath12k_buffer_addr **pp_buf_addr,
u8 *rbm, u32 *msdu_cnt)
void ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
u32 *sw_cookie,
struct ath12k_buffer_addr **pp_buf_addr,
u8 *rbm, u32 *msdu_cnt)
{
struct hal_reo_entrance_ring *reo_ent_ring =
(struct hal_reo_entrance_ring *)rx_desc;
@ -474,11 +483,14 @@ void ath12k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
*pp_buf_addr = (void *)buf_addr_info;
}
void ath12k_hal_rx_msdu_list_get(struct ath12k *ar,
struct hal_rx_msdu_link *link_desc,
struct hal_rx_msdu_list *msdu_list,
u16 *num_msdus)
void ath12k_wifi7_hal_rx_msdu_list_get(struct ath12k *ar,
void *link_desc_opaque,
void *msdu_list_opaque, u16 *num_msdus)
{
struct hal_rx_msdu_link *link_desc =
(struct hal_rx_msdu_link *)link_desc_opaque;
struct hal_rx_msdu_list *msdu_list =
(struct hal_rx_msdu_list *)msdu_list_opaque;
struct hal_rx_msdu_details *msdu_details = NULL;
struct rx_msdu_desc *msdu_desc_info = NULL;
u32 last = 0, first = 0;
@ -523,10 +535,11 @@ void ath12k_hal_rx_msdu_list_get(struct ath12k *ar,
*num_msdus = i;
}
void ath12k_hal_rx_msdu_link_desc_set(struct ath12k_base *ab,
struct hal_wbm_release_ring *desc,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action)
void
ath12k_wifi7_hal_rx_msdu_link_desc_set(struct ath12k_base *ab,
struct hal_wbm_release_ring *desc,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action)
{
desc->buf_addr_info = *buf_addr_info;
desc->info0 |= le32_encode_bits(HAL_WBM_REL_SRC_MODULE_SW,
@ -536,8 +549,9 @@ void ath12k_hal_rx_msdu_link_desc_set(struct ath12k_base *ab,
HAL_WBM_RELEASE_INFO0_DESC_TYPE);
}
void ath12k_hal_reo_status_queue_stats(struct ath12k_base *ab, struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void ath12k_wifi7_hal_reo_status_queue_stats(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct hal_reo_get_queue_stats_status *desc =
(struct hal_reo_get_queue_stats_status *)tlv->value;
@ -599,8 +613,9 @@ void ath12k_hal_reo_status_queue_stats(struct ath12k_base *ab, struct hal_tlv_64
HAL_REO_GET_QUEUE_STATS_STATUS_INFO5_LOOPING_CNT));
}
void ath12k_hal_reo_flush_queue_status(struct ath12k_base *ab, struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void ath12k_wifi7_hal_reo_flush_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct hal_reo_flush_queue_status *desc =
(struct hal_reo_flush_queue_status *)tlv->value;
@ -616,8 +631,10 @@ void ath12k_hal_reo_flush_queue_status(struct ath12k_base *ab, struct hal_tlv_64
HAL_REO_FLUSH_QUEUE_INFO0_ERR_DETECTED);
}
void ath12k_hal_reo_flush_cache_status(struct ath12k_base *ab, struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void
ath12k_wifi7_hal_reo_flush_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct ath12k_hal *hal = &ab->hal;
struct hal_reo_flush_cache_status *desc =
@ -657,8 +674,9 @@ void ath12k_hal_reo_flush_cache_status(struct ath12k_base *ab, struct hal_tlv_64
HAL_REO_FLUSH_CACHE_STATUS_INFO0_FLUSH_COUNT);
}
void ath12k_hal_reo_unblk_cache_status(struct ath12k_base *ab, struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void ath12k_wifi7_hal_reo_unblk_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct ath12k_hal *hal = &ab->hal;
struct hal_reo_unblock_cache_status *desc =
@ -684,9 +702,10 @@ void ath12k_hal_reo_unblk_cache_status(struct ath12k_base *ab, struct hal_tlv_64
hal->avail_blk_resource &= ~BIT(hal->current_blk_index);
}
void ath12k_hal_reo_flush_timeout_list_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void
ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct hal_reo_flush_timeout_list_status *desc =
(struct hal_reo_flush_timeout_list_status *)tlv->value;
@ -713,9 +732,10 @@ void ath12k_hal_reo_flush_timeout_list_status(struct ath12k_base *ab,
HAL_REO_FLUSH_TIMEOUT_STATUS_INFO1_FWD_BUF_COUNT);
}
void ath12k_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void
ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct hal_reo_desc_thresh_reached_status *desc =
(struct hal_reo_desc_thresh_reached_status *)tlv->value;
@ -748,9 +768,9 @@ void ath12k_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab,
HAL_REO_DESC_THRESH_STATUS_INFO4_LINK_DESC_COUNTER_SUM);
}
void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
void ath12k_wifi7_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status)
{
struct hal_reo_status_hdr *desc =
(struct hal_reo_status_hdr *)tlv->value;
@ -763,7 +783,7 @@ void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
HAL_REO_STATUS_HDR_INFO0_EXEC_STATUS);
}
u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid)
u32 ath12k_wifi7_hal_reo_qdesc_size(u32 ba_window_size, u8 tid)
{
u32 num_ext_desc, num_1k_desc = 0;
@ -789,15 +809,15 @@ u32 ath12k_hal_reo_qdesc_size(u32 ba_window_size, u8 tid)
(num_1k_desc * sizeof(struct hal_rx_reo_queue_1k));
}
void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc,
int tid, u32 ba_window_size,
u32 start_seq, enum hal_pn_type type)
void ath12k_wifi7_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc,
int tid, u32 ba_window_size,
u32 start_seq, enum hal_pn_type type)
{
struct hal_rx_reo_queue_ext *ext_desc;
ath12k_hal_reo_set_desc_hdr(&qdesc->desc_hdr, HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0);
ath12k_wifi7_hal_reo_set_desc_hdr(&qdesc->desc_hdr, HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_0);
qdesc->rx_queue_num = le32_encode_bits(tid, HAL_RX_REO_QUEUE_RX_QUEUE_NUMBER);
@ -855,21 +875,24 @@ void ath12k_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc,
* queue descriptor in Rx peer entry as part of dp_rx_tid_update.
*/
memset(ext_desc, 0, 3 * sizeof(*ext_desc));
ath12k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1);
ath12k_wifi7_hal_reo_set_desc_hdr(&ext_desc->desc_hdr,
HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_1);
ext_desc++;
ath12k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2);
ath12k_wifi7_hal_reo_set_desc_hdr(&ext_desc->desc_hdr,
HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2);
ext_desc++;
ath12k_hal_reo_set_desc_hdr(&ext_desc->desc_hdr, HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3);
ath12k_wifi7_hal_reo_set_desc_hdr(&ext_desc->desc_hdr,
HAL_DESC_REO_OWNED,
HAL_DESC_REO_QUEUE_EXT_DESC,
REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3);
}
void ath12k_hal_reo_init_cmd_ring(struct ath12k_base *ab,
struct hal_srng *srng)
void ath12k_wifi7_hal_reo_init_cmd_ring(struct ath12k_base *ab,
struct hal_srng *srng)
{
struct hal_srng_params params;
struct hal_tlv_64_hdr *tlv;
@ -893,8 +916,10 @@ void ath12k_hal_reo_init_cmd_ring(struct ath12k_base *ab,
}
}
void ath12k_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map)
void ath12k_wifi7_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map)
{
struct ath12k_hal *hal = &ab->hal;
u32 reo_base = HAL_SEQ_WCSS_UMAC_REO_REG;
u32 val;
@ -904,7 +929,7 @@ void ath12k_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map)
u32_encode_bits(1, HAL_REO1_GEN_ENABLE_AGING_FLUSH_ENABLE);
ath12k_hif_write32(ab, reo_base + HAL_REO1_GEN_ENABLE, val);
val = ath12k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTRL_ADDR(ab));
val = ath12k_hif_read32(ab, reo_base + HAL_REO1_MISC_CTRL_ADDR(hal));
val &= ~(HAL_REO1_MISC_CTL_FRAG_DST_RING |
HAL_REO1_MISC_CTL_BAR_DST_RING);
@ -912,15 +937,15 @@ void ath12k_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map)
HAL_REO1_MISC_CTL_FRAG_DST_RING);
val |= u32_encode_bits(HAL_SRNG_RING_ID_REO2SW0,
HAL_REO1_MISC_CTL_BAR_DST_RING);
ath12k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTRL_ADDR(ab), val);
ath12k_hif_write32(ab, reo_base + HAL_REO1_MISC_CTRL_ADDR(hal), val);
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(ab),
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_0(hal),
HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC);
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(ab),
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_1(hal),
HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC);
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(ab),
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_2(hal),
HAL_DEFAULT_BE_BK_VI_REO_TIMEOUT_USEC);
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(ab),
ath12k_hif_write32(ab, reo_base + HAL_REO1_AGING_THRESH_IX_3(hal),
HAL_DEFAULT_VO_REO_TIMEOUT_USEC);
ath12k_hif_write32(ab, reo_base + HAL_REO1_DEST_RING_CTRL_IX_2,
@ -929,19 +954,21 @@ void ath12k_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map)
ring_hash_map);
}
void ath12k_hal_reo_shared_qaddr_cache_clear(struct ath12k_base *ab)
void ath12k_wifi7_hal_reo_shared_qaddr_cache_clear(struct ath12k_base *ab)
{
u32 val;
struct ath12k_hal *hal = &ab->hal;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
lockdep_assert_held(&ab->base_lock);
lockdep_assert_held(&dp->dp_lock);
val = ath12k_hif_read32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_ADDR(ab));
HAL_REO1_QDESC_ADDR(hal));
val |= u32_encode_bits(1, HAL_REO_QDESC_ADDR_READ_CLEAR_QDESC_ARRAY);
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_ADDR(ab), val);
HAL_REO1_QDESC_ADDR(hal), val);
val &= ~HAL_REO_QDESC_ADDR_READ_CLEAR_QDESC_ARRAY;
ath12k_hif_write32(ab, HAL_SEQ_WCSS_UMAC_REO_REG +
HAL_REO1_QDESC_ADDR(ab), val);
HAL_REO1_QDESC_ADDR(hal), val);
}

View File

@ -1,12 +1,16 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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_HAL_RX_H
#define ATH12K_HAL_RX_H
#include "hal_desc.h"
struct hal_reo_status;
struct hal_rx_wbm_rel_info {
u32 cookie;
enum hal_wbm_rel_src_module err_rel_src;
@ -17,11 +21,9 @@ struct hal_rx_wbm_rel_info {
bool continuation;
void *rx_desc;
bool hw_cc_done;
__le32 peer_metadata;
};
#define HAL_INVALID_PEERID 0x3fff
#define VHT_SIG_SU_NSS_MASK 0x7
#define HAL_RX_MPDU_INFO_PN_GET_BYTE1(__val) \
le32_get_bits((__val), GENMASK(7, 0))
@ -39,69 +41,10 @@ struct hal_rx_mon_status_tlv_hdr {
u8 value[];
};
enum hal_rx_su_mu_coding {
HAL_RX_SU_MU_CODING_BCC,
HAL_RX_SU_MU_CODING_LDPC,
HAL_RX_SU_MU_CODING_MAX,
};
enum hal_rx_gi {
HAL_RX_GI_0_8_US,
HAL_RX_GI_0_4_US,
HAL_RX_GI_1_6_US,
HAL_RX_GI_3_2_US,
HAL_RX_GI_MAX,
};
enum hal_rx_bw {
HAL_RX_BW_20MHZ,
HAL_RX_BW_40MHZ,
HAL_RX_BW_80MHZ,
HAL_RX_BW_160MHZ,
HAL_RX_BW_320MHZ,
HAL_RX_BW_MAX,
};
enum hal_rx_preamble {
HAL_RX_PREAMBLE_11A,
HAL_RX_PREAMBLE_11B,
HAL_RX_PREAMBLE_11N,
HAL_RX_PREAMBLE_11AC,
HAL_RX_PREAMBLE_11AX,
HAL_RX_PREAMBLE_11BA,
HAL_RX_PREAMBLE_11BE,
HAL_RX_PREAMBLE_MAX,
};
enum hal_rx_reception_type {
HAL_RX_RECEPTION_TYPE_SU,
HAL_RX_RECEPTION_TYPE_MU_MIMO,
HAL_RX_RECEPTION_TYPE_MU_OFDMA,
HAL_RX_RECEPTION_TYPE_MU_OFDMA_MIMO,
HAL_RX_RECEPTION_TYPE_MAX,
};
enum hal_rx_legacy_rate {
HAL_RX_LEGACY_RATE_1_MBPS,
HAL_RX_LEGACY_RATE_2_MBPS,
HAL_RX_LEGACY_RATE_5_5_MBPS,
HAL_RX_LEGACY_RATE_6_MBPS,
HAL_RX_LEGACY_RATE_9_MBPS,
HAL_RX_LEGACY_RATE_11_MBPS,
HAL_RX_LEGACY_RATE_12_MBPS,
HAL_RX_LEGACY_RATE_18_MBPS,
HAL_RX_LEGACY_RATE_24_MBPS,
HAL_RX_LEGACY_RATE_36_MBPS,
HAL_RX_LEGACY_RATE_48_MBPS,
HAL_RX_LEGACY_RATE_54_MBPS,
HAL_RX_LEGACY_RATE_INVALID,
};
#define HAL_TLV_STATUS_PPDU_NOT_DONE 0
#define HAL_TLV_STATUS_PPDU_DONE 1
#define HAL_TLV_STATUS_BUF_DONE 2
#define HAL_TLV_STATUS_PPDU_NON_STD_DONE 3
#define HAL_RX_FCS_LEN 4
enum hal_rx_mon_status {
HAL_RX_MON_STATUS_PPDU_NOT_DONE,
@ -113,167 +56,6 @@ enum hal_rx_mon_status {
HAL_RX_MON_STATUS_MSDU_END,
};
#define HAL_RX_MAX_MPDU 1024
#define HAL_RX_NUM_WORDS_PER_PPDU_BITMAP (HAL_RX_MAX_MPDU >> 5)
struct hal_rx_user_status {
u32 mcs:4,
nss:3,
ofdma_info_valid:1,
ul_ofdma_ru_start_index:7,
ul_ofdma_ru_width:7,
ul_ofdma_ru_size:8;
u32 ul_ofdma_user_v0_word0;
u32 ul_ofdma_user_v0_word1;
u32 ast_index;
u32 tid;
u16 tcp_msdu_count;
u16 tcp_ack_msdu_count;
u16 udp_msdu_count;
u16 other_msdu_count;
u16 frame_control;
u8 frame_control_info_valid;
u8 data_sequence_control_info_valid;
u16 first_data_seq_ctrl;
u32 preamble_type;
u16 ht_flags;
u16 vht_flags;
u16 he_flags;
u8 rs_flags;
u8 ldpc;
u32 mpdu_cnt_fcs_ok;
u32 mpdu_cnt_fcs_err;
u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
u32 mpdu_ok_byte_count;
u32 mpdu_err_byte_count;
bool ampdu_present;
u16 ampdu_id;
};
#define HAL_MAX_UL_MU_USERS 37
struct hal_rx_u_sig_info {
bool ul_dl;
u8 bw;
u8 ppdu_type_comp_mode;
u8 eht_sig_mcs;
u8 num_eht_sig_sym;
struct ieee80211_radiotap_eht_usig usig;
};
#define HAL_RX_MON_MAX_AGGR_SIZE 128
struct hal_rx_tlv_aggr_info {
bool in_progress;
u16 cur_len;
u16 tlv_tag;
u8 buf[HAL_RX_MON_MAX_AGGR_SIZE];
};
struct hal_rx_radiotap_eht {
__le32 known;
__le32 data[9];
};
#define EHT_MAX_USER_INFO 4
struct hal_rx_eht_info {
u8 num_user_info;
struct hal_rx_radiotap_eht eht;
u32 user_info[EHT_MAX_USER_INFO];
};
struct hal_rx_mon_ppdu_info {
u32 ppdu_id;
u32 last_ppdu_id;
u64 ppdu_ts;
u32 num_mpdu_fcs_ok;
u32 num_mpdu_fcs_err;
u32 preamble_type;
u32 mpdu_len;
u16 chan_num;
u16 freq;
u16 tcp_msdu_count;
u16 tcp_ack_msdu_count;
u16 udp_msdu_count;
u16 other_msdu_count;
u16 peer_id;
u8 rate;
u8 mcs;
u8 nss;
u8 bw;
u8 vht_flag_values1;
u8 vht_flag_values2;
u8 vht_flag_values3[4];
u8 vht_flag_values4;
u8 vht_flag_values5;
u16 vht_flag_values6;
u8 is_stbc;
u8 gi;
u8 sgi;
u8 ldpc;
u8 beamformed;
u8 rssi_comb;
u16 tid;
u8 fc_valid;
u16 ht_flags;
u16 vht_flags;
u16 he_flags;
u16 he_mu_flags;
u8 dcm;
u8 ru_alloc;
u8 reception_type;
u64 tsft;
u64 rx_duration;
u16 frame_control;
u32 ast_index;
u8 rs_fcs_err;
u8 rs_flags;
u8 cck_flag;
u8 ofdm_flag;
u8 ulofdma_flag;
u8 frame_control_info_valid;
u16 he_per_user_1;
u16 he_per_user_2;
u8 he_per_user_position;
u8 he_per_user_known;
u16 he_flags1;
u16 he_flags2;
u8 he_RU[4];
u16 he_data1;
u16 he_data2;
u16 he_data3;
u16 he_data4;
u16 he_data5;
u16 he_data6;
u32 ppdu_len;
u32 prev_ppdu_id;
u32 device_id;
u16 first_data_seq_ctrl;
u8 monitor_direct_used;
u8 data_sequence_control_info_valid;
u8 ltf_size;
u8 rxpcu_filter_pass;
s8 rssi_chain[8][8];
u32 num_users;
u32 mpdu_fcs_ok_bitmap[HAL_RX_NUM_WORDS_PER_PPDU_BITMAP];
u8 addr1[ETH_ALEN];
u8 addr2[ETH_ALEN];
u8 addr3[ETH_ALEN];
u8 addr4[ETH_ALEN];
struct hal_rx_user_status userstats[HAL_MAX_UL_MU_USERS];
u8 userid;
bool first_msdu_in_mpdu;
bool is_ampdu;
u8 medium_prot_type;
bool ppdu_continuation;
bool eht_usig;
struct hal_rx_u_sig_info u_sig_info;
bool is_eht;
struct hal_rx_eht_info eht_info;
struct hal_rx_tlv_aggr_info tlv_aggr;
};
#define HAL_RX_PPDU_START_INFO0_PPDU_ID GENMASK(15, 0)
#define HAL_RX_PPDU_START_INFO1_CHAN_NUM GENMASK(15, 0)
#define HAL_RX_PPDU_START_INFO1_CHAN_FREQ GENMASK(31, 16)
@ -531,11 +313,6 @@ struct hal_rx_rxpcu_classification_overview {
u32 rsvd0;
} __packed;
struct hal_rx_msdu_desc_info {
u32 msdu_flags;
u16 msdu_len; /* 14 bits for length */
};
#define HAL_RX_NUM_MSDU_DESC 6
struct hal_rx_msdu_list {
struct hal_rx_msdu_desc_info msdu_info[HAL_RX_NUM_MSDU_DESC];
@ -588,15 +365,6 @@ struct hal_rx_resp_req_info {
#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_2 0xBDBEEF
#define REO_QUEUE_DESC_MAGIC_DEBUG_PATTERN_3 0xCDBEEF
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VALID BIT(30)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W0_VER BIT(31)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_NSS GENMASK(2, 0)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_MCS GENMASK(6, 3)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_LDPC BIT(7)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_DCM BIT(8)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_START GENMASK(15, 9)
#define HAL_RX_UL_OFDMA_USER_INFO_V0_W1_RU_SIZE GENMASK(18, 16)
/* HE Radiotap data1 Mask */
#define HE_SU_FORMAT_TYPE 0x0000
#define HE_EXT_SU_FORMAT_TYPE 0x0001
@ -1044,128 +812,60 @@ enum hal_mon_reception_type {
#define HAL_RU_PER80(ru_per80, num_80mhz, ru_idx_per80mhz) \
(HAL_RU(ru_per80, num_80mhz, ru_idx_per80mhz))
#define RU_INVALID 0
#define RU_26 1
#define RU_52 2
#define RU_106 4
#define RU_242 9
#define RU_484 18
#define RU_996 37
#define RU_2X996 74
#define RU_3X996 111
#define RU_4X996 148
#define RU_52_26 (RU_52 + RU_26)
#define RU_106_26 (RU_106 + RU_26)
#define RU_484_242 (RU_484 + RU_242)
#define RU_996_484 (RU_996 + RU_484)
#define RU_996_484_242 (RU_996 + RU_484_242)
#define RU_2X996_484 (RU_2X996 + RU_484)
#define RU_3X996_484 (RU_3X996 + RU_484)
enum ath12k_eht_ru_size {
ATH12K_EHT_RU_26,
ATH12K_EHT_RU_52,
ATH12K_EHT_RU_106,
ATH12K_EHT_RU_242,
ATH12K_EHT_RU_484,
ATH12K_EHT_RU_996,
ATH12K_EHT_RU_996x2,
ATH12K_EHT_RU_996x4,
ATH12K_EHT_RU_52_26,
ATH12K_EHT_RU_106_26,
ATH12K_EHT_RU_484_242,
ATH12K_EHT_RU_996_484,
ATH12K_EHT_RU_996_484_242,
ATH12K_EHT_RU_996x2_484,
ATH12K_EHT_RU_996x3,
ATH12K_EHT_RU_996x3_484,
/* Keep last */
ATH12K_EHT_RU_INVALID,
};
#define HAL_RX_RU_ALLOC_TYPE_MAX ATH12K_EHT_RU_INVALID
static inline
enum nl80211_he_ru_alloc ath12k_he_ru_tones_to_nl80211_he_ru_alloc(u16 ru_tones)
{
enum nl80211_he_ru_alloc ret;
switch (ru_tones) {
case RU_52:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_52;
break;
case RU_106:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_106;
break;
case RU_242:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_242;
break;
case RU_484:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_484;
break;
case RU_996:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_996;
break;
case RU_2X996:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_2x996;
break;
case RU_26:
fallthrough;
default:
ret = NL80211_RATE_INFO_HE_RU_ALLOC_26;
break;
}
return ret;
}
void ath12k_hal_reo_status_queue_stats(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_flush_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_flush_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_unblk_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_flush_timeout_list_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link, u32 *num_msdus,
u32 *msdu_cookies,
enum hal_rx_buf_return_buf_manager *rbm);
void ath12k_hal_rx_msdu_link_desc_set(struct ath12k_base *ab,
struct hal_wbm_release_ring *desc,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action);
void ath12k_hal_rx_buf_addr_info_set(struct ath12k_buffer_addr *binfo,
dma_addr_t paddr, u32 cookie, u8 manager);
void ath12k_hal_rx_buf_addr_info_get(struct ath12k_buffer_addr *binfo,
dma_addr_t *paddr,
u32 *cookie, u8 *rbm);
int ath12k_hal_desc_reo_parse_err(struct ath12k_base *ab,
struct hal_reo_dest_ring *desc,
dma_addr_t *paddr, u32 *desc_bank);
int ath12k_hal_wbm_desc_parse_err(struct ath12k_base *ab, void *desc,
struct hal_rx_wbm_rel_info *rel_info);
void ath12k_hal_rx_reo_ent_paddr_get(struct ath12k_base *ab,
struct ath12k_buffer_addr *buff_addr,
dma_addr_t *paddr, u32 *cookie);
void ath12k_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr, u32 *sw_cookie,
struct ath12k_buffer_addr **pp_buf_addr,
u8 *rbm, u32 *msdu_cnt);
void ath12k_hal_rx_msdu_list_get(struct ath12k *ar,
struct hal_rx_msdu_link *link_desc,
struct hal_rx_msdu_list *msdu_list,
u16 *num_msdus);
void ath12k_wifi7_hal_reo_status_queue_stats(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_flush_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_flush_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_unblk_cache_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_flush_timeout_list_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_desc_thresh_reached_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_reo_update_rx_reo_queue_status(struct ath12k_base *ab,
struct hal_tlv_64_hdr *tlv,
struct hal_reo_status *status);
void ath12k_wifi7_hal_rx_msdu_link_info_get(struct hal_rx_msdu_link *link, u32 *num_msdus,
u32 *msdu_cookies,
enum hal_rx_buf_return_buf_manager *rbm);
void ath12k_wifi7_hal_rx_msdu_link_desc_set(struct ath12k_base *ab,
struct hal_wbm_release_ring *desc,
struct ath12k_buffer_addr *buf_addr_info,
enum hal_wbm_rel_bm_act action);
void ath12k_wifi7_hal_rx_buf_addr_info_set(struct ath12k_buffer_addr *binfo,
dma_addr_t paddr, u32 cookie, u8 manager);
void ath12k_wifi7_hal_rx_buf_addr_info_get(struct ath12k_buffer_addr *binfo,
dma_addr_t *paddr,
u32 *cookie, u8 *rbm);
int ath12k_wifi7_hal_desc_reo_parse_err(struct ath12k_dp *dp,
struct hal_reo_dest_ring *desc,
dma_addr_t *paddr, u32 *desc_bank);
int ath12k_wifi7_hal_wbm_desc_parse_err(struct ath12k_dp *dp, void *desc,
struct hal_rx_wbm_rel_info *rel_info);
void ath12k_wifi7_hal_rx_reo_ent_paddr_get(struct ath12k_buffer_addr *buff_addr,
dma_addr_t *paddr, u32 *cookie);
void ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get(void *rx_desc, dma_addr_t *paddr,
u32 *sw_cookie,
struct ath12k_buffer_addr **pp_buf_addr,
u8 *rbm, u32 *msdu_cnt);
void ath12k_wifi7_hal_rx_msdu_list_get(struct ath12k *ar,
void *link_desc,
void *msdu_list_opaque,
u16 *num_msdus);
void ath12k_wifi7_hal_reo_init_cmd_ring(struct ath12k_base *ab,
struct hal_srng *srng);
void ath12k_wifi7_hal_reo_shared_qaddr_cache_clear(struct ath12k_base *ab);
void ath12k_wifi7_hal_reo_hw_setup(struct ath12k_base *ab, u32 ring_hash_map);
void ath12k_wifi7_hal_reo_qdesc_setup(struct hal_rx_reo_queue *qdesc,
int tid, u32 ba_window_size,
u32 start_seq, enum hal_pn_type type);
#endif

View File

@ -1,18 +1,11 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-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_RX_DESC_H
#define ATH12K_RX_DESC_H
enum rx_desc_decap_type {
RX_DESC_DECAP_TYPE_RAW,
RX_DESC_DECAP_TYPE_NATIVE_WIFI,
RX_DESC_DECAP_TYPE_ETHERNET2_DIX,
RX_DESC_DECAP_TYPE_8023,
};
enum rx_desc_decrypt_status_code {
RX_DESC_DECRYPT_STATUS_CODE_OK,
RX_DESC_DECRYPT_STATUS_CODE_UNPROTECTED_FRAME,
@ -631,40 +624,6 @@ struct rx_mpdu_start_qcn9274_compact {
*
*/
enum rx_msdu_start_pkt_type {
RX_MSDU_START_PKT_TYPE_11A,
RX_MSDU_START_PKT_TYPE_11B,
RX_MSDU_START_PKT_TYPE_11N,
RX_MSDU_START_PKT_TYPE_11AC,
RX_MSDU_START_PKT_TYPE_11AX,
RX_MSDU_START_PKT_TYPE_11BA,
RX_MSDU_START_PKT_TYPE_11BE,
};
enum rx_msdu_start_sgi {
RX_MSDU_START_SGI_0_8_US,
RX_MSDU_START_SGI_0_4_US,
RX_MSDU_START_SGI_1_6_US,
RX_MSDU_START_SGI_3_2_US,
};
enum rx_msdu_start_recv_bw {
RX_MSDU_START_RECV_BW_20MHZ,
RX_MSDU_START_RECV_BW_40MHZ,
RX_MSDU_START_RECV_BW_80MHZ,
RX_MSDU_START_RECV_BW_160MHZ,
};
enum rx_msdu_start_reception_type {
RX_MSDU_START_RECEPTION_TYPE_SU,
RX_MSDU_START_RECEPTION_TYPE_DL_MU_MIMO,
RX_MSDU_START_RECEPTION_TYPE_DL_MU_OFDMA,
RX_MSDU_START_RECEPTION_TYPE_DL_MU_OFDMA_MIMO,
RX_MSDU_START_RECEPTION_TYPE_UL_MU_MIMO,
RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA,
RX_MSDU_START_RECEPTION_TYPE_UL_MU_OFDMA_MIMO,
};
#define RX_MSDU_END_64_TLV_SRC_LINK_ID GENMASK(24, 22)
#define RX_MSDU_END_INFO0_RXPCU_MPDU_FITLER GENMASK(1, 0)
@ -1495,12 +1454,6 @@ struct rx_msdu_end_qcn9274_compact {
*
*/
struct hal_rx_desc_qcn9274 {
struct rx_msdu_end_qcn9274 msdu_end;
struct rx_mpdu_start_qcn9274 mpdu_start;
u8 msdu_payload[];
} __packed;
struct hal_rx_desc_qcn9274_compact {
struct rx_msdu_end_qcn9274_compact msdu_end;
struct rx_mpdu_start_qcn9274_compact mpdu_start;
@ -1530,15 +1483,9 @@ struct hal_rx_desc_wcn7850 {
struct hal_rx_desc {
union {
struct hal_rx_desc_qcn9274 qcn9274;
struct hal_rx_desc_qcn9274_compact qcn9274_compact;
struct hal_rx_desc_wcn7850 wcn7850;
} u;
} __packed;
#define MAX_USER_POS 8
#define MAX_MU_GROUP_ID 64
#define MAX_MU_GROUP_SHOW 16
#define MAX_MU_GROUP_LENGTH (6 * MAX_MU_GROUP_SHOW)
#endif /* ATH12K_RX_DESC_H */

View File

@ -1,13 +1,13 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "hal_desc.h"
#include "hal.h"
#include "../hal.h"
#include "hal_tx.h"
#include "hif.h"
#include "../hif.h"
#include "hal.h"
#define DSCP_TID_MAP_TBL_ENTRY_SIZE 64
@ -29,9 +29,9 @@ static inline u8 dscp2tid(u8 dscp)
return dscp >> 3;
}
void ath12k_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
struct hal_tcl_data_cmd *tcl_cmd,
struct hal_tx_info *ti)
void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
struct hal_tcl_data_cmd *tcl_cmd,
struct hal_tx_info *ti)
{
tcl_cmd->buf_addr_info.info0 =
le32_encode_bits(ti->paddr, BUFFER_ADDR_INFO0_ADDR);
@ -66,7 +66,7 @@ void ath12k_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
tcl_cmd->info5 = 0;
}
void ath12k_hal_tx_set_dscp_tid_map(struct ath12k_base *ab, int id)
void ath12k_wifi7_hal_tx_set_dscp_tid_map(struct ath12k_base *ab, int id)
{
u32 ctrl_reg_val;
u32 addr;
@ -136,10 +136,3 @@ void ath12k_hal_tx_set_dscp_tid_map(struct ath12k_base *ab, int id)
HAL_TCL1_RING_CMN_CTRL_REG,
ctrl_reg_val);
}
void ath12k_hal_tx_configure_bank_register(struct ath12k_base *ab, u32 bank_config,
u8 bank_id)
{
ath12k_hif_write32(ab, HAL_TCL_SW_CONFIG_BANK_ADDR + 4 * bank_id,
bank_config);
}

View File

@ -1,21 +1,14 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) 2021-2022, 2024-2025 Qualcomm Innovation Center, Inc.
* All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_HAL_TX_H
#define ATH12K_HAL_TX_H
#include "../mac.h"
#include "hal_desc.h"
#include "core.h"
#define HAL_TX_ADDRX_EN 1
#define HAL_TX_ADDRY_EN 2
#define HAL_TX_ADDR_SEARCH_DEFAULT 0
#define HAL_TX_ADDR_SEARCH_INDEX 1
/* TODO: check all these data can be managed with struct ath12k_tx_desc_info for perf */
struct hal_tx_info {
@ -188,13 +181,14 @@ struct hal_tx_fes_status_end {
/* STA mode will have MCAST_PKT_CTRL instead of DSCP_TID_MAP bitfield */
#define HAL_TX_BANK_CONFIG_DSCP_TIP_MAP_ID GENMASK(22, 17)
void ath12k_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
struct hal_tcl_data_cmd *tcl_cmd,
struct hal_tx_info *ti);
void ath12k_hal_tx_set_dscp_tid_map(struct ath12k_base *ab, int id);
int ath12k_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
enum hal_reo_cmd_type type,
struct ath12k_hal_reo_cmd *cmd);
void ath12k_hal_tx_configure_bank_register(struct ath12k_base *ab, u32 bank_config,
u8 bank_id);
void ath12k_wifi7_hal_tx_set_dscp_tid_map(struct ath12k_base *ab, int id);
void ath12k_wifi7_hal_tx_cmd_desc_setup(struct ath12k_base *ab,
struct hal_tcl_data_cmd *tcl_cmd,
struct hal_tx_info *ti);
int ath12k_wifi7_hal_reo_cmd_send(struct ath12k_base *ab, struct hal_srng *srng,
enum hal_reo_cmd_type type,
struct ath12k_hal_reo_cmd *cmd);
void ath12k_wifi7_hal_tx_configure_bank_register(struct ath12k_base *ab,
u32 bank_config,
u8 bank_id);
#endif

View File

@ -0,0 +1,805 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "hal_desc.h"
#include "hal_wcn7850.h"
#include "hw.h"
#include "hal.h"
#include "hal_tx.h"
static const struct hal_srng_config hw_srng_config_template[] = {
/* TODO: max_rings can populated by querying HW capabilities */
[HAL_REO_DST] = {
.start_ring_id = HAL_SRNG_RING_ID_REO2SW1,
.max_rings = 8,
.entry_size = sizeof(struct hal_reo_dest_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_REO_REO2SW1_RING_BASE_MSB_RING_SIZE,
},
[HAL_REO_EXCEPTION] = {
/* Designating REO2SW0 ring as exception ring.
* Any of theREO2SW rings can be used as exception ring.
*/
.start_ring_id = HAL_SRNG_RING_ID_REO2SW0,
.max_rings = 1,
.entry_size = sizeof(struct hal_reo_dest_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_REO_REO2SW0_RING_BASE_MSB_RING_SIZE,
},
[HAL_REO_REINJECT] = {
.start_ring_id = HAL_SRNG_RING_ID_SW2REO,
.max_rings = 4,
.entry_size = sizeof(struct hal_reo_entrance_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_REO_SW2REO_RING_BASE_MSB_RING_SIZE,
},
[HAL_REO_CMD] = {
.start_ring_id = HAL_SRNG_RING_ID_REO_CMD,
.max_rings = 1,
.entry_size = (sizeof(struct hal_tlv_64_hdr) +
sizeof(struct hal_reo_get_queue_stats)) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_REO_CMD_RING_BASE_MSB_RING_SIZE,
},
[HAL_REO_STATUS] = {
.start_ring_id = HAL_SRNG_RING_ID_REO_STATUS,
.max_rings = 1,
.entry_size = (sizeof(struct hal_tlv_64_hdr) +
sizeof(struct hal_reo_get_queue_stats_status)) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_REO_STATUS_RING_BASE_MSB_RING_SIZE,
},
[HAL_TCL_DATA] = {
.start_ring_id = HAL_SRNG_RING_ID_SW2TCL1,
.max_rings = 6,
.entry_size = sizeof(struct hal_tcl_data_cmd) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_SW2TCL1_RING_BASE_MSB_RING_SIZE,
},
[HAL_TCL_CMD] = {
.start_ring_id = HAL_SRNG_RING_ID_SW2TCL_CMD,
.max_rings = 1,
.entry_size = sizeof(struct hal_tcl_gse_cmd) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_SW2TCL1_CMD_RING_BASE_MSB_RING_SIZE,
},
[HAL_TCL_STATUS] = {
.start_ring_id = HAL_SRNG_RING_ID_TCL_STATUS,
.max_rings = 1,
.entry_size = (sizeof(struct hal_tlv_hdr) +
sizeof(struct hal_tcl_status_ring)) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_TCL_STATUS_RING_BASE_MSB_RING_SIZE,
},
[HAL_CE_SRC] = {
.start_ring_id = HAL_SRNG_RING_ID_CE0_SRC,
.max_rings = 16,
.entry_size = sizeof(struct hal_ce_srng_src_desc) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_CE_SRC_RING_BASE_MSB_RING_SIZE,
},
[HAL_CE_DST] = {
.start_ring_id = HAL_SRNG_RING_ID_CE0_DST,
.max_rings = 16,
.entry_size = sizeof(struct hal_ce_srng_dest_desc) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_CE_DST_RING_BASE_MSB_RING_SIZE,
},
[HAL_CE_DST_STATUS] = {
.start_ring_id = HAL_SRNG_RING_ID_CE0_DST_STATUS,
.max_rings = 16,
.entry_size = sizeof(struct hal_ce_srng_dst_status_desc) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_CE_DST_STATUS_RING_BASE_MSB_RING_SIZE,
},
[HAL_WBM_IDLE_LINK] = {
.start_ring_id = HAL_SRNG_RING_ID_WBM_IDLE_LINK,
.max_rings = 1,
.entry_size = sizeof(struct hal_wbm_link_desc) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_WBM_IDLE_LINK_RING_BASE_MSB_RING_SIZE,
},
[HAL_SW2WBM_RELEASE] = {
.start_ring_id = HAL_SRNG_RING_ID_WBM_SW0_RELEASE,
.max_rings = 2,
.entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_SW2WBM_RELEASE_RING_BASE_MSB_RING_SIZE,
},
[HAL_WBM2SW_RELEASE] = {
.start_ring_id = HAL_SRNG_RING_ID_WBM2SW0_RELEASE,
.max_rings = 8,
.entry_size = sizeof(struct hal_wbm_release_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_UMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_WBM2SW_RELEASE_RING_BASE_MSB_RING_SIZE,
},
[HAL_RXDMA_BUF] = {
.start_ring_id = HAL_SRNG_SW2RXDMA_BUF0,
.max_rings = 1,
.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_DMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_RXDMA_RING_MAX_SIZE_BE,
},
[HAL_RXDMA_DST] = {
.start_ring_id = HAL_SRNG_RING_ID_WMAC1_RXDMA2SW0,
.max_rings = 0,
.entry_size = 0,
.mac_type = ATH12K_HAL_SRNG_PMAC,
.ring_dir = HAL_SRNG_DIR_DST,
.max_size = HAL_RXDMA_RING_MAX_SIZE_BE,
},
[HAL_RXDMA_MONITOR_BUF] = {},
[HAL_RXDMA_MONITOR_STATUS] = {
.start_ring_id = HAL_SRNG_RING_ID_WMAC1_SW2RXDMA1_STATBUF,
.max_rings = 1,
.entry_size = sizeof(struct hal_wbm_buffer_ring) >> 2,
.mac_type = ATH12K_HAL_SRNG_PMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_RXDMA_RING_MAX_SIZE_BE,
},
[HAL_RXDMA_MONITOR_DESC] = { 0, },
[HAL_RXDMA_DIR_BUF] = {
.start_ring_id = HAL_SRNG_RING_ID_RXDMA_DIR_BUF,
.max_rings = 2,
.entry_size = 8 >> 2, /* TODO: Define the struct */
.mac_type = ATH12K_HAL_SRNG_PMAC,
.ring_dir = HAL_SRNG_DIR_SRC,
.max_size = HAL_RXDMA_RING_MAX_SIZE_BE,
},
[HAL_PPE2TCL] = {},
[HAL_PPE_RELEASE] = {},
[HAL_TX_MONITOR_BUF] = {},
[HAL_RXDMA_MONITOR_DST] = {},
[HAL_TX_MONITOR_DST] = {}
};
const struct ath12k_hw_regs wcn7850_regs = {
/* SW2TCL(x) R0 ring configuration address */
.tcl1_ring_id = 0x00000908,
.tcl1_ring_misc = 0x00000910,
.tcl1_ring_tp_addr_lsb = 0x0000091c,
.tcl1_ring_tp_addr_msb = 0x00000920,
.tcl1_ring_consumer_int_setup_ix0 = 0x00000930,
.tcl1_ring_consumer_int_setup_ix1 = 0x00000934,
.tcl1_ring_msi1_base_lsb = 0x00000948,
.tcl1_ring_msi1_base_msb = 0x0000094c,
.tcl1_ring_msi1_data = 0x00000950,
.tcl_ring_base_lsb = 0x00000b58,
.tcl1_ring_base_lsb = 0x00000900,
.tcl1_ring_base_msb = 0x00000904,
.tcl2_ring_base_lsb = 0x00000978,
/* TCL STATUS ring address */
.tcl_status_ring_base_lsb = 0x00000d38,
.wbm_idle_ring_base_lsb = 0x00000d3c,
.wbm_idle_ring_misc_addr = 0x00000d4c,
.wbm_r0_idle_list_cntl_addr = 0x00000240,
.wbm_r0_idle_list_size_addr = 0x00000244,
.wbm_scattered_ring_base_lsb = 0x00000250,
.wbm_scattered_ring_base_msb = 0x00000254,
.wbm_scattered_desc_head_info_ix0 = 0x00000260,
.wbm_scattered_desc_head_info_ix1 = 0x00000264,
.wbm_scattered_desc_tail_info_ix0 = 0x00000270,
.wbm_scattered_desc_tail_info_ix1 = 0x00000274,
.wbm_scattered_desc_ptr_hp_addr = 0x00000027c,
.wbm_sw_release_ring_base_lsb = 0x0000037c,
.wbm_sw1_release_ring_base_lsb = 0x00000284,
.wbm0_release_ring_base_lsb = 0x00000e08,
.wbm1_release_ring_base_lsb = 0x00000e80,
/* PCIe base address */
.pcie_qserdes_sysclk_en_sel = 0x01e0e0a8,
.pcie_pcs_osc_dtct_config_base = 0x01e0f45c,
/* PPE release ring address */
.ppe_rel_ring_base = 0x0000043c,
/* REO DEST ring address */
.reo2_ring_base = 0x0000055c,
.reo1_misc_ctrl_addr = 0x00000b7c,
.reo1_sw_cookie_cfg0 = 0x00000050,
.reo1_sw_cookie_cfg1 = 0x00000054,
.reo1_qdesc_lut_base0 = 0x00000058,
.reo1_qdesc_lut_base1 = 0x0000005c,
.reo1_ring_base_lsb = 0x000004e4,
.reo1_ring_base_msb = 0x000004e8,
.reo1_ring_id = 0x000004ec,
.reo1_ring_misc = 0x000004f4,
.reo1_ring_hp_addr_lsb = 0x000004f8,
.reo1_ring_hp_addr_msb = 0x000004fc,
.reo1_ring_producer_int_setup = 0x00000508,
.reo1_ring_msi1_base_lsb = 0x0000052C,
.reo1_ring_msi1_base_msb = 0x00000530,
.reo1_ring_msi1_data = 0x00000534,
.reo1_aging_thres_ix0 = 0x00000b08,
.reo1_aging_thres_ix1 = 0x00000b0c,
.reo1_aging_thres_ix2 = 0x00000b10,
.reo1_aging_thres_ix3 = 0x00000b14,
/* REO Exception ring address */
.reo2_sw0_ring_base = 0x000008a4,
/* REO Reinject ring address */
.sw2reo_ring_base = 0x00000304,
.sw2reo1_ring_base = 0x0000037c,
/* REO cmd ring address */
.reo_cmd_ring_base = 0x0000028c,
/* REO status ring address */
.reo_status_ring_base = 0x00000a84,
/* CE base address */
.umac_ce0_src_reg_base = 0x01b80000,
.umac_ce0_dest_reg_base = 0x01b81000,
.umac_ce1_src_reg_base = 0x01b82000,
.umac_ce1_dest_reg_base = 0x01b83000,
.gcc_gcc_pcie_hot_rst = 0x1e40304,
};
static inline
bool ath12k_hal_rx_desc_get_first_msdu_wcn7850(struct hal_rx_desc *desc)
{
return !!le16_get_bits(desc->u.wcn7850.msdu_end.info5,
RX_MSDU_END_INFO5_FIRST_MSDU);
}
static inline
bool ath12k_hal_rx_desc_get_last_msdu_wcn7850(struct hal_rx_desc *desc)
{
return !!le16_get_bits(desc->u.wcn7850.msdu_end.info5,
RX_MSDU_END_INFO5_LAST_MSDU);
}
u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc)
{
return le16_get_bits(desc->u.wcn7850.msdu_end.info5,
RX_MSDU_END_INFO5_L3_HDR_PADDING);
}
static inline
bool ath12k_hal_rx_desc_encrypt_valid_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.mpdu_start.info4,
RX_MPDU_START_INFO4_ENCRYPT_INFO_VALID);
}
static inline
u32 ath12k_hal_rx_desc_get_encrypt_type_wcn7850(struct hal_rx_desc *desc)
{
if (!ath12k_hal_rx_desc_encrypt_valid_wcn7850(desc))
return HAL_ENCRYPT_TYPE_OPEN;
return le32_get_bits(desc->u.wcn7850.mpdu_start.info2,
RX_MPDU_START_INFO2_ENC_TYPE);
}
static inline
u8 ath12k_hal_rx_desc_get_decap_type_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info11,
RX_MSDU_END_INFO11_DECAP_FORMAT);
}
static inline
u8 ath12k_hal_rx_desc_get_mesh_ctl_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info11,
RX_MSDU_END_INFO11_MESH_CTRL_PRESENT);
}
static inline
bool ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.mpdu_start.info4,
RX_MPDU_START_INFO4_MPDU_SEQ_CTRL_VALID);
}
static inline
bool ath12k_hal_rx_desc_get_mpdu_fc_valid_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.mpdu_start.info4,
RX_MPDU_START_INFO4_MPDU_FCTRL_VALID);
}
static inline
u16 ath12k_hal_rx_desc_get_mpdu_start_seq_no_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.mpdu_start.info4,
RX_MPDU_START_INFO4_MPDU_SEQ_NUM);
}
static inline
u16 ath12k_hal_rx_desc_get_msdu_len_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info10,
RX_MSDU_END_INFO10_MSDU_LENGTH);
}
static inline
u8 ath12k_hal_rx_desc_get_msdu_sgi_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
RX_MSDU_END_INFO12_SGI);
}
static inline
u8 ath12k_hal_rx_desc_get_msdu_rate_mcs_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
RX_MSDU_END_INFO12_RATE_MCS);
}
static inline
u8 ath12k_hal_rx_desc_get_msdu_rx_bw_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
RX_MSDU_END_INFO12_RECV_BW);
}
static inline
u32 ath12k_hal_rx_desc_get_msdu_freq_wcn7850(struct hal_rx_desc *desc)
{
return __le32_to_cpu(desc->u.wcn7850.msdu_end.phy_meta_data);
}
static inline
u8 ath12k_hal_rx_desc_get_msdu_pkt_type_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
RX_MSDU_END_INFO12_PKT_TYPE);
}
static inline
u8 ath12k_hal_rx_desc_get_msdu_nss_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.msdu_end.info12,
RX_MSDU_END_INFO12_MIMO_SS_BITMAP);
}
static inline
u8 ath12k_hal_rx_desc_get_mpdu_tid_wcn7850(struct hal_rx_desc *desc)
{
return le32_get_bits(desc->u.wcn7850.mpdu_start.info2,
RX_MPDU_START_INFO2_TID);
}
static inline
u16 ath12k_hal_rx_desc_get_mpdu_peer_id_wcn7850(struct hal_rx_desc *desc)
{
return __le16_to_cpu(desc->u.wcn7850.mpdu_start.sw_peer_id);
}
void ath12k_hal_rx_desc_copy_end_tlv_wcn7850(struct hal_rx_desc *fdesc,
struct hal_rx_desc *ldesc)
{
memcpy(&fdesc->u.wcn7850.msdu_end, &ldesc->u.wcn7850.msdu_end,
sizeof(struct rx_msdu_end_qcn9274));
}
u32 ath12k_hal_rx_desc_get_mpdu_start_tag_wcn7850(struct hal_rx_desc *desc)
{
return le64_get_bits(desc->u.wcn7850.mpdu_start_tag,
HAL_TLV_HDR_TAG);
}
u32 ath12k_hal_rx_desc_get_mpdu_ppdu_id_wcn7850(struct hal_rx_desc *desc)
{
return __le16_to_cpu(desc->u.wcn7850.mpdu_start.phy_ppdu_id);
}
void ath12k_hal_rx_desc_set_msdu_len_wcn7850(struct hal_rx_desc *desc, u16 len)
{
u32 info = __le32_to_cpu(desc->u.wcn7850.msdu_end.info10);
info &= ~RX_MSDU_END_INFO10_MSDU_LENGTH;
info |= u32_encode_bits(len, RX_MSDU_END_INFO10_MSDU_LENGTH);
desc->u.wcn7850.msdu_end.info10 = __cpu_to_le32(info);
}
u8 *ath12k_hal_rx_desc_get_msdu_payload_wcn7850(struct hal_rx_desc *desc)
{
return &desc->u.wcn7850.msdu_payload[0];
}
u32 ath12k_hal_rx_desc_get_mpdu_start_offset_wcn7850(void)
{
return offsetof(struct hal_rx_desc_wcn7850, mpdu_start_tag);
}
u32 ath12k_hal_rx_desc_get_msdu_end_offset_wcn7850(void)
{
return offsetof(struct hal_rx_desc_wcn7850, msdu_end_tag);
}
static inline
bool ath12k_hal_rx_desc_mac_addr2_valid_wcn7850(struct hal_rx_desc *desc)
{
return __le32_to_cpu(desc->u.wcn7850.mpdu_start.info4) &
RX_MPDU_START_INFO4_MAC_ADDR2_VALID;
}
static inline
u8 *ath12k_hal_rx_desc_mpdu_start_addr2_wcn7850(struct hal_rx_desc *desc)
{
return desc->u.wcn7850.mpdu_start.addr2;
}
static inline
bool ath12k_hal_rx_desc_is_da_mcbc_wcn7850(struct hal_rx_desc *desc)
{
return __le32_to_cpu(desc->u.wcn7850.msdu_end.info13) &
RX_MSDU_END_INFO13_MCAST_BCAST;
}
static inline
bool ath12k_hal_rx_h_msdu_done_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.msdu_end.info14,
RX_MSDU_END_INFO14_MSDU_DONE);
}
static inline
bool ath12k_hal_rx_h_l4_cksum_fail_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.msdu_end.info13,
RX_MSDU_END_INFO13_TCP_UDP_CKSUM_FAIL);
}
static inline
bool ath12k_hal_rx_h_ip_cksum_fail_wcn7850(struct hal_rx_desc *desc)
{
return !!le32_get_bits(desc->u.wcn7850.msdu_end.info13,
RX_MSDU_END_INFO13_IP_CKSUM_FAIL);
}
static inline
bool ath12k_hal_rx_h_is_decrypted_wcn7850(struct hal_rx_desc *desc)
{
return (le32_get_bits(desc->u.wcn7850.msdu_end.info14,
RX_MSDU_END_INFO14_DECRYPT_STATUS_CODE) ==
RX_DESC_DECRYPT_STATUS_CODE_OK);
}
u32 ath12k_hal_get_rx_desc_size_wcn7850(void)
{
return sizeof(struct hal_rx_desc_wcn7850);
}
u8 ath12k_hal_rx_desc_get_msdu_src_link_wcn7850(struct hal_rx_desc *desc)
{
return 0;
}
static u32 ath12k_hal_rx_h_mpdu_err_wcn7850(struct hal_rx_desc *desc)
{
u32 info = __le32_to_cpu(desc->u.wcn7850.msdu_end.info13);
u32 errmap = 0;
if (info & RX_MSDU_END_INFO13_FCS_ERR)
errmap |= HAL_RX_MPDU_ERR_FCS;
if (info & RX_MSDU_END_INFO13_DECRYPT_ERR)
errmap |= HAL_RX_MPDU_ERR_DECRYPT;
if (info & RX_MSDU_END_INFO13_TKIP_MIC_ERR)
errmap |= HAL_RX_MPDU_ERR_TKIP_MIC;
if (info & RX_MSDU_END_INFO13_A_MSDU_ERROR)
errmap |= HAL_RX_MPDU_ERR_AMSDU_ERR;
if (info & RX_MSDU_END_INFO13_OVERFLOW_ERR)
errmap |= HAL_RX_MPDU_ERR_OVERFLOW;
if (info & RX_MSDU_END_INFO13_MSDU_LEN_ERR)
errmap |= HAL_RX_MPDU_ERR_MSDU_LEN;
if (info & RX_MSDU_END_INFO13_MPDU_LEN_ERR)
errmap |= HAL_RX_MPDU_ERR_MPDU_LEN;
return errmap;
}
void ath12k_hal_rx_desc_get_crypto_hdr_wcn7850(struct hal_rx_desc *desc,
u8 *crypto_hdr,
enum hal_encrypt_type enctype)
{
unsigned int key_id;
switch (enctype) {
case HAL_ENCRYPT_TYPE_OPEN:
return;
case HAL_ENCRYPT_TYPE_TKIP_NO_MIC:
case HAL_ENCRYPT_TYPE_TKIP_MIC:
crypto_hdr[0] =
HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.wcn7850.mpdu_start.pn[0]);
crypto_hdr[1] = 0;
crypto_hdr[2] =
HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.wcn7850.mpdu_start.pn[0]);
break;
case HAL_ENCRYPT_TYPE_CCMP_128:
case HAL_ENCRYPT_TYPE_CCMP_256:
case HAL_ENCRYPT_TYPE_GCMP_128:
case HAL_ENCRYPT_TYPE_AES_GCMP_256:
crypto_hdr[0] =
HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.wcn7850.mpdu_start.pn[0]);
crypto_hdr[1] =
HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.wcn7850.mpdu_start.pn[0]);
crypto_hdr[2] = 0;
break;
case HAL_ENCRYPT_TYPE_WEP_40:
case HAL_ENCRYPT_TYPE_WEP_104:
case HAL_ENCRYPT_TYPE_WEP_128:
case HAL_ENCRYPT_TYPE_WAPI_GCM_SM4:
case HAL_ENCRYPT_TYPE_WAPI:
return;
}
key_id = u32_get_bits(__le32_to_cpu(desc->u.wcn7850.mpdu_start.info5),
RX_MPDU_START_INFO5_KEY_ID);
crypto_hdr[3] = 0x20 | (key_id << 6);
crypto_hdr[4] = HAL_RX_MPDU_INFO_PN_GET_BYTE3(desc->u.wcn7850.mpdu_start.pn[0]);
crypto_hdr[5] = HAL_RX_MPDU_INFO_PN_GET_BYTE4(desc->u.wcn7850.mpdu_start.pn[0]);
crypto_hdr[6] = HAL_RX_MPDU_INFO_PN_GET_BYTE1(desc->u.wcn7850.mpdu_start.pn[1]);
crypto_hdr[7] = HAL_RX_MPDU_INFO_PN_GET_BYTE2(desc->u.wcn7850.mpdu_start.pn[1]);
}
void ath12k_hal_rx_desc_get_dot11_hdr_wcn7850(struct hal_rx_desc *desc,
struct ieee80211_hdr *hdr)
{
hdr->frame_control = desc->u.wcn7850.mpdu_start.frame_ctrl;
hdr->duration_id = desc->u.wcn7850.mpdu_start.duration;
ether_addr_copy(hdr->addr1, desc->u.wcn7850.mpdu_start.addr1);
ether_addr_copy(hdr->addr2, desc->u.wcn7850.mpdu_start.addr2);
ether_addr_copy(hdr->addr3, desc->u.wcn7850.mpdu_start.addr3);
if (__le32_to_cpu(desc->u.wcn7850.mpdu_start.info4) &
RX_MPDU_START_INFO4_MAC_ADDR4_VALID) {
ether_addr_copy(hdr->addr4, desc->u.wcn7850.mpdu_start.addr4);
}
hdr->seq_ctrl = desc->u.wcn7850.mpdu_start.seq_ctrl;
}
void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_data,
struct hal_rx_desc *rx_desc,
struct hal_rx_desc *ldesc)
{
rx_desc_data->is_first_msdu = ath12k_hal_rx_desc_get_first_msdu_wcn7850(ldesc);
rx_desc_data->is_last_msdu = ath12k_hal_rx_desc_get_last_msdu_wcn7850(ldesc);
rx_desc_data->l3_pad_bytes = ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(ldesc);
rx_desc_data->enctype = ath12k_hal_rx_desc_get_encrypt_type_wcn7850(rx_desc);
rx_desc_data->decap_type = ath12k_hal_rx_desc_get_decap_type_wcn7850(rx_desc);
rx_desc_data->mesh_ctrl_present =
ath12k_hal_rx_desc_get_mesh_ctl_wcn7850(rx_desc);
rx_desc_data->seq_ctl_valid =
ath12k_hal_rx_desc_get_mpdu_seq_ctl_vld_wcn7850(rx_desc);
rx_desc_data->fc_valid = ath12k_hal_rx_desc_get_mpdu_fc_valid_wcn7850(rx_desc);
rx_desc_data->seq_no = ath12k_hal_rx_desc_get_mpdu_start_seq_no_wcn7850(rx_desc);
rx_desc_data->msdu_len = ath12k_hal_rx_desc_get_msdu_len_wcn7850(ldesc);
rx_desc_data->sgi = ath12k_hal_rx_desc_get_msdu_sgi_wcn7850(rx_desc);
rx_desc_data->rate_mcs = ath12k_hal_rx_desc_get_msdu_rate_mcs_wcn7850(rx_desc);
rx_desc_data->bw = ath12k_hal_rx_desc_get_msdu_rx_bw_wcn7850(rx_desc);
rx_desc_data->phy_meta_data = ath12k_hal_rx_desc_get_msdu_freq_wcn7850(rx_desc);
rx_desc_data->pkt_type = ath12k_hal_rx_desc_get_msdu_pkt_type_wcn7850(rx_desc);
rx_desc_data->nss = hweight8(ath12k_hal_rx_desc_get_msdu_nss_wcn7850(rx_desc));
rx_desc_data->tid = ath12k_hal_rx_desc_get_mpdu_tid_wcn7850(rx_desc);
rx_desc_data->peer_id = ath12k_hal_rx_desc_get_mpdu_peer_id_wcn7850(rx_desc);
rx_desc_data->addr2_present = ath12k_hal_rx_desc_mac_addr2_valid_wcn7850(rx_desc);
rx_desc_data->addr2 = ath12k_hal_rx_desc_mpdu_start_addr2_wcn7850(rx_desc);
rx_desc_data->is_mcbc = ath12k_hal_rx_desc_is_da_mcbc_wcn7850(rx_desc);
rx_desc_data->msdu_done = ath12k_hal_rx_h_msdu_done_wcn7850(ldesc);
rx_desc_data->l4_csum_fail = ath12k_hal_rx_h_l4_cksum_fail_wcn7850(rx_desc);
rx_desc_data->ip_csum_fail = ath12k_hal_rx_h_ip_cksum_fail_wcn7850(rx_desc);
rx_desc_data->is_decrypted = ath12k_hal_rx_h_is_decrypted_wcn7850(rx_desc);
rx_desc_data->err_bitmap = ath12k_hal_rx_h_mpdu_err_wcn7850(rx_desc);
}
static int ath12k_hal_srng_create_config_wcn7850(struct ath12k_hal *hal)
{
struct hal_srng_config *s;
hal->srng_config = kmemdup(hw_srng_config_template,
sizeof(hw_srng_config_template),
GFP_KERNEL);
if (!hal->srng_config)
return -ENOMEM;
s = &hal->srng_config[HAL_REO_DST];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO1_RING_HP;
s->reg_size[0] = HAL_REO2_RING_BASE_LSB(hal) - HAL_REO1_RING_BASE_LSB(hal);
s->reg_size[1] = HAL_REO2_RING_HP - HAL_REO1_RING_HP;
s = &hal->srng_config[HAL_REO_EXCEPTION];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_SW0_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_SW0_RING_HP;
s = &hal->srng_config[HAL_REO_REINJECT];
s->max_rings = 1;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_SW2REO_RING_HP;
s = &hal->srng_config[HAL_REO_CMD];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_CMD_HP;
s = &hal->srng_config[HAL_REO_STATUS];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_REO_REG + HAL_REO_STATUS_HP;
s = &hal->srng_config[HAL_TCL_DATA];
s->max_rings = 5;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL1_RING_HP;
s->reg_size[0] = HAL_TCL2_RING_BASE_LSB(hal) - HAL_TCL1_RING_BASE_LSB(hal);
s->reg_size[1] = HAL_TCL2_RING_HP - HAL_TCL1_RING_HP;
s = &hal->srng_config[HAL_TCL_CMD];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_RING_HP;
s = &hal->srng_config[HAL_TCL_STATUS];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_TCL_REG + HAL_TCL_STATUS_RING_HP;
s = &hal->srng_config[HAL_CE_SRC];
s->max_rings = 12;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(hal) + HAL_CE_DST_RING_BASE_LSB;
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(hal) + HAL_CE_DST_RING_HP;
s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(hal);
s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_SRC_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(hal);
s = &hal->srng_config[HAL_CE_DST];
s->max_rings = 12;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal) + HAL_CE_DST_RING_BASE_LSB;
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal) + HAL_CE_DST_RING_HP;
s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal);
s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal);
s = &hal->srng_config[HAL_CE_DST_STATUS];
s->max_rings = 12;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal) +
HAL_CE_DST_STATUS_RING_BASE_LSB;
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal) + HAL_CE_DST_STATUS_RING_HP;
s->reg_size[0] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal);
s->reg_size[1] = HAL_SEQ_WCSS_UMAC_CE1_DST_REG(hal) -
HAL_SEQ_WCSS_UMAC_CE0_DST_REG(hal);
s = &hal->srng_config[HAL_WBM_IDLE_LINK];
s->reg_start[0] =
HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_IDLE_LINK_RING_HP;
s = &hal->srng_config[HAL_SW2WBM_RELEASE];
s->max_rings = 1;
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG +
HAL_WBM_SW_RELEASE_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM_SW_RELEASE_RING_HP;
s = &hal->srng_config[HAL_WBM2SW_RELEASE];
s->reg_start[0] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_BASE_LSB(hal);
s->reg_start[1] = HAL_SEQ_WCSS_UMAC_WBM_REG + HAL_WBM0_RELEASE_RING_HP;
s->reg_size[0] = HAL_WBM1_RELEASE_RING_BASE_LSB(hal) -
HAL_WBM0_RELEASE_RING_BASE_LSB(hal);
s->reg_size[1] = HAL_WBM1_RELEASE_RING_HP - HAL_WBM0_RELEASE_RING_HP;
s = &hal->srng_config[HAL_RXDMA_BUF];
s->max_rings = 2;
s->mac_type = ATH12K_HAL_SRNG_PMAC;
s = &hal->srng_config[HAL_RXDMA_DST];
s->max_rings = 1;
s->entry_size = sizeof(struct hal_reo_entrance_ring) >> 2;
/* below rings are not used */
s = &hal->srng_config[HAL_RXDMA_DIR_BUF];
s->max_rings = 0;
s = &hal->srng_config[HAL_PPE2TCL];
s->max_rings = 0;
s = &hal->srng_config[HAL_PPE_RELEASE];
s->max_rings = 0;
s = &hal->srng_config[HAL_TX_MONITOR_BUF];
s->max_rings = 0;
s = &hal->srng_config[HAL_TX_MONITOR_DST];
s->max_rings = 0;
s = &hal->srng_config[HAL_PPE2TCL];
s->max_rings = 0;
return 0;
}
const struct ath12k_hal_tcl_to_wbm_rbm_map
ath12k_hal_tcl_to_wbm_rbm_map_wcn7850[DP_TCL_NUM_RING_MAX] = {
{
.wbm_ring_num = 0,
.rbm_id = HAL_RX_BUF_RBM_SW0_BM,
},
{
.wbm_ring_num = 2,
.rbm_id = HAL_RX_BUF_RBM_SW2_BM,
},
{
.wbm_ring_num = 4,
.rbm_id = HAL_RX_BUF_RBM_SW4_BM,
},
};
const struct ath12k_hw_hal_params ath12k_hw_hal_params_wcn7850 = {
.rx_buf_rbm = HAL_RX_BUF_RBM_SW1_BM,
.wbm2sw_cc_enable = HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW0_EN |
HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW2_EN |
HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW3_EN |
HAL_WBM_SW_COOKIE_CONV_CFG_WBM2SW4_EN,
};
const struct hal_ops hal_wcn7850_ops = {
.create_srng_config = ath12k_hal_srng_create_config_wcn7850,
.rx_desc_set_msdu_len = ath12k_hal_rx_desc_set_msdu_len_wcn7850,
.rx_desc_get_dot11_hdr = ath12k_hal_rx_desc_get_dot11_hdr_wcn7850,
.rx_desc_get_crypto_header = ath12k_hal_rx_desc_get_crypto_hdr_wcn7850,
.rx_desc_copy_end_tlv = ath12k_hal_rx_desc_copy_end_tlv_wcn7850,
.rx_desc_get_msdu_src_link_id = ath12k_hal_rx_desc_get_msdu_src_link_wcn7850,
.extract_rx_desc_data = ath12k_hal_extract_rx_desc_data_wcn7850,
.rx_desc_get_l3_pad_bytes = ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850,
.rx_desc_get_mpdu_start_tag = ath12k_hal_rx_desc_get_mpdu_start_tag_wcn7850,
.rx_desc_get_mpdu_ppdu_id = ath12k_hal_rx_desc_get_mpdu_ppdu_id_wcn7850,
.rx_desc_get_msdu_payload = ath12k_hal_rx_desc_get_msdu_payload_wcn7850,
.ce_dst_setup = ath12k_wifi7_hal_ce_dst_setup,
.srng_src_hw_init = ath12k_wifi7_hal_srng_src_hw_init,
.srng_dst_hw_init = ath12k_wifi7_hal_srng_dst_hw_init,
.set_umac_srng_ptr_addr = ath12k_wifi7_hal_set_umac_srng_ptr_addr,
.srng_update_shadow_config = ath12k_wifi7_hal_srng_update_shadow_config,
.srng_get_ring_id = ath12k_wifi7_hal_srng_get_ring_id,
.ce_get_desc_size = ath12k_wifi7_hal_ce_get_desc_size,
.ce_src_set_desc = ath12k_wifi7_hal_ce_src_set_desc,
.ce_dst_set_desc = ath12k_wifi7_hal_ce_dst_set_desc,
.ce_dst_status_get_length = ath12k_wifi7_hal_ce_dst_status_get_length,
.set_link_desc_addr = ath12k_wifi7_hal_set_link_desc_addr,
.tx_set_dscp_tid_map = ath12k_wifi7_hal_tx_set_dscp_tid_map,
.tx_configure_bank_register =
ath12k_wifi7_hal_tx_configure_bank_register,
.reoq_lut_addr_read_enable = ath12k_wifi7_hal_reoq_lut_addr_read_enable,
.reoq_lut_set_max_peerid = ath12k_wifi7_hal_reoq_lut_set_max_peerid,
.write_reoq_lut_addr = ath12k_wifi7_hal_write_reoq_lut_addr,
.write_ml_reoq_lut_addr = ath12k_wifi7_hal_write_ml_reoq_lut_addr,
.setup_link_idle_list = ath12k_wifi7_hal_setup_link_idle_list,
.reo_init_cmd_ring = ath12k_wifi7_hal_reo_init_cmd_ring,
.reo_shared_qaddr_cache_clear = ath12k_wifi7_hal_reo_shared_qaddr_cache_clear,
.reo_hw_setup = ath12k_wifi7_hal_reo_hw_setup,
.rx_buf_addr_info_set = ath12k_wifi7_hal_rx_buf_addr_info_set,
.rx_buf_addr_info_get = ath12k_wifi7_hal_rx_buf_addr_info_get,
.cc_config = ath12k_wifi7_hal_cc_config,
.get_idle_link_rbm = ath12k_wifi7_hal_get_idle_link_rbm,
.rx_msdu_list_get = ath12k_wifi7_hal_rx_msdu_list_get,
.rx_reo_ent_buf_paddr_get = ath12k_wifi7_hal_rx_reo_ent_buf_paddr_get,
};

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_HAL_WCN7850_H
#define ATH12K_HAL_WCN7850_H
#include "../hal.h"
#include "hal_rx.h"
#include "hal.h"
extern const struct hal_ops hal_wcn7850_ops;
extern const struct ath12k_hw_regs wcn7850_regs;
extern const struct ath12k_hal_tcl_to_wbm_rbm_map
ath12k_hal_tcl_to_wbm_rbm_map_wcn7850[DP_TCL_NUM_RING_MAX];
extern const struct ath12k_hw_hal_params ath12k_hw_hal_params_wcn7850;
u8 ath12k_hal_rx_desc_get_l3_pad_bytes_wcn7850(struct hal_rx_desc *desc);
void ath12k_hal_rx_desc_copy_end_tlv_wcn7850(struct hal_rx_desc *fdesc,
struct hal_rx_desc *ldesc);
u32 ath12k_hal_rx_desc_get_mpdu_start_tag_wcn7850(struct hal_rx_desc *desc);
u32 ath12k_hal_rx_desc_get_mpdu_ppdu_id_wcn7850(struct hal_rx_desc *desc);
void ath12k_hal_rx_desc_set_msdu_len_wcn7850(struct hal_rx_desc *desc, u16 len);
u8 *ath12k_hal_rx_desc_get_msdu_payload_wcn7850(struct hal_rx_desc *desc);
u32 ath12k_hal_rx_desc_get_mpdu_start_offset_wcn7850(void);
u32 ath12k_hal_rx_desc_get_msdu_end_offset_wcn7850(void);
u32 ath12k_hal_get_rx_desc_size_wcn7850(void);
u8 ath12k_hal_rx_desc_get_msdu_src_link_wcn7850(struct hal_rx_desc *desc);
void ath12k_hal_rx_desc_get_crypto_hdr_wcn7850(struct hal_rx_desc *desc,
u8 *crypto_hdr,
enum hal_encrypt_type enctype);
void ath12k_hal_rx_desc_get_dot11_hdr_wcn7850(struct hal_rx_desc *desc,
struct ieee80211_hdr *hdr);
void ath12k_hal_extract_rx_desc_data_wcn7850(struct hal_rx_desc_data *rx_desc_data,
struct hal_rx_desc *rx_desc,
struct hal_rx_desc *ldesc);
#endif

View File

@ -0,0 +1,945 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/bitfield.h>
#include "../debug.h"
#include "../core.h"
#include "../ce.h"
#include "ce.h"
#include "../hw.h"
#include "hw.h"
#include "../mhi.h"
#include "mhi.h"
#include "dp_rx.h"
#include "../peer.h"
#include "wmi.h"
#include "../wow.h"
#include "../debugfs.h"
#include "../debugfs_sta.h"
#include "../testmode.h"
#include "hal.h"
#include "dp_tx.h"
static const guid_t wcn7850_uuid = GUID_INIT(0xf634f534, 0x6147, 0x11ec,
0x90, 0xd6, 0x02, 0x42,
0xac, 0x12, 0x00, 0x03);
static u8 ath12k_wifi7_hw_qcn9274_mac_from_pdev_id(int pdev_idx)
{
return pdev_idx;
}
static int
ath12k_wifi7_hw_mac_id_to_pdev_id_qcn9274(const struct ath12k_hw_params *hw,
int mac_id)
{
return mac_id;
}
static int
ath12k_wifi7_hw_mac_id_to_srng_id_qcn9274(const struct ath12k_hw_params *hw,
int mac_id)
{
return 0;
}
static u8 ath12k_wifi7_hw_get_ring_selector_qcn9274(struct sk_buff *skb)
{
return smp_processor_id();
}
static bool ath12k_wifi7_dp_srng_is_comp_ring_qcn9274(int ring_num)
{
if (ring_num < 3 || ring_num == 4)
return true;
return false;
}
static bool
ath12k_wifi7_is_frame_link_agnostic_qcn9274(struct ath12k_link_vif *arvif,
struct ieee80211_mgmt *mgmt)
{
return ieee80211_is_action(mgmt->frame_control);
}
static int
ath12k_wifi7_hw_mac_id_to_pdev_id_wcn7850(const struct ath12k_hw_params *hw,
int mac_id)
{
return 0;
}
static int
ath12k_wifi7_hw_mac_id_to_srng_id_wcn7850(const struct ath12k_hw_params *hw,
int mac_id)
{
return mac_id;
}
static u8 ath12k_wifi7_hw_get_ring_selector_wcn7850(struct sk_buff *skb)
{
return skb_get_queue_mapping(skb);
}
static bool ath12k_wifi7_dp_srng_is_comp_ring_wcn7850(int ring_num)
{
if (ring_num == 0 || ring_num == 2 || ring_num == 4)
return true;
return false;
}
static bool ath12k_is_addba_resp_action_code(struct ieee80211_mgmt *mgmt)
{
if (!ieee80211_is_action(mgmt->frame_control))
return false;
if (mgmt->u.action.category != WLAN_CATEGORY_BACK)
return false;
if (mgmt->u.action.u.addba_resp.action_code != WLAN_ACTION_ADDBA_RESP)
return false;
return true;
}
static bool
ath12k_wifi7_is_frame_link_agnostic_wcn7850(struct ath12k_link_vif *arvif,
struct ieee80211_mgmt *mgmt)
{
struct ieee80211_vif *vif = ath12k_ahvif_to_vif(arvif->ahvif);
struct ath12k_hw *ah = ath12k_ar_to_ah(arvif->ar);
struct ath12k_base *ab = arvif->ar->ab;
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_dp_peer *peer;
__le16 fc = mgmt->frame_control;
spin_lock_bh(&dp->dp_lock);
if (!ath12k_dp_link_peer_find_by_addr(dp, mgmt->da)) {
spin_lock_bh(&ah->dp_hw.peer_lock);
peer = ath12k_dp_peer_find_by_addr(&ah->dp_hw, mgmt->da);
if (!peer || (peer && !peer->is_mlo)) {
spin_unlock_bh(&ah->dp_hw.peer_lock);
spin_unlock_bh(&dp->dp_lock);
return false;
}
spin_unlock_bh(&ah->dp_hw.peer_lock);
}
spin_unlock_bh(&dp->dp_lock);
if (vif->type == NL80211_IFTYPE_STATION)
return arvif->is_up &&
(vif->valid_links == vif->active_links) &&
!ieee80211_is_probe_req(fc) &&
!ieee80211_is_auth(fc) &&
!ieee80211_is_deauth(fc) &&
!ath12k_is_addba_resp_action_code(mgmt);
if (vif->type == NL80211_IFTYPE_AP)
return !(ieee80211_is_probe_resp(fc) || ieee80211_is_auth(fc) ||
ieee80211_is_assoc_resp(fc) || ieee80211_is_reassoc_resp(fc) ||
ath12k_is_addba_resp_action_code(mgmt));
return false;
}
static const struct ath12k_hw_ops qcn9274_ops = {
.get_hw_mac_from_pdev_id = ath12k_wifi7_hw_qcn9274_mac_from_pdev_id,
.mac_id_to_pdev_id = ath12k_wifi7_hw_mac_id_to_pdev_id_qcn9274,
.mac_id_to_srng_id = ath12k_wifi7_hw_mac_id_to_srng_id_qcn9274,
.rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_qcn9274,
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_qcn9274,
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_qcn9274,
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_qcn9274,
};
static const struct ath12k_hw_ops wcn7850_ops = {
.get_hw_mac_from_pdev_id = ath12k_wifi7_hw_qcn9274_mac_from_pdev_id,
.mac_id_to_pdev_id = ath12k_wifi7_hw_mac_id_to_pdev_id_wcn7850,
.mac_id_to_srng_id = ath12k_wifi7_hw_mac_id_to_srng_id_wcn7850,
.rxdma_ring_sel_config = ath12k_dp_rxdma_ring_sel_config_wcn7850,
.get_ring_selector = ath12k_wifi7_hw_get_ring_selector_wcn7850,
.dp_srng_is_tx_comp_ring = ath12k_wifi7_dp_srng_is_comp_ring_wcn7850,
.is_frame_link_agnostic = ath12k_wifi7_is_frame_link_agnostic_wcn7850,
};
#define ATH12K_TX_RING_MASK_0 0x1
#define ATH12K_TX_RING_MASK_1 0x2
#define ATH12K_TX_RING_MASK_2 0x4
#define ATH12K_TX_RING_MASK_3 0x8
#define ATH12K_TX_RING_MASK_4 0x10
#define ATH12K_RX_RING_MASK_0 0x1
#define ATH12K_RX_RING_MASK_1 0x2
#define ATH12K_RX_RING_MASK_2 0x4
#define ATH12K_RX_RING_MASK_3 0x8
#define ATH12K_RX_ERR_RING_MASK_0 0x1
#define ATH12K_RX_WBM_REL_RING_MASK_0 0x1
#define ATH12K_REO_STATUS_RING_MASK_0 0x1
#define ATH12K_HOST2RXDMA_RING_MASK_0 0x1
#define ATH12K_RX_MON_RING_MASK_0 0x1
#define ATH12K_RX_MON_RING_MASK_1 0x2
#define ATH12K_RX_MON_RING_MASK_2 0x4
#define ATH12K_TX_MON_RING_MASK_0 0x1
#define ATH12K_TX_MON_RING_MASK_1 0x2
#define ATH12K_RX_MON_STATUS_RING_MASK_0 0x1
#define ATH12K_RX_MON_STATUS_RING_MASK_1 0x2
#define ATH12K_RX_MON_STATUS_RING_MASK_2 0x4
static const struct ath12k_hw_ring_mask ath12k_wifi7_hw_ring_mask_qcn9274 = {
.tx = {
ATH12K_TX_RING_MASK_0,
ATH12K_TX_RING_MASK_1,
ATH12K_TX_RING_MASK_2,
ATH12K_TX_RING_MASK_3,
},
.rx_mon_dest = {
0, 0, 0, 0,
0, 0, 0, 0,
ATH12K_RX_MON_RING_MASK_0,
ATH12K_RX_MON_RING_MASK_1,
ATH12K_RX_MON_RING_MASK_2,
},
.rx = {
0, 0, 0, 0,
ATH12K_RX_RING_MASK_0,
ATH12K_RX_RING_MASK_1,
ATH12K_RX_RING_MASK_2,
ATH12K_RX_RING_MASK_3,
},
.rx_err = {
0, 0, 0,
ATH12K_RX_ERR_RING_MASK_0,
},
.rx_wbm_rel = {
0, 0, 0,
ATH12K_RX_WBM_REL_RING_MASK_0,
},
.reo_status = {
0, 0, 0,
ATH12K_REO_STATUS_RING_MASK_0,
},
.host2rxdma = {
0, 0, 0,
ATH12K_HOST2RXDMA_RING_MASK_0,
},
.tx_mon_dest = {
0, 0, 0,
},
};
static const struct ath12k_hw_ring_mask ath12k_wifi7_hw_ring_mask_ipq5332 = {
.tx = {
ATH12K_TX_RING_MASK_0,
ATH12K_TX_RING_MASK_1,
ATH12K_TX_RING_MASK_2,
ATH12K_TX_RING_MASK_3,
},
.rx_mon_dest = {
0, 0, 0, 0, 0, 0, 0, 0,
ATH12K_RX_MON_RING_MASK_0,
},
.rx = {
0, 0, 0, 0,
ATH12K_RX_RING_MASK_0,
ATH12K_RX_RING_MASK_1,
ATH12K_RX_RING_MASK_2,
ATH12K_RX_RING_MASK_3,
},
.rx_err = {
0, 0, 0,
ATH12K_RX_ERR_RING_MASK_0,
},
.rx_wbm_rel = {
0, 0, 0,
ATH12K_RX_WBM_REL_RING_MASK_0,
},
.reo_status = {
0, 0, 0,
ATH12K_REO_STATUS_RING_MASK_0,
},
.host2rxdma = {
0, 0, 0,
ATH12K_HOST2RXDMA_RING_MASK_0,
},
.tx_mon_dest = {
ATH12K_TX_MON_RING_MASK_0,
ATH12K_TX_MON_RING_MASK_1,
},
};
static const struct ath12k_hw_ring_mask ath12k_wifi7_hw_ring_mask_wcn7850 = {
.tx = {
ATH12K_TX_RING_MASK_0,
ATH12K_TX_RING_MASK_1,
ATH12K_TX_RING_MASK_2,
},
.rx_mon_dest = {
},
.rx_mon_status = {
0, 0, 0, 0,
ATH12K_RX_MON_STATUS_RING_MASK_0,
ATH12K_RX_MON_STATUS_RING_MASK_1,
ATH12K_RX_MON_STATUS_RING_MASK_2,
},
.rx = {
0, 0, 0,
ATH12K_RX_RING_MASK_0,
ATH12K_RX_RING_MASK_1,
ATH12K_RX_RING_MASK_2,
ATH12K_RX_RING_MASK_3,
},
.rx_err = {
ATH12K_RX_ERR_RING_MASK_0,
},
.rx_wbm_rel = {
ATH12K_RX_WBM_REL_RING_MASK_0,
},
.reo_status = {
ATH12K_REO_STATUS_RING_MASK_0,
},
.host2rxdma = {
},
.tx_mon_dest = {
},
};
static const struct ce_ie_addr ath12k_wifi7_ce_ie_addr_ipq5332 = {
.ie1_reg_addr = CE_HOST_IE_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
.ie2_reg_addr = CE_HOST_IE_2_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
.ie3_reg_addr = CE_HOST_IE_3_ADDRESS - HAL_IPQ5332_CE_WFSS_REG_BASE,
};
static const struct ce_remap ath12k_wifi7_ce_remap_ipq5332 = {
.base = HAL_IPQ5332_CE_WFSS_REG_BASE,
.size = HAL_IPQ5332_CE_SIZE,
.cmem_offset = HAL_SEQ_WCSS_CMEM_OFFSET,
};
static const struct ath12k_hw_params ath12k_wifi7_hw_params[] = {
{
.name = "qcn9274 hw1.0",
.hw_rev = ATH12K_HW_QCN9274_HW10,
.fw = {
.dir = "QCN9274/hw1.0",
.board_size = 256 * 1024,
.cal_offset = 128 * 1024,
.m3_loader = ath12k_m3_fw_loader_driver,
},
.max_radios = 1,
.single_pdev_only = false,
.qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274,
.internal_sleep_clock = false,
.hw_ops = &qcn9274_ops,
.ring_mask = &ath12k_wifi7_hw_ring_mask_qcn9274,
.host_ce_config = ath12k_wifi7_host_ce_config_qcn9274,
.ce_count = 16,
.target_ce_config = ath12k_wifi7_target_ce_config_wlan_qcn9274,
.target_ce_count = 12,
.svc_to_ce_map =
ath12k_wifi7_target_service_to_ce_map_wlan_qcn9274,
.svc_to_ce_map_len = 18,
.rxdma1_enable = false,
.num_rxdma_per_pdev = 1,
.num_rxdma_dst_ring = 0,
.rx_mac_buf_ring = false,
.vdev_start_delay = false,
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_AP_VLAN),
.supports_monitor = false,
.idle_ps = false,
.download_calib = true,
.supports_suspend = false,
.tcl_ring_retry = true,
.reoq_lut_support = true,
.supports_shadow_regs = false,
.num_tcl_banks = 48,
.max_tx_ring = 4,
.mhi_config = &ath12k_wifi7_mhi_config_qcn9274,
.wmi_init = ath12k_wifi7_wmi_init_qcn9274,
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
.rfkill_pin = 0,
.rfkill_cfg = 0,
.rfkill_on_level = 0,
.rddm_size = 0x600000,
.def_num_link = 0,
.max_mlo_peer = 256,
.otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
.supports_sta_ps = false,
.acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true,
.iova_mask = 0,
.supports_aspm = false,
.ce_ie_addr = NULL,
.ce_remap = NULL,
.bdf_addr_offset = 0,
.current_cc_support = false,
.dp_primary_link_only = true,
},
{
.name = "wcn7850 hw2.0",
.hw_rev = ATH12K_HW_WCN7850_HW20,
.fw = {
.dir = "WCN7850/hw2.0",
.board_size = 256 * 1024,
.cal_offset = 256 * 1024,
.m3_loader = ath12k_m3_fw_loader_driver,
},
.max_radios = 1,
.single_pdev_only = true,
.qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_WCN7850,
.internal_sleep_clock = true,
.hw_ops = &wcn7850_ops,
.ring_mask = &ath12k_wifi7_hw_ring_mask_wcn7850,
.host_ce_config = ath12k_wifi7_host_ce_config_wcn7850,
.ce_count = 9,
.target_ce_config = ath12k_wifi7_target_ce_config_wlan_wcn7850,
.target_ce_count = 9,
.svc_to_ce_map =
ath12k_wifi7_target_service_to_ce_map_wlan_wcn7850,
.svc_to_ce_map_len = 14,
.rxdma1_enable = false,
.num_rxdma_per_pdev = 2,
.num_rxdma_dst_ring = 1,
.rx_mac_buf_ring = true,
.vdev_start_delay = true,
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO),
.supports_monitor = true,
.idle_ps = true,
.download_calib = false,
.supports_suspend = true,
.tcl_ring_retry = false,
.reoq_lut_support = false,
.supports_shadow_regs = true,
.num_tcl_banks = 7,
.max_tx_ring = 3,
.mhi_config = &ath12k_wifi7_mhi_config_wcn7850,
.wmi_init = ath12k_wifi7_wmi_init_wcn7850,
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01) |
BIT(CNSS_PCIE_PERST_NO_PULL_V01),
.rfkill_pin = 48,
.rfkill_cfg = 0,
.rfkill_on_level = 1,
.rddm_size = 0x780000,
.def_num_link = 2,
.max_mlo_peer = 32,
.otp_board_id_register = 0,
.supports_sta_ps = true,
.acpi_guid = &wcn7850_uuid,
.supports_dynamic_smps_6ghz = false,
.iova_mask = ATH12K_PCIE_MAX_PAYLOAD_SIZE - 1,
.supports_aspm = true,
.ce_ie_addr = NULL,
.ce_remap = NULL,
.bdf_addr_offset = 0,
.current_cc_support = true,
.dp_primary_link_only = false,
},
{
.name = "qcn9274 hw2.0",
.hw_rev = ATH12K_HW_QCN9274_HW20,
.fw = {
.dir = "QCN9274/hw2.0",
.board_size = 256 * 1024,
.cal_offset = 128 * 1024,
.m3_loader = ath12k_m3_fw_loader_driver,
},
.max_radios = 2,
.single_pdev_only = false,
.qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_QCN9274,
.internal_sleep_clock = false,
.hw_ops = &qcn9274_ops,
.ring_mask = &ath12k_wifi7_hw_ring_mask_qcn9274,
.host_ce_config = ath12k_wifi7_host_ce_config_qcn9274,
.ce_count = 16,
.target_ce_config = ath12k_wifi7_target_ce_config_wlan_qcn9274,
.target_ce_count = 12,
.svc_to_ce_map =
ath12k_wifi7_target_service_to_ce_map_wlan_qcn9274,
.svc_to_ce_map_len = 18,
.rxdma1_enable = true,
.num_rxdma_per_pdev = 1,
.num_rxdma_dst_ring = 0,
.rx_mac_buf_ring = false,
.vdev_start_delay = false,
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT) |
BIT(NL80211_IFTYPE_AP_VLAN),
.supports_monitor = true,
.idle_ps = false,
.download_calib = true,
.supports_suspend = false,
.tcl_ring_retry = true,
.reoq_lut_support = true,
.supports_shadow_regs = false,
.num_tcl_banks = 48,
.max_tx_ring = 4,
.mhi_config = &ath12k_wifi7_mhi_config_qcn9274,
.wmi_init = ath12k_wifi7_wmi_init_qcn9274,
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
.rfkill_pin = 0,
.rfkill_cfg = 0,
.rfkill_on_level = 0,
.rddm_size = 0x600000,
.def_num_link = 0,
.max_mlo_peer = 256,
.otp_board_id_register = QCN9274_QFPROM_RAW_RFA_PDET_ROW13_LSB,
.supports_sta_ps = false,
.acpi_guid = NULL,
.supports_dynamic_smps_6ghz = true,
.iova_mask = 0,
.supports_aspm = false,
.ce_ie_addr = NULL,
.ce_remap = NULL,
.bdf_addr_offset = 0,
.current_cc_support = false,
.dp_primary_link_only = true,
},
{
.name = "ipq5332 hw1.0",
.hw_rev = ATH12K_HW_IPQ5332_HW10,
.fw = {
.dir = "IPQ5332/hw1.0",
.board_size = 256 * 1024,
.cal_offset = 128 * 1024,
.m3_loader = ath12k_m3_fw_loader_remoteproc,
},
.max_radios = 1,
.single_pdev_only = false,
.qmi_service_ins_id = ATH12K_QMI_WLFW_SERVICE_INS_ID_V01_IPQ5332,
.internal_sleep_clock = false,
.hw_ops = &qcn9274_ops,
.ring_mask = &ath12k_wifi7_hw_ring_mask_ipq5332,
.host_ce_config = ath12k_wifi7_host_ce_config_ipq5332,
.ce_count = 12,
.target_ce_config = ath12k_wifi7_target_ce_config_wlan_ipq5332,
.target_ce_count = 12,
.svc_to_ce_map =
ath12k_wifi7_target_service_to_ce_map_wlan_ipq5332,
.svc_to_ce_map_len = 18,
.rxdma1_enable = false,
.num_rxdma_per_pdev = 1,
.num_rxdma_dst_ring = 0,
.rx_mac_buf_ring = false,
.vdev_start_delay = false,
.interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_AP) |
BIT(NL80211_IFTYPE_MESH_POINT),
.supports_monitor = false,
.idle_ps = false,
.download_calib = true,
.supports_suspend = false,
.tcl_ring_retry = true,
.reoq_lut_support = false,
.supports_shadow_regs = false,
.num_tcl_banks = 48,
.max_tx_ring = 4,
.wmi_init = &ath12k_wifi7_wmi_init_qcn9274,
.qmi_cnss_feature_bitmap = BIT(CNSS_QDSS_CFG_MISS_V01),
.rfkill_pin = 0,
.rfkill_cfg = 0,
.rfkill_on_level = 0,
.rddm_size = 0,
.def_num_link = 0,
.max_mlo_peer = 256,
.otp_board_id_register = 0,
.supports_sta_ps = false,
.acpi_guid = NULL,
.supports_dynamic_smps_6ghz = false,
.iova_mask = 0,
.supports_aspm = false,
.ce_ie_addr = &ath12k_wifi7_ce_ie_addr_ipq5332,
.ce_remap = &ath12k_wifi7_ce_remap_ipq5332,
.bdf_addr_offset = 0xC00000,
.dp_primary_link_only = true,
},
};
/* Note: called under rcu_read_lock() */
static void ath12k_wifi7_mac_op_tx(struct ieee80211_hw *hw,
struct ieee80211_tx_control *control,
struct sk_buff *skb)
{
struct ath12k_skb_cb *skb_cb = ATH12K_SKB_CB(skb);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
struct ath12k_vif *ahvif = ath12k_vif_to_ahvif(vif);
struct ath12k_link_vif *arvif = &ahvif->deflink;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_sta *sta = control->sta;
struct ath12k_link_vif *tmp_arvif;
u32 info_flags = info->flags;
struct sk_buff *msdu_copied;
struct ath12k *ar, *tmp_ar;
struct ath12k_pdev_dp *dp_pdev, *tmp_dp_pdev;
struct ath12k_dp_link_peer *peer;
unsigned long links_map;
bool is_mcast = false;
bool is_dvlan = false;
struct ethhdr *eth;
bool is_prb_rsp;
u16 mcbc_gsn;
u8 link_id;
int ret;
struct ath12k_dp *tmp_dp;
if (ahvif->vdev_type == WMI_VDEV_TYPE_MONITOR) {
ieee80211_free_txskb(hw, skb);
return;
}
link_id = u32_get_bits(info->control.flags, IEEE80211_TX_CTRL_MLO_LINK);
memset(skb_cb, 0, sizeof(*skb_cb));
skb_cb->vif = vif;
if (key) {
skb_cb->cipher = key->cipher;
skb_cb->flags |= ATH12K_SKB_CIPHER_SET;
}
/* handle only for MLO case, use deflink for non MLO case */
if (ieee80211_vif_is_mld(vif)) {
link_id = ath12k_mac_get_tx_link(sta, vif, link_id, skb, info_flags);
if (link_id >= IEEE80211_MLD_MAX_NUM_LINKS) {
ieee80211_free_txskb(hw, skb);
return;
}
} else {
link_id = 0;
}
arvif = rcu_dereference(ahvif->link[link_id]);
if (!arvif || !arvif->ar) {
ath12k_warn(ahvif->ah, "failed to find arvif link id %u for frame transmission",
link_id);
ieee80211_free_txskb(hw, skb);
return;
}
ar = arvif->ar;
skb_cb->link_id = link_id;
/*
* as skb_cb is common currently for dp and mgmt tx processing
* set this in the common mac op tx function.
*/
skb_cb->ar = ar;
is_prb_rsp = ieee80211_is_probe_resp(hdr->frame_control);
if (info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
eth = (struct ethhdr *)skb->data;
is_mcast = is_multicast_ether_addr(eth->h_dest);
skb_cb->flags |= ATH12K_SKB_HW_80211_ENCAP;
} else if (ieee80211_is_mgmt(hdr->frame_control)) {
if (sta && sta->mlo)
skb_cb->flags |= ATH12K_SKB_MLO_STA;
ret = ath12k_mac_mgmt_tx(ar, skb, is_prb_rsp);
if (ret) {
ath12k_warn(ar->ab, "failed to queue management frame %d\n",
ret);
ieee80211_free_txskb(hw, skb);
}
return;
}
if (!(info_flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
is_mcast = is_multicast_ether_addr(hdr->addr1);
/* This is case only for P2P_GO */
if (vif->type == NL80211_IFTYPE_AP && vif->p2p)
ath12k_mac_add_p2p_noa_ie(ar, vif, skb, is_prb_rsp);
dp_pdev = ath12k_dp_to_pdev_dp(ar->ab->dp, ar->pdev_idx);
if (!dp_pdev) {
ieee80211_free_txskb(hw, skb);
return;
}
/* Checking if it is a DVLAN frame */
if (!test_bit(ATH12K_FLAG_HW_CRYPTO_DISABLED, &ar->ab->dev_flags) &&
!(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) &&
!(skb_cb->flags & ATH12K_SKB_CIPHER_SET) &&
ieee80211_has_protected(hdr->frame_control))
is_dvlan = true;
if (!vif->valid_links || !is_mcast || is_dvlan ||
(skb_cb->flags & ATH12K_SKB_HW_80211_ENCAP) ||
test_bit(ATH12K_FLAG_RAW_MODE, &ar->ab->dev_flags)) {
ret = ath12k_wifi7_dp_tx(dp_pdev, arvif, skb, false, 0, is_mcast);
if (unlikely(ret)) {
ath12k_warn(ar->ab, "failed to transmit frame %d\n", ret);
ieee80211_free_txskb(ar->ah->hw, skb);
return;
}
} else {
mcbc_gsn = atomic_inc_return(&ahvif->dp_vif.mcbc_gsn) & 0xfff;
links_map = ahvif->links_map;
for_each_set_bit(link_id, &links_map,
IEEE80211_MLD_MAX_NUM_LINKS) {
tmp_arvif = rcu_dereference(ahvif->link[link_id]);
if (!tmp_arvif || !tmp_arvif->is_up)
continue;
tmp_ar = tmp_arvif->ar;
tmp_dp_pdev = ath12k_dp_to_pdev_dp(tmp_ar->ab->dp,
tmp_ar->pdev_idx);
if (!tmp_dp_pdev)
continue;
msdu_copied = skb_copy(skb, GFP_ATOMIC);
if (!msdu_copied) {
ath12k_err(ar->ab,
"skb copy failure link_id 0x%X vdevid 0x%X\n",
link_id, tmp_arvif->vdev_id);
continue;
}
ath12k_mlo_mcast_update_tx_link_address(vif, link_id,
msdu_copied,
info_flags);
skb_cb = ATH12K_SKB_CB(msdu_copied);
skb_cb->link_id = link_id;
skb_cb->vif = vif;
skb_cb->ar = tmp_ar;
/* For open mode, skip peer find logic */
if (unlikely(!ahvif->dp_vif.key_cipher))
goto skip_peer_find;
tmp_dp = ath12k_ab_to_dp(tmp_ar->ab);
spin_lock_bh(&tmp_dp->dp_lock);
peer = ath12k_dp_link_peer_find_by_addr(tmp_dp,
tmp_arvif->bssid);
if (!peer || !peer->dp_peer) {
spin_unlock_bh(&tmp_dp->dp_lock);
ath12k_warn(tmp_ar->ab,
"failed to find peer for vdev_id 0x%X addr %pM link_map 0x%X\n",
tmp_arvif->vdev_id, tmp_arvif->bssid,
ahvif->links_map);
dev_kfree_skb_any(msdu_copied);
continue;
}
key = peer->dp_peer->keys[peer->dp_peer->mcast_keyidx];
if (key) {
skb_cb->cipher = key->cipher;
skb_cb->flags |= ATH12K_SKB_CIPHER_SET;
hdr = (struct ieee80211_hdr *)msdu_copied->data;
if (!ieee80211_has_protected(hdr->frame_control))
hdr->frame_control |=
cpu_to_le16(IEEE80211_FCTL_PROTECTED);
}
spin_unlock_bh(&tmp_dp->dp_lock);
skip_peer_find:
ret = ath12k_wifi7_dp_tx(tmp_dp_pdev, tmp_arvif,
msdu_copied, true, mcbc_gsn, is_mcast);
if (unlikely(ret)) {
if (ret == -ENOMEM) {
/* Drops are expected during heavy multicast
* frame flood. Print with debug log
* level to avoid lot of console prints
*/
ath12k_dbg(ar->ab, ATH12K_DBG_MAC,
"failed to transmit frame %d\n",
ret);
} else {
ath12k_warn(ar->ab,
"failed to transmit frame %d\n",
ret);
}
dev_kfree_skb_any(msdu_copied);
}
}
ieee80211_free_txskb(ar->ah->hw, skb);
}
}
static const struct ieee80211_ops ath12k_ops_wifi7 = {
.tx = ath12k_wifi7_mac_op_tx,
.wake_tx_queue = ieee80211_handle_wake_tx_queue,
.start = ath12k_mac_op_start,
.stop = ath12k_mac_op_stop,
.reconfig_complete = ath12k_mac_op_reconfig_complete,
.add_interface = ath12k_mac_op_add_interface,
.remove_interface = ath12k_mac_op_remove_interface,
.update_vif_offload = ath12k_mac_op_update_vif_offload,
.config = ath12k_mac_op_config,
.link_info_changed = ath12k_mac_op_link_info_changed,
.vif_cfg_changed = ath12k_mac_op_vif_cfg_changed,
.change_vif_links = ath12k_mac_op_change_vif_links,
.configure_filter = ath12k_mac_op_configure_filter,
.hw_scan = ath12k_mac_op_hw_scan,
.cancel_hw_scan = ath12k_mac_op_cancel_hw_scan,
.set_key = ath12k_mac_op_set_key,
.set_rekey_data = ath12k_mac_op_set_rekey_data,
.sta_state = ath12k_mac_op_sta_state,
.sta_set_txpwr = ath12k_mac_op_sta_set_txpwr,
.link_sta_rc_update = ath12k_mac_op_link_sta_rc_update,
.conf_tx = ath12k_mac_op_conf_tx,
.set_antenna = ath12k_mac_op_set_antenna,
.get_antenna = ath12k_mac_op_get_antenna,
.ampdu_action = ath12k_mac_op_ampdu_action,
.add_chanctx = ath12k_mac_op_add_chanctx,
.remove_chanctx = ath12k_mac_op_remove_chanctx,
.change_chanctx = ath12k_mac_op_change_chanctx,
.assign_vif_chanctx = ath12k_mac_op_assign_vif_chanctx,
.unassign_vif_chanctx = ath12k_mac_op_unassign_vif_chanctx,
.switch_vif_chanctx = ath12k_mac_op_switch_vif_chanctx,
.get_txpower = ath12k_mac_op_get_txpower,
.set_rts_threshold = ath12k_mac_op_set_rts_threshold,
.set_frag_threshold = ath12k_mac_op_set_frag_threshold,
.set_bitrate_mask = ath12k_mac_op_set_bitrate_mask,
.get_survey = ath12k_mac_op_get_survey,
.flush = ath12k_mac_op_flush,
.sta_statistics = ath12k_mac_op_sta_statistics,
.link_sta_statistics = ath12k_mac_op_link_sta_statistics,
.remain_on_channel = ath12k_mac_op_remain_on_channel,
.cancel_remain_on_channel = ath12k_mac_op_cancel_remain_on_channel,
.change_sta_links = ath12k_mac_op_change_sta_links,
.can_activate_links = ath12k_mac_op_can_activate_links,
#ifdef CONFIG_PM
.suspend = ath12k_wow_op_suspend,
.resume = ath12k_wow_op_resume,
.set_wakeup = ath12k_wow_op_set_wakeup,
#endif
#ifdef CONFIG_ATH12K_DEBUGFS
.vif_add_debugfs = ath12k_debugfs_op_vif_add,
#endif
CFG80211_TESTMODE_CMD(ath12k_tm_cmd)
#ifdef CONFIG_ATH12K_DEBUGFS
.link_sta_add_debugfs = ath12k_debugfs_link_sta_op_add,
#endif
};
int ath12k_wifi7_hw_init(struct ath12k_base *ab)
{
const struct ath12k_hw_params *hw_params = NULL;
int i;
for (i = 0; i < ARRAY_SIZE(ath12k_wifi7_hw_params); i++) {
hw_params = &ath12k_wifi7_hw_params[i];
if (hw_params->hw_rev == ab->hw_rev)
break;
}
if (i == ARRAY_SIZE(ath12k_wifi7_hw_params)) {
ath12k_err(ab, "Unsupported Wi-Fi 7 hardware version: 0x%x\n",
ab->hw_rev);
return -EINVAL;
}
ab->hw_params = hw_params;
ab->ath12k_ops = &ath12k_ops_wifi7;
ath12k_wifi7_hal_init(ab);
ath12k_info(ab, "Wi-Fi 7 Hardware name: %s\n", ab->hw_params->name);
return 0;
}

View File

@ -0,0 +1,13 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_WIFI7_HW_H
#define ATH12K_WIFI7_HW_H
struct ath12k_base;
int ath12k_wifi7_hw_init(struct ath12k_base *ab);
#endif /* ATH12K_WIFI7_HW_H */

View File

@ -0,0 +1,138 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "../mhi.h"
#include "mhi.h"
static const struct mhi_channel_config ath12k_wifi7_mhi_channels_qcn9274[] = {
{
.num = 20,
.name = "IPCR",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
.name = "IPCR",
.num_elements = 32,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
static struct mhi_event_config ath12k_wifi7_mhi_events_qcn9274[] = {
{
.num_elements = 32,
.irq_moderation_ms = 0,
.irq = 1,
.data_type = MHI_ER_CTRL,
.mode = MHI_DB_BRST_DISABLE,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
{
.num_elements = 256,
.irq_moderation_ms = 1,
.irq = 2,
.mode = MHI_DB_BRST_DISABLE,
.priority = 1,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
};
const struct mhi_controller_config ath12k_wifi7_mhi_config_qcn9274 = {
.max_channels = 30,
.timeout_ms = 10000,
.use_bounce_buf = false,
.buf_len = 0,
.num_channels = ARRAY_SIZE(ath12k_wifi7_mhi_channels_qcn9274),
.ch_cfg = ath12k_wifi7_mhi_channels_qcn9274,
.num_events = ARRAY_SIZE(ath12k_wifi7_mhi_events_qcn9274),
.event_cfg = ath12k_wifi7_mhi_events_qcn9274,
};
static const struct mhi_channel_config ath12k_wifi7_mhi_channels_wcn7850[] = {
{
.num = 20,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_TO_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = false,
},
{
.num = 21,
.name = "IPCR",
.num_elements = 64,
.event_ring = 1,
.dir = DMA_FROM_DEVICE,
.ee_mask = 0x4,
.pollcfg = 0,
.doorbell = MHI_DB_BRST_DISABLE,
.lpm_notify = false,
.offload_channel = false,
.doorbell_mode_switch = false,
.auto_queue = true,
},
};
static struct mhi_event_config ath12k_wifi7_mhi_events_wcn7850[] = {
{
.num_elements = 32,
.irq_moderation_ms = 0,
.irq = 1,
.mode = MHI_DB_BRST_DISABLE,
.data_type = MHI_ER_CTRL,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
{
.num_elements = 256,
.irq_moderation_ms = 1,
.irq = 2,
.mode = MHI_DB_BRST_DISABLE,
.priority = 1,
.hardware_event = false,
.client_managed = false,
.offload_channel = false,
},
};
const struct mhi_controller_config ath12k_wifi7_mhi_config_wcn7850 = {
.max_channels = 128,
.timeout_ms = 2000,
.use_bounce_buf = false,
.buf_len = 8192,
.num_channels = ARRAY_SIZE(ath12k_wifi7_mhi_channels_wcn7850),
.ch_cfg = ath12k_wifi7_mhi_channels_wcn7850,
.num_events = ARRAY_SIZE(ath12k_wifi7_mhi_events_wcn7850),
.event_cfg = ath12k_wifi7_mhi_events_wcn7850,
};

View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef _ATH12K_WIFI7_MHI_H
#define _ATH12K_WIFI7_MHI_H
extern const struct mhi_controller_config ath12k_wifi7_mhi_config_qcn9274;
extern const struct mhi_controller_config ath12k_wifi7_mhi_config_wcn7850;
#endif /* _ATH12K_WIFI7_MHI_H */

View File

@ -0,0 +1,191 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include <linux/pci.h>
#include "../pci.h"
#include "pci.h"
#include "../core.h"
#include "../hif.h"
#include "../mhi.h"
#include "hw.h"
#include "../hal.h"
#include "dp.h"
#include "core.h"
#include "hal.h"
#define QCN9274_DEVICE_ID 0x1109
#define WCN7850_DEVICE_ID 0x1107
#define ATH12K_PCI_W7_SOC_HW_VERSION_1 1
#define ATH12K_PCI_W7_SOC_HW_VERSION_2 2
#define TCSR_SOC_HW_VERSION 0x1B00000
#define TCSR_SOC_HW_VERSION_MAJOR_MASK GENMASK(11, 8)
#define TCSR_SOC_HW_VERSION_MINOR_MASK GENMASK(7, 4)
static const struct pci_device_id ath12k_wifi7_pci_id_table[] = {
{ PCI_VDEVICE(QCOM, QCN9274_DEVICE_ID) },
{ PCI_VDEVICE(QCOM, WCN7850_DEVICE_ID) },
{}
};
MODULE_DEVICE_TABLE(pci, ath12k_wifi7_pci_id_table);
/* TODO: revisit IRQ mapping for new SRNG's */
static const struct ath12k_msi_config ath12k_wifi7_msi_config[] = {
{
.total_vectors = 16,
.total_users = 3,
.users = (struct ath12k_msi_user[]) {
{ .name = "MHI", .num_vectors = 3, .base_vector = 0 },
{ .name = "CE", .num_vectors = 5, .base_vector = 3 },
{ .name = "DP", .num_vectors = 8, .base_vector = 8 },
},
},
};
static const struct ath12k_pci_ops ath12k_wifi7_pci_ops_qcn9274 = {
.wakeup = NULL,
.release = NULL,
};
static int ath12k_wifi7_pci_bus_wake_up(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
return mhi_device_get_sync(ab_pci->mhi_ctrl->mhi_dev);
}
static void ath12k_wifi7_pci_bus_release(struct ath12k_base *ab)
{
struct ath12k_pci *ab_pci = ath12k_pci_priv(ab);
mhi_device_put(ab_pci->mhi_ctrl->mhi_dev);
}
static const struct ath12k_pci_ops ath12k_wifi7_pci_ops_wcn7850 = {
.wakeup = ath12k_wifi7_pci_bus_wake_up,
.release = ath12k_wifi7_pci_bus_release,
};
static
void ath12k_wifi7_pci_read_hw_version(struct ath12k_base *ab,
u32 *major, u32 *minor)
{
u32 soc_hw_version;
soc_hw_version = ath12k_pci_read32(ab, TCSR_SOC_HW_VERSION);
*major = u32_get_bits(soc_hw_version, TCSR_SOC_HW_VERSION_MAJOR_MASK);
*minor = u32_get_bits(soc_hw_version, TCSR_SOC_HW_VERSION_MINOR_MASK);
}
static int ath12k_wifi7_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev)
{
u32 soc_hw_version_major, soc_hw_version_minor;
struct ath12k_pci *ab_pci;
struct ath12k_base *ab;
int ret;
ab = pci_get_drvdata(pdev);
if (!ab)
return -EINVAL;
ab_pci = ath12k_pci_priv(ab);
if (!ab_pci)
return -EINVAL;
switch (pci_dev->device) {
case QCN9274_DEVICE_ID:
ab_pci->msi_config = &ath12k_wifi7_msi_config[0];
ab->static_window_map = true;
ab_pci->pci_ops = &ath12k_wifi7_pci_ops_qcn9274;
ath12k_wifi7_pci_read_hw_version(ab, &soc_hw_version_major,
&soc_hw_version_minor);
ab->target_mem_mode = ath12k_core_get_memory_mode(ab);
switch (soc_hw_version_major) {
case ATH12K_PCI_W7_SOC_HW_VERSION_2:
ab->hw_rev = ATH12K_HW_QCN9274_HW20;
break;
case ATH12K_PCI_W7_SOC_HW_VERSION_1:
ab->hw_rev = ATH12K_HW_QCN9274_HW10;
break;
default:
dev_err(&pdev->dev,
"Unknown hardware version found for QCN9274: 0x%x\n",
soc_hw_version_major);
return -EOPNOTSUPP;
}
break;
case WCN7850_DEVICE_ID:
ab->id.bdf_search = ATH12K_BDF_SEARCH_BUS_AND_BOARD;
ab_pci->msi_config = &ath12k_wifi7_msi_config[0];
ab->static_window_map = false;
ab_pci->pci_ops = &ath12k_wifi7_pci_ops_wcn7850;
ath12k_wifi7_pci_read_hw_version(ab, &soc_hw_version_major,
&soc_hw_version_minor);
ab->target_mem_mode = ATH12K_QMI_MEMORY_MODE_DEFAULT;
switch (soc_hw_version_major) {
case ATH12K_PCI_W7_SOC_HW_VERSION_2:
ab->hw_rev = ATH12K_HW_WCN7850_HW20;
break;
default:
dev_err(&pdev->dev,
"Unknown hardware version found for WCN7850: 0x%x\n",
soc_hw_version_major);
return -EOPNOTSUPP;
}
break;
default:
dev_err(&pdev->dev, "Unknown Wi-Fi 7 PCI device found: 0x%x\n",
pci_dev->device);
return -EOPNOTSUPP;
}
ret = ath12k_wifi7_hw_init(ab);
if (ret) {
dev_err(&pdev->dev, "WiFi-7 hw_init for PCI failed: %d\n", ret);
return ret;
}
return 0;
}
static const struct ath12k_pci_reg_base ath12k_wifi7_reg_base = {
.umac_base = HAL_SEQ_WCSS_UMAC_OFFSET,
.ce_reg_base = HAL_CE_WFSS_CE_REG_BASE,
};
static struct ath12k_pci_driver ath12k_wifi7_pci_driver = {
.name = "ath12k_wifi7_pci",
.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)
{
int ret;
ret = ath12k_pci_register_driver(ATH12K_DEVICE_FAMILY_WIFI7,
&ath12k_wifi7_pci_driver);
if (ret) {
pr_err("Failed to register ath12k Wi-Fi 7 driver: %d\n",
ret);
return ret;
}
return 0;
}
void ath12k_wifi7_pci_exit(void)
{
ath12k_pci_unregister_driver(ATH12K_DEVICE_FAMILY_WIFI7);
}

View File

@ -0,0 +1,12 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_PCI_WIFI7_H
#define ATH12K_PCI_WIFI7_H
int ath12k_wifi7_pci_init(void);
void ath12k_wifi7_pci_exit(void);
#endif /* ATH12K_PCI_WIFI7_H */

View File

@ -0,0 +1,105 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#include "../core.h"
#include "wmi.h"
void ath12k_wifi7_wmi_init_qcn9274(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config)
{
config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab);
config->num_peers = ab->num_radios *
ath12k_core_get_max_peers_per_radio(ab);
config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;
config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
config->num_peer_keys = TARGET_NUM_PEER_KEYS;
config->ast_skid_limit = TARGET_AST_SKID_LIMIT;
config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
config->rx_decap_mode = TARGET_DECAP_MODE_RAW;
else
config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS;
config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS;
config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE;
config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
config->num_wds_entries = TARGET_NUM_WDS_ENTRIES;
config->dma_burst_size = TARGET_DMA_BURST_SIZE;
config->rx_skip_defrag_timeout_dup_detection_check =
TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
config->vow_config = TARGET_VOW_CONFIG;
config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV;
config->num_msdu_desc = TARGET_NUM_MSDU_DESC;
config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;
config->rx_batchmode = TARGET_RX_BATCHMODE;
/* Indicates host supports peer map v3 and unmap v2 support */
config->peer_map_unmap_version = 0x32;
config->twt_ap_pdev_count = ab->num_radios;
config->twt_ap_sta_count = 1000;
config->ema_max_vap_cnt = ab->num_radios;
config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD;
config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt;
if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map))
config->peer_metadata_ver = ATH12K_PEER_METADATA_V1B;
}
void ath12k_wifi7_wmi_init_wcn7850(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config)
{
config->num_vdevs = 4;
config->num_peers = 16;
config->num_tids = 32;
config->num_offload_peers = 3;
config->num_offload_reorder_buffs = 3;
config->num_peer_keys = TARGET_NUM_PEER_KEYS;
config->ast_skid_limit = TARGET_AST_SKID_LIMIT;
config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
config->num_mcast_groups = 0;
config->num_mcast_table_elems = 0;
config->mcast2ucast_mode = 0;
config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
config->num_wds_entries = 0;
config->dma_burst_size = 0;
config->rx_skip_defrag_timeout_dup_detection_check = 0;
config->vow_config = TARGET_VOW_CONFIG;
config->gtk_offload_max_vdev = 2;
config->num_msdu_desc = 0x400;
config->beacon_tx_offload_max_vdev = 2;
config->rx_batchmode = TARGET_RX_BATCHMODE;
config->peer_map_unmap_version = 0x1;
config->use_pdev_id = 1;
config->max_frag_entries = 0xa;
config->num_tdls_vdevs = 0x1;
config->num_tdls_conn_table_entries = 8;
config->beacon_tx_offload_max_vdev = 0x2;
config->num_multicast_filter_entries = 0x20;
config->num_wow_filters = 0x16;
config->num_keep_alive_pattern = 0;
}

View File

@ -0,0 +1,15 @@
/* SPDX-License-Identifier: BSD-3-Clause-Clear */
/*
* Copyright (c) 2018-2021 The Linux Foundation. All rights reserved.
* Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
#ifndef ATH12K_WMI_WIFI7_H
#define ATH12K_WMI_WIFI7_H
void ath12k_wifi7_wmi_init_qcn9274(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
void ath12k_wifi7_wmi_init_wcn7850(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
#endif

View File

@ -206,103 +206,6 @@ static __le32 ath12k_wmi_tlv_cmd_hdr(u32 cmd, u32 len)
return ath12k_wmi_tlv_hdr(cmd, len - TLV_HDR_SIZE);
}
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config)
{
config->num_vdevs = ab->num_radios * TARGET_NUM_VDEVS(ab);
config->num_peers = ab->num_radios *
ath12k_core_get_max_peers_per_radio(ab);
config->num_offload_peers = TARGET_NUM_OFFLD_PEERS;
config->num_offload_reorder_buffs = TARGET_NUM_OFFLD_REORDER_BUFFS;
config->num_peer_keys = TARGET_NUM_PEER_KEYS;
config->ast_skid_limit = TARGET_AST_SKID_LIMIT;
config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
if (test_bit(ATH12K_FLAG_RAW_MODE, &ab->dev_flags))
config->rx_decap_mode = TARGET_DECAP_MODE_RAW;
else
config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
config->num_mcast_groups = TARGET_NUM_MCAST_GROUPS;
config->num_mcast_table_elems = TARGET_NUM_MCAST_TABLE_ELEMS;
config->mcast2ucast_mode = TARGET_MCAST2UCAST_MODE;
config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
config->num_wds_entries = TARGET_NUM_WDS_ENTRIES;
config->dma_burst_size = TARGET_DMA_BURST_SIZE;
config->rx_skip_defrag_timeout_dup_detection_check =
TARGET_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
config->vow_config = TARGET_VOW_CONFIG;
config->gtk_offload_max_vdev = TARGET_GTK_OFFLOAD_MAX_VDEV;
config->num_msdu_desc = TARGET_NUM_MSDU_DESC;
config->beacon_tx_offload_max_vdev = ab->num_radios * TARGET_MAX_BCN_OFFLD;
config->rx_batchmode = TARGET_RX_BATCHMODE;
/* Indicates host supports peer map v3 and unmap v2 support */
config->peer_map_unmap_version = 0x32;
config->twt_ap_pdev_count = ab->num_radios;
config->twt_ap_sta_count = 1000;
config->ema_max_vap_cnt = ab->num_radios;
config->ema_max_profile_period = TARGET_EMA_MAX_PROFILE_PERIOD;
config->beacon_tx_offload_max_vdev += config->ema_max_vap_cnt;
if (test_bit(WMI_TLV_SERVICE_PEER_METADATA_V1A_V1B_SUPPORT, ab->wmi_ab.svc_map))
config->peer_metadata_ver = ATH12K_PEER_METADATA_V1B;
}
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config)
{
config->num_vdevs = 4;
config->num_peers = 16;
config->num_tids = 32;
config->num_offload_peers = 3;
config->num_offload_reorder_buffs = 3;
config->num_peer_keys = TARGET_NUM_PEER_KEYS;
config->ast_skid_limit = TARGET_AST_SKID_LIMIT;
config->tx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_chain_mask = (1 << ab->target_caps.num_rf_chains) - 1;
config->rx_timeout_pri[0] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[1] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[2] = TARGET_RX_TIMEOUT_LO_PRI;
config->rx_timeout_pri[3] = TARGET_RX_TIMEOUT_HI_PRI;
config->rx_decap_mode = TARGET_DECAP_MODE_NATIVE_WIFI;
config->scan_max_pending_req = TARGET_SCAN_MAX_PENDING_REQS;
config->bmiss_offload_max_vdev = TARGET_BMISS_OFFLOAD_MAX_VDEV;
config->roam_offload_max_vdev = TARGET_ROAM_OFFLOAD_MAX_VDEV;
config->roam_offload_max_ap_profiles = TARGET_ROAM_OFFLOAD_MAX_AP_PROFILES;
config->num_mcast_groups = 0;
config->num_mcast_table_elems = 0;
config->mcast2ucast_mode = 0;
config->tx_dbg_log_size = TARGET_TX_DBG_LOG_SIZE;
config->num_wds_entries = 0;
config->dma_burst_size = 0;
config->rx_skip_defrag_timeout_dup_detection_check = 0;
config->vow_config = TARGET_VOW_CONFIG;
config->gtk_offload_max_vdev = 2;
config->num_msdu_desc = 0x400;
config->beacon_tx_offload_max_vdev = 2;
config->rx_batchmode = TARGET_RX_BATCHMODE;
config->peer_map_unmap_version = 0x1;
config->use_pdev_id = 1;
config->max_frag_entries = 0xa;
config->num_tdls_vdevs = 0x1;
config->num_tdls_conn_table_entries = 8;
config->beacon_tx_offload_max_vdev = 0x2;
config->num_multicast_filter_entries = 0x20;
config->num_wow_filters = 0x16;
config->num_keep_alive_pattern = 0;
}
#define PRIMAP(_hw_mode_) \
[_hw_mode_] = _hw_mode_##_PRI
@ -4217,6 +4120,7 @@ int ath12k_wmi_set_hw_mode(struct ath12k_base *ab,
int ath12k_wmi_cmd_init(struct ath12k_base *ab)
{
struct ath12k_dp *dp = ath12k_ab_to_dp(ab);
struct ath12k_wmi_base *wmi_ab = &ab->wmi_ab;
struct ath12k_wmi_init_cmd_arg arg = {};
@ -4237,7 +4141,7 @@ int ath12k_wmi_cmd_init(struct ath12k_base *ab)
arg.num_band_to_mac = ab->num_radios;
ath12k_fill_band_to_mac_param(ab, arg.band_to_mac);
ab->dp.peer_metadata_ver = arg.res_cfg.peer_metadata_ver;
dp->peer_metadata_ver = arg.res_cfg.peer_metadata_ver;
return ath12k_init_cmd_send(&wmi_ab->wmi[0], &arg);
}
@ -7379,8 +7283,8 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
struct wmi_peer_sta_kickout_arg arg = {};
struct ath12k_link_vif *arvif;
struct ieee80211_sta *sta;
struct ath12k_peer *peer;
unsigned int link_id;
struct ath12k_sta *ahsta;
struct ath12k_link_sta *arsta;
struct ath12k *ar;
if (ath12k_pull_peer_sta_kickout_ev(ab, skb, &arg) != 0) {
@ -7392,42 +7296,24 @@ static void ath12k_peer_sta_kickout_event(struct ath12k_base *ab, struct sk_buff
spin_lock_bh(&ab->base_lock);
peer = ath12k_peer_find_by_addr(ab, arg.mac_addr);
arsta = ath12k_link_sta_find_by_addr(ab, arg.mac_addr);
if (!peer) {
ath12k_warn(ab, "peer not found %pM\n",
if (!arsta) {
ath12k_warn(ab, "arsta not found %pM\n",
arg.mac_addr);
goto exit;
}
arvif = ath12k_mac_get_arvif_by_vdev_id(ab, peer->vdev_id);
arvif = arsta->arvif;
if (!arvif) {
ath12k_warn(ab, "invalid vdev id in peer sta kickout ev %d",
peer->vdev_id);
ath12k_warn(ab, "invalid arvif in peer sta kickout ev for STA %pM",
arg.mac_addr);
goto exit;
}
ar = arvif->ar;
if (peer->mlo) {
sta = ieee80211_find_sta_by_link_addrs(ath12k_ar_to_hw(ar),
arg.mac_addr,
NULL, &link_id);
if (peer->link_id != link_id) {
ath12k_warn(ab,
"Spurious quick kickout for MLO STA %pM with invalid link_id, peer: %d, sta: %d\n",
arg.mac_addr, peer->link_id, link_id);
goto exit;
}
} else {
sta = ieee80211_find_sta_by_ifaddr(ath12k_ar_to_hw(ar),
arg.mac_addr, NULL);
}
if (!sta) {
ath12k_warn(ab, "Spurious quick kickout for %sSTA %pM\n",
peer->mlo ? "MLO " : "", arg.mac_addr);
goto exit;
}
ahsta = arsta->ahsta;
sta = ath12k_ahsta_to_sta(ahsta);
ath12k_dbg(ab, ATH12K_DBG_WMI,
"peer sta kickout event %pM reason: %d rssi: %d\n",

View File

@ -9,6 +9,7 @@
#include <net/mac80211.h>
#include "htc.h"
#include "cmn_defs.h"
/* Naming conventions for structures:
*
@ -5151,8 +5152,6 @@ struct wmi_probe_tmpl_cmd {
__le32 buf_len;
} __packed;
#define MAX_RADIOS 2
#define WMI_MLO_CMD_TIMEOUT_HZ (5 * HZ)
#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
#define WMI_SEND_TIMEOUT_HZ (3 * HZ)
@ -6323,10 +6322,6 @@ struct ath12k_wmi_rssi_dbm_conv_info_arg {
s8 min_nf_dbm;
};
void ath12k_wmi_init_qcn9274(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
void ath12k_wmi_init_wcn7850(struct ath12k_base *ab,
struct ath12k_wmi_resource_config_arg *config);
int ath12k_wmi_cmd_send(struct ath12k_wmi_pdev *wmi, struct sk_buff *skb,
u32 cmd_id);
struct sk_buff *ath12k_wmi_alloc_skb(struct ath12k_wmi_base *wmi_sc, u32 len);

View File

@ -1,7 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause-Clear
/*
* Copyright (c) 2020 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/delay.h>
@ -919,6 +919,7 @@ cleanup:
exit:
return ret ? 1 : 0;
}
EXPORT_SYMBOL(ath12k_wow_op_suspend);
void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
@ -929,6 +930,7 @@ void ath12k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
device_set_wakeup_enable(ar->ab->dev, enabled);
}
EXPORT_SYMBOL(ath12k_wow_op_set_wakeup);
int ath12k_wow_op_resume(struct ieee80211_hw *hw)
{
@ -1001,6 +1003,7 @@ exit:
return ret;
}
EXPORT_SYMBOL(ath12k_wow_op_resume);
int ath12k_wow_init(struct ath12k *ar)
{