ath10k: import ath10k driver
Import ISC-licensed ath10k driver assumed to be based on Linux kvalo/ath.git master at 6bae9de622d3ef4805aba40e763eb4b0975c4f6d. Import support to redirect fwlogs to kernel messages from https://chromium-review.googlesource.com/c/chromiumos/third_party/kernel/+/389075 Complement the driver to make compile on FreeBSD using LinuxKPI with changes covered by #ifdef (__FreeBSD__). Further select updates were applied since the initial import in order to keep compiling along with other LinuxKPI based drivers. Any other native driver using BUS_PROBE_DEFAULT will attach ignoring this one by default given bsd_probe_return is set to a lower priority. Add the module build framework. We only support PCI parts. The firmware is provided by port net/wifi-firmware-ath10k-kmod. Given the lack of full license texts on most files this is imported under the draft policy for handling SPDX files (D29226). [1] Approved by: core (emaste, 2022-04-08) [1] MFC after: 2 months
This commit is contained in:
parent
ebacd8013f
commit
da8fa4e37a
90
sys/contrib/dev/athk/ath10k/Kconfig
Normal file
90
sys/contrib/dev/athk/ath10k/Kconfig
Normal file
@ -0,0 +1,90 @@
|
||||
# SPDX-License-Identifier: ISC
|
||||
config ATH10K
|
||||
tristate "Atheros 802.11ac wireless cards support"
|
||||
depends on MAC80211 && HAS_DMA
|
||||
select ATH_COMMON
|
||||
select CRC32
|
||||
select WANT_DEV_COREDUMP
|
||||
select ATH10K_CE
|
||||
help
|
||||
This module adds support for wireless adapters based on
|
||||
Atheros IEEE 802.11ac family of chipsets.
|
||||
|
||||
If you choose to build a module, it'll be called ath10k.
|
||||
|
||||
config ATH10K_CE
|
||||
bool
|
||||
|
||||
config ATH10K_PCI
|
||||
tristate "Atheros ath10k PCI support"
|
||||
depends on ATH10K && PCI
|
||||
help
|
||||
This module adds support for PCIE bus
|
||||
|
||||
config ATH10K_AHB
|
||||
bool "Atheros ath10k AHB support"
|
||||
depends on ATH10K_PCI && OF && RESET_CONTROLLER
|
||||
help
|
||||
This module adds support for AHB bus
|
||||
|
||||
config ATH10K_SDIO
|
||||
tristate "Atheros ath10k SDIO support"
|
||||
depends on ATH10K && MMC
|
||||
help
|
||||
This module adds support for SDIO/MMC bus.
|
||||
|
||||
config ATH10K_USB
|
||||
tristate "Atheros ath10k USB support (EXPERIMENTAL)"
|
||||
depends on ATH10K && USB
|
||||
help
|
||||
This module adds experimental support for USB bus. Currently
|
||||
work in progress and will not fully work.
|
||||
|
||||
config ATH10K_SNOC
|
||||
tristate "Qualcomm ath10k SNOC support"
|
||||
depends on ATH10K
|
||||
depends on ARCH_QCOM || COMPILE_TEST
|
||||
select QCOM_SCM
|
||||
select QCOM_QMI_HELPERS
|
||||
help
|
||||
This module adds support for integrated WCN3990 chip connected
|
||||
to system NOC(SNOC).
|
||||
|
||||
config ATH10K_DEBUG
|
||||
bool "Atheros ath10k debugging"
|
||||
depends on ATH10K
|
||||
help
|
||||
Enables debug support
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config ATH10K_DEBUGFS
|
||||
bool "Atheros ath10k debugfs support"
|
||||
depends on ATH10K && DEBUG_FS
|
||||
help
|
||||
Enabled debugfs support
|
||||
|
||||
If unsure, say Y to make it easier to debug problems.
|
||||
|
||||
config ATH10K_SPECTRAL
|
||||
bool "Atheros ath10k spectral scan support"
|
||||
depends on ATH10K_DEBUGFS
|
||||
select RELAY
|
||||
default n
|
||||
help
|
||||
Say Y to enable access to the FFT/spectral data via debugfs.
|
||||
|
||||
config ATH10K_TRACING
|
||||
bool "Atheros ath10k tracing support"
|
||||
depends on ATH10K
|
||||
depends on EVENT_TRACING
|
||||
help
|
||||
Select this to ath10k use tracing infrastructure.
|
||||
|
||||
config ATH10K_DFS_CERTIFIED
|
||||
bool "Atheros DFS support for certified platforms"
|
||||
depends on ATH10K && CFG80211_CERTIFICATION_ONUS
|
||||
default n
|
||||
help
|
||||
This option enables DFS support for initiating radiation on
|
||||
ath10k.
|
45
sys/contrib/dev/athk/ath10k/Makefile
Normal file
45
sys/contrib/dev/athk/ath10k/Makefile
Normal file
@ -0,0 +1,45 @@
|
||||
# SPDX-License-Identifier: ISC
|
||||
obj-$(CONFIG_ATH10K) += ath10k_core.o
|
||||
ath10k_core-y += mac.o \
|
||||
debug.o \
|
||||
core.o \
|
||||
htc.o \
|
||||
htt.o \
|
||||
htt_rx.o \
|
||||
htt_tx.o \
|
||||
txrx.o \
|
||||
wmi.o \
|
||||
wmi-tlv.o \
|
||||
bmi.o \
|
||||
hw.o \
|
||||
p2p.o \
|
||||
swap.o
|
||||
|
||||
ath10k_core-$(CONFIG_ATH10K_SPECTRAL) += spectral.o
|
||||
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
|
||||
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
|
||||
ath10k_core-$(CONFIG_THERMAL) += thermal.o
|
||||
ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
|
||||
ath10k_core-$(CONFIG_PM) += wow.o
|
||||
ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o
|
||||
ath10k_core-$(CONFIG_ATH10K_CE) += ce.o
|
||||
ath10k_core-${CONFIG_FWLOG) += fwlog.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
|
||||
ath10k_pci-y += pci.o
|
||||
|
||||
ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_SDIO) += ath10k_sdio.o
|
||||
ath10k_sdio-y += sdio.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_USB) += ath10k_usb.o
|
||||
ath10k_usb-y += usb.o
|
||||
|
||||
obj-$(CONFIG_ATH10K_SNOC) += ath10k_snoc.o
|
||||
ath10k_snoc-y += qmi.o \
|
||||
qmi_wlfw_v01.o \
|
||||
snoc.o
|
||||
|
||||
# for tracing framework to find trace.h
|
||||
CFLAGS_trace.o := -I$(src)
|
879
sys/contrib/dev/athk/ath10k/ahb.c
Normal file
879
sys/contrib/dev/athk/ath10k/ahb.c
Normal file
@ -0,0 +1,879 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2016-2017 Qualcomm Atheros, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/reset.h>
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "pci.h"
|
||||
#include "ahb.h"
|
||||
|
||||
static const struct of_device_id ath10k_ahb_of_match[] = {
|
||||
{ .compatible = "qcom,ipq4019-wifi",
|
||||
.data = (void *)ATH10K_HW_QCA4019
|
||||
},
|
||||
{ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match);
|
||||
|
||||
#define QCA4019_SRAM_ADDR 0x000C0000
|
||||
#define QCA4019_SRAM_LEN 0x00040000 /* 256 kb */
|
||||
|
||||
static inline struct ath10k_ahb *ath10k_ahb_priv(struct ath10k *ar)
|
||||
{
|
||||
return &((struct ath10k_pci *)ar->drv_priv)->ahb[0];
|
||||
}
|
||||
|
||||
static void ath10k_ahb_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
iowrite32(value, ar_ahb->mem + offset);
|
||||
}
|
||||
|
||||
static u32 ath10k_ahb_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
return ioread32(ar_ahb->mem + offset);
|
||||
}
|
||||
|
||||
static u32 ath10k_ahb_gcc_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
return ioread32(ar_ahb->gcc_mem + offset);
|
||||
}
|
||||
|
||||
static void ath10k_ahb_tcsr_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
iowrite32(value, ar_ahb->tcsr_mem + offset);
|
||||
}
|
||||
|
||||
static u32 ath10k_ahb_tcsr_read32(struct ath10k *ar, u32 offset)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
return ioread32(ar_ahb->tcsr_mem + offset);
|
||||
}
|
||||
|
||||
static u32 ath10k_ahb_soc_read32(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
return ath10k_ahb_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_get_num_banks(struct ath10k *ar)
|
||||
{
|
||||
if (ar->hw_rev == ATH10K_HW_QCA4019)
|
||||
return 1;
|
||||
|
||||
ath10k_warn(ar, "unknown number of banks, assuming 1\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_clock_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
struct device *dev;
|
||||
|
||||
dev = &ar_ahb->pdev->dev;
|
||||
|
||||
ar_ahb->cmd_clk = devm_clk_get(dev, "wifi_wcss_cmd");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->cmd_clk)) {
|
||||
ath10k_err(ar, "failed to get cmd clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->cmd_clk));
|
||||
return ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV;
|
||||
}
|
||||
|
||||
ar_ahb->ref_clk = devm_clk_get(dev, "wifi_wcss_ref");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->ref_clk)) {
|
||||
ath10k_err(ar, "failed to get ref clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->ref_clk));
|
||||
return ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV;
|
||||
}
|
||||
|
||||
ar_ahb->rtc_clk = devm_clk_get(dev, "wifi_wcss_rtc");
|
||||
if (IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
|
||||
ath10k_err(ar, "failed to get rtc clk: %ld\n",
|
||||
PTR_ERR(ar_ahb->rtc_clk));
|
||||
return ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_clock_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
ar_ahb->cmd_clk = NULL;
|
||||
ar_ahb->ref_clk = NULL;
|
||||
ar_ahb->rtc_clk = NULL;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_clock_enable(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(ar_ahb->cmd_clk) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->ref_clk) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->rtc_clk)) {
|
||||
ath10k_err(ar, "clock(s) is/are not initialized\n");
|
||||
ret = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ar_ahb->cmd_clk);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable cmd clk: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ar_ahb->ref_clk);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable ref clk: %d\n", ret);
|
||||
goto err_cmd_clk_disable;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(ar_ahb->rtc_clk);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable rtc clk: %d\n", ret);
|
||||
goto err_ref_clk_disable;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_ref_clk_disable:
|
||||
clk_disable_unprepare(ar_ahb->ref_clk);
|
||||
|
||||
err_cmd_clk_disable:
|
||||
clk_disable_unprepare(ar_ahb->cmd_clk);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_clock_disable(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
clk_disable_unprepare(ar_ahb->cmd_clk);
|
||||
|
||||
clk_disable_unprepare(ar_ahb->ref_clk);
|
||||
|
||||
clk_disable_unprepare(ar_ahb->rtc_clk);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_rst_ctrl_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
struct device *dev;
|
||||
|
||||
dev = &ar_ahb->pdev->dev;
|
||||
|
||||
ar_ahb->core_cold_rst = devm_reset_control_get_exclusive(dev,
|
||||
"wifi_core_cold");
|
||||
if (IS_ERR(ar_ahb->core_cold_rst)) {
|
||||
ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n",
|
||||
PTR_ERR(ar_ahb->core_cold_rst));
|
||||
return PTR_ERR(ar_ahb->core_cold_rst);
|
||||
}
|
||||
|
||||
ar_ahb->radio_cold_rst = devm_reset_control_get_exclusive(dev,
|
||||
"wifi_radio_cold");
|
||||
if (IS_ERR(ar_ahb->radio_cold_rst)) {
|
||||
ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n",
|
||||
PTR_ERR(ar_ahb->radio_cold_rst));
|
||||
return PTR_ERR(ar_ahb->radio_cold_rst);
|
||||
}
|
||||
|
||||
ar_ahb->radio_warm_rst = devm_reset_control_get_exclusive(dev,
|
||||
"wifi_radio_warm");
|
||||
if (IS_ERR(ar_ahb->radio_warm_rst)) {
|
||||
ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n",
|
||||
PTR_ERR(ar_ahb->radio_warm_rst));
|
||||
return PTR_ERR(ar_ahb->radio_warm_rst);
|
||||
}
|
||||
|
||||
ar_ahb->radio_srif_rst = devm_reset_control_get_exclusive(dev,
|
||||
"wifi_radio_srif");
|
||||
if (IS_ERR(ar_ahb->radio_srif_rst)) {
|
||||
ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n",
|
||||
PTR_ERR(ar_ahb->radio_srif_rst));
|
||||
return PTR_ERR(ar_ahb->radio_srif_rst);
|
||||
}
|
||||
|
||||
ar_ahb->cpu_init_rst = devm_reset_control_get_exclusive(dev,
|
||||
"wifi_cpu_init");
|
||||
if (IS_ERR(ar_ahb->cpu_init_rst)) {
|
||||
ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n",
|
||||
PTR_ERR(ar_ahb->cpu_init_rst));
|
||||
return PTR_ERR(ar_ahb->cpu_init_rst);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_rst_ctrl_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
ar_ahb->core_cold_rst = NULL;
|
||||
ar_ahb->radio_cold_rst = NULL;
|
||||
ar_ahb->radio_warm_rst = NULL;
|
||||
ar_ahb->radio_srif_rst = NULL;
|
||||
ar_ahb->cpu_init_rst = NULL;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_release_reset(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
|
||||
ath10k_err(ar, "rst ctrl(s) is/are not initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(ar_ahb->radio_cold_rst);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to deassert radio cold rst: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(ar_ahb->radio_warm_rst);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to deassert radio warm rst: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(ar_ahb->radio_srif_rst);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to deassert radio srif rst: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = reset_control_deassert(ar_ahb->cpu_init_rst);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to deassert cpu init rst: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_halt_axi_bus(struct ath10k *ar, u32 haltreq_reg,
|
||||
u32 haltack_reg)
|
||||
{
|
||||
unsigned long timeout;
|
||||
u32 val;
|
||||
|
||||
/* Issue halt axi bus request */
|
||||
val = ath10k_ahb_tcsr_read32(ar, haltreq_reg);
|
||||
val |= AHB_AXI_BUS_HALT_REQ;
|
||||
ath10k_ahb_tcsr_write32(ar, haltreq_reg, val);
|
||||
|
||||
/* Wait for axi bus halted ack */
|
||||
timeout = jiffies + msecs_to_jiffies(ATH10K_AHB_AXI_BUS_HALT_TIMEOUT);
|
||||
do {
|
||||
val = ath10k_ahb_tcsr_read32(ar, haltack_reg);
|
||||
if (val & AHB_AXI_BUS_HALT_ACK)
|
||||
break;
|
||||
|
||||
mdelay(1);
|
||||
} while (time_before(jiffies, timeout));
|
||||
|
||||
if (!(val & AHB_AXI_BUS_HALT_ACK)) {
|
||||
ath10k_err(ar, "failed to halt axi bus: %d\n", val);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_AHB, "axi bus halted\n");
|
||||
}
|
||||
|
||||
static void ath10k_ahb_halt_chip(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
u32 core_id, glb_cfg_reg, haltreq_reg, haltack_reg;
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->radio_cold_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->radio_warm_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->radio_srif_rst) ||
|
||||
IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
|
||||
ath10k_err(ar, "rst ctrl(s) is/are not initialized\n");
|
||||
return;
|
||||
}
|
||||
|
||||
core_id = ath10k_ahb_read32(ar, ATH10K_AHB_WLAN_CORE_ID_REG);
|
||||
|
||||
switch (core_id) {
|
||||
case 0:
|
||||
glb_cfg_reg = ATH10K_AHB_TCSR_WIFI0_GLB_CFG;
|
||||
haltreq_reg = ATH10K_AHB_TCSR_WCSS0_HALTREQ;
|
||||
haltack_reg = ATH10K_AHB_TCSR_WCSS0_HALTACK;
|
||||
break;
|
||||
case 1:
|
||||
glb_cfg_reg = ATH10K_AHB_TCSR_WIFI1_GLB_CFG;
|
||||
haltreq_reg = ATH10K_AHB_TCSR_WCSS1_HALTREQ;
|
||||
haltack_reg = ATH10K_AHB_TCSR_WCSS1_HALTACK;
|
||||
break;
|
||||
default:
|
||||
ath10k_err(ar, "invalid core id %d found, skipping reset sequence\n",
|
||||
core_id);
|
||||
return;
|
||||
}
|
||||
|
||||
ath10k_ahb_halt_axi_bus(ar, haltreq_reg, haltack_reg);
|
||||
|
||||
val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg);
|
||||
val |= TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK;
|
||||
ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val);
|
||||
|
||||
ret = reset_control_assert(ar_ahb->core_cold_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to assert core cold rst: %d\n", ret);
|
||||
msleep(1);
|
||||
|
||||
ret = reset_control_assert(ar_ahb->radio_cold_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to assert radio cold rst: %d\n", ret);
|
||||
msleep(1);
|
||||
|
||||
ret = reset_control_assert(ar_ahb->radio_warm_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to assert radio warm rst: %d\n", ret);
|
||||
msleep(1);
|
||||
|
||||
ret = reset_control_assert(ar_ahb->radio_srif_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to assert radio srif rst: %d\n", ret);
|
||||
msleep(1);
|
||||
|
||||
ret = reset_control_assert(ar_ahb->cpu_init_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to assert cpu init rst: %d\n", ret);
|
||||
msleep(10);
|
||||
|
||||
/* Clear halt req and core clock disable req before
|
||||
* deasserting wifi core reset.
|
||||
*/
|
||||
val = ath10k_ahb_tcsr_read32(ar, haltreq_reg);
|
||||
val &= ~AHB_AXI_BUS_HALT_REQ;
|
||||
ath10k_ahb_tcsr_write32(ar, haltreq_reg, val);
|
||||
|
||||
val = ath10k_ahb_tcsr_read32(ar, glb_cfg_reg);
|
||||
val &= ~TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK;
|
||||
ath10k_ahb_tcsr_write32(ar, glb_cfg_reg, val);
|
||||
|
||||
ret = reset_control_deassert(ar_ahb->core_cold_rst);
|
||||
if (ret)
|
||||
ath10k_err(ar, "failed to deassert core cold rst: %d\n", ret);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_AHB, "core %d reset done\n", core_id);
|
||||
}
|
||||
|
||||
static irqreturn_t ath10k_ahb_interrupt_handler(int irq, void *arg)
|
||||
{
|
||||
struct ath10k *ar = arg;
|
||||
|
||||
if (!ath10k_pci_irq_pending(ar))
|
||||
return IRQ_NONE;
|
||||
|
||||
ath10k_pci_disable_and_clear_legacy_irq(ar);
|
||||
ath10k_pci_irq_msi_fw_mask(ar);
|
||||
napi_schedule(&ar->napi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_request_irq_legacy(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
int ret;
|
||||
|
||||
ret = request_irq(ar_ahb->irq,
|
||||
ath10k_ahb_interrupt_handler,
|
||||
IRQF_SHARED, "ath10k_ahb", ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to request legacy irq %d: %d\n",
|
||||
ar_ahb->irq, ret);
|
||||
return ret;
|
||||
}
|
||||
ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_release_irq_legacy(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
free_irq(ar_ahb->irq, ar);
|
||||
}
|
||||
|
||||
static void ath10k_ahb_irq_disable(struct ath10k *ar)
|
||||
{
|
||||
ath10k_ce_disable_interrupts(ar);
|
||||
ath10k_pci_disable_and_clear_legacy_irq(ar);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_resource_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
struct platform_device *pdev;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
pdev = ar_ahb->pdev;
|
||||
|
||||
ar_ahb->mem = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
|
||||
if (IS_ERR(ar_ahb->mem)) {
|
||||
ath10k_err(ar, "mem ioremap error\n");
|
||||
ret = PTR_ERR(ar_ahb->mem);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ar_ahb->mem_len = resource_size(res);
|
||||
|
||||
ar_ahb->gcc_mem = ioremap(ATH10K_GCC_REG_BASE,
|
||||
ATH10K_GCC_REG_SIZE);
|
||||
if (!ar_ahb->gcc_mem) {
|
||||
ath10k_err(ar, "gcc mem ioremap error\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_mem_unmap;
|
||||
}
|
||||
|
||||
ar_ahb->tcsr_mem = ioremap(ATH10K_TCSR_REG_BASE,
|
||||
ATH10K_TCSR_REG_SIZE);
|
||||
if (!ar_ahb->tcsr_mem) {
|
||||
ath10k_err(ar, "tcsr mem ioremap error\n");
|
||||
ret = -ENOMEM;
|
||||
goto err_gcc_mem_unmap;
|
||||
}
|
||||
|
||||
ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to set 32-bit dma mask: %d\n", ret);
|
||||
goto err_tcsr_mem_unmap;
|
||||
}
|
||||
|
||||
ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to set 32-bit consistent dma: %d\n",
|
||||
ret);
|
||||
goto err_tcsr_mem_unmap;
|
||||
}
|
||||
|
||||
ret = ath10k_ahb_clock_init(ar);
|
||||
if (ret)
|
||||
goto err_tcsr_mem_unmap;
|
||||
|
||||
ret = ath10k_ahb_rst_ctrl_init(ar);
|
||||
if (ret)
|
||||
goto err_clock_deinit;
|
||||
|
||||
ar_ahb->irq = platform_get_irq_byname(pdev, "legacy");
|
||||
if (ar_ahb->irq < 0) {
|
||||
ath10k_err(ar, "failed to get irq number: %d\n", ar_ahb->irq);
|
||||
ret = ar_ahb->irq;
|
||||
goto err_clock_deinit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "irq: %d\n", ar_ahb->irq);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "mem: 0x%pK mem_len: %lu gcc mem: 0x%pK tcsr_mem: 0x%pK\n",
|
||||
ar_ahb->mem, ar_ahb->mem_len,
|
||||
ar_ahb->gcc_mem, ar_ahb->tcsr_mem);
|
||||
return 0;
|
||||
|
||||
err_clock_deinit:
|
||||
ath10k_ahb_clock_deinit(ar);
|
||||
|
||||
err_tcsr_mem_unmap:
|
||||
iounmap(ar_ahb->tcsr_mem);
|
||||
|
||||
err_gcc_mem_unmap:
|
||||
ar_ahb->tcsr_mem = NULL;
|
||||
iounmap(ar_ahb->gcc_mem);
|
||||
|
||||
err_mem_unmap:
|
||||
ar_ahb->gcc_mem = NULL;
|
||||
devm_iounmap(&pdev->dev, ar_ahb->mem);
|
||||
|
||||
out:
|
||||
ar_ahb->mem = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_resource_deinit(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
struct device *dev;
|
||||
|
||||
dev = &ar_ahb->pdev->dev;
|
||||
|
||||
if (ar_ahb->mem)
|
||||
devm_iounmap(dev, ar_ahb->mem);
|
||||
|
||||
if (ar_ahb->gcc_mem)
|
||||
iounmap(ar_ahb->gcc_mem);
|
||||
|
||||
if (ar_ahb->tcsr_mem)
|
||||
iounmap(ar_ahb->tcsr_mem);
|
||||
|
||||
ar_ahb->mem = NULL;
|
||||
ar_ahb->gcc_mem = NULL;
|
||||
ar_ahb->tcsr_mem = NULL;
|
||||
|
||||
ath10k_ahb_clock_deinit(ar);
|
||||
ath10k_ahb_rst_ctrl_deinit(ar);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_prepare_device(struct ath10k *ar)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = ath10k_ahb_clock_enable(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to enable clocks\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Clock for the target is supplied from outside of target (ie,
|
||||
* external clock module controlled by the host). Target needs
|
||||
* to know what frequency target cpu is configured which is needed
|
||||
* for target internal use. Read target cpu frequency info from
|
||||
* gcc register and write into target's scratch register where
|
||||
* target expects this information.
|
||||
*/
|
||||
val = ath10k_ahb_gcc_read32(ar, ATH10K_AHB_GCC_FEPLL_PLL_DIV);
|
||||
ath10k_ahb_write32(ar, ATH10K_AHB_WIFI_SCRATCH_5_REG, val);
|
||||
|
||||
ret = ath10k_ahb_release_reset(ar);
|
||||
if (ret)
|
||||
goto err_clk_disable;
|
||||
|
||||
ath10k_ahb_irq_disable(ar);
|
||||
|
||||
ath10k_ahb_write32(ar, FW_INDICATOR_ADDRESS, FW_IND_HOST_READY);
|
||||
|
||||
ret = ath10k_pci_wait_for_target_init(ar);
|
||||
if (ret)
|
||||
goto err_halt_chip;
|
||||
|
||||
return 0;
|
||||
|
||||
err_halt_chip:
|
||||
ath10k_ahb_halt_chip(ar);
|
||||
|
||||
err_clk_disable:
|
||||
ath10k_ahb_clock_disable(ar);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_chip_reset(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_ahb_halt_chip(ar);
|
||||
ath10k_ahb_clock_disable(ar);
|
||||
|
||||
ret = ath10k_ahb_prepare_device(ar);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_wake_target_cpu(struct ath10k *ar)
|
||||
{
|
||||
u32 addr, val;
|
||||
|
||||
addr = SOC_CORE_BASE_ADDRESS | CORE_CTRL_ADDRESS;
|
||||
val = ath10k_ahb_read32(ar, addr);
|
||||
val |= ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK;
|
||||
ath10k_ahb_write32(ar, addr, val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_hif_start(struct ath10k *ar)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif start\n");
|
||||
|
||||
ath10k_core_napi_enable(ar);
|
||||
ath10k_ce_enable_interrupts(ar);
|
||||
ath10k_pci_enable_legacy_irq(ar);
|
||||
|
||||
ath10k_pci_rx_post(ar);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ath10k_ahb_hif_stop(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif stop\n");
|
||||
|
||||
ath10k_ahb_irq_disable(ar);
|
||||
synchronize_irq(ar_ahb->irq);
|
||||
|
||||
ath10k_core_napi_sync_disable(ar);
|
||||
|
||||
ath10k_pci_flush(ar);
|
||||
}
|
||||
|
||||
static int ath10k_ahb_hif_power_up(struct ath10k *ar,
|
||||
enum ath10k_firmware_mode fw_mode)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot ahb hif power up\n");
|
||||
|
||||
ret = ath10k_ahb_chip_reset(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to reset chip: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_pci_init_pipes(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to initialize CE: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_pci_init_config(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to setup init config: %d\n", ret);
|
||||
goto err_ce_deinit;
|
||||
}
|
||||
|
||||
ret = ath10k_ahb_wake_target_cpu(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "could not wake up target CPU: %d\n", ret);
|
||||
goto err_ce_deinit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_ce_deinit:
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 ath10k_ahb_qca4019_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
|
||||
{
|
||||
u32 val = 0, region = addr & 0xfffff;
|
||||
|
||||
val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
|
||||
|
||||
if (region >= QCA4019_SRAM_ADDR && region <=
|
||||
(QCA4019_SRAM_ADDR + QCA4019_SRAM_LEN)) {
|
||||
/* SRAM contents for QCA4019 can be directly accessed and
|
||||
* no conversions are required
|
||||
*/
|
||||
val |= region;
|
||||
} else {
|
||||
val |= 0x100000 | region;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static const struct ath10k_hif_ops ath10k_ahb_hif_ops = {
|
||||
.tx_sg = ath10k_pci_hif_tx_sg,
|
||||
.diag_read = ath10k_pci_hif_diag_read,
|
||||
.diag_write = ath10k_pci_diag_write_mem,
|
||||
.exchange_bmi_msg = ath10k_pci_hif_exchange_bmi_msg,
|
||||
.start = ath10k_ahb_hif_start,
|
||||
.stop = ath10k_ahb_hif_stop,
|
||||
.map_service_to_pipe = ath10k_pci_hif_map_service_to_pipe,
|
||||
.get_default_pipe = ath10k_pci_hif_get_default_pipe,
|
||||
.send_complete_check = ath10k_pci_hif_send_complete_check,
|
||||
.get_free_queue_number = ath10k_pci_hif_get_free_queue_number,
|
||||
.power_up = ath10k_ahb_hif_power_up,
|
||||
.power_down = ath10k_pci_hif_power_down,
|
||||
.read32 = ath10k_ahb_read32,
|
||||
.write32 = ath10k_ahb_write32,
|
||||
};
|
||||
|
||||
static const struct ath10k_bus_ops ath10k_ahb_bus_ops = {
|
||||
.read32 = ath10k_ahb_read32,
|
||||
.write32 = ath10k_ahb_write32,
|
||||
.get_num_banks = ath10k_ahb_get_num_banks,
|
||||
};
|
||||
|
||||
static int ath10k_ahb_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ath10k *ar;
|
||||
struct ath10k_ahb *ar_ahb;
|
||||
struct ath10k_pci *ar_pci;
|
||||
const struct of_device_id *of_id;
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
size_t size;
|
||||
int ret;
|
||||
struct ath10k_bus_params bus_params = {};
|
||||
|
||||
of_id = of_match_device(ath10k_ahb_of_match, &pdev->dev);
|
||||
if (!of_id) {
|
||||
dev_err(&pdev->dev, "failed to find matching device tree id\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hw_rev = (enum ath10k_hw_rev)of_id->data;
|
||||
|
||||
size = sizeof(*ar_pci) + sizeof(*ar_ahb);
|
||||
ar = ath10k_core_create(size, &pdev->dev, ATH10K_BUS_AHB,
|
||||
hw_rev, &ath10k_ahb_hif_ops);
|
||||
if (!ar) {
|
||||
dev_err(&pdev->dev, "failed to allocate core\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "ahb probe\n");
|
||||
|
||||
ar_pci = ath10k_pci_priv(ar);
|
||||
ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
ar_ahb->pdev = pdev;
|
||||
platform_set_drvdata(pdev, ar);
|
||||
|
||||
ret = ath10k_ahb_resource_init(ar);
|
||||
if (ret)
|
||||
goto err_core_destroy;
|
||||
|
||||
ar->dev_id = 0;
|
||||
ar_pci->mem = ar_ahb->mem;
|
||||
ar_pci->mem_len = ar_ahb->mem_len;
|
||||
ar_pci->ar = ar;
|
||||
ar_pci->ce.bus_ops = &ath10k_ahb_bus_ops;
|
||||
ar_pci->targ_cpu_to_ce_addr = ath10k_ahb_qca4019_targ_cpu_to_ce_addr;
|
||||
ar->ce_priv = &ar_pci->ce;
|
||||
|
||||
ret = ath10k_pci_setup_resource(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to setup resource: %d\n", ret);
|
||||
goto err_resource_deinit;
|
||||
}
|
||||
|
||||
ath10k_pci_init_napi(ar);
|
||||
|
||||
ret = ath10k_ahb_request_irq_legacy(ar);
|
||||
if (ret)
|
||||
goto err_free_pipes;
|
||||
|
||||
ret = ath10k_ahb_prepare_device(ar);
|
||||
if (ret)
|
||||
goto err_free_irq;
|
||||
|
||||
ath10k_pci_ce_deinit(ar);
|
||||
|
||||
bus_params.dev_type = ATH10K_DEV_TYPE_LL;
|
||||
bus_params.chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
|
||||
if (bus_params.chip_id == 0xffffffff) {
|
||||
ath10k_err(ar, "failed to get chip id\n");
|
||||
ret = -ENODEV;
|
||||
goto err_halt_device;
|
||||
}
|
||||
|
||||
ret = ath10k_core_register(ar, &bus_params);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to register driver core: %d\n", ret);
|
||||
goto err_halt_device;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_halt_device:
|
||||
ath10k_ahb_halt_chip(ar);
|
||||
ath10k_ahb_clock_disable(ar);
|
||||
|
||||
err_free_irq:
|
||||
ath10k_ahb_release_irq_legacy(ar);
|
||||
|
||||
err_free_pipes:
|
||||
ath10k_pci_release_resource(ar);
|
||||
|
||||
err_resource_deinit:
|
||||
ath10k_ahb_resource_deinit(ar);
|
||||
|
||||
err_core_destroy:
|
||||
ath10k_core_destroy(ar);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_ahb_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ath10k *ar = platform_get_drvdata(pdev);
|
||||
struct ath10k_ahb *ar_ahb;
|
||||
|
||||
if (!ar)
|
||||
return -EINVAL;
|
||||
|
||||
ar_ahb = ath10k_ahb_priv(ar);
|
||||
|
||||
if (!ar_ahb)
|
||||
return -EINVAL;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_AHB, "ahb remove\n");
|
||||
|
||||
ath10k_core_unregister(ar);
|
||||
ath10k_ahb_irq_disable(ar);
|
||||
ath10k_ahb_release_irq_legacy(ar);
|
||||
ath10k_pci_release_resource(ar);
|
||||
ath10k_ahb_halt_chip(ar);
|
||||
ath10k_ahb_clock_disable(ar);
|
||||
ath10k_ahb_resource_deinit(ar);
|
||||
ath10k_core_destroy(ar);
|
||||
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver ath10k_ahb_driver = {
|
||||
.driver = {
|
||||
.name = "ath10k_ahb",
|
||||
.of_match_table = ath10k_ahb_of_match,
|
||||
},
|
||||
.probe = ath10k_ahb_probe,
|
||||
.remove = ath10k_ahb_remove,
|
||||
};
|
||||
|
||||
int ath10k_ahb_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = platform_driver_register(&ath10k_ahb_driver);
|
||||
if (ret)
|
||||
printk(KERN_ERR "failed to register ath10k ahb driver: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath10k_ahb_exit(void)
|
||||
{
|
||||
platform_driver_unregister(&ath10k_ahb_driver);
|
||||
}
|
76
sys/contrib/dev/athk/ath10k/ahb.h
Normal file
76
sys/contrib/dev/athk/ath10k/ahb.h
Normal file
@ -0,0 +1,76 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _AHB_H_
|
||||
#define _AHB_H_
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
struct ath10k_ahb {
|
||||
struct platform_device *pdev;
|
||||
void __iomem *mem;
|
||||
unsigned long mem_len;
|
||||
void __iomem *gcc_mem;
|
||||
void __iomem *tcsr_mem;
|
||||
|
||||
int irq;
|
||||
|
||||
struct clk *cmd_clk;
|
||||
struct clk *ref_clk;
|
||||
struct clk *rtc_clk;
|
||||
|
||||
struct reset_control *core_cold_rst;
|
||||
struct reset_control *radio_cold_rst;
|
||||
struct reset_control *radio_warm_rst;
|
||||
struct reset_control *radio_srif_rst;
|
||||
struct reset_control *cpu_init_rst;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH10K_AHB
|
||||
|
||||
#define ATH10K_GCC_REG_BASE 0x1800000
|
||||
#define ATH10K_GCC_REG_SIZE 0x60000
|
||||
|
||||
#define ATH10K_TCSR_REG_BASE 0x1900000
|
||||
#define ATH10K_TCSR_REG_SIZE 0x80000
|
||||
|
||||
#define ATH10K_AHB_GCC_FEPLL_PLL_DIV 0x2f020
|
||||
#define ATH10K_AHB_WIFI_SCRATCH_5_REG 0x4f014
|
||||
|
||||
#define ATH10K_AHB_WLAN_CORE_ID_REG 0x82030
|
||||
|
||||
#define ATH10K_AHB_TCSR_WIFI0_GLB_CFG 0x49000
|
||||
#define ATH10K_AHB_TCSR_WIFI1_GLB_CFG 0x49004
|
||||
#define TCSR_WIFIX_GLB_CFG_DISABLE_CORE_CLK BIT(25)
|
||||
|
||||
#define ATH10K_AHB_TCSR_WCSS0_HALTREQ 0x52000
|
||||
#define ATH10K_AHB_TCSR_WCSS1_HALTREQ 0x52010
|
||||
#define ATH10K_AHB_TCSR_WCSS0_HALTACK 0x52004
|
||||
#define ATH10K_AHB_TCSR_WCSS1_HALTACK 0x52014
|
||||
|
||||
#define ATH10K_AHB_AXI_BUS_HALT_TIMEOUT 10 /* msec */
|
||||
#define AHB_AXI_BUS_HALT_REQ 1
|
||||
#define AHB_AXI_BUS_HALT_ACK 1
|
||||
|
||||
#define ATH10K_AHB_CORE_CTRL_CPU_INTR_MASK 1
|
||||
|
||||
int ath10k_ahb_init(void);
|
||||
void ath10k_ahb_exit(void);
|
||||
|
||||
#else /* CONFIG_ATH10K_AHB */
|
||||
|
||||
static inline int ath10k_ahb_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_ahb_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH10K_AHB */
|
||||
|
||||
#endif /* _AHB_H_ */
|
539
sys/contrib/dev/athk/ath10k/bmi.c
Normal file
539
sys/contrib/dev/athk/ath10k/bmi.c
Normal file
@ -0,0 +1,539 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2014,2016-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include "bmi.h"
|
||||
#include "hif.h"
|
||||
#include "debug.h"
|
||||
#include "htc.h"
|
||||
#include "hw.h"
|
||||
|
||||
void ath10k_bmi_start(struct ath10k *ar)
|
||||
{
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi start\n");
|
||||
|
||||
ar->bmi.done_sent = false;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_bmi_start);
|
||||
|
||||
int ath10k_bmi_done(struct ath10k *ar)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.done);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi done\n");
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi skipped\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
ar->bmi.done_sent = true;
|
||||
cmd.id = __cpu_to_le32(BMI_DONE);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
|
||||
u32 resplen = sizeof(resp.get_target_info);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info\n");
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to get target info from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (resplen < sizeof(resp.get_target_info)) {
|
||||
ath10k_warn(ar, "invalid get_target_info response length (%d)\n",
|
||||
resplen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
target_info->version = __le32_to_cpu(resp.get_target_info.version);
|
||||
target_info->type = __le32_to_cpu(resp.get_target_info.type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define TARGET_VERSION_SENTINAL 0xffffffffu
|
||||
|
||||
int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.get_target_info);
|
||||
u32 resplen, ver_len;
|
||||
__le32 tmp;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi get target info SDIO\n");
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "BMI Get Target Info Command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_GET_TARGET_INFO);
|
||||
|
||||
/* Step 1: Read 4 bytes of the target info and check if it is
|
||||
* the special sentinal version word or the first word in the
|
||||
* version response.
|
||||
*/
|
||||
resplen = sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &tmp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Some SDIO boards have a special sentinal byte before the real
|
||||
* version response.
|
||||
*/
|
||||
if (__le32_to_cpu(tmp) == TARGET_VERSION_SENTINAL) {
|
||||
/* Step 1b: Read the version length */
|
||||
resplen = sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0, &tmp,
|
||||
&resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
ver_len = __le32_to_cpu(tmp);
|
||||
|
||||
/* Step 2: Check the target info length */
|
||||
if (ver_len != sizeof(resp.get_target_info)) {
|
||||
ath10k_warn(ar, "Unexpected target info len: %u. Expected: %zu\n",
|
||||
ver_len, sizeof(resp.get_target_info));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Step 3: Read the rest of the version response */
|
||||
resplen = sizeof(resp.get_target_info) - sizeof(u32);
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, NULL, 0,
|
||||
&resp.get_target_info.version,
|
||||
&resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
target_info->version = __le32_to_cpu(resp.get_target_info.version);
|
||||
target_info->type = __le32_to_cpu(resp.get_target_info.type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar,
|
||||
#if defined(__linux__)
|
||||
u32 address, void *buffer, u32 length)
|
||||
#elif defined(__FreeBSD__)
|
||||
u32 address, u8 *buffer, u32 length)
|
||||
#endif
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_mem);
|
||||
u32 rxlen;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read address 0x%x length %d\n",
|
||||
address, length);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
while (length) {
|
||||
rxlen = min_t(u32, length, BMI_MAX_DATA_SIZE);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_READ_MEMORY);
|
||||
cmd.read_mem.addr = __cpu_to_le32(address);
|
||||
cmd.read_mem.len = __cpu_to_le32(rxlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen,
|
||||
&resp, &rxlen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from the device (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(buffer, resp.read_mem.payload, rxlen);
|
||||
address += rxlen;
|
||||
buffer += rxlen;
|
||||
length -= rxlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ath10k_bmi_read_memory);
|
||||
|
||||
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.write_soc_reg);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI,
|
||||
"bmi write soc register 0x%08x val 0x%08x\n",
|
||||
address, reg_val);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "bmi write soc register command in progress\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_WRITE_SOC_REGISTER);
|
||||
cmd.write_soc_reg.addr = __cpu_to_le32(address);
|
||||
cmd.write_soc_reg.value = __cpu_to_le32(reg_val);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "Unable to write soc register to device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.read_soc_reg);
|
||||
u32 resplen = sizeof(resp.read_soc_reg);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register 0x%08x\n",
|
||||
address);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "bmi read soc register command in progress\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_READ_SOC_REGISTER);
|
||||
cmd.read_soc_reg.addr = __cpu_to_le32(address);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "Unable to read soc register from device: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*reg_val = __le32_to_cpu(resp.read_soc_reg.value);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi read soc register value 0x%08x\n",
|
||||
*reg_val);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar,
|
||||
#if defined(__linux__)
|
||||
u32 address, const void *buffer, u32 length)
|
||||
#elif defined(__FreeBSD__)
|
||||
u32 address, const u8 *buffer, u32 length)
|
||||
#endif
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.write_mem);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi write address 0x%x length %d\n",
|
||||
address, length);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
|
||||
|
||||
/* copy before roundup to avoid reading beyond buffer*/
|
||||
memcpy(cmd.write_mem.payload, buffer, txlen);
|
||||
txlen = roundup(txlen, 4);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_WRITE_MEMORY);
|
||||
cmd.write_mem.addr = __cpu_to_le32(address);
|
||||
cmd.write_mem.len = __cpu_to_le32(txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* fixup roundup() so `length` zeroes out for last chunk */
|
||||
txlen = min(txlen, length);
|
||||
|
||||
address += txlen;
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
union bmi_resp resp;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.execute);
|
||||
u32 resplen = sizeof(resp.execute);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute address 0x%x param 0x%x\n",
|
||||
address, param);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_EXECUTE);
|
||||
cmd.execute.addr = __cpu_to_le32(address);
|
||||
cmd.execute.param = __cpu_to_le32(param);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, &resp, &resplen);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to read from the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (resplen < sizeof(resp.execute)) {
|
||||
ath10k_warn(ar, "invalid execute response length (%d)\n",
|
||||
resplen);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
*result = __le32_to_cpu(resp.execute.result);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi execute result 0x%x\n", *result);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
static int ath10k_bmi_lz_data_large(struct ath10k *ar, const void *buffer, u32 length)
|
||||
#elif defined(__FreeBSD__)
|
||||
static int ath10k_bmi_lz_data_large(struct ath10k *ar, const u8 *buffer, u32 length)
|
||||
#endif
|
||||
{
|
||||
struct bmi_cmd *cmd;
|
||||
u32 hdrlen = sizeof(cmd->id) + sizeof(cmd->lz_data);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
size_t buf_len;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "large bmi lz data buffer 0x%pK length %d\n",
|
||||
buffer, length);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
buf_len = sizeof(*cmd) + BMI_MAX_LARGE_DATA_SIZE - BMI_MAX_DATA_SIZE;
|
||||
cmd = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_LARGE_DATA_SIZE - hdrlen);
|
||||
|
||||
WARN_ON_ONCE(txlen & 3);
|
||||
|
||||
cmd->id = __cpu_to_le32(BMI_LZ_DATA);
|
||||
cmd->lz_data.len = __cpu_to_le32(txlen);
|
||||
memcpy(cmd->lz_data.payload, buffer, txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device\n");
|
||||
kfree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
kfree(cmd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(__linux__)
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length)
|
||||
#elif defined(__FreeBSD__)
|
||||
static
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const u8 *buffer, u32 length)
|
||||
#endif
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 hdrlen = sizeof(cmd.id) + sizeof(cmd.lz_data);
|
||||
u32 txlen;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz data buffer 0x%pK length %d\n",
|
||||
buffer, length);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
while (length) {
|
||||
txlen = min(length, BMI_MAX_DATA_SIZE - hdrlen);
|
||||
|
||||
WARN_ON_ONCE(txlen & 3);
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_LZ_DATA);
|
||||
cmd.lz_data.len = __cpu_to_le32(txlen);
|
||||
memcpy(cmd.lz_data.payload, buffer, txlen);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, hdrlen + txlen,
|
||||
NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to write to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
buffer += txlen;
|
||||
length -= txlen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.lz_start);
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI, "bmi lz stream start address 0x%x\n",
|
||||
address);
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_LZ_STREAM_START);
|
||||
cmd.lz_start.addr = __cpu_to_le32(address);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to Start LZ Stream to the device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar,
|
||||
u32 address, const void *buffer, u32 length)
|
||||
{
|
||||
u8 trailer[4] = {};
|
||||
u32 head_len = rounddown(length, 4);
|
||||
u32 trailer_len = length - head_len;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BMI,
|
||||
"bmi fast download address 0x%x buffer 0x%pK length %d\n",
|
||||
address, buffer, length);
|
||||
|
||||
ret = ath10k_bmi_lz_stream_start(ar, address);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* copy the last word into a zero padded buffer */
|
||||
if (trailer_len > 0)
|
||||
#if defined(__linux__)
|
||||
memcpy(trailer, buffer + head_len, trailer_len);
|
||||
#elif defined(__FreeBSD__)
|
||||
memcpy(trailer, (const u8 *)buffer + head_len, trailer_len);
|
||||
#endif
|
||||
|
||||
if (ar->hw_params.bmi_large_size_download)
|
||||
ret = ath10k_bmi_lz_data_large(ar, buffer, head_len);
|
||||
else
|
||||
ret = ath10k_bmi_lz_data(ar, buffer, head_len);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (trailer_len > 0)
|
||||
ret = ath10k_bmi_lz_data(ar, trailer, 4);
|
||||
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Close compressed stream and open a new (fake) one.
|
||||
* This serves mainly to flush Target caches.
|
||||
*/
|
||||
ret = ath10k_bmi_lz_stream_start(ar, 0x00);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_bmi_set_start(struct ath10k *ar, u32 address)
|
||||
{
|
||||
struct bmi_cmd cmd;
|
||||
u32 cmdlen = sizeof(cmd.id) + sizeof(cmd.set_app_start);
|
||||
int ret;
|
||||
|
||||
if (ar->bmi.done_sent) {
|
||||
ath10k_warn(ar, "bmi set start command disallowed\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
cmd.id = __cpu_to_le32(BMI_SET_APP_START);
|
||||
cmd.set_app_start.addr = __cpu_to_le32(address);
|
||||
|
||||
ret = ath10k_hif_exchange_bmi_msg(ar, &cmd, cmdlen, NULL, NULL);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "unable to set start to the device:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
286
sys/contrib/dev/athk/ath10k/bmi.h
Normal file
286
sys/contrib/dev/athk/ath10k/bmi.h
Normal file
@ -0,0 +1,286 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2015,2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _BMI_H_
|
||||
#define _BMI_H_
|
||||
|
||||
#include "core.h"
|
||||
|
||||
/*
|
||||
* Bootloader Messaging Interface (BMI)
|
||||
*
|
||||
* BMI is a very simple messaging interface used during initialization
|
||||
* to read memory, write memory, execute code, and to define an
|
||||
* application entry PC.
|
||||
*
|
||||
* It is used to download an application to QCA988x, to provide
|
||||
* patches to code that is already resident on QCA988x, and generally
|
||||
* to examine and modify state. The Host has an opportunity to use
|
||||
* BMI only once during bootup. Once the Host issues a BMI_DONE
|
||||
* command, this opportunity ends.
|
||||
*
|
||||
* The Host writes BMI requests to mailbox0, and reads BMI responses
|
||||
* from mailbox0. BMI requests all begin with a command
|
||||
* (see below for specific commands), and are followed by
|
||||
* command-specific data.
|
||||
*
|
||||
* Flow control:
|
||||
* The Host can only issue a command once the Target gives it a
|
||||
* "BMI Command Credit", using AR8K Counter #4. As soon as the
|
||||
* Target has completed a command, it issues another BMI Command
|
||||
* Credit (so the Host can issue the next command).
|
||||
*
|
||||
* BMI handles all required Target-side cache flushing.
|
||||
*/
|
||||
|
||||
/* Maximum data size used for BMI transfers */
|
||||
#define BMI_MAX_DATA_SIZE 256
|
||||
|
||||
/* len = cmd + addr + length */
|
||||
#define BMI_MAX_CMDBUF_SIZE (BMI_MAX_DATA_SIZE + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32))
|
||||
|
||||
/* Maximum data size used for large BMI transfers */
|
||||
#define BMI_MAX_LARGE_DATA_SIZE 2048
|
||||
|
||||
/* len = cmd + addr + length */
|
||||
#define BMI_MAX_LARGE_CMDBUF_SIZE (BMI_MAX_LARGE_DATA_SIZE + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32) + \
|
||||
sizeof(u32))
|
||||
|
||||
/* BMI Commands */
|
||||
|
||||
enum bmi_cmd_id {
|
||||
BMI_NO_COMMAND = 0,
|
||||
BMI_DONE = 1,
|
||||
BMI_READ_MEMORY = 2,
|
||||
BMI_WRITE_MEMORY = 3,
|
||||
BMI_EXECUTE = 4,
|
||||
BMI_SET_APP_START = 5,
|
||||
BMI_READ_SOC_REGISTER = 6,
|
||||
BMI_READ_SOC_WORD = 6,
|
||||
BMI_WRITE_SOC_REGISTER = 7,
|
||||
BMI_WRITE_SOC_WORD = 7,
|
||||
BMI_GET_TARGET_ID = 8,
|
||||
BMI_GET_TARGET_INFO = 8,
|
||||
BMI_ROMPATCH_INSTALL = 9,
|
||||
BMI_ROMPATCH_UNINSTALL = 10,
|
||||
BMI_ROMPATCH_ACTIVATE = 11,
|
||||
BMI_ROMPATCH_DEACTIVATE = 12,
|
||||
BMI_LZ_STREAM_START = 13, /* should be followed by LZ_DATA */
|
||||
BMI_LZ_DATA = 14,
|
||||
BMI_NVRAM_PROCESS = 15,
|
||||
};
|
||||
|
||||
#define BMI_NVRAM_SEG_NAME_SZ 16
|
||||
|
||||
#define BMI_PARAM_GET_EEPROM_BOARD_ID 0x10
|
||||
#define BMI_PARAM_GET_FLASH_BOARD_ID 0x8000
|
||||
#define BMI_PARAM_FLASH_SECTION_ALL 0x10000
|
||||
|
||||
/* Dual-band Extended Board ID */
|
||||
#define BMI_PARAM_GET_EXT_BOARD_ID 0x40000
|
||||
#define ATH10K_BMI_EXT_BOARD_ID_SUPPORT 0x40000
|
||||
|
||||
#define ATH10K_BMI_BOARD_ID_FROM_OTP_MASK 0x7c00
|
||||
#define ATH10K_BMI_BOARD_ID_FROM_OTP_LSB 10
|
||||
|
||||
#define ATH10K_BMI_CHIP_ID_FROM_OTP_MASK 0x18000
|
||||
#define ATH10K_BMI_CHIP_ID_FROM_OTP_LSB 15
|
||||
|
||||
#define ATH10K_BMI_BOARD_ID_STATUS_MASK 0xff
|
||||
#define ATH10K_BMI_EBOARD_ID_STATUS_MASK 0xff
|
||||
|
||||
struct bmi_cmd {
|
||||
__le32 id; /* enum bmi_cmd_id */
|
||||
union {
|
||||
struct {
|
||||
} done;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
} read_mem;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 len;
|
||||
u8 payload[];
|
||||
} write_mem;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 param;
|
||||
} execute;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} set_app_start;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} read_soc_reg;
|
||||
struct {
|
||||
__le32 addr;
|
||||
__le32 value;
|
||||
} write_soc_reg;
|
||||
struct {
|
||||
} get_target_info;
|
||||
struct {
|
||||
__le32 rom_addr;
|
||||
__le32 ram_addr; /* or value */
|
||||
__le32 size;
|
||||
__le32 activate; /* 0=install, but dont activate */
|
||||
} rompatch_install;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_uninstall;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[]; /* length of @count */
|
||||
} rompatch_activate;
|
||||
struct {
|
||||
__le32 count;
|
||||
__le32 patch_ids[]; /* length of @count */
|
||||
} rompatch_deactivate;
|
||||
struct {
|
||||
__le32 addr;
|
||||
} lz_start;
|
||||
struct {
|
||||
__le32 len; /* max BMI_MAX_DATA_SIZE */
|
||||
u8 payload[]; /* length of @len */
|
||||
} lz_data;
|
||||
struct {
|
||||
u8 name[BMI_NVRAM_SEG_NAME_SZ];
|
||||
} nvram_process;
|
||||
u8 payload[BMI_MAX_CMDBUF_SIZE];
|
||||
};
|
||||
} __packed;
|
||||
|
||||
union bmi_resp {
|
||||
struct {
|
||||
DECLARE_FLEX_ARRAY(u8, payload);
|
||||
} read_mem;
|
||||
struct {
|
||||
__le32 result;
|
||||
} execute;
|
||||
struct {
|
||||
__le32 value;
|
||||
} read_soc_reg;
|
||||
struct {
|
||||
__le32 len;
|
||||
__le32 version;
|
||||
__le32 type;
|
||||
} get_target_info;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_install;
|
||||
struct {
|
||||
__le32 patch_id;
|
||||
} rompatch_uninstall;
|
||||
struct {
|
||||
/* 0 = nothing executed
|
||||
* otherwise = NVRAM segment return value
|
||||
*/
|
||||
__le32 result;
|
||||
} nvram_process;
|
||||
u8 payload[BMI_MAX_CMDBUF_SIZE];
|
||||
} __packed;
|
||||
|
||||
struct bmi_target_info {
|
||||
u32 version;
|
||||
u32 type;
|
||||
};
|
||||
|
||||
struct bmi_segmented_file_header {
|
||||
__le32 magic_num;
|
||||
__le32 file_flags;
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
struct bmi_segmented_metadata {
|
||||
__le32 addr;
|
||||
__le32 length;
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
#define BMI_SGMTFILE_MAGIC_NUM 0x544d4753 /* "SGMT" */
|
||||
#define BMI_SGMTFILE_FLAG_COMPRESS 1
|
||||
|
||||
/* Special values for bmi_segmented_metadata.length (all have high bit set) */
|
||||
|
||||
/* end of segmented data */
|
||||
#define BMI_SGMTFILE_DONE 0xffffffff
|
||||
|
||||
/* Board Data segment */
|
||||
#define BMI_SGMTFILE_BDDATA 0xfffffffe
|
||||
|
||||
/* set beginning address */
|
||||
#define BMI_SGMTFILE_BEGINADDR 0xfffffffd
|
||||
|
||||
/* immediate function execution */
|
||||
#define BMI_SGMTFILE_EXEC 0xfffffffc
|
||||
|
||||
/* in jiffies */
|
||||
#define BMI_COMMUNICATION_TIMEOUT_HZ (3 * HZ)
|
||||
|
||||
#define BMI_CE_NUM_TO_TARG 0
|
||||
#define BMI_CE_NUM_TO_HOST 1
|
||||
|
||||
void ath10k_bmi_start(struct ath10k *ar);
|
||||
int ath10k_bmi_done(struct ath10k *ar);
|
||||
int ath10k_bmi_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
int ath10k_bmi_get_target_info_sdio(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
#if defined(__linux__)
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar, u32 address,
|
||||
void *buffer, u32 length);
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
const void *buffer, u32 length);
|
||||
#elif defined(__FreeBSD__)
|
||||
int ath10k_bmi_read_memory(struct ath10k *ar, u32 address,
|
||||
u8 *buffer, u32 length);
|
||||
int ath10k_bmi_write_memory(struct ath10k *ar, u32 address,
|
||||
const u8 *buffer, u32 length);
|
||||
#endif
|
||||
|
||||
#define ath10k_bmi_read32(ar, item, val) \
|
||||
({ \
|
||||
int ret; \
|
||||
u32 addr; \
|
||||
__le32 tmp; \
|
||||
\
|
||||
addr = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_read_memory(ar, addr, (u8 *)&tmp, 4); \
|
||||
if (!ret) \
|
||||
*val = __le32_to_cpu(tmp); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
#define ath10k_bmi_write32(ar, item, val) \
|
||||
({ \
|
||||
int ret; \
|
||||
u32 address; \
|
||||
__le32 v = __cpu_to_le32(val); \
|
||||
\
|
||||
address = host_interest_item_address(HI_ITEM(item)); \
|
||||
ret = ath10k_bmi_write_memory(ar, address, \
|
||||
(u8 *)&v, sizeof(v)); \
|
||||
ret; \
|
||||
})
|
||||
|
||||
int ath10k_bmi_execute(struct ath10k *ar, u32 address, u32 param, u32 *result);
|
||||
int ath10k_bmi_lz_stream_start(struct ath10k *ar, u32 address);
|
||||
#if defined(__linux__)
|
||||
int ath10k_bmi_lz_data(struct ath10k *ar, const void *buffer, u32 length);
|
||||
#endif
|
||||
|
||||
int ath10k_bmi_fast_download(struct ath10k *ar, u32 address,
|
||||
const void *buffer, u32 length);
|
||||
int ath10k_bmi_read_soc_reg(struct ath10k *ar, u32 address, u32 *reg_val);
|
||||
int ath10k_bmi_write_soc_reg(struct ath10k *ar, u32 address, u32 reg_val);
|
||||
int ath10k_bmi_set_start(struct ath10k *ar, u32 address);
|
||||
|
||||
#endif /* _BMI_H_ */
|
2047
sys/contrib/dev/athk/ath10k/ce.c
Normal file
2047
sys/contrib/dev/athk/ath10k/ce.c
Normal file
File diff suppressed because it is too large
Load Diff
427
sys/contrib/dev/athk/ath10k/ce.h
Normal file
427
sys/contrib/dev/athk/ath10k/ce.h
Normal file
@ -0,0 +1,427 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _CE_H_
|
||||
#define _CE_H_
|
||||
|
||||
#include "hif.h"
|
||||
|
||||
#define CE_HTT_H2T_MSG_SRC_NENTRIES 8192
|
||||
|
||||
/* Descriptor rings must be aligned to this boundary */
|
||||
#define CE_DESC_RING_ALIGN 8
|
||||
#define CE_SEND_FLAG_GATHER 0x00010000
|
||||
|
||||
/*
|
||||
* Copy Engine support: low-level Target-side Copy Engine API.
|
||||
* This is a hardware access layer used by code that understands
|
||||
* how to use copy engines.
|
||||
*/
|
||||
|
||||
struct ath10k_ce_pipe;
|
||||
|
||||
#define CE_DESC_FLAGS_GATHER (1 << 0)
|
||||
#define CE_DESC_FLAGS_BYTE_SWAP (1 << 1)
|
||||
#define CE_WCN3990_DESC_FLAGS_GATHER BIT(31)
|
||||
|
||||
#define CE_DESC_ADDR_MASK GENMASK_ULL(34, 0)
|
||||
#define CE_DESC_ADDR_HI_MASK GENMASK(4, 0)
|
||||
|
||||
/* Following desc flags are used in QCA99X0 */
|
||||
#define CE_DESC_FLAGS_HOST_INT_DIS (1 << 2)
|
||||
#define CE_DESC_FLAGS_TGT_INT_DIS (1 << 3)
|
||||
|
||||
#define CE_DESC_FLAGS_META_DATA_MASK ar->hw_values->ce_desc_meta_data_mask
|
||||
#define CE_DESC_FLAGS_META_DATA_LSB ar->hw_values->ce_desc_meta_data_lsb
|
||||
|
||||
#define CE_DDR_RRI_MASK GENMASK(15, 0)
|
||||
#define CE_DDR_DRRI_SHIFT 16
|
||||
|
||||
struct ce_desc {
|
||||
__le32 addr;
|
||||
__le16 nbytes;
|
||||
__le16 flags; /* %CE_DESC_FLAGS_ */
|
||||
};
|
||||
|
||||
struct ce_desc_64 {
|
||||
__le64 addr;
|
||||
__le16 nbytes; /* length in register map */
|
||||
__le16 flags; /* fw_metadata_high */
|
||||
__le32 toeplitz_hash_result;
|
||||
};
|
||||
|
||||
#define CE_DESC_SIZE sizeof(struct ce_desc)
|
||||
#define CE_DESC_SIZE_64 sizeof(struct ce_desc_64)
|
||||
|
||||
struct ath10k_ce_ring {
|
||||
/* Number of entries in this ring; must be power of 2 */
|
||||
unsigned int nentries;
|
||||
unsigned int nentries_mask;
|
||||
|
||||
/*
|
||||
* For dest ring, this is the next index to be processed
|
||||
* by software after it was/is received into.
|
||||
*
|
||||
* For src ring, this is the last descriptor that was sent
|
||||
* and completion processed by software.
|
||||
*
|
||||
* Regardless of src or dest ring, this is an invariant
|
||||
* (modulo ring size):
|
||||
* write index >= read index >= sw_index
|
||||
*/
|
||||
unsigned int sw_index;
|
||||
/* cached copy */
|
||||
unsigned int write_index;
|
||||
/*
|
||||
* For src ring, this is the next index not yet processed by HW.
|
||||
* This is a cached copy of the real HW index (read index), used
|
||||
* for avoiding reading the HW index register more often than
|
||||
* necessary.
|
||||
* This extends the invariant:
|
||||
* write index >= read index >= hw_index >= sw_index
|
||||
*
|
||||
* For dest ring, this is currently unused.
|
||||
*/
|
||||
/* cached copy */
|
||||
unsigned int hw_index;
|
||||
|
||||
/* Start of DMA-coherent area reserved for descriptors */
|
||||
/* Host address space */
|
||||
void *base_addr_owner_space_unaligned;
|
||||
/* CE address space */
|
||||
dma_addr_t base_addr_ce_space_unaligned;
|
||||
|
||||
/*
|
||||
* Actual start of descriptors.
|
||||
* Aligned to descriptor-size boundary.
|
||||
* Points into reserved DMA-coherent area, above.
|
||||
*/
|
||||
/* Host address space */
|
||||
void *base_addr_owner_space;
|
||||
|
||||
/* CE address space */
|
||||
dma_addr_t base_addr_ce_space;
|
||||
|
||||
char *shadow_base_unaligned;
|
||||
struct ce_desc_64 *shadow_base;
|
||||
|
||||
/* keep last */
|
||||
void *per_transfer_context[];
|
||||
};
|
||||
|
||||
struct ath10k_ce_pipe {
|
||||
struct ath10k *ar;
|
||||
unsigned int id;
|
||||
|
||||
unsigned int attr_flags;
|
||||
|
||||
u32 ctrl_addr;
|
||||
|
||||
void (*send_cb)(struct ath10k_ce_pipe *);
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *);
|
||||
|
||||
unsigned int src_sz_max;
|
||||
struct ath10k_ce_ring *src_ring;
|
||||
struct ath10k_ce_ring *dest_ring;
|
||||
const struct ath10k_ce_ops *ops;
|
||||
};
|
||||
|
||||
/* Copy Engine settable attributes */
|
||||
struct ce_attr;
|
||||
|
||||
struct ath10k_bus_ops {
|
||||
u32 (*read32)(struct ath10k *ar, u32 offset);
|
||||
void (*write32)(struct ath10k *ar, u32 offset, u32 value);
|
||||
int (*get_num_banks)(struct ath10k *ar);
|
||||
};
|
||||
|
||||
static inline struct ath10k_ce *ath10k_ce_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_ce *)ar->ce_priv;
|
||||
}
|
||||
|
||||
struct ath10k_ce {
|
||||
/* protects CE info */
|
||||
spinlock_t ce_lock;
|
||||
const struct ath10k_bus_ops *bus_ops;
|
||||
struct ath10k_ce_pipe ce_states[CE_COUNT_MAX];
|
||||
u32 *vaddr_rri;
|
||||
dma_addr_t paddr_rri;
|
||||
};
|
||||
|
||||
/*==================Send====================*/
|
||||
|
||||
/* ath10k_ce_send flags */
|
||||
#define CE_SEND_FLAG_BYTE_SWAP 1
|
||||
|
||||
/*
|
||||
* Queue a source buffer to be sent to an anonymous destination buffer.
|
||||
* ce - which copy engine to use
|
||||
* buffer - address of buffer
|
||||
* nbytes - number of bytes to send
|
||||
* transfer_id - arbitrary ID; reflected to destination
|
||||
* flags - CE_SEND_FLAG_* values
|
||||
* Returns 0 on success; otherwise an error status.
|
||||
*
|
||||
* Note: If no flags are specified, use CE's default data swap mode.
|
||||
*
|
||||
* Implementation note: pushes 1 buffer to Source ring
|
||||
*/
|
||||
int ath10k_ce_send(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_send_context,
|
||||
dma_addr_t buffer,
|
||||
unsigned int nbytes,
|
||||
/* 14 bits */
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
int ath10k_ce_send_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void *per_transfer_context,
|
||||
dma_addr_t buffer,
|
||||
unsigned int nbytes,
|
||||
unsigned int transfer_id,
|
||||
unsigned int flags);
|
||||
|
||||
void __ath10k_ce_send_revert(struct ath10k_ce_pipe *pipe);
|
||||
|
||||
int ath10k_ce_num_free_src_entries(struct ath10k_ce_pipe *pipe);
|
||||
|
||||
/*==================Recv=======================*/
|
||||
|
||||
int __ath10k_ce_rx_num_free_bufs(struct ath10k_ce_pipe *pipe);
|
||||
int ath10k_ce_rx_post_buf(struct ath10k_ce_pipe *pipe, void *ctx,
|
||||
dma_addr_t paddr);
|
||||
void ath10k_ce_rx_update_write_idx(struct ath10k_ce_pipe *pipe, u32 nentries);
|
||||
|
||||
/* recv flags */
|
||||
/* Data is byte-swapped */
|
||||
#define CE_RECV_FLAG_SWAPPED 1
|
||||
|
||||
/*
|
||||
* Supply data for the next completed unprocessed receive descriptor.
|
||||
* Pops buffer from Dest ring.
|
||||
*/
|
||||
int ath10k_ce_completed_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
unsigned int *nbytesp);
|
||||
/*
|
||||
* Supply data for the next completed unprocessed send descriptor.
|
||||
* Pops 1 completed send buffer from Source ring.
|
||||
*/
|
||||
int ath10k_ce_completed_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp);
|
||||
|
||||
int ath10k_ce_completed_send_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp);
|
||||
|
||||
/*==================CE Engine Initialization=======================*/
|
||||
|
||||
int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_deinit_pipe(struct ath10k *ar, unsigned int ce_id);
|
||||
int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
|
||||
const struct ce_attr *attr);
|
||||
void ath10k_ce_free_pipe(struct ath10k *ar, int ce_id);
|
||||
|
||||
/*==================CE Engine Shutdown=======================*/
|
||||
/*
|
||||
* Support clean shutdown by allowing the caller to revoke
|
||||
* receive buffers. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_revoke_recv_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
dma_addr_t *bufferp);
|
||||
|
||||
int ath10k_ce_completed_recv_next_nolock(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
unsigned int *nbytesp);
|
||||
|
||||
/*
|
||||
* Support clean shutdown by allowing the caller to cancel
|
||||
* pending sends. Target DMA must be stopped before using
|
||||
* this API.
|
||||
*/
|
||||
int ath10k_ce_cancel_send_next(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
dma_addr_t *bufferp,
|
||||
unsigned int *nbytesp,
|
||||
unsigned int *transfer_idp);
|
||||
|
||||
/*==================CE Interrupt Handlers====================*/
|
||||
void ath10k_ce_per_engine_service_any(struct ath10k *ar);
|
||||
void ath10k_ce_per_engine_service(struct ath10k *ar, unsigned int ce_id);
|
||||
void ath10k_ce_disable_interrupt(struct ath10k *ar, int ce_id);
|
||||
void ath10k_ce_disable_interrupts(struct ath10k *ar);
|
||||
void ath10k_ce_enable_interrupt(struct ath10k *ar, int ce_id);
|
||||
void ath10k_ce_enable_interrupts(struct ath10k *ar);
|
||||
void ath10k_ce_dump_registers(struct ath10k *ar,
|
||||
struct ath10k_fw_crash_data *crash_data);
|
||||
|
||||
void ath10k_ce_alloc_rri(struct ath10k *ar);
|
||||
void ath10k_ce_free_rri(struct ath10k *ar);
|
||||
|
||||
/* ce_attr.flags values */
|
||||
/* Use NonSnooping PCIe accesses? */
|
||||
#define CE_ATTR_NO_SNOOP BIT(0)
|
||||
|
||||
/* Byte swap data words */
|
||||
#define CE_ATTR_BYTE_SWAP_DATA BIT(1)
|
||||
|
||||
/* Swizzle descriptors? */
|
||||
#define CE_ATTR_SWIZZLE_DESCRIPTORS BIT(2)
|
||||
|
||||
/* no interrupt on copy completion */
|
||||
#define CE_ATTR_DIS_INTR BIT(3)
|
||||
|
||||
/* no interrupt, only polling */
|
||||
#define CE_ATTR_POLL BIT(4)
|
||||
|
||||
/* Attributes of an instance of a Copy Engine */
|
||||
struct ce_attr {
|
||||
/* CE_ATTR_* values */
|
||||
unsigned int flags;
|
||||
|
||||
/* #entries in source ring - Must be a power of 2 */
|
||||
unsigned int src_nentries;
|
||||
|
||||
/*
|
||||
* Max source send size for this CE.
|
||||
* This is also the minimum size of a destination buffer.
|
||||
*/
|
||||
unsigned int src_sz_max;
|
||||
|
||||
/* #entries in destination ring - Must be a power of 2 */
|
||||
unsigned int dest_nentries;
|
||||
|
||||
void (*send_cb)(struct ath10k_ce_pipe *);
|
||||
void (*recv_cb)(struct ath10k_ce_pipe *);
|
||||
};
|
||||
|
||||
struct ath10k_ce_ops {
|
||||
struct ath10k_ce_ring *(*ce_alloc_src_ring)(struct ath10k *ar,
|
||||
u32 ce_id,
|
||||
const struct ce_attr *attr);
|
||||
struct ath10k_ce_ring *(*ce_alloc_dst_ring)(struct ath10k *ar,
|
||||
u32 ce_id,
|
||||
const struct ce_attr *attr);
|
||||
int (*ce_rx_post_buf)(struct ath10k_ce_pipe *pipe, void *ctx,
|
||||
dma_addr_t paddr);
|
||||
int (*ce_completed_recv_next_nolock)(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
u32 *nbytesp);
|
||||
int (*ce_revoke_recv_next)(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp,
|
||||
dma_addr_t *nbytesp);
|
||||
void (*ce_extract_desc_data)(struct ath10k *ar,
|
||||
struct ath10k_ce_ring *src_ring,
|
||||
u32 sw_index, dma_addr_t *bufferp,
|
||||
u32 *nbytesp, u32 *transfer_idp);
|
||||
void (*ce_free_pipe)(struct ath10k *ar, int ce_id);
|
||||
int (*ce_send_nolock)(struct ath10k_ce_pipe *pipe,
|
||||
void *per_transfer_context,
|
||||
dma_addr_t buffer, u32 nbytes,
|
||||
u32 transfer_id, u32 flags);
|
||||
void (*ce_set_src_ring_base_addr_hi)(struct ath10k *ar,
|
||||
u32 ce_ctrl_addr,
|
||||
u64 addr);
|
||||
void (*ce_set_dest_ring_base_addr_hi)(struct ath10k *ar,
|
||||
u32 ce_ctrl_addr,
|
||||
u64 addr);
|
||||
int (*ce_completed_send_next_nolock)(struct ath10k_ce_pipe *ce_state,
|
||||
void **per_transfer_contextp);
|
||||
};
|
||||
|
||||
static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
|
||||
{
|
||||
return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
|
||||
}
|
||||
|
||||
#define COPY_ENGINE_ID(COPY_ENGINE_BASE_ADDRESS) (((COPY_ENGINE_BASE_ADDRESS) \
|
||||
- CE0_BASE_ADDRESS) / (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS))
|
||||
|
||||
#define CE_SRC_RING_TO_DESC(baddr, idx) \
|
||||
(&(((struct ce_desc *)baddr)[idx]))
|
||||
|
||||
#define CE_DEST_RING_TO_DESC(baddr, idx) \
|
||||
(&(((struct ce_desc *)baddr)[idx]))
|
||||
|
||||
#define CE_SRC_RING_TO_DESC_64(baddr, idx) \
|
||||
(&(((struct ce_desc_64 *)baddr)[idx]))
|
||||
|
||||
#define CE_DEST_RING_TO_DESC_64(baddr, idx) \
|
||||
(&(((struct ce_desc_64 *)baddr)[idx]))
|
||||
|
||||
/* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
|
||||
#define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
|
||||
(((int)(toidx) - (int)(fromidx)) & (nentries_mask))
|
||||
|
||||
#define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
|
||||
#define CE_RING_IDX_ADD(nentries_mask, idx, num) \
|
||||
(((idx) + (num)) & (nentries_mask))
|
||||
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB \
|
||||
ar->regs->ce_wrap_intr_sum_host_msi_lsb
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK \
|
||||
ar->regs->ce_wrap_intr_sum_host_msi_mask
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(x) \
|
||||
(((x) & CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_MASK) >> \
|
||||
CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_LSB)
|
||||
#define CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS 0x0000
|
||||
|
||||
static inline u32 ath10k_ce_interrupt_summary(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_ce *ce = ath10k_ce_priv(ar);
|
||||
|
||||
return CE_WRAPPER_INTERRUPT_SUMMARY_HOST_MSI_GET(
|
||||
ce->bus_ops->read32((ar), CE_WRAPPER_BASE_ADDRESS +
|
||||
CE_WRAPPER_INTERRUPT_SUMMARY_ADDRESS));
|
||||
}
|
||||
|
||||
/* Host software's Copy Engine configuration. */
|
||||
#define CE_ATTR_FLAGS 0
|
||||
|
||||
/*
|
||||
* Configuration information for a Copy Engine pipe.
|
||||
* Passed from Host to Target during startup (one per CE).
|
||||
*
|
||||
* NOTE: Structure is shared between Host software and Target firmware!
|
||||
*/
|
||||
struct ce_pipe_config {
|
||||
__le32 pipenum;
|
||||
__le32 pipedir;
|
||||
__le32 nentries;
|
||||
__le32 nbytes_max;
|
||||
__le32 flags;
|
||||
__le32 reserved;
|
||||
};
|
||||
|
||||
/*
|
||||
* Directions for interconnect pipe configuration.
|
||||
* These definitions may be used during configuration and are shared
|
||||
* between Host and Target.
|
||||
*
|
||||
* Pipe Directions are relative to the Host, so PIPEDIR_IN means
|
||||
* "coming IN over air through Target to Host" as with a WiFi Rx operation.
|
||||
* Conversely, PIPEDIR_OUT means "going OUT from Host through Target over air"
|
||||
* as with a WiFi Tx operation. This is somewhat awkward for the "middle-man"
|
||||
* Target since things that are "PIPEDIR_OUT" are coming IN to the Target
|
||||
* over the interconnect.
|
||||
*/
|
||||
#define PIPEDIR_NONE 0
|
||||
#define PIPEDIR_IN 1 /* Target-->Host, WiFi Rx direction */
|
||||
#define PIPEDIR_OUT 2 /* Host->Target, WiFi Tx direction */
|
||||
#define PIPEDIR_INOUT 3 /* bidirectional */
|
||||
|
||||
/* Establish a mapping between a service/direction and a pipe. */
|
||||
struct ce_service_to_pipe {
|
||||
__le32 service_id;
|
||||
__le32 pipedir;
|
||||
__le32 pipenum;
|
||||
};
|
||||
|
||||
#endif /* _CE_H_ */
|
3729
sys/contrib/dev/athk/ath10k/core.c
Normal file
3729
sys/contrib/dev/athk/ath10k/core.c
Normal file
File diff suppressed because it is too large
Load Diff
1360
sys/contrib/dev/athk/ath10k/core.h
Normal file
1360
sys/contrib/dev/athk/ath10k/core.h
Normal file
File diff suppressed because it is too large
Load Diff
1663
sys/contrib/dev/athk/ath10k/coredump.c
Normal file
1663
sys/contrib/dev/athk/ath10k/coredump.c
Normal file
File diff suppressed because it is too large
Load Diff
226
sys/contrib/dev/athk/ath10k/coredump.h
Normal file
226
sys/contrib/dev/athk/ath10k/coredump.h
Normal file
@ -0,0 +1,226 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _COREDUMP_H_
|
||||
#define _COREDUMP_H_
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#define ATH10K_FW_CRASH_DUMP_VERSION 1
|
||||
|
||||
/**
|
||||
* enum ath10k_fw_crash_dump_type - types of data in the dump file
|
||||
* @ATH10K_FW_CRASH_DUMP_REGDUMP: Register crash dump in binary format
|
||||
*/
|
||||
enum ath10k_fw_crash_dump_type {
|
||||
ATH10K_FW_CRASH_DUMP_REGISTERS = 0,
|
||||
ATH10K_FW_CRASH_DUMP_CE_DATA = 1,
|
||||
|
||||
/* contains multiple struct ath10k_dump_ram_data_hdr */
|
||||
ATH10K_FW_CRASH_DUMP_RAM_DATA = 2,
|
||||
|
||||
ATH10K_FW_CRASH_DUMP_MAX,
|
||||
};
|
||||
|
||||
struct ath10k_tlv_dump_data {
|
||||
/* see ath10k_fw_crash_dump_type above */
|
||||
__le32 type;
|
||||
|
||||
/* in bytes */
|
||||
__le32 tlv_len;
|
||||
|
||||
/* pad to 32-bit boundaries as needed */
|
||||
u8 tlv_data[];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_dump_file_data {
|
||||
/* dump file information */
|
||||
|
||||
/* "ATH10K-FW-DUMP" */
|
||||
char df_magic[16];
|
||||
|
||||
__le32 len;
|
||||
|
||||
/* file dump version */
|
||||
__le32 version;
|
||||
|
||||
/* some info we can get from ath10k struct that might help */
|
||||
|
||||
guid_t guid;
|
||||
|
||||
__le32 chip_id;
|
||||
|
||||
/* 0 for now, in place for later hardware */
|
||||
__le32 bus_type;
|
||||
|
||||
__le32 target_version;
|
||||
__le32 fw_version_major;
|
||||
__le32 fw_version_minor;
|
||||
__le32 fw_version_release;
|
||||
__le32 fw_version_build;
|
||||
__le32 phy_capability;
|
||||
__le32 hw_min_tx_power;
|
||||
__le32 hw_max_tx_power;
|
||||
__le32 ht_cap_info;
|
||||
__le32 vht_cap_info;
|
||||
__le32 num_rf_chains;
|
||||
|
||||
/* firmware version string */
|
||||
char fw_ver[ETHTOOL_FWVERS_LEN];
|
||||
|
||||
/* Kernel related information */
|
||||
|
||||
/* time-of-day stamp */
|
||||
__le64 tv_sec;
|
||||
|
||||
/* time-of-day stamp, nano-seconds */
|
||||
__le64 tv_nsec;
|
||||
|
||||
/* LINUX_VERSION_CODE */
|
||||
__le32 kernel_ver_code;
|
||||
|
||||
/* VERMAGIC_STRING */
|
||||
char kernel_ver[64];
|
||||
|
||||
/* room for growth w/out changing binary format */
|
||||
u8 unused[128];
|
||||
|
||||
/* struct ath10k_tlv_dump_data + more */
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_dump_ram_data_hdr {
|
||||
/* enum ath10k_mem_region_type */
|
||||
__le32 region_type;
|
||||
|
||||
__le32 start;
|
||||
|
||||
/* length of payload data, not including this header */
|
||||
__le32 length;
|
||||
|
||||
u8 data[];
|
||||
};
|
||||
|
||||
/* magic number to fill the holes not copied due to sections in regions */
|
||||
#define ATH10K_MAGIC_NOT_COPIED 0xAA
|
||||
|
||||
/* part of user space ABI */
|
||||
enum ath10k_mem_region_type {
|
||||
ATH10K_MEM_REGION_TYPE_REG = 1,
|
||||
ATH10K_MEM_REGION_TYPE_DRAM = 2,
|
||||
ATH10K_MEM_REGION_TYPE_AXI = 3,
|
||||
ATH10K_MEM_REGION_TYPE_IRAM1 = 4,
|
||||
ATH10K_MEM_REGION_TYPE_IRAM2 = 5,
|
||||
ATH10K_MEM_REGION_TYPE_IOSRAM = 6,
|
||||
ATH10K_MEM_REGION_TYPE_IOREG = 7,
|
||||
ATH10K_MEM_REGION_TYPE_MSA = 8,
|
||||
};
|
||||
|
||||
/* Define a section of the region which should be copied. As not all parts
|
||||
* of the memory is possible to copy, for example some of the registers can
|
||||
* be like that, sections can be used to define what is safe to copy.
|
||||
*
|
||||
* To minimize the size of the array, the list must obey the format:
|
||||
* '{start0,stop0},{start1,stop1},{start2,stop2}....' The values below must
|
||||
* also obey to 'start0 < stop0 < start1 < stop1 < start2 < ...', otherwise
|
||||
* we may encouter error in the dump processing.
|
||||
*/
|
||||
struct ath10k_mem_section {
|
||||
u32 start;
|
||||
u32 end;
|
||||
};
|
||||
|
||||
/* One region of a memory layout. If the sections field is null entire
|
||||
* region is copied. If sections is non-null only the areas specified in
|
||||
* sections are copied and rest of the areas are filled with
|
||||
* ATH10K_MAGIC_NOT_COPIED.
|
||||
*/
|
||||
struct ath10k_mem_region {
|
||||
enum ath10k_mem_region_type type;
|
||||
u32 start;
|
||||
u32 len;
|
||||
|
||||
const char *name;
|
||||
|
||||
struct {
|
||||
const struct ath10k_mem_section *sections;
|
||||
u32 size;
|
||||
} section_table;
|
||||
};
|
||||
|
||||
/* Contains the memory layout of a hardware version identified with the
|
||||
* hardware id, split into regions.
|
||||
*/
|
||||
struct ath10k_hw_mem_layout {
|
||||
u32 hw_id;
|
||||
u32 hw_rev;
|
||||
enum ath10k_bus bus;
|
||||
|
||||
struct {
|
||||
const struct ath10k_mem_region *regions;
|
||||
int size;
|
||||
} region_table;
|
||||
};
|
||||
|
||||
/* FIXME: where to put this? */
|
||||
extern unsigned long ath10k_coredump_mask;
|
||||
|
||||
#ifdef CONFIG_DEV_COREDUMP
|
||||
|
||||
int ath10k_coredump_submit(struct ath10k *ar);
|
||||
struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar);
|
||||
int ath10k_coredump_create(struct ath10k *ar);
|
||||
int ath10k_coredump_register(struct ath10k *ar);
|
||||
void ath10k_coredump_unregister(struct ath10k *ar);
|
||||
void ath10k_coredump_destroy(struct ath10k *ar);
|
||||
|
||||
const struct ath10k_hw_mem_layout *_ath10k_coredump_get_mem_layout(struct ath10k *ar);
|
||||
const struct ath10k_hw_mem_layout *ath10k_coredump_get_mem_layout(struct ath10k *ar);
|
||||
|
||||
#else /* CONFIG_DEV_COREDUMP */
|
||||
|
||||
static inline int ath10k_coredump_submit(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct ath10k_fw_crash_data *ath10k_coredump_new(struct ath10k *ar)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline int ath10k_coredump_create(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_coredump_register(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_coredump_unregister(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_coredump_destroy(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline const struct ath10k_hw_mem_layout *
|
||||
ath10k_coredump_get_mem_layout(struct ath10k *ar)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline const struct ath10k_hw_mem_layout *
|
||||
_ath10k_coredump_get_mem_layout(struct ath10k *ar)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_DEV_COREDUMP */
|
||||
|
||||
#endif /* _COREDUMP_H_ */
|
2794
sys/contrib/dev/athk/ath10k/debug.c
Normal file
2794
sys/contrib/dev/athk/ath10k/debug.c
Normal file
File diff suppressed because it is too large
Load Diff
292
sys/contrib/dev/athk/ath10k/debug.h
Normal file
292
sys/contrib/dev/athk/ath10k/debug.h
Normal file
@ -0,0 +1,292 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _DEBUG_H_
|
||||
#define _DEBUG_H_
|
||||
|
||||
#include <linux/types.h>
|
||||
#include "trace.h"
|
||||
|
||||
enum ath10k_debug_mask {
|
||||
ATH10K_DBG_PCI = 0x00000001,
|
||||
ATH10K_DBG_WMI = 0x00000002,
|
||||
ATH10K_DBG_HTC = 0x00000004,
|
||||
ATH10K_DBG_HTT = 0x00000008,
|
||||
ATH10K_DBG_MAC = 0x00000010,
|
||||
ATH10K_DBG_BOOT = 0x00000020,
|
||||
ATH10K_DBG_PCI_DUMP = 0x00000040,
|
||||
ATH10K_DBG_HTT_DUMP = 0x00000080,
|
||||
ATH10K_DBG_MGMT = 0x00000100,
|
||||
ATH10K_DBG_DATA = 0x00000200,
|
||||
ATH10K_DBG_BMI = 0x00000400,
|
||||
ATH10K_DBG_REGULATORY = 0x00000800,
|
||||
ATH10K_DBG_TESTMODE = 0x00001000,
|
||||
ATH10K_DBG_WMI_PRINT = 0x00002000,
|
||||
ATH10K_DBG_PCI_PS = 0x00004000,
|
||||
ATH10K_DBG_AHB = 0x00008000,
|
||||
ATH10K_DBG_SDIO = 0x00010000,
|
||||
ATH10K_DBG_SDIO_DUMP = 0x00020000,
|
||||
ATH10K_DBG_USB = 0x00040000,
|
||||
ATH10K_DBG_USB_BULK = 0x00080000,
|
||||
ATH10K_DBG_SNOC = 0x00100000,
|
||||
ATH10K_DBG_QMI = 0x00200000,
|
||||
ATH10K_DBG_STA = 0x00400000,
|
||||
ATH10K_DBG_ANY = 0xffffffff,
|
||||
};
|
||||
|
||||
enum ath10k_pktlog_filter {
|
||||
ATH10K_PKTLOG_RX = 0x000000001,
|
||||
ATH10K_PKTLOG_TX = 0x000000002,
|
||||
ATH10K_PKTLOG_RCFIND = 0x000000004,
|
||||
ATH10K_PKTLOG_RCUPDATE = 0x000000008,
|
||||
ATH10K_PKTLOG_DBG_PRINT = 0x000000010,
|
||||
ATH10K_PKTLOG_PEER_STATS = 0x000000040,
|
||||
ATH10K_PKTLOG_ANY = 0x00000005f,
|
||||
};
|
||||
|
||||
enum ath10k_dbg_aggr_mode {
|
||||
ATH10K_DBG_AGGR_MODE_AUTO,
|
||||
ATH10K_DBG_AGGR_MODE_MANUAL,
|
||||
ATH10K_DBG_AGGR_MODE_MAX,
|
||||
};
|
||||
|
||||
/* Types of packet log events */
|
||||
enum ath_pktlog_type {
|
||||
ATH_PKTLOG_TYPE_TX_CTRL = 1,
|
||||
ATH_PKTLOG_TYPE_TX_STAT,
|
||||
};
|
||||
|
||||
struct ath10k_pktlog_hdr {
|
||||
__le16 flags;
|
||||
__le16 missed_cnt;
|
||||
__le16 log_type; /* Type of log information foll this header */
|
||||
__le16 size; /* Size of variable length log information in bytes */
|
||||
__le32 timestamp;
|
||||
u8 payload[];
|
||||
} __packed;
|
||||
|
||||
/* FIXME: How to calculate the buffer size sanely? */
|
||||
#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
|
||||
|
||||
#define ATH10K_TX_POWER_MAX_VAL 70
|
||||
#define ATH10K_TX_POWER_MIN_VAL 0
|
||||
|
||||
extern unsigned int ath10k_debug_mask;
|
||||
|
||||
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
|
||||
__printf(2, 3) void ath10k_err(struct ath10k *ar, const char *fmt, ...);
|
||||
__printf(2, 3) void ath10k_warn(struct ath10k *ar, const char *fmt, ...);
|
||||
|
||||
void ath10k_debug_print_hwfw_info(struct ath10k *ar);
|
||||
void ath10k_debug_print_board_info(struct ath10k *ar);
|
||||
void ath10k_debug_print_boot_info(struct ath10k *ar);
|
||||
void ath10k_print_driver_info(struct ath10k *ar);
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUGFS
|
||||
int ath10k_debug_start(struct ath10k *ar);
|
||||
void ath10k_debug_stop(struct ath10k *ar);
|
||||
int ath10k_debug_create(struct ath10k *ar);
|
||||
void ath10k_debug_destroy(struct ath10k *ar);
|
||||
int ath10k_debug_register(struct ath10k *ar);
|
||||
void ath10k_debug_unregister(struct ath10k *ar);
|
||||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats);
|
||||
void
|
||||
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats_final *tpc_stats);
|
||||
void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer, int len);
|
||||
|
||||
#define ATH10K_DFS_STAT_INC(ar, c) (ar->debug.dfs_stats.c++)
|
||||
|
||||
void ath10k_debug_get_et_strings(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
u32 sset, u8 *data);
|
||||
int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif, int sset);
|
||||
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
struct ethtool_stats *stats, u64 *data);
|
||||
|
||||
static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
|
||||
{
|
||||
return ar->debug.fw_dbglog_mask;
|
||||
}
|
||||
|
||||
static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar)
|
||||
{
|
||||
return ar->debug.fw_dbglog_level;
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
|
||||
{
|
||||
return ar->debug.enable_extd_tx_stats;
|
||||
}
|
||||
|
||||
int ath10k_debug_fw_stats_request(struct ath10k *ar);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ath10k_debug_start(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_stop(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_create(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_destroy(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_register(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_unregister(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_fw_stats_process(struct ath10k *ar,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_tpc_stats_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats *tpc_stats)
|
||||
{
|
||||
kfree(tpc_stats);
|
||||
}
|
||||
|
||||
static inline void
|
||||
ath10k_debug_tpc_stats_final_process(struct ath10k *ar,
|
||||
struct ath10k_tpc_stats_final *tpc_stats)
|
||||
{
|
||||
kfree(tpc_stats);
|
||||
}
|
||||
|
||||
static inline void ath10k_debug_dbglog_add(struct ath10k *ar, u8 *buffer,
|
||||
int len)
|
||||
{
|
||||
}
|
||||
|
||||
static inline u64 ath10k_debug_get_fw_dbglog_mask(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline u32 ath10k_debug_get_fw_dbglog_level(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_is_extd_tx_stats_enabled(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_debug_fw_stats_request(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define ATH10K_DFS_STAT_INC(ar, c) do { } while (0)
|
||||
|
||||
#define ath10k_debug_get_et_strings NULL
|
||||
#define ath10k_debug_get_et_sset_count NULL
|
||||
#define ath10k_debug_get_et_stats NULL
|
||||
|
||||
#endif /* CONFIG_ATH10K_DEBUGFS */
|
||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir);
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats);
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long unchain_cnt,
|
||||
unsigned long drop_cnt,
|
||||
unsigned long drop_cnt_filter,
|
||||
unsigned long queued_msdus);
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
|
||||
u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges);
|
||||
#else
|
||||
static inline
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long unchain_cnt,
|
||||
unsigned long drop_cnt,
|
||||
unsigned long drop_cnt_filter,
|
||||
unsigned long queued_msdus)
|
||||
{
|
||||
}
|
||||
|
||||
static inline
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar,
|
||||
u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_MAC80211_DEBUGFS */
|
||||
|
||||
#ifdef CONFIG_ATH10K_DEBUG
|
||||
__printf(3, 4) void __ath10k_dbg(struct ath10k *ar,
|
||||
enum ath10k_debug_mask mask,
|
||||
const char *fmt, ...);
|
||||
void ath10k_dbg_dump(struct ath10k *ar,
|
||||
enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len);
|
||||
#else /* CONFIG_ATH10K_DEBUG */
|
||||
|
||||
static inline int __ath10k_dbg(struct ath10k *ar,
|
||||
enum ath10k_debug_mask dbg_mask,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_dbg_dump(struct ath10k *ar,
|
||||
enum ath10k_debug_mask mask,
|
||||
const char *msg, const char *prefix,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ATH10K_DEBUG */
|
||||
|
||||
#if !defined(CONFIG_ATH10K_TRACING)
|
||||
#define trace_ath10k_log_dbg_enabled() (0)
|
||||
#endif
|
||||
|
||||
/* Avoid calling __ath10k_dbg() if debug_mask is not set and tracing
|
||||
* disabled.
|
||||
*/
|
||||
#define ath10k_dbg(ar, dbg_mask, fmt, ...) \
|
||||
do { \
|
||||
if ((ath10k_debug_mask & dbg_mask) || \
|
||||
trace_ath10k_log_dbg_enabled()) \
|
||||
__ath10k_dbg(ar, dbg_mask, fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
#endif /* _DEBUG_H_ */
|
777
sys/contrib/dev/athk/ath10k/debugfs_sta.c
Normal file
777
sys/contrib/dev/athk/ath10k/debugfs_sta.c
Normal file
@ -0,0 +1,777 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "wmi-ops.h"
|
||||
#include "txrx.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void ath10k_rx_stats_update_amsdu_subfrm(struct ath10k *ar,
|
||||
struct ath10k_sta_tid_stats *stats,
|
||||
u32 msdu_count)
|
||||
{
|
||||
if (msdu_count == 1)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_1]++;
|
||||
else if (msdu_count == 2)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_2]++;
|
||||
else if (msdu_count == 3)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_3]++;
|
||||
else if (msdu_count == 4)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_4]++;
|
||||
else if (msdu_count > 4)
|
||||
stats->rx_pkt_amsdu[ATH10K_AMSDU_SUBFRM_NUM_MORE]++;
|
||||
}
|
||||
|
||||
static void ath10k_rx_stats_update_ampdu_subfrm(struct ath10k *ar,
|
||||
struct ath10k_sta_tid_stats *stats,
|
||||
u32 mpdu_count)
|
||||
{
|
||||
if (mpdu_count <= 10)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_10]++;
|
||||
else if (mpdu_count <= 20)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_20]++;
|
||||
else if (mpdu_count <= 30)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_30]++;
|
||||
else if (mpdu_count <= 40)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_40]++;
|
||||
else if (mpdu_count <= 50)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_50]++;
|
||||
else if (mpdu_count <= 60)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_60]++;
|
||||
else if (mpdu_count > 60)
|
||||
stats->rx_pkt_ampdu[ATH10K_AMPDU_SUBFRM_NUM_MORE]++;
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_tid_stats_ampdu(struct ath10k *ar, u16 peer_id, u8 tid,
|
||||
struct htt_rx_indication_mpdu_range *ranges,
|
||||
int num_ranges)
|
||||
{
|
||||
struct ath10k_sta *arsta;
|
||||
struct ath10k_peer *peer;
|
||||
int i;
|
||||
|
||||
if (tid > IEEE80211_NUM_TIDS || !(ar->sta_tid_stats_mask & BIT(tid)))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
peer = ath10k_peer_find_by_id(ar, peer_id);
|
||||
if (!peer || !peer->sta)
|
||||
goto out;
|
||||
|
||||
arsta = (struct ath10k_sta *)peer->sta->drv_priv;
|
||||
|
||||
for (i = 0; i < num_ranges; i++)
|
||||
ath10k_rx_stats_update_ampdu_subfrm(ar,
|
||||
&arsta->tid_stats[tid],
|
||||
ranges[i].mpdu_count);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_tid_stats(struct ath10k *ar, u8 *first_hdr,
|
||||
unsigned long num_msdus,
|
||||
enum ath10k_pkt_rx_err err,
|
||||
unsigned long unchain_cnt,
|
||||
unsigned long drop_cnt,
|
||||
unsigned long drop_cnt_filter,
|
||||
unsigned long queued_msdus)
|
||||
{
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ath10k_sta_tid_stats *stats;
|
||||
u8 tid = IEEE80211_NUM_TIDS;
|
||||
bool non_data_frm = false;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)first_hdr;
|
||||
if (!ieee80211_is_data(hdr->frame_control))
|
||||
non_data_frm = true;
|
||||
|
||||
if (ieee80211_is_data_qos(hdr->frame_control))
|
||||
tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
|
||||
|
||||
if (!(ar->sta_tid_stats_mask & BIT(tid)) || non_data_frm)
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, hdr->addr2, NULL);
|
||||
if (!sta)
|
||||
goto exit;
|
||||
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
stats = &arsta->tid_stats[tid];
|
||||
stats->rx_pkt_from_fw += num_msdus;
|
||||
stats->rx_pkt_unchained += unchain_cnt;
|
||||
stats->rx_pkt_drop_chained += drop_cnt;
|
||||
stats->rx_pkt_drop_filter += drop_cnt_filter;
|
||||
if (err != ATH10K_PKT_RX_ERR_MAX)
|
||||
stats->rx_pkt_err[err] += queued_msdus;
|
||||
stats->rx_pkt_queued_for_mac += queued_msdus;
|
||||
ath10k_rx_stats_update_amsdu_subfrm(ar, &arsta->tid_stats[tid],
|
||||
num_msdus);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
exit:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath10k_sta_update_extd_stats_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
struct ath10k_fw_extd_stats_peer *peer;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(peer, &stats->peers_extd, list) {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
|
||||
NULL);
|
||||
if (!sta)
|
||||
continue;
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
arsta->rx_duration += (u64)peer->rx_duration;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void ath10k_sta_update_stats_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
struct ath10k_fw_stats_peer *peer;
|
||||
struct ieee80211_sta *sta;
|
||||
struct ath10k_sta *arsta;
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry(peer, &stats->peers, list) {
|
||||
sta = ieee80211_find_sta_by_ifaddr(ar->hw, peer->peer_macaddr,
|
||||
NULL);
|
||||
if (!sta)
|
||||
continue;
|
||||
arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
arsta->rx_duration += (u64)peer->rx_duration;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||
struct ath10k_fw_stats *stats)
|
||||
{
|
||||
if (stats->extended)
|
||||
ath10k_sta_update_extd_stats_rx_duration(ar, stats);
|
||||
else
|
||||
ath10k_sta_update_stats_rx_duration(ar, stats);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
char buf[32];
|
||||
int len = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
|
||||
(arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
|
||||
"auto" : "manual");
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
u32 aggr_mode;
|
||||
int ret;
|
||||
|
||||
if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
|
||||
return -EINVAL;
|
||||
|
||||
if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if ((ar->state != ATH10K_STATE_ON) ||
|
||||
(aggr_mode == arsta->aggr_mode)) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
arsta->aggr_mode = aggr_mode;
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_aggr_mode = {
|
||||
.read = ath10k_dbg_sta_read_aggr_mode,
|
||||
.write = ath10k_dbg_sta_write_aggr_mode,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
u32 tid, buf_size;
|
||||
int ret;
|
||||
char buf[64] = {0};
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
|
||||
user_buf, count);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ret = sscanf(buf, "%u %u", &tid, &buf_size);
|
||||
if (ret != 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Valid TID values are 0 through 15 */
|
||||
if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if ((ar->state != ATH10K_STATE_ON) ||
|
||||
(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
|
||||
tid, buf_size);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
|
||||
arsta->arvif->vdev_id, sta->addr, tid, buf_size);
|
||||
}
|
||||
|
||||
ret = count;
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_addba = {
|
||||
.write = ath10k_dbg_sta_write_addba,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
u32 tid, status;
|
||||
int ret;
|
||||
char buf[64] = {0};
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
|
||||
user_buf, count);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ret = sscanf(buf, "%u %u", &tid, &status);
|
||||
if (ret != 2)
|
||||
return -EINVAL;
|
||||
|
||||
/* Valid TID values are 0 through 15 */
|
||||
if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if ((ar->state != ATH10K_STATE_ON) ||
|
||||
(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
|
||||
tid, status);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
|
||||
arsta->arvif->vdev_id, sta->addr, tid, status);
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_addba_resp = {
|
||||
.write = ath10k_dbg_sta_write_addba_resp,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
u32 tid, initiator, reason;
|
||||
int ret;
|
||||
char buf[64] = {0};
|
||||
|
||||
ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos,
|
||||
user_buf, count);
|
||||
if (ret <= 0)
|
||||
return ret;
|
||||
|
||||
ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
|
||||
if (ret != 3)
|
||||
return -EINVAL;
|
||||
|
||||
/* Valid TID values are 0 through 15 */
|
||||
if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if ((ar->state != ATH10K_STATE_ON) ||
|
||||
(arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
|
||||
ret = count;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
|
||||
tid, initiator, reason);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
|
||||
arsta->arvif->vdev_id, sta->addr, tid, initiator,
|
||||
reason);
|
||||
}
|
||||
ret = count;
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_delba = {
|
||||
.write = ath10k_dbg_sta_write_delba,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_peer_debug_trigger(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
char buf[8];
|
||||
int len = 0;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
len = scnprintf(buf, sizeof(buf) - len,
|
||||
"Write 1 to once trigger the debug logs\n");
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
ath10k_dbg_sta_write_peer_debug_trigger(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
u8 peer_debug_trigger;
|
||||
int ret;
|
||||
|
||||
if (kstrtou8_from_user(user_buf, count, 0, &peer_debug_trigger))
|
||||
return -EINVAL;
|
||||
|
||||
if (peer_debug_trigger != 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_wmi_peer_set_param(ar, arsta->arvif->vdev_id, sta->addr,
|
||||
ar->wmi.peer_param->debug, peer_debug_trigger);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set param to trigger peer tid logs for station ret: %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_peer_debug_trigger = {
|
||||
.open = simple_open,
|
||||
.read = ath10k_dbg_sta_read_peer_debug_trigger,
|
||||
.write = ath10k_dbg_sta_write_peer_debug_trigger,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_peer_ps_state(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
char buf[20];
|
||||
int len = 0;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
len = scnprintf(buf, sizeof(buf) - len, "%d\n",
|
||||
arsta->peer_ps_state);
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static const struct file_operations fops_peer_ps_state = {
|
||||
.open = simple_open,
|
||||
.read = ath10k_dbg_sta_read_peer_ps_state,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static char *get_err_str(enum ath10k_pkt_rx_err i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_PKT_RX_ERR_FCS:
|
||||
return "fcs_err";
|
||||
case ATH10K_PKT_RX_ERR_TKIP:
|
||||
return "tkip_err";
|
||||
case ATH10K_PKT_RX_ERR_CRYPT:
|
||||
return "crypt_err";
|
||||
case ATH10K_PKT_RX_ERR_PEER_IDX_INVAL:
|
||||
return "peer_idx_inval";
|
||||
case ATH10K_PKT_RX_ERR_MAX:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
static char *get_num_ampdu_subfrm_str(enum ath10k_ampdu_subfrm_num i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_10:
|
||||
return "upto 10";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_20:
|
||||
return "11-20";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_30:
|
||||
return "21-30";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_40:
|
||||
return "31-40";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_50:
|
||||
return "41-50";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_60:
|
||||
return "51-60";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_MORE:
|
||||
return ">60";
|
||||
case ATH10K_AMPDU_SUBFRM_NUM_MAX:
|
||||
return "0";
|
||||
}
|
||||
|
||||
return "0";
|
||||
}
|
||||
|
||||
static char *get_num_amsdu_subfrm_str(enum ath10k_amsdu_subfrm_num i)
|
||||
{
|
||||
switch (i) {
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_1:
|
||||
return "1";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_2:
|
||||
return "2";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_3:
|
||||
return "3";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_4:
|
||||
return "4";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_MORE:
|
||||
return ">4";
|
||||
case ATH10K_AMSDU_SUBFRM_NUM_MAX:
|
||||
return "0";
|
||||
}
|
||||
|
||||
return "0";
|
||||
}
|
||||
|
||||
#define PRINT_TID_STATS(_field, _tabs) \
|
||||
do { \
|
||||
int k = 0; \
|
||||
for (j = 0; j <= IEEE80211_NUM_TIDS; j++) { \
|
||||
if (ar->sta_tid_stats_mask & BIT(j)) { \
|
||||
len += scnprintf(buf + len, buf_len - len, \
|
||||
"[%02d] %-10lu ", \
|
||||
j, stats[j]._field); \
|
||||
k++; \
|
||||
if (k % 8 == 0) { \
|
||||
len += scnprintf(buf + len, \
|
||||
buf_len - len, "\n"); \
|
||||
len += scnprintf(buf + len, \
|
||||
buf_len - len, \
|
||||
_tabs); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
len += scnprintf(buf + len, buf_len - len, "\n"); \
|
||||
} while (0)
|
||||
|
||||
static ssize_t ath10k_dbg_sta_read_tid_stats(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
struct ath10k_sta_tid_stats *stats = arsta->tid_stats;
|
||||
size_t len = 0, buf_len = 1048 * IEEE80211_NUM_TIDS;
|
||||
char *buf;
|
||||
int i, j;
|
||||
ssize_t ret;
|
||||
|
||||
buf = kzalloc(buf_len, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"\n\t\tDriver Rx pkt stats per tid, ([tid] count)\n");
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"\t\t------------------------------------------\n");
|
||||
len += scnprintf(buf + len, buf_len - len, "MSDUs from FW\t\t\t");
|
||||
PRINT_TID_STATS(rx_pkt_from_fw, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "MSDUs unchained\t\t\t");
|
||||
PRINT_TID_STATS(rx_pkt_unchained, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs locally dropped:chained\t");
|
||||
PRINT_TID_STATS(rx_pkt_drop_chained, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs locally dropped:filtered\t");
|
||||
PRINT_TID_STATS(rx_pkt_drop_filter, "\t\t\t\t");
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs queued for mac80211\t");
|
||||
PRINT_TID_STATS(rx_pkt_queued_for_mac, "\t\t\t\t");
|
||||
|
||||
for (i = 0; i < ATH10K_PKT_RX_ERR_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"MSDUs with error:%s\t", get_err_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_err[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
for (i = 0; i < ATH10K_AMPDU_SUBFRM_NUM_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"A-MPDU num subframes %s\t",
|
||||
get_num_ampdu_subfrm_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_ampdu[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||
for (i = 0; i < ATH10K_AMSDU_SUBFRM_NUM_MAX; i++) {
|
||||
len += scnprintf(buf + len, buf_len - len,
|
||||
"A-MSDU num subframes %s\t\t",
|
||||
get_num_amsdu_subfrm_str(i));
|
||||
PRINT_TID_STATS(rx_pkt_amsdu[i], "\t\t\t\t");
|
||||
}
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ret = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tid_stats_dump = {
|
||||
.open = simple_open,
|
||||
.read = ath10k_dbg_sta_read_tid_stats,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_dbg_sta_dump_tx_stats(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ieee80211_sta *sta = file->private_data;
|
||||
struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
|
||||
struct ath10k *ar = arsta->arvif->ar;
|
||||
struct ath10k_htt_data_stats *stats;
|
||||
const char *str_name[ATH10K_STATS_TYPE_MAX] = {"succ", "fail",
|
||||
"retry", "ampdu"};
|
||||
const char *str[ATH10K_COUNTER_TYPE_MAX] = {"bytes", "packets"};
|
||||
int len = 0, i, j, k, retval = 0;
|
||||
const int size = 16 * 4096;
|
||||
char *buf;
|
||||
|
||||
buf = kzalloc(size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (!arsta->tx_stats) {
|
||||
ath10k_warn(ar, "failed to get tx stats");
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
kfree(buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
for (k = 0; k < ATH10K_STATS_TYPE_MAX; k++) {
|
||||
for (j = 0; j < ATH10K_COUNTER_TYPE_MAX; j++) {
|
||||
stats = &arsta->tx_stats->stats[k];
|
||||
len += scnprintf(buf + len, size - len, "%s_%s\n",
|
||||
str_name[k],
|
||||
str[j]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" VHT MCS %s\n",
|
||||
str[j]);
|
||||
for (i = 0; i < ATH10K_VHT_MCS_NUM; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" %llu ",
|
||||
stats->vht[j][i]);
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
len += scnprintf(buf + len, size - len, " HT MCS %s\n",
|
||||
str[j]);
|
||||
for (i = 0; i < ATH10K_HT_MCS_NUM; i++)
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" %llu ", stats->ht[j][i]);
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" BW %s (20,5,10,40,80,160 MHz)\n", str[j]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" %llu %llu %llu %llu %llu %llu\n",
|
||||
stats->bw[j][0], stats->bw[j][1],
|
||||
stats->bw[j][2], stats->bw[j][3],
|
||||
stats->bw[j][4], stats->bw[j][5]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" NSS %s (1x1,2x2,3x3,4x4)\n", str[j]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" %llu %llu %llu %llu\n",
|
||||
stats->nss[j][0], stats->nss[j][1],
|
||||
stats->nss[j][2], stats->nss[j][3]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" GI %s (LGI,SGI)\n",
|
||||
str[j]);
|
||||
len += scnprintf(buf + len, size - len, " %llu %llu\n",
|
||||
stats->gi[j][0], stats->gi[j][1]);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" legacy rate %s (1,2 ... Mbps)\n ",
|
||||
str[j]);
|
||||
for (i = 0; i < ATH10K_LEGACY_NUM; i++)
|
||||
len += scnprintf(buf + len, size - len, "%llu ",
|
||||
stats->legacy[j][i]);
|
||||
len += scnprintf(buf + len, size - len, "\n");
|
||||
len += scnprintf(buf + len, size - len,
|
||||
" Rate table %s (1,2 ... Mbps)\n ",
|
||||
str[j]);
|
||||
for (i = 0; i < ATH10K_RATE_TABLE_NUM; i++) {
|
||||
len += scnprintf(buf + len, size - len, "%llu ",
|
||||
stats->rate_table[j][i]);
|
||||
if (!((i + 1) % 8))
|
||||
len +=
|
||||
scnprintf(buf + len, size - len, "\n ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"\nTX duration\n %llu usecs\n",
|
||||
arsta->tx_stats->tx_duration);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"BA fails\n %llu\n", arsta->tx_stats->ba_fails);
|
||||
len += scnprintf(buf + len, size - len,
|
||||
"ack fails\n %llu\n", arsta->tx_stats->ack_fails);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (len > size)
|
||||
len = size;
|
||||
retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
kfree(buf);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_tx_stats = {
|
||||
.read = ath10k_dbg_sta_dump_tx_stats,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
struct ieee80211_sta *sta, struct dentry *dir)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
debugfs_create_file("aggr_mode", 0644, dir, sta, &fops_aggr_mode);
|
||||
debugfs_create_file("addba", 0200, dir, sta, &fops_addba);
|
||||
debugfs_create_file("addba_resp", 0200, dir, sta, &fops_addba_resp);
|
||||
debugfs_create_file("delba", 0200, dir, sta, &fops_delba);
|
||||
debugfs_create_file("peer_debug_trigger", 0600, dir, sta,
|
||||
&fops_peer_debug_trigger);
|
||||
debugfs_create_file("dump_tid_stats", 0400, dir, sta,
|
||||
&fops_tid_stats_dump);
|
||||
|
||||
if (ath10k_peer_stats_enabled(ar) &&
|
||||
ath10k_debug_is_extd_tx_stats_enabled(ar))
|
||||
debugfs_create_file("tx_stats", 0400, dir, sta,
|
||||
&fops_tx_stats);
|
||||
debugfs_create_file("peer_ps_state", 0400, dir, sta,
|
||||
&fops_peer_ps_state);
|
||||
}
|
1563
sys/contrib/dev/athk/ath10k/fwlog.c
Normal file
1563
sys/contrib/dev/athk/ath10k/fwlog.c
Normal file
File diff suppressed because it is too large
Load Diff
23
sys/contrib/dev/athk/ath10k/fwlog.h
Normal file
23
sys/contrib/dev/athk/ath10k/fwlog.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef _FWLOG_
|
||||
#define _FWLOG_
|
||||
|
||||
void ath10k_fwlog_register(struct ath10k *ar);
|
||||
void ath10k_fwlog_unregister(struct ath10k *ar);
|
||||
|
||||
void ath10k_handle_fwlog_msg(struct ath10k *ar, struct sk_buff *skb);
|
||||
#endif /* _FWLOG_ */
|
258
sys/contrib/dev/athk/ath10k/hif.h
Normal file
258
sys/contrib/dev/athk/ath10k/hif.h
Normal file
@ -0,0 +1,258 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2015,2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _HIF_H_
|
||||
#define _HIF_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "core.h"
|
||||
#include "bmi.h"
|
||||
#include "debug.h"
|
||||
|
||||
/* Types of fw logging mode */
|
||||
enum ath_dbg_mode {
|
||||
ATH10K_ENABLE_FW_LOG_DIAG,
|
||||
ATH10K_ENABLE_FW_LOG_CE,
|
||||
};
|
||||
|
||||
struct ath10k_hif_sg_item {
|
||||
u16 transfer_id;
|
||||
void *transfer_context; /* NULL = tx completion callback not called */
|
||||
void *vaddr; /* for debugging mostly */
|
||||
dma_addr_t paddr;
|
||||
u16 len;
|
||||
};
|
||||
|
||||
struct ath10k_hif_ops {
|
||||
/* send a scatter-gather list to the target */
|
||||
int (*tx_sg)(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_hif_sg_item *items, int n_items);
|
||||
|
||||
/* read firmware memory through the diagnose interface */
|
||||
int (*diag_read)(struct ath10k *ar, u32 address, void *buf,
|
||||
size_t buf_len);
|
||||
|
||||
int (*diag_write)(struct ath10k *ar, u32 address, const void *data,
|
||||
int nbytes);
|
||||
/*
|
||||
* API to handle HIF-specific BMI message exchanges, this API is
|
||||
* synchronous and only allowed to be called from a context that
|
||||
* can block (sleep)
|
||||
*/
|
||||
int (*exchange_bmi_msg)(struct ath10k *ar,
|
||||
void *request, u32 request_len,
|
||||
void *response, u32 *response_len);
|
||||
|
||||
/* Post BMI phase, after FW is loaded. Starts regular operation */
|
||||
int (*start)(struct ath10k *ar);
|
||||
|
||||
/* Clean up what start() did. This does not revert to BMI phase. If
|
||||
* desired so, call power_down() and power_up()
|
||||
*/
|
||||
void (*stop)(struct ath10k *ar);
|
||||
|
||||
int (*start_post)(struct ath10k *ar);
|
||||
|
||||
int (*get_htt_tx_complete)(struct ath10k *ar);
|
||||
|
||||
int (*map_service_to_pipe)(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe);
|
||||
|
||||
void (*get_default_pipe)(struct ath10k *ar, u8 *ul_pipe, u8 *dl_pipe);
|
||||
|
||||
/*
|
||||
* Check if prior sends have completed.
|
||||
*
|
||||
* Check whether the pipe in question has any completed
|
||||
* sends that have not yet been processed.
|
||||
* This function is only relevant for HIF pipes that are configured
|
||||
* to be polled rather than interrupt-driven.
|
||||
*/
|
||||
void (*send_complete_check)(struct ath10k *ar, u8 pipe_id, int force);
|
||||
|
||||
u16 (*get_free_queue_number)(struct ath10k *ar, u8 pipe_id);
|
||||
|
||||
u32 (*read32)(struct ath10k *ar, u32 address);
|
||||
|
||||
void (*write32)(struct ath10k *ar, u32 address, u32 value);
|
||||
|
||||
/* Power up the device and enter BMI transfer mode for FW download */
|
||||
int (*power_up)(struct ath10k *ar, enum ath10k_firmware_mode fw_mode);
|
||||
|
||||
/* Power down the device and free up resources. stop() must be called
|
||||
* before this if start() was called earlier
|
||||
*/
|
||||
void (*power_down)(struct ath10k *ar);
|
||||
|
||||
int (*suspend)(struct ath10k *ar);
|
||||
int (*resume)(struct ath10k *ar);
|
||||
|
||||
/* fetch calibration data from target eeprom */
|
||||
int (*fetch_cal_eeprom)(struct ath10k *ar, void **data,
|
||||
size_t *data_len);
|
||||
|
||||
int (*get_target_info)(struct ath10k *ar,
|
||||
struct bmi_target_info *target_info);
|
||||
int (*set_target_log_mode)(struct ath10k *ar, u8 fw_log_mode);
|
||||
};
|
||||
|
||||
static inline int ath10k_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_hif_sg_item *items,
|
||||
int n_items)
|
||||
{
|
||||
return ar->hif.ops->tx_sg(ar, pipe_id, items, n_items);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
return ar->hif.ops->diag_read(ar, address, buf, buf_len);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_diag_write(struct ath10k *ar, u32 address,
|
||||
const void *data, int nbytes)
|
||||
{
|
||||
if (!ar->hif.ops->diag_write)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->diag_write(ar, address, data, nbytes);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_exchange_bmi_msg(struct ath10k *ar,
|
||||
void *request, u32 request_len,
|
||||
void *response, u32 *response_len)
|
||||
{
|
||||
return ar->hif.ops->exchange_bmi_msg(ar, request, request_len,
|
||||
response, response_len);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_start(struct ath10k *ar)
|
||||
{
|
||||
return ar->hif.ops->start(ar);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_stop(struct ath10k *ar)
|
||||
{
|
||||
return ar->hif.ops->stop(ar);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_start_post(struct ath10k *ar)
|
||||
{
|
||||
if (ar->hif.ops->start_post)
|
||||
return ar->hif.ops->start_post(ar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_get_htt_tx_complete(struct ath10k *ar)
|
||||
{
|
||||
if (ar->hif.ops->get_htt_tx_complete)
|
||||
return ar->hif.ops->get_htt_tx_complete(ar);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_map_service_to_pipe(struct ath10k *ar,
|
||||
u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
return ar->hif.ops->map_service_to_pipe(ar, service_id,
|
||||
ul_pipe, dl_pipe);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_get_default_pipe(struct ath10k *ar,
|
||||
u8 *ul_pipe, u8 *dl_pipe)
|
||||
{
|
||||
ar->hif.ops->get_default_pipe(ar, ul_pipe, dl_pipe);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_send_complete_check(struct ath10k *ar,
|
||||
u8 pipe_id, int force)
|
||||
{
|
||||
if (ar->hif.ops->send_complete_check)
|
||||
ar->hif.ops->send_complete_check(ar, pipe_id, force);
|
||||
}
|
||||
|
||||
static inline u16 ath10k_hif_get_free_queue_number(struct ath10k *ar,
|
||||
u8 pipe_id)
|
||||
{
|
||||
return ar->hif.ops->get_free_queue_number(ar, pipe_id);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_power_up(struct ath10k *ar,
|
||||
enum ath10k_firmware_mode fw_mode)
|
||||
{
|
||||
return ar->hif.ops->power_up(ar, fw_mode);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_power_down(struct ath10k *ar)
|
||||
{
|
||||
ar->hif.ops->power_down(ar);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_suspend(struct ath10k *ar)
|
||||
{
|
||||
if (!ar->hif.ops->suspend)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->suspend(ar);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_resume(struct ath10k *ar)
|
||||
{
|
||||
if (!ar->hif.ops->resume)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->resume(ar);
|
||||
}
|
||||
|
||||
static inline u32 ath10k_hif_read32(struct ath10k *ar, u32 address)
|
||||
{
|
||||
if (!ar->hif.ops->read32) {
|
||||
ath10k_warn(ar, "hif read32 not supported\n");
|
||||
return 0xdeaddead;
|
||||
}
|
||||
|
||||
return ar->hif.ops->read32(ar, address);
|
||||
}
|
||||
|
||||
static inline void ath10k_hif_write32(struct ath10k *ar,
|
||||
u32 address, u32 data)
|
||||
{
|
||||
if (!ar->hif.ops->write32) {
|
||||
ath10k_warn(ar, "hif write32 not supported\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ar->hif.ops->write32(ar, address, data);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_fetch_cal_eeprom(struct ath10k *ar,
|
||||
void **data,
|
||||
size_t *data_len)
|
||||
{
|
||||
if (!ar->hif.ops->fetch_cal_eeprom)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->fetch_cal_eeprom(ar, data, data_len);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_get_target_info(struct ath10k *ar,
|
||||
struct bmi_target_info *tgt_info)
|
||||
{
|
||||
if (!ar->hif.ops->get_target_info)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->get_target_info(ar, tgt_info);
|
||||
}
|
||||
|
||||
static inline int ath10k_hif_set_target_log_mode(struct ath10k *ar,
|
||||
u8 fw_log_mode)
|
||||
{
|
||||
if (!ar->hif.ops->set_target_log_mode)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return ar->hif.ops->set_target_log_mode(ar, fw_log_mode);
|
||||
}
|
||||
#endif /* _HIF_H_ */
|
1306
sys/contrib/dev/athk/ath10k/htc.c
Normal file
1306
sys/contrib/dev/athk/ath10k/htc.c
Normal file
File diff suppressed because it is too large
Load Diff
435
sys/contrib/dev/athk/ath10k/htc.h
Normal file
435
sys/contrib/dev/athk/ath10k/htc.h
Normal file
@ -0,0 +1,435 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _HTC_H_
|
||||
#define _HTC_H_
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/bitfield.h>
|
||||
|
||||
struct ath10k;
|
||||
|
||||
/****************/
|
||||
/* HTC protocol */
|
||||
/****************/
|
||||
|
||||
/*
|
||||
* HTC - host-target control protocol
|
||||
*
|
||||
* tx packets are generally <htc_hdr><payload>
|
||||
* rx packets are more complex: <htc_hdr><payload><trailer>
|
||||
*
|
||||
* The payload + trailer length is stored in len.
|
||||
* To get payload-only length one needs to payload - trailer_len.
|
||||
*
|
||||
* Trailer contains (possibly) multiple <htc_record>.
|
||||
* Each record is a id-len-value.
|
||||
*
|
||||
* HTC header flags, control_byte0, control_byte1
|
||||
* have different meaning depending whether its tx
|
||||
* or rx.
|
||||
*
|
||||
* Alignment: htc_hdr, payload and trailer are
|
||||
* 4-byte aligned.
|
||||
*/
|
||||
|
||||
#define HTC_HOST_MAX_MSG_PER_RX_BUNDLE 32
|
||||
|
||||
enum ath10k_htc_tx_flags {
|
||||
ATH10K_HTC_FLAG_NEED_CREDIT_UPDATE = 0x01,
|
||||
ATH10K_HTC_FLAG_SEND_BUNDLE = 0x02
|
||||
};
|
||||
|
||||
enum ath10k_htc_rx_flags {
|
||||
ATH10K_HTC_FLAGS_RECV_1MORE_BLOCK = 0x01,
|
||||
ATH10K_HTC_FLAG_TRAILER_PRESENT = 0x02,
|
||||
};
|
||||
|
||||
#define ATH10K_HTC_FLAG_BUNDLE_MASK GENMASK(7, 4)
|
||||
|
||||
/* bits 2-3 are for extra bundle count bits 4-5 */
|
||||
#define ATH10K_HTC_BUNDLE_EXTRA_MASK GENMASK(3, 2)
|
||||
#define ATH10K_HTC_BUNDLE_EXTRA_SHIFT 4
|
||||
|
||||
static inline unsigned int ath10k_htc_get_bundle_count(u8 max_msgs, u8 flags)
|
||||
{
|
||||
unsigned int count, extra_count = 0;
|
||||
|
||||
count = FIELD_GET(ATH10K_HTC_FLAG_BUNDLE_MASK, flags);
|
||||
|
||||
if (max_msgs > 16)
|
||||
extra_count = FIELD_GET(ATH10K_HTC_BUNDLE_EXTRA_MASK, flags) <<
|
||||
ATH10K_HTC_BUNDLE_EXTRA_SHIFT;
|
||||
|
||||
return count + extra_count;
|
||||
}
|
||||
|
||||
struct ath10k_htc_hdr {
|
||||
u8 eid; /* @enum ath10k_htc_ep_id */
|
||||
u8 flags; /* @enum ath10k_htc_tx_flags, ath10k_htc_rx_flags */
|
||||
__le16 len;
|
||||
union {
|
||||
u8 trailer_len; /* for rx */
|
||||
u8 control_byte0;
|
||||
} __packed;
|
||||
union {
|
||||
u8 seq_no; /* for tx */
|
||||
u8 control_byte1;
|
||||
} __packed;
|
||||
union {
|
||||
__le16 pad_len;
|
||||
struct {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_msg_id {
|
||||
ATH10K_HTC_MSG_READY_ID = 1,
|
||||
ATH10K_HTC_MSG_CONNECT_SERVICE_ID = 2,
|
||||
ATH10K_HTC_MSG_CONNECT_SERVICE_RESP_ID = 3,
|
||||
ATH10K_HTC_MSG_SETUP_COMPLETE_ID = 4,
|
||||
ATH10K_HTC_MSG_SETUP_COMPLETE_EX_ID = 5,
|
||||
ATH10K_HTC_MSG_SEND_SUSPEND_COMPLETE = 6
|
||||
};
|
||||
|
||||
enum ath10k_htc_version {
|
||||
ATH10K_HTC_VERSION_2P0 = 0x00, /* 2.0 */
|
||||
ATH10K_HTC_VERSION_2P1 = 0x01, /* 2.1 */
|
||||
};
|
||||
|
||||
enum ath10k_htc_conn_flags {
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_FOURTH = 0x0,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_ONE_HALF = 0x1,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_THREE_FOURTHS = 0x2,
|
||||
ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_UNITY = 0x3,
|
||||
#define ATH10K_HTC_CONN_FLAGS_THRESHOLD_LEVEL_MASK 0x3
|
||||
ATH10K_HTC_CONN_FLAGS_REDUCE_CREDIT_DRIBBLE = 1 << 2,
|
||||
ATH10K_HTC_CONN_FLAGS_DISABLE_CREDIT_FLOW_CTRL = 1 << 3
|
||||
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_MASK 0xFF00
|
||||
#define ATH10K_HTC_CONN_FLAGS_RECV_ALLOC_LSB 8
|
||||
};
|
||||
|
||||
#define ATH10K_HTC_MSG_READY_EXT_ALT_DATA_MASK 0xFFF
|
||||
|
||||
enum ath10k_htc_conn_svc_status {
|
||||
ATH10K_HTC_CONN_SVC_STATUS_SUCCESS = 0,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NOT_FOUND = 1,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_FAILED = 2,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_RESOURCES = 3,
|
||||
ATH10K_HTC_CONN_SVC_STATUS_NO_MORE_EP = 4
|
||||
};
|
||||
|
||||
#define ATH10K_MAX_MSG_PER_HTC_TX_BUNDLE 32
|
||||
#define ATH10K_MIN_MSG_PER_HTC_TX_BUNDLE 2
|
||||
#define ATH10K_MIN_CREDIT_PER_HTC_TX_BUNDLE 2
|
||||
|
||||
enum ath10k_htc_setup_complete_flags {
|
||||
ATH10K_HTC_SETUP_COMPLETE_FLAGS_RX_BNDL_EN = 1
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_msg_hdr {
|
||||
__le16 message_id; /* @enum htc_message_id */
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_unknown {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_ready {
|
||||
__le16 credit_count;
|
||||
__le16 credit_size;
|
||||
u8 max_endpoints;
|
||||
u8 pad0;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_ready_extended {
|
||||
struct ath10k_htc_ready base;
|
||||
u8 htc_version; /* @enum ath10k_htc_version */
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
union {
|
||||
__le16 reserved;
|
||||
struct {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
} __packed;
|
||||
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_conn_svc {
|
||||
__le16 service_id;
|
||||
__le16 flags; /* @enum ath10k_htc_conn_flags */
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_conn_svc_response {
|
||||
__le16 service_id;
|
||||
u8 status; /* @enum ath10k_htc_conn_svc_status */
|
||||
u8 eid;
|
||||
__le16 max_msg_size;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_setup_complete_extended {
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
__le32 flags; /* @enum htc_setup_complete_flags */
|
||||
u8 max_msgs_per_bundled_recv;
|
||||
u8 pad2;
|
||||
u8 pad3;
|
||||
u8 pad4;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_msg {
|
||||
struct ath10k_ath10k_htc_msg_hdr hdr;
|
||||
union {
|
||||
/* host-to-target */
|
||||
struct ath10k_htc_conn_svc connect_service;
|
||||
struct ath10k_htc_ready ready;
|
||||
struct ath10k_htc_ready_extended ready_ext;
|
||||
struct ath10k_htc_unknown unknown;
|
||||
struct ath10k_htc_setup_complete_extended setup_complete_ext;
|
||||
|
||||
/* target-to-host */
|
||||
struct ath10k_htc_conn_svc_response connect_service_response;
|
||||
};
|
||||
} __packed __aligned(4);
|
||||
|
||||
enum ath10k_ath10k_htc_record_id {
|
||||
ATH10K_HTC_RECORD_NULL = 0,
|
||||
ATH10K_HTC_RECORD_CREDITS = 1,
|
||||
ATH10K_HTC_RECORD_LOOKAHEAD = 2,
|
||||
ATH10K_HTC_RECORD_LOOKAHEAD_BUNDLE = 3,
|
||||
};
|
||||
|
||||
struct ath10k_ath10k_htc_record_hdr {
|
||||
u8 id; /* @enum ath10k_ath10k_htc_record_id */
|
||||
u8 len;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_credit_report {
|
||||
u8 eid; /* @enum ath10k_htc_ep_id */
|
||||
u8 credits;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_lookahead_report {
|
||||
u8 pre_valid;
|
||||
u8 pad0;
|
||||
u8 pad1;
|
||||
u8 pad2;
|
||||
u8 lookahead[4];
|
||||
u8 post_valid;
|
||||
u8 pad3;
|
||||
u8 pad4;
|
||||
u8 pad5;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_lookahead_bundle {
|
||||
u8 lookahead[4];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_htc_record {
|
||||
struct ath10k_ath10k_htc_record_hdr hdr;
|
||||
union {
|
||||
struct ath10k_htc_credit_report credit_report[0];
|
||||
struct ath10k_htc_lookahead_report lookahead_report[0];
|
||||
struct ath10k_htc_lookahead_bundle lookahead_bundle[0];
|
||||
u8 pauload[0];
|
||||
};
|
||||
} __packed __aligned(4);
|
||||
|
||||
/*
|
||||
* note: the trailer offset is dynamic depending
|
||||
* on payload length. this is only a struct layout draft
|
||||
*/
|
||||
struct ath10k_htc_frame {
|
||||
struct ath10k_htc_hdr hdr;
|
||||
union {
|
||||
struct ath10k_htc_msg msg;
|
||||
u8 payload[0];
|
||||
};
|
||||
struct ath10k_htc_record trailer[0];
|
||||
} __packed __aligned(4);
|
||||
|
||||
/*******************/
|
||||
/* Host-side stuff */
|
||||
/*******************/
|
||||
|
||||
enum ath10k_htc_svc_gid {
|
||||
ATH10K_HTC_SVC_GRP_RSVD = 0,
|
||||
ATH10K_HTC_SVC_GRP_WMI = 1,
|
||||
ATH10K_HTC_SVC_GRP_NMI = 2,
|
||||
ATH10K_HTC_SVC_GRP_HTT = 3,
|
||||
ATH10K_LOG_SERVICE_GROUP = 6,
|
||||
|
||||
ATH10K_HTC_SVC_GRP_TEST = 254,
|
||||
ATH10K_HTC_SVC_GRP_LAST = 255,
|
||||
};
|
||||
|
||||
#define SVC(group, idx) \
|
||||
(int)(((int)(group) << 8) | (int)(idx))
|
||||
|
||||
enum ath10k_htc_svc_id {
|
||||
/* NOTE: service ID of 0x0000 is reserved and should never be used */
|
||||
ATH10K_HTC_SVC_ID_RESERVED = 0x0000,
|
||||
ATH10K_HTC_SVC_ID_UNUSED = ATH10K_HTC_SVC_ID_RESERVED,
|
||||
|
||||
ATH10K_HTC_SVC_ID_RSVD_CTRL = SVC(ATH10K_HTC_SVC_GRP_RSVD, 1),
|
||||
ATH10K_HTC_SVC_ID_WMI_CONTROL = SVC(ATH10K_HTC_SVC_GRP_WMI, 0),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_BE = SVC(ATH10K_HTC_SVC_GRP_WMI, 1),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_BK = SVC(ATH10K_HTC_SVC_GRP_WMI, 2),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_VI = SVC(ATH10K_HTC_SVC_GRP_WMI, 3),
|
||||
ATH10K_HTC_SVC_ID_WMI_DATA_VO = SVC(ATH10K_HTC_SVC_GRP_WMI, 4),
|
||||
|
||||
ATH10K_HTC_SVC_ID_NMI_CONTROL = SVC(ATH10K_HTC_SVC_GRP_NMI, 0),
|
||||
ATH10K_HTC_SVC_ID_NMI_DATA = SVC(ATH10K_HTC_SVC_GRP_NMI, 1),
|
||||
|
||||
ATH10K_HTC_SVC_ID_HTT_DATA_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 0),
|
||||
|
||||
ATH10K_HTC_SVC_ID_HTT_DATA2_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 1),
|
||||
ATH10K_HTC_SVC_ID_HTT_DATA3_MSG = SVC(ATH10K_HTC_SVC_GRP_HTT, 2),
|
||||
ATH10K_HTC_SVC_ID_HTT_LOG_MSG = SVC(ATH10K_LOG_SERVICE_GROUP, 0),
|
||||
/* raw stream service (i.e. flash, tcmd, calibration apps) */
|
||||
ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS = SVC(ATH10K_HTC_SVC_GRP_TEST, 0),
|
||||
};
|
||||
|
||||
#undef SVC
|
||||
|
||||
enum ath10k_htc_ep_id {
|
||||
ATH10K_HTC_EP_UNUSED = -1,
|
||||
ATH10K_HTC_EP_0 = 0,
|
||||
ATH10K_HTC_EP_1 = 1,
|
||||
ATH10K_HTC_EP_2,
|
||||
ATH10K_HTC_EP_3,
|
||||
ATH10K_HTC_EP_4,
|
||||
ATH10K_HTC_EP_5,
|
||||
ATH10K_HTC_EP_6,
|
||||
ATH10K_HTC_EP_7,
|
||||
ATH10K_HTC_EP_8,
|
||||
ATH10K_HTC_EP_COUNT,
|
||||
};
|
||||
|
||||
struct ath10k_htc_ops {
|
||||
void (*target_send_suspend_complete)(struct ath10k *ar);
|
||||
};
|
||||
|
||||
struct ath10k_htc_ep_ops {
|
||||
void (*ep_tx_complete)(struct ath10k *, struct sk_buff *);
|
||||
void (*ep_rx_complete)(struct ath10k *, struct sk_buff *);
|
||||
void (*ep_tx_credits)(struct ath10k *);
|
||||
};
|
||||
|
||||
/* service connection information */
|
||||
struct ath10k_htc_svc_conn_req {
|
||||
u16 service_id;
|
||||
struct ath10k_htc_ep_ops ep_ops;
|
||||
int max_send_queue_depth;
|
||||
};
|
||||
|
||||
/* service connection response information */
|
||||
struct ath10k_htc_svc_conn_resp {
|
||||
u8 buffer_len;
|
||||
u8 actual_len;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
unsigned int max_msg_len;
|
||||
u8 connect_resp_code;
|
||||
};
|
||||
|
||||
#define ATH10K_NUM_CONTROL_TX_BUFFERS 2
|
||||
#define ATH10K_HTC_MAX_LEN 4096
|
||||
#define ATH10K_HTC_MAX_CTRL_MSG_LEN 256
|
||||
#define ATH10K_HTC_WAIT_TIMEOUT_HZ (1 * HZ)
|
||||
#define ATH10K_HTC_CONTROL_BUFFER_SIZE (ATH10K_HTC_MAX_CTRL_MSG_LEN + \
|
||||
sizeof(struct ath10k_htc_hdr))
|
||||
#define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1 * HZ)
|
||||
|
||||
struct ath10k_htc_ep {
|
||||
struct ath10k_htc *htc;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
enum ath10k_htc_svc_id service_id;
|
||||
struct ath10k_htc_ep_ops ep_ops;
|
||||
|
||||
int max_tx_queue_depth;
|
||||
int max_ep_message_len;
|
||||
u8 ul_pipe_id;
|
||||
u8 dl_pipe_id;
|
||||
|
||||
u8 seq_no; /* for debugging */
|
||||
int tx_credits;
|
||||
int tx_credit_size;
|
||||
bool tx_credit_flow_enabled;
|
||||
bool bundle_tx;
|
||||
struct sk_buff_head tx_req_head;
|
||||
struct sk_buff_head tx_complete_head;
|
||||
|
||||
};
|
||||
|
||||
struct ath10k_htc_svc_tx_credits {
|
||||
u16 service_id;
|
||||
u8 credit_allocation;
|
||||
};
|
||||
|
||||
struct ath10k_htc {
|
||||
struct ath10k *ar;
|
||||
struct ath10k_htc_ep endpoint[ATH10K_HTC_EP_COUNT];
|
||||
|
||||
/* protects endpoints */
|
||||
spinlock_t tx_lock;
|
||||
|
||||
struct ath10k_htc_ops htc_ops;
|
||||
|
||||
u8 control_resp_buffer[ATH10K_HTC_MAX_CTRL_MSG_LEN];
|
||||
int control_resp_len;
|
||||
|
||||
struct completion ctl_resp;
|
||||
|
||||
int total_transmit_credits;
|
||||
int target_credit_size;
|
||||
u8 max_msgs_per_htc_bundle;
|
||||
int alt_data_credit_size;
|
||||
};
|
||||
|
||||
int ath10k_htc_init(struct ath10k *ar);
|
||||
int ath10k_htc_wait_target(struct ath10k_htc *htc);
|
||||
void ath10k_htc_setup_tx_req(struct ath10k_htc_ep *ep);
|
||||
int ath10k_htc_start(struct ath10k_htc *htc);
|
||||
int ath10k_htc_connect_service(struct ath10k_htc *htc,
|
||||
struct ath10k_htc_svc_conn_req *conn_req,
|
||||
struct ath10k_htc_svc_conn_resp *conn_resp);
|
||||
void ath10k_htc_change_tx_credit_flow(struct ath10k_htc *htc,
|
||||
enum ath10k_htc_ep_id eid,
|
||||
bool enable);
|
||||
int ath10k_htc_send(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
void ath10k_htc_stop_hl(struct ath10k *ar);
|
||||
|
||||
int ath10k_htc_send_hl(struct ath10k_htc *htc, enum ath10k_htc_ep_id eid,
|
||||
struct sk_buff *packet);
|
||||
struct sk_buff *ath10k_htc_alloc_skb(struct ath10k *ar, int size);
|
||||
void ath10k_htc_tx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_rx_completion_handler(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_htc_notify_tx_completion(struct ath10k_htc_ep *ep,
|
||||
struct sk_buff *skb);
|
||||
int ath10k_htc_process_trailer(struct ath10k_htc *htc,
|
||||
u8 *buffer,
|
||||
int length,
|
||||
enum ath10k_htc_ep_id src_eid,
|
||||
void *next_lookaheads,
|
||||
int *next_lookaheads_len);
|
||||
|
||||
#endif
|
436
sys/contrib/dev/athk/ath10k/htt.c
Normal file
436
sys/contrib/dev/athk/ath10k/htt.c
Normal file
@ -0,0 +1,436 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "htt.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "hif.h"
|
||||
|
||||
static const enum htt_t2h_msg_type htt_main_t2h_msg_types[] = {
|
||||
[HTT_MAIN_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_INSPECT_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
[HTT_MAIN_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
};
|
||||
|
||||
static const enum htt_t2h_msg_type htt_10x_t2h_msg_types[] = {
|
||||
[HTT_10X_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_10X_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_10X_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_10X_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_10X_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_10X_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
[HTT_10X_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
[HTT_10X_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
|
||||
[HTT_10X_T2H_MSG_TYPE_STATS_NOUPLOAD] = HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
||||
[HTT_10X_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
};
|
||||
|
||||
static const enum htt_t2h_msg_type htt_tlv_t2h_msg_types[] = {
|
||||
[HTT_TLV_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_TLV_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_INSPECT_IND] = HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND,
|
||||
[HTT_TLV_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE] =
|
||||
HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE,
|
||||
[HTT_TLV_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
[HTT_TLV_T2H_MSG_TYPE_RX_OFLD_PKT_ERR] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFLD_PKT_ERR,
|
||||
[HTT_TLV_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
};
|
||||
|
||||
static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = {
|
||||
[HTT_10_4_T2H_MSG_TYPE_VERSION_CONF] = HTT_T2H_MSG_TYPE_VERSION_CONF,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_IND] = HTT_T2H_MSG_TYPE_RX_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_FLUSH] = HTT_T2H_MSG_TYPE_RX_FLUSH,
|
||||
[HTT_10_4_T2H_MSG_TYPE_PEER_MAP] = HTT_T2H_MSG_TYPE_PEER_MAP,
|
||||
[HTT_10_4_T2H_MSG_TYPE_PEER_UNMAP] = HTT_T2H_MSG_TYPE_PEER_UNMAP,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_ADDBA] = HTT_T2H_MSG_TYPE_RX_ADDBA,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_DELBA] = HTT_T2H_MSG_TYPE_RX_DELBA,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_COMPL_IND] = HTT_T2H_MSG_TYPE_TX_COMPL_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_PKTLOG] = HTT_T2H_MSG_TYPE_PKTLOG,
|
||||
[HTT_10_4_T2H_MSG_TYPE_STATS_CONF] = HTT_T2H_MSG_TYPE_STATS_CONF,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_FRAG_IND] = HTT_T2H_MSG_TYPE_RX_FRAG_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_SEC_IND] = HTT_T2H_MSG_TYPE_SEC_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RC_UPDATE_IND] = HTT_T2H_MSG_TYPE_RC_UPDATE_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_INSPECT_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_INSPECT_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_MGMT_TX_COMPL_IND] =
|
||||
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION,
|
||||
[HTT_10_4_T2H_MSG_TYPE_CHAN_CHANGE] = HTT_T2H_MSG_TYPE_CHAN_CHANGE,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_PN_IND] = HTT_T2H_MSG_TYPE_RX_PN_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND] =
|
||||
HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TEST] = HTT_T2H_MSG_TYPE_TEST,
|
||||
[HTT_10_4_T2H_MSG_TYPE_EN_STATS] = HTT_T2H_MSG_TYPE_EN_STATS,
|
||||
[HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM] =
|
||||
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
|
||||
[HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] =
|
||||
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
||||
[HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
|
||||
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
|
||||
[HTT_10_4_T2H_MSG_TYPE_PEER_STATS] =
|
||||
HTT_T2H_MSG_TYPE_PEER_STATS,
|
||||
};
|
||||
|
||||
const struct ath10k_htt_rx_desc_ops qca988x_rx_desc_ops = {
|
||||
.rx_desc_size = sizeof(struct htt_rx_desc_v1),
|
||||
.rx_desc_msdu_payload_offset = offsetof(struct htt_rx_desc_v1, msdu_payload)
|
||||
};
|
||||
|
||||
static int ath10k_qca99x0_rx_desc_get_l3_pad_bytes(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v1 *rx_desc = container_of(rxd,
|
||||
struct htt_rx_desc_v1,
|
||||
base);
|
||||
|
||||
return MS(__le32_to_cpu(rx_desc->msdu_end.qca99x0.info1),
|
||||
RX_MSDU_END_INFO1_L3_HDR_PAD);
|
||||
}
|
||||
|
||||
static bool ath10k_qca99x0_rx_desc_msdu_limit_error(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v1 *rx_desc = container_of(rxd,
|
||||
struct htt_rx_desc_v1,
|
||||
base);
|
||||
|
||||
return !!(rx_desc->msdu_end.common.info0 &
|
||||
__cpu_to_le32(RX_MSDU_END_INFO0_MSDU_LIMIT_ERR));
|
||||
}
|
||||
|
||||
const struct ath10k_htt_rx_desc_ops qca99x0_rx_desc_ops = {
|
||||
.rx_desc_size = sizeof(struct htt_rx_desc_v1),
|
||||
.rx_desc_msdu_payload_offset = offsetof(struct htt_rx_desc_v1, msdu_payload),
|
||||
|
||||
.rx_desc_get_l3_pad_bytes = ath10k_qca99x0_rx_desc_get_l3_pad_bytes,
|
||||
.rx_desc_get_msdu_limit_error = ath10k_qca99x0_rx_desc_msdu_limit_error,
|
||||
};
|
||||
|
||||
static void ath10k_rx_desc_wcn3990_get_offsets(struct htt_rx_ring_rx_desc_offsets *off)
|
||||
{
|
||||
#define desc_offset(x) (offsetof(struct htt_rx_desc_v2, x) / 4)
|
||||
off->mac80211_hdr_offset = __cpu_to_le16(desc_offset(rx_hdr_status));
|
||||
off->msdu_payload_offset = __cpu_to_le16(desc_offset(msdu_payload));
|
||||
off->ppdu_start_offset = __cpu_to_le16(desc_offset(ppdu_start));
|
||||
off->ppdu_end_offset = __cpu_to_le16(desc_offset(ppdu_end));
|
||||
off->mpdu_start_offset = __cpu_to_le16(desc_offset(mpdu_start));
|
||||
off->mpdu_end_offset = __cpu_to_le16(desc_offset(mpdu_end));
|
||||
off->msdu_start_offset = __cpu_to_le16(desc_offset(msdu_start));
|
||||
off->msdu_end_offset = __cpu_to_le16(desc_offset(msdu_end));
|
||||
off->rx_attention_offset = __cpu_to_le16(desc_offset(attention));
|
||||
off->frag_info_offset = __cpu_to_le16(desc_offset(frag_info));
|
||||
#undef desc_offset
|
||||
}
|
||||
|
||||
static struct htt_rx_desc *
|
||||
ath10k_rx_desc_wcn3990_from_raw_buffer(void *buff)
|
||||
{
|
||||
return &((struct htt_rx_desc_v2 *)buff)->base;
|
||||
}
|
||||
|
||||
static struct rx_attention *
|
||||
ath10k_rx_desc_wcn3990_get_attention(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->attention;
|
||||
}
|
||||
|
||||
static struct rx_frag_info_common *
|
||||
ath10k_rx_desc_wcn3990_get_frag_info(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->frag_info.common;
|
||||
}
|
||||
|
||||
static struct rx_mpdu_start *
|
||||
ath10k_rx_desc_wcn3990_get_mpdu_start(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->mpdu_start;
|
||||
}
|
||||
|
||||
static struct rx_mpdu_end *
|
||||
ath10k_rx_desc_wcn3990_get_mpdu_end(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->mpdu_end;
|
||||
}
|
||||
|
||||
static struct rx_msdu_start_common *
|
||||
ath10k_rx_desc_wcn3990_get_msdu_start(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->msdu_start.common;
|
||||
}
|
||||
|
||||
static struct rx_msdu_end_common *
|
||||
ath10k_rx_desc_wcn3990_get_msdu_end(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->msdu_end.common;
|
||||
}
|
||||
|
||||
static struct rx_ppdu_start *
|
||||
ath10k_rx_desc_wcn3990_get_ppdu_start(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->ppdu_start;
|
||||
}
|
||||
|
||||
static struct rx_ppdu_end_common *
|
||||
ath10k_rx_desc_wcn3990_get_ppdu_end(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return &rx_desc->ppdu_end.common;
|
||||
}
|
||||
|
||||
static u8 *
|
||||
ath10k_rx_desc_wcn3990_get_rx_hdr_status(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return rx_desc->rx_hdr_status;
|
||||
}
|
||||
|
||||
static u8 *
|
||||
ath10k_rx_desc_wcn3990_get_msdu_payload(struct htt_rx_desc *rxd)
|
||||
{
|
||||
struct htt_rx_desc_v2 *rx_desc = container_of(rxd, struct htt_rx_desc_v2, base);
|
||||
|
||||
return rx_desc->msdu_payload;
|
||||
}
|
||||
|
||||
const struct ath10k_htt_rx_desc_ops wcn3990_rx_desc_ops = {
|
||||
.rx_desc_size = sizeof(struct htt_rx_desc_v2),
|
||||
.rx_desc_msdu_payload_offset = offsetof(struct htt_rx_desc_v2, msdu_payload),
|
||||
|
||||
.rx_desc_from_raw_buffer = ath10k_rx_desc_wcn3990_from_raw_buffer,
|
||||
.rx_desc_get_offsets = ath10k_rx_desc_wcn3990_get_offsets,
|
||||
.rx_desc_get_attention = ath10k_rx_desc_wcn3990_get_attention,
|
||||
.rx_desc_get_frag_info = ath10k_rx_desc_wcn3990_get_frag_info,
|
||||
.rx_desc_get_mpdu_start = ath10k_rx_desc_wcn3990_get_mpdu_start,
|
||||
.rx_desc_get_mpdu_end = ath10k_rx_desc_wcn3990_get_mpdu_end,
|
||||
.rx_desc_get_msdu_start = ath10k_rx_desc_wcn3990_get_msdu_start,
|
||||
.rx_desc_get_msdu_end = ath10k_rx_desc_wcn3990_get_msdu_end,
|
||||
.rx_desc_get_ppdu_start = ath10k_rx_desc_wcn3990_get_ppdu_start,
|
||||
.rx_desc_get_ppdu_end = ath10k_rx_desc_wcn3990_get_ppdu_end,
|
||||
.rx_desc_get_rx_hdr_status = ath10k_rx_desc_wcn3990_get_rx_hdr_status,
|
||||
.rx_desc_get_msdu_payload = ath10k_rx_desc_wcn3990_get_msdu_payload,
|
||||
};
|
||||
|
||||
int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k_htc_svc_conn_req conn_req;
|
||||
struct ath10k_htc_svc_conn_resp conn_resp;
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_htc_ep *ep;
|
||||
int status;
|
||||
|
||||
memset(&conn_req, 0, sizeof(conn_req));
|
||||
memset(&conn_resp, 0, sizeof(conn_resp));
|
||||
|
||||
conn_req.ep_ops.ep_tx_complete = ath10k_htt_htc_tx_complete;
|
||||
conn_req.ep_ops.ep_rx_complete = ath10k_htt_htc_t2h_msg_handler;
|
||||
conn_req.ep_ops.ep_tx_credits = ath10k_htt_op_ep_tx_credits;
|
||||
|
||||
/* connect to control service */
|
||||
conn_req.service_id = ATH10K_HTC_SVC_ID_HTT_DATA_MSG;
|
||||
|
||||
status = ath10k_htc_connect_service(&htt->ar->htc, &conn_req,
|
||||
&conn_resp);
|
||||
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
htt->eid = conn_resp.eid;
|
||||
|
||||
if (ar->bus_param.dev_type == ATH10K_DEV_TYPE_HL) {
|
||||
ep = &ar->htc.endpoint[htt->eid];
|
||||
ath10k_htc_setup_tx_req(ep);
|
||||
}
|
||||
|
||||
htt->disable_tx_comp = ath10k_hif_get_htt_tx_complete(htt->ar);
|
||||
if (htt->disable_tx_comp)
|
||||
ath10k_htc_change_tx_credit_flow(&htt->ar->htc, htt->eid, true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_init(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_htt *htt = &ar->htt;
|
||||
|
||||
htt->ar = ar;
|
||||
|
||||
/*
|
||||
* Prefetch enough data to satisfy target
|
||||
* classification engine.
|
||||
* This is for LL chips. HL chips will probably
|
||||
* transfer all frame in the tx fragment.
|
||||
*/
|
||||
htt->prefetch_len =
|
||||
36 + /* 802.11 + qos + ht */
|
||||
4 + /* 802.1q */
|
||||
8 + /* llc snap */
|
||||
2; /* ip4 dscp or ip6 priority */
|
||||
|
||||
switch (ar->running_fw->fw_file.htt_op_version) {
|
||||
case ATH10K_FW_HTT_OP_VERSION_10_4:
|
||||
ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_10_1:
|
||||
ar->htt.t2h_msg_types = htt_10x_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_10X_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_TLV:
|
||||
ar->htt.t2h_msg_types = htt_tlv_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_TLV_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_MAIN:
|
||||
ar->htt.t2h_msg_types = htt_main_t2h_msg_types;
|
||||
ar->htt.t2h_msg_types_max = HTT_MAIN_T2H_NUM_MSGS;
|
||||
break;
|
||||
case ATH10K_FW_HTT_OP_VERSION_MAX:
|
||||
case ATH10K_FW_HTT_OP_VERSION_UNSET:
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
ath10k_htt_set_tx_ops(htt);
|
||||
ath10k_htt_set_rx_ops(htt);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)
|
||||
|
||||
static int ath10k_htt_verify_version(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt target version %d.%d\n",
|
||||
htt->target_version_major, htt->target_version_minor);
|
||||
|
||||
if (htt->target_version_major != 2 &&
|
||||
htt->target_version_major != 3) {
|
||||
ath10k_err(ar, "unsupported htt major version %d. supported versions are 2 and 3\n",
|
||||
htt->target_version_major);
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_htt_setup(struct ath10k_htt *htt)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
int status;
|
||||
|
||||
init_completion(&htt->target_version_received);
|
||||
|
||||
status = ath10k_htt_h2t_ver_req_msg(htt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = wait_for_completion_timeout(&htt->target_version_received,
|
||||
HTT_TARGET_VERSION_TIMEOUT_HZ);
|
||||
if (status == 0) {
|
||||
ath10k_warn(ar, "htt version request timed out\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
status = ath10k_htt_verify_version(htt);
|
||||
if (status) {
|
||||
ath10k_warn(ar, "failed to verify htt version: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ath10k_htt_send_frag_desc_bank_cfg(htt);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = ath10k_htt_send_rx_ring_cfg(htt);
|
||||
if (status) {
|
||||
ath10k_warn(ar, "failed to setup rx ring: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
status = ath10k_htt_h2t_aggr_cfg_msg(htt,
|
||||
htt->max_num_ampdu,
|
||||
htt->max_num_amsdu);
|
||||
if (status) {
|
||||
ath10k_warn(ar, "failed to setup amsdu/ampdu limit: %d\n",
|
||||
status);
|
||||
return status;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
2478
sys/contrib/dev/athk/ath10k/htt.h
Normal file
2478
sys/contrib/dev/athk/ath10k/htt.h
Normal file
File diff suppressed because it is too large
Load Diff
4611
sys/contrib/dev/athk/ath10k/htt_rx.c
Normal file
4611
sys/contrib/dev/athk/ath10k/htt_rx.c
Normal file
File diff suppressed because it is too large
Load Diff
1835
sys/contrib/dev/athk/ath10k/htt_tx.c
Normal file
1835
sys/contrib/dev/athk/ath10k/htt_tx.c
Normal file
File diff suppressed because it is too large
Load Diff
1191
sys/contrib/dev/athk/ath10k/hw.c
Normal file
1191
sys/contrib/dev/athk/ath10k/hw.c
Normal file
File diff suppressed because it is too large
Load Diff
1200
sys/contrib/dev/athk/ath10k/hw.h
Normal file
1200
sys/contrib/dev/athk/ath10k/hw.h
Normal file
File diff suppressed because it is too large
Load Diff
10318
sys/contrib/dev/athk/ath10k/mac.c
Normal file
10318
sys/contrib/dev/athk/ath10k/mac.c
Normal file
File diff suppressed because it is too large
Load Diff
95
sys/contrib/dev/athk/ath10k/mac.h
Normal file
95
sys/contrib/dev/athk/ath10k/mac.h
Normal file
@ -0,0 +1,95 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _MAC_H_
|
||||
#define _MAC_H_
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "core.h"
|
||||
|
||||
#define WEP_KEYID_SHIFT 6
|
||||
|
||||
enum wmi_tlv_tx_pause_id;
|
||||
enum wmi_tlv_tx_pause_action;
|
||||
|
||||
struct ath10k_generic_iter {
|
||||
struct ath10k *ar;
|
||||
int ret;
|
||||
};
|
||||
|
||||
struct rfc1042_hdr {
|
||||
u8 llc_dsap;
|
||||
u8 llc_ssap;
|
||||
u8 llc_ctrl;
|
||||
u8 snap_oui[3];
|
||||
__be16 snap_type;
|
||||
} __packed;
|
||||
|
||||
struct ath10k *ath10k_mac_create(size_t priv_size);
|
||||
void ath10k_mac_destroy(struct ath10k *ar);
|
||||
int ath10k_mac_register(struct ath10k *ar);
|
||||
void ath10k_mac_unregister(struct ath10k *ar);
|
||||
struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id);
|
||||
void __ath10k_scan_finish(struct ath10k *ar);
|
||||
void ath10k_scan_finish(struct ath10k *ar);
|
||||
void ath10k_scan_timeout_work(struct work_struct *work);
|
||||
void ath10k_offchan_tx_purge(struct ath10k *ar);
|
||||
void ath10k_offchan_tx_work(struct work_struct *work);
|
||||
void ath10k_mgmt_over_wmi_tx_purge(struct ath10k *ar);
|
||||
void ath10k_mgmt_over_wmi_tx_work(struct work_struct *work);
|
||||
void ath10k_halt(struct ath10k *ar);
|
||||
void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif);
|
||||
void ath10k_drain_tx(struct ath10k *ar);
|
||||
bool ath10k_mac_is_peer_wep_key_set(struct ath10k *ar, const u8 *addr,
|
||||
u8 keyidx);
|
||||
int ath10k_mac_vif_chan(struct ieee80211_vif *vif,
|
||||
struct cfg80211_chan_def *def);
|
||||
|
||||
void ath10k_mac_handle_beacon(struct ath10k *ar, struct sk_buff *skb);
|
||||
void ath10k_mac_handle_beacon_miss(struct ath10k *ar, u32 vdev_id);
|
||||
void ath10k_mac_handle_tx_pause_vdev(struct ath10k *ar, u32 vdev_id,
|
||||
enum wmi_tlv_tx_pause_id pause_id,
|
||||
enum wmi_tlv_tx_pause_action action);
|
||||
|
||||
u8 ath10k_mac_hw_rate_to_idx(const struct ieee80211_supported_band *sband,
|
||||
u8 hw_rate, bool cck);
|
||||
u8 ath10k_mac_bitrate_to_idx(const struct ieee80211_supported_band *sband,
|
||||
u32 bitrate);
|
||||
|
||||
void ath10k_mac_tx_lock(struct ath10k *ar, int reason);
|
||||
void ath10k_mac_tx_unlock(struct ath10k *ar, int reason);
|
||||
void ath10k_mac_vif_tx_lock(struct ath10k_vif *arvif, int reason);
|
||||
void ath10k_mac_vif_tx_unlock(struct ath10k_vif *arvif, int reason);
|
||||
bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar);
|
||||
void ath10k_mac_tx_push_pending(struct ath10k *ar);
|
||||
int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq);
|
||||
struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
|
||||
u16 peer_id,
|
||||
u8 tid);
|
||||
int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val);
|
||||
void ath10k_mac_wait_tx_complete(struct ath10k *ar);
|
||||
int ath10k_mac_rfkill_enable_radio(struct ath10k *ar, bool enable);
|
||||
|
||||
static inline void ath10k_tx_h_seq_no(struct ieee80211_vif *vif,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct ath10k_vif *arvif = (void *)vif->drv_priv;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
|
||||
if (arvif->tx_seq_no == 0)
|
||||
arvif->tx_seq_no = 0x1000;
|
||||
|
||||
if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT)
|
||||
arvif->tx_seq_no += 0x10;
|
||||
hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
|
||||
hdr->seq_ctrl |= cpu_to_le16(arvif->tx_seq_no);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _MAC_H_ */
|
145
sys/contrib/dev/athk/ath10k/p2p.c
Normal file
145
sys/contrib/dev/athk/ath10k/p2p.c
Normal file
@ -0,0 +1,145 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "wmi.h"
|
||||
#include "mac.h"
|
||||
#include "p2p.h"
|
||||
|
||||
static void ath10k_p2p_noa_ie_fill(u8 *data, size_t len,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ieee80211_p2p_noa_attr *noa_attr;
|
||||
u8 ctwindow_oppps = noa->ctwindow_oppps;
|
||||
u8 ctwindow = ctwindow_oppps >> WMI_P2P_OPPPS_CTWINDOW_OFFSET;
|
||||
bool oppps = !!(ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT);
|
||||
__le16 *noa_attr_len;
|
||||
u16 attr_len;
|
||||
u8 noa_descriptors = noa->num_descriptors;
|
||||
int i;
|
||||
|
||||
/* P2P IE */
|
||||
data[0] = WLAN_EID_VENDOR_SPECIFIC;
|
||||
data[1] = len - 2;
|
||||
data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
|
||||
data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
|
||||
data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
|
||||
data[5] = WLAN_OUI_TYPE_WFA_P2P;
|
||||
|
||||
/* NOA ATTR */
|
||||
data[6] = IEEE80211_P2P_ATTR_ABSENCE_NOTICE;
|
||||
noa_attr_len = (__le16 *)&data[7]; /* 2 bytes */
|
||||
noa_attr = (struct ieee80211_p2p_noa_attr *)&data[9];
|
||||
|
||||
noa_attr->index = noa->index;
|
||||
noa_attr->oppps_ctwindow = ctwindow;
|
||||
if (oppps)
|
||||
noa_attr->oppps_ctwindow |= IEEE80211_P2P_OPPPS_ENABLE_BIT;
|
||||
|
||||
for (i = 0; i < noa_descriptors; i++) {
|
||||
noa_attr->desc[i].count =
|
||||
__le32_to_cpu(noa->descriptors[i].type_count);
|
||||
noa_attr->desc[i].duration = noa->descriptors[i].duration;
|
||||
noa_attr->desc[i].interval = noa->descriptors[i].interval;
|
||||
noa_attr->desc[i].start_time = noa->descriptors[i].start_time;
|
||||
}
|
||||
|
||||
attr_len = 2; /* index + oppps_ctwindow */
|
||||
attr_len += noa_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
|
||||
*noa_attr_len = __cpu_to_le16(attr_len);
|
||||
}
|
||||
|
||||
static size_t ath10k_p2p_noa_ie_len_compute(const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
if (!noa->num_descriptors &&
|
||||
!(noa->ctwindow_oppps & WMI_P2P_OPPPS_ENABLE_BIT))
|
||||
return 0;
|
||||
|
||||
len += 1 + 1 + 4; /* EID + len + OUI */
|
||||
len += 1 + 2; /* noa attr + attr len */
|
||||
len += 1 + 1; /* index + oppps_ctwindow */
|
||||
len += noa->num_descriptors * sizeof(struct ieee80211_p2p_noa_desc);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static void ath10k_p2p_noa_ie_assign(struct ath10k_vif *arvif, void *ie,
|
||||
size_t len)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
kfree(arvif->u.ap.noa_data);
|
||||
|
||||
arvif->u.ap.noa_data = ie;
|
||||
arvif->u.ap.noa_len = len;
|
||||
}
|
||||
|
||||
static void __ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
void *ie;
|
||||
size_t len;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
ath10k_p2p_noa_ie_assign(arvif, NULL, 0);
|
||||
|
||||
len = ath10k_p2p_noa_ie_len_compute(noa);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
ie = kmalloc(len, GFP_ATOMIC);
|
||||
if (!ie)
|
||||
return;
|
||||
|
||||
ath10k_p2p_noa_ie_fill(ie, len, noa);
|
||||
ath10k_p2p_noa_ie_assign(arvif, ie, len);
|
||||
}
|
||||
|
||||
void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
__ath10k_p2p_noa_update(arvif, noa);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
struct ath10k_p2p_noa_arg {
|
||||
u32 vdev_id;
|
||||
const struct wmi_p2p_noa_info *noa;
|
||||
};
|
||||
|
||||
static void ath10k_p2p_noa_update_vdev_iter(void *data, u8 *mac,
|
||||
struct ieee80211_vif *vif)
|
||||
{
|
||||
struct ath10k_vif *arvif = (void *)vif->drv_priv;
|
||||
struct ath10k_p2p_noa_arg *arg = data;
|
||||
|
||||
if (arvif->vdev_id != arg->vdev_id)
|
||||
return;
|
||||
|
||||
ath10k_p2p_noa_update(arvif, arg->noa);
|
||||
}
|
||||
|
||||
void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
|
||||
const struct wmi_p2p_noa_info *noa)
|
||||
{
|
||||
struct ath10k_p2p_noa_arg arg = {
|
||||
.vdev_id = vdev_id,
|
||||
.noa = noa,
|
||||
};
|
||||
|
||||
ieee80211_iterate_active_interfaces_atomic(ar->hw,
|
||||
ATH10K_ITER_NORMAL_FLAGS,
|
||||
ath10k_p2p_noa_update_vdev_iter,
|
||||
&arg);
|
||||
}
|
17
sys/contrib/dev/athk/ath10k/p2p.h
Normal file
17
sys/contrib/dev/athk/ath10k/p2p.h
Normal file
@ -0,0 +1,17 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2015 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _P2P_H
|
||||
#define _P2P_H
|
||||
|
||||
struct ath10k_vif;
|
||||
struct wmi_p2p_noa_info;
|
||||
|
||||
void ath10k_p2p_noa_update(struct ath10k_vif *arvif,
|
||||
const struct wmi_p2p_noa_info *noa);
|
||||
void ath10k_p2p_noa_update_by_vdev_id(struct ath10k *ar, u32 vdev_id,
|
||||
const struct wmi_p2p_noa_info *noa);
|
||||
|
||||
#endif
|
3958
sys/contrib/dev/athk/ath10k/pci.c
Normal file
3958
sys/contrib/dev/athk/ath10k/pci.c
Normal file
File diff suppressed because it is too large
Load Diff
259
sys/contrib/dev/athk/ath10k/pci.h
Normal file
259
sys/contrib/dev/athk/ath10k/pci.h
Normal file
@ -0,0 +1,259 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _PCI_H_
|
||||
#define _PCI_H_
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include "hw.h"
|
||||
#include "ce.h"
|
||||
#include "ahb.h"
|
||||
|
||||
/*
|
||||
* maximum number of bytes that can be
|
||||
* handled atomically by DiagRead/DiagWrite
|
||||
*/
|
||||
#define DIAG_TRANSFER_LIMIT 2048
|
||||
|
||||
struct bmi_xfer {
|
||||
bool tx_done;
|
||||
bool rx_done;
|
||||
bool wait_for_resp;
|
||||
u32 resp_len;
|
||||
};
|
||||
|
||||
/*
|
||||
* PCI-specific Target state
|
||||
*
|
||||
* NOTE: Structure is shared between Host software and Target firmware!
|
||||
*
|
||||
* Much of this may be of interest to the Host so
|
||||
* HOST_INTEREST->hi_interconnect_state points here
|
||||
* (and all members are 32-bit quantities in order to
|
||||
* facilitate Host access). In particular, Host software is
|
||||
* required to initialize pipe_cfg_addr and svc_to_pipe_map.
|
||||
*/
|
||||
struct pcie_state {
|
||||
/* Pipe configuration Target address */
|
||||
/* NB: ce_pipe_config[CE_COUNT] */
|
||||
u32 pipe_cfg_addr;
|
||||
|
||||
/* Service to pipe map Target address */
|
||||
/* NB: service_to_pipe[PIPE_TO_CE_MAP_CN] */
|
||||
u32 svc_to_pipe_map;
|
||||
|
||||
/* number of MSI interrupts requested */
|
||||
u32 msi_requested;
|
||||
|
||||
/* number of MSI interrupts granted */
|
||||
u32 msi_granted;
|
||||
|
||||
/* Message Signalled Interrupt address */
|
||||
u32 msi_addr;
|
||||
|
||||
/* Base data */
|
||||
u32 msi_data;
|
||||
|
||||
/*
|
||||
* Data for firmware interrupt;
|
||||
* MSI data for other interrupts are
|
||||
* in various SoC registers
|
||||
*/
|
||||
u32 msi_fw_intr_data;
|
||||
|
||||
/* PCIE_PWR_METHOD_* */
|
||||
u32 power_mgmt_method;
|
||||
|
||||
/* PCIE_CONFIG_FLAG_* */
|
||||
u32 config_flags;
|
||||
};
|
||||
|
||||
/* PCIE_CONFIG_FLAG definitions */
|
||||
#define PCIE_CONFIG_FLAG_ENABLE_L1 0x0000001
|
||||
|
||||
/* Per-pipe state. */
|
||||
struct ath10k_pci_pipe {
|
||||
/* Handle of underlying Copy Engine */
|
||||
struct ath10k_ce_pipe *ce_hdl;
|
||||
|
||||
/* Our pipe number; facilitiates use of pipe_info ptrs. */
|
||||
u8 pipe_num;
|
||||
|
||||
/* Convenience back pointer to hif_ce_state. */
|
||||
struct ath10k *hif_ce_state;
|
||||
|
||||
size_t buf_sz;
|
||||
|
||||
/* protects compl_free and num_send_allowed */
|
||||
spinlock_t pipe_lock;
|
||||
};
|
||||
|
||||
struct ath10k_pci_supp_chip {
|
||||
u32 dev_id;
|
||||
u32 rev_id;
|
||||
};
|
||||
|
||||
enum ath10k_pci_irq_mode {
|
||||
ATH10K_PCI_IRQ_AUTO = 0,
|
||||
ATH10K_PCI_IRQ_LEGACY = 1,
|
||||
ATH10K_PCI_IRQ_MSI = 2,
|
||||
};
|
||||
|
||||
struct ath10k_pci {
|
||||
struct pci_dev *pdev;
|
||||
struct device *dev;
|
||||
struct ath10k *ar;
|
||||
void __iomem *mem;
|
||||
size_t mem_len;
|
||||
|
||||
/* Operating interrupt mode */
|
||||
enum ath10k_pci_irq_mode oper_irq_mode;
|
||||
|
||||
struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
|
||||
|
||||
/* Copy Engine used for Diagnostic Accesses */
|
||||
struct ath10k_ce_pipe *ce_diag;
|
||||
/* For protecting ce_diag */
|
||||
struct mutex ce_diag_mutex;
|
||||
|
||||
struct work_struct dump_work;
|
||||
|
||||
struct ath10k_ce ce;
|
||||
struct timer_list rx_post_retry;
|
||||
|
||||
/* Due to HW quirks it is recommended to disable ASPM during device
|
||||
* bootup. To do that the original PCI-E Link Control is stored before
|
||||
* device bootup is executed and re-programmed later.
|
||||
*/
|
||||
u16 link_ctl;
|
||||
|
||||
/* Protects ps_awake and ps_wake_refcount */
|
||||
spinlock_t ps_lock;
|
||||
|
||||
/* The device has a special powersave-oriented register. When device is
|
||||
* considered asleep it drains less power and driver is forbidden from
|
||||
* accessing most MMIO registers. If host were to access them without
|
||||
* waking up the device might scribble over host memory or return
|
||||
* 0xdeadbeef readouts.
|
||||
*/
|
||||
unsigned long ps_wake_refcount;
|
||||
|
||||
/* Waking up takes some time (up to 2ms in some cases) so it can be bad
|
||||
* for latency. To mitigate this the device isn't immediately allowed
|
||||
* to sleep after all references are undone - instead there's a grace
|
||||
* period after which the powersave register is updated unless some
|
||||
* activity to/from device happened in the meantime.
|
||||
*
|
||||
* Also see comments on ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC.
|
||||
*/
|
||||
struct timer_list ps_timer;
|
||||
|
||||
/* MMIO registers are used to communicate with the device. With
|
||||
* intensive traffic accessing powersave register would be a bit
|
||||
* wasteful overhead and would needlessly stall CPU. It is far more
|
||||
* efficient to rely on a variable in RAM and update it only upon
|
||||
* powersave register state changes.
|
||||
*/
|
||||
bool ps_awake;
|
||||
|
||||
/* pci power save, disable for QCA988X and QCA99X0.
|
||||
* Writing 'false' to this variable avoids frequent locking
|
||||
* on MMIO read/write.
|
||||
*/
|
||||
bool pci_ps;
|
||||
|
||||
/* Chip specific pci reset routine used to do a safe reset */
|
||||
int (*pci_soft_reset)(struct ath10k *ar);
|
||||
|
||||
/* Chip specific pci full reset function */
|
||||
int (*pci_hard_reset)(struct ath10k *ar);
|
||||
|
||||
/* chip specific methods for converting target CPU virtual address
|
||||
* space to CE address space
|
||||
*/
|
||||
u32 (*targ_cpu_to_ce_addr)(struct ath10k *ar, u32 addr);
|
||||
|
||||
struct ce_attr *attr;
|
||||
struct ce_pipe_config *pipe_config;
|
||||
struct ce_service_to_pipe *serv_to_pipe;
|
||||
|
||||
/* Keep this entry in the last, memory for struct ath10k_ahb is
|
||||
* allocated (ahb support enabled case) in the continuation of
|
||||
* this struct.
|
||||
*/
|
||||
struct ath10k_ahb ahb[];
|
||||
|
||||
};
|
||||
|
||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_pci *)ar->drv_priv;
|
||||
}
|
||||
|
||||
#define ATH10K_PCI_RX_POST_RETRY_MS 50
|
||||
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
|
||||
#define PCIE_WAKE_TIMEOUT 30000 /* 30ms */
|
||||
#define PCIE_WAKE_LATE_US 10000 /* 10ms */
|
||||
|
||||
#define BAR_NUM 0
|
||||
|
||||
#define CDC_WAR_MAGIC_STR 0xceef0000
|
||||
#define CDC_WAR_DATA_CE 4
|
||||
|
||||
/* Wait up to this many Ms for a Diagnostic Access CE operation to complete */
|
||||
#define DIAG_ACCESS_CE_TIMEOUT_US 10000 /* 10 ms */
|
||||
#define DIAG_ACCESS_CE_WAIT_US 50
|
||||
|
||||
void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value);
|
||||
void ath10k_pci_soc_write32(struct ath10k *ar, u32 addr, u32 val);
|
||||
void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val);
|
||||
|
||||
u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
|
||||
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
|
||||
u32 ath10k_pci_reg_read32(struct ath10k *ar, u32 addr);
|
||||
|
||||
int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||
struct ath10k_hif_sg_item *items, int n_items);
|
||||
int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
||||
size_t buf_len);
|
||||
int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||
const void *data, int nbytes);
|
||||
int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar, void *req, u32 req_len,
|
||||
void *resp, u32 *resp_len);
|
||||
int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
||||
u8 *ul_pipe, u8 *dl_pipe);
|
||||
void ath10k_pci_hif_get_default_pipe(struct ath10k *ar, u8 *ul_pipe,
|
||||
u8 *dl_pipe);
|
||||
void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||
int force);
|
||||
u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe);
|
||||
void ath10k_pci_hif_power_down(struct ath10k *ar);
|
||||
int ath10k_pci_alloc_pipes(struct ath10k *ar);
|
||||
void ath10k_pci_free_pipes(struct ath10k *ar);
|
||||
void ath10k_pci_rx_replenish_retry(struct timer_list *t);
|
||||
void ath10k_pci_ce_deinit(struct ath10k *ar);
|
||||
void ath10k_pci_init_napi(struct ath10k *ar);
|
||||
int ath10k_pci_init_pipes(struct ath10k *ar);
|
||||
int ath10k_pci_init_config(struct ath10k *ar);
|
||||
void ath10k_pci_rx_post(struct ath10k *ar);
|
||||
void ath10k_pci_flush(struct ath10k *ar);
|
||||
void ath10k_pci_enable_legacy_irq(struct ath10k *ar);
|
||||
bool ath10k_pci_irq_pending(struct ath10k *ar);
|
||||
void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar);
|
||||
void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar);
|
||||
int ath10k_pci_wait_for_target_init(struct ath10k *ar);
|
||||
int ath10k_pci_setup_resource(struct ath10k *ar);
|
||||
void ath10k_pci_release_resource(struct ath10k *ar);
|
||||
|
||||
/* QCA6174 is known to have Tx/Rx issues when SOC_WAKE register is poked too
|
||||
* frequently. To avoid this put SoC to sleep after a very conservative grace
|
||||
* period. Adjust with great care.
|
||||
*/
|
||||
#define ATH10K_PCI_SLEEP_GRACE_PERIOD_MSEC 60
|
||||
|
||||
#endif /* _PCI_H_ */
|
1094
sys/contrib/dev/athk/ath10k/qmi.c
Normal file
1094
sys/contrib/dev/athk/ath10k/qmi.c
Normal file
File diff suppressed because it is too large
Load Diff
122
sys/contrib/dev/athk/ath10k/qmi.h
Normal file
122
sys/contrib/dev/athk/ath10k/qmi.h
Normal file
@ -0,0 +1,122 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
#ifndef _ATH10K_QMI_H_
|
||||
#define _ATH10K_QMI_H_
|
||||
|
||||
#include <linux/soc/qcom/qmi.h>
|
||||
#include <linux/qrtr.h>
|
||||
#include "qmi_wlfw_v01.h"
|
||||
|
||||
#define MAX_NUM_MEMORY_REGIONS 2
|
||||
#define MAX_TIMESTAMP_LEN 32
|
||||
#define MAX_BUILD_ID_LEN 128
|
||||
#define MAX_NUM_CAL_V01 5
|
||||
|
||||
enum ath10k_qmi_driver_event_type {
|
||||
ATH10K_QMI_EVENT_SERVER_ARRIVE,
|
||||
ATH10K_QMI_EVENT_SERVER_EXIT,
|
||||
ATH10K_QMI_EVENT_FW_READY_IND,
|
||||
ATH10K_QMI_EVENT_FW_DOWN_IND,
|
||||
ATH10K_QMI_EVENT_MSA_READY_IND,
|
||||
ATH10K_QMI_EVENT_MAX,
|
||||
};
|
||||
|
||||
struct ath10k_msa_mem_info {
|
||||
phys_addr_t addr;
|
||||
u32 size;
|
||||
bool secure;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_chip_info {
|
||||
u32 chip_id;
|
||||
u32 chip_family;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_board_info {
|
||||
u32 board_id;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_soc_info {
|
||||
u32 soc_id;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_cal_data {
|
||||
u32 cal_id;
|
||||
u32 total_size;
|
||||
u8 *data;
|
||||
};
|
||||
|
||||
struct ath10k_tgt_pipe_cfg {
|
||||
__le32 pipe_num;
|
||||
__le32 pipe_dir;
|
||||
__le32 nentries;
|
||||
__le32 nbytes_max;
|
||||
__le32 flags;
|
||||
__le32 reserved;
|
||||
};
|
||||
|
||||
struct ath10k_svc_pipe_cfg {
|
||||
__le32 service_id;
|
||||
__le32 pipe_dir;
|
||||
__le32 pipe_num;
|
||||
};
|
||||
|
||||
struct ath10k_shadow_reg_cfg {
|
||||
__le16 ce_id;
|
||||
__le16 reg_offset;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_wlan_enable_cfg {
|
||||
u32 num_ce_tgt_cfg;
|
||||
struct ath10k_tgt_pipe_cfg *ce_tgt_cfg;
|
||||
u32 num_ce_svc_pipe_cfg;
|
||||
struct ath10k_svc_pipe_cfg *ce_svc_cfg;
|
||||
u32 num_shadow_reg_cfg;
|
||||
struct ath10k_shadow_reg_cfg *shadow_reg_cfg;
|
||||
};
|
||||
|
||||
struct ath10k_qmi_driver_event {
|
||||
struct list_head list;
|
||||
enum ath10k_qmi_driver_event_type type;
|
||||
void *data;
|
||||
};
|
||||
|
||||
enum ath10k_qmi_state {
|
||||
ATH10K_QMI_STATE_INIT_DONE,
|
||||
ATH10K_QMI_STATE_DEINIT,
|
||||
};
|
||||
|
||||
struct ath10k_qmi {
|
||||
struct ath10k *ar;
|
||||
struct qmi_handle qmi_hdl;
|
||||
struct sockaddr_qrtr sq;
|
||||
struct work_struct event_work;
|
||||
struct workqueue_struct *event_wq;
|
||||
struct list_head event_list;
|
||||
spinlock_t event_lock; /* spinlock for qmi event list */
|
||||
u32 nr_mem_region;
|
||||
struct ath10k_msa_mem_info mem_region[MAX_NUM_MEMORY_REGIONS];
|
||||
struct ath10k_qmi_chip_info chip_info;
|
||||
struct ath10k_qmi_board_info board_info;
|
||||
struct ath10k_qmi_soc_info soc_info;
|
||||
char fw_build_id[MAX_BUILD_ID_LEN + 1];
|
||||
u32 fw_version;
|
||||
bool fw_ready;
|
||||
char fw_build_timestamp[MAX_TIMESTAMP_LEN + 1];
|
||||
struct ath10k_qmi_cal_data cal_data[MAX_NUM_CAL_V01];
|
||||
bool msa_fixed_perm;
|
||||
enum ath10k_qmi_state state;
|
||||
};
|
||||
|
||||
int ath10k_qmi_wlan_enable(struct ath10k *ar,
|
||||
struct ath10k_qmi_wlan_enable_cfg *config,
|
||||
enum wlfw_driver_mode_enum_v01 mode,
|
||||
const char *version);
|
||||
int ath10k_qmi_wlan_disable(struct ath10k *ar);
|
||||
int ath10k_qmi_init(struct ath10k *ar, u32 msa_size);
|
||||
int ath10k_qmi_deinit(struct ath10k *ar);
|
||||
int ath10k_qmi_set_fw_log_mode(struct ath10k *ar, u8 fw_log_mode);
|
||||
|
||||
#endif /* ATH10K_QMI_H */
|
2308
sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.c
Normal file
2308
sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.c
Normal file
File diff suppressed because it is too large
Load Diff
693
sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.h
Normal file
693
sys/contrib/dev/athk/ath10k/qmi_wlfw_v01.h
Normal file
@ -0,0 +1,693 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef WCN3990_QMI_SVC_V01_H
|
||||
#define WCN3990_QMI_SVC_V01_H
|
||||
|
||||
#define WLFW_SERVICE_ID_V01 0x45
|
||||
#define WLFW_SERVICE_VERS_V01 0x01
|
||||
|
||||
#define QMI_WLFW_BDF_DOWNLOAD_REQ_V01 0x0025
|
||||
#define QMI_WLFW_MEM_READY_IND_V01 0x0037
|
||||
#define QMI_WLFW_DYNAMIC_FEATURE_MASK_RESP_V01 0x003B
|
||||
#define QMI_WLFW_INITIATE_CAL_UPDATE_IND_V01 0x002A
|
||||
#define QMI_WLFW_HOST_CAP_REQ_V01 0x0034
|
||||
#define QMI_WLFW_M3_INFO_REQ_V01 0x003C
|
||||
#define QMI_WLFW_CAP_REQ_V01 0x0024
|
||||
#define QMI_WLFW_FW_INIT_DONE_IND_V01 0x0038
|
||||
#define QMI_WLFW_CAL_REPORT_REQ_V01 0x0026
|
||||
#define QMI_WLFW_M3_INFO_RESP_V01 0x003C
|
||||
#define QMI_WLFW_CAL_UPDATE_RESP_V01 0x0029
|
||||
#define QMI_WLFW_CAL_DOWNLOAD_RESP_V01 0x0027
|
||||
#define QMI_WLFW_XO_CAL_IND_V01 0x003D
|
||||
#define QMI_WLFW_INI_RESP_V01 0x002F
|
||||
#define QMI_WLFW_CAL_REPORT_RESP_V01 0x0026
|
||||
#define QMI_WLFW_MAC_ADDR_RESP_V01 0x0033
|
||||
#define QMI_WLFW_INITIATE_CAL_DOWNLOAD_IND_V01 0x0028
|
||||
#define QMI_WLFW_HOST_CAP_RESP_V01 0x0034
|
||||
#define QMI_WLFW_MSA_READY_IND_V01 0x002B
|
||||
#define QMI_WLFW_ATHDIAG_WRITE_RESP_V01 0x0031
|
||||
#define QMI_WLFW_WLAN_MODE_REQ_V01 0x0022
|
||||
#define QMI_WLFW_IND_REGISTER_REQ_V01 0x0020
|
||||
#define QMI_WLFW_WLAN_CFG_RESP_V01 0x0023
|
||||
#define QMI_WLFW_REQUEST_MEM_IND_V01 0x0035
|
||||
#define QMI_WLFW_REJUVENATE_IND_V01 0x0039
|
||||
#define QMI_WLFW_DYNAMIC_FEATURE_MASK_REQ_V01 0x003B
|
||||
#define QMI_WLFW_ATHDIAG_WRITE_REQ_V01 0x0031
|
||||
#define QMI_WLFW_WLAN_MODE_RESP_V01 0x0022
|
||||
#define QMI_WLFW_RESPOND_MEM_REQ_V01 0x0036
|
||||
#define QMI_WLFW_PIN_CONNECT_RESULT_IND_V01 0x002C
|
||||
#define QMI_WLFW_FW_READY_IND_V01 0x0021
|
||||
#define QMI_WLFW_MSA_READY_RESP_V01 0x002E
|
||||
#define QMI_WLFW_CAL_UPDATE_REQ_V01 0x0029
|
||||
#define QMI_WLFW_INI_REQ_V01 0x002F
|
||||
#define QMI_WLFW_BDF_DOWNLOAD_RESP_V01 0x0025
|
||||
#define QMI_WLFW_REJUVENATE_ACK_RESP_V01 0x003A
|
||||
#define QMI_WLFW_MSA_INFO_RESP_V01 0x002D
|
||||
#define QMI_WLFW_MSA_READY_REQ_V01 0x002E
|
||||
#define QMI_WLFW_CAP_RESP_V01 0x0024
|
||||
#define QMI_WLFW_REJUVENATE_ACK_REQ_V01 0x003A
|
||||
#define QMI_WLFW_ATHDIAG_READ_RESP_V01 0x0030
|
||||
#define QMI_WLFW_VBATT_REQ_V01 0x0032
|
||||
#define QMI_WLFW_MAC_ADDR_REQ_V01 0x0033
|
||||
#define QMI_WLFW_RESPOND_MEM_RESP_V01 0x0036
|
||||
#define QMI_WLFW_VBATT_RESP_V01 0x0032
|
||||
#define QMI_WLFW_MSA_INFO_REQ_V01 0x002D
|
||||
#define QMI_WLFW_CAL_DOWNLOAD_REQ_V01 0x0027
|
||||
#define QMI_WLFW_ATHDIAG_READ_REQ_V01 0x0030
|
||||
#define QMI_WLFW_WLAN_CFG_REQ_V01 0x0023
|
||||
#define QMI_WLFW_IND_REGISTER_RESP_V01 0x0020
|
||||
|
||||
#define QMI_WLFW_MAX_MEM_REG_V01 2
|
||||
#define QMI_WLFW_MAX_NUM_MEM_SEG_V01 16
|
||||
#define QMI_WLFW_MAX_NUM_CAL_V01 5
|
||||
#define QMI_WLFW_MAX_DATA_SIZE_V01 6144
|
||||
#define QMI_WLFW_FUNCTION_NAME_LEN_V01 128
|
||||
#define QMI_WLFW_MAX_NUM_CE_V01 12
|
||||
#define QMI_WLFW_MAX_TIMESTAMP_LEN_V01 32
|
||||
#define QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01 6144
|
||||
#define QMI_WLFW_MAX_NUM_GPIO_V01 32
|
||||
#define QMI_WLFW_MAX_BUILD_ID_LEN_V01 128
|
||||
#define QMI_WLFW_MAX_NUM_MEM_CFG_V01 2
|
||||
#define QMI_WLFW_MAX_STR_LEN_V01 16
|
||||
#define QMI_WLFW_MAX_NUM_SHADOW_REG_V01 24
|
||||
#define QMI_WLFW_MAC_ADDR_SIZE_V01 6
|
||||
#define QMI_WLFW_MAX_SHADOW_REG_V2 36
|
||||
#define QMI_WLFW_MAX_NUM_SVC_V01 24
|
||||
|
||||
enum wlfw_driver_mode_enum_v01 {
|
||||
QMI_WLFW_MISSION_V01 = 0,
|
||||
QMI_WLFW_FTM_V01 = 1,
|
||||
QMI_WLFW_EPPING_V01 = 2,
|
||||
QMI_WLFW_WALTEST_V01 = 3,
|
||||
QMI_WLFW_OFF_V01 = 4,
|
||||
QMI_WLFW_CCPM_V01 = 5,
|
||||
QMI_WLFW_QVIT_V01 = 6,
|
||||
QMI_WLFW_CALIBRATION_V01 = 7,
|
||||
};
|
||||
|
||||
enum wlfw_cal_temp_id_enum_v01 {
|
||||
QMI_WLFW_CAL_TEMP_IDX_0_V01 = 0,
|
||||
QMI_WLFW_CAL_TEMP_IDX_1_V01 = 1,
|
||||
QMI_WLFW_CAL_TEMP_IDX_2_V01 = 2,
|
||||
QMI_WLFW_CAL_TEMP_IDX_3_V01 = 3,
|
||||
QMI_WLFW_CAL_TEMP_IDX_4_V01 = 4,
|
||||
};
|
||||
|
||||
enum wlfw_pipedir_enum_v01 {
|
||||
QMI_WLFW_PIPEDIR_NONE_V01 = 0,
|
||||
QMI_WLFW_PIPEDIR_IN_V01 = 1,
|
||||
QMI_WLFW_PIPEDIR_OUT_V01 = 2,
|
||||
QMI_WLFW_PIPEDIR_INOUT_V01 = 3,
|
||||
};
|
||||
|
||||
enum wlfw_mem_type_enum_v01 {
|
||||
QMI_WLFW_MEM_TYPE_MSA_V01 = 0,
|
||||
QMI_WLFW_MEM_TYPE_DDR_V01 = 1,
|
||||
};
|
||||
|
||||
#define QMI_WLFW_CE_ATTR_FLAGS_V01 ((u32)0x00)
|
||||
#define QMI_WLFW_CE_ATTR_NO_SNOOP_V01 ((u32)0x01)
|
||||
#define QMI_WLFW_CE_ATTR_BYTE_SWAP_DATA_V01 ((u32)0x02)
|
||||
#define QMI_WLFW_CE_ATTR_SWIZZLE_DESCRIPTORS_V01 ((u32)0x04)
|
||||
#define QMI_WLFW_CE_ATTR_DISABLE_INTR_V01 ((u32)0x08)
|
||||
#define QMI_WLFW_CE_ATTR_ENABLE_POLL_V01 ((u32)0x10)
|
||||
|
||||
#define QMI_WLFW_ALREADY_REGISTERED_V01 ((u64)0x01ULL)
|
||||
#define QMI_WLFW_FW_READY_V01 ((u64)0x02ULL)
|
||||
#define QMI_WLFW_MSA_READY_V01 ((u64)0x04ULL)
|
||||
#define QMI_WLFW_MEM_READY_V01 ((u64)0x08ULL)
|
||||
#define QMI_WLFW_FW_INIT_DONE_V01 ((u64)0x10ULL)
|
||||
|
||||
#define QMI_WLFW_FW_REJUVENATE_V01 ((u64)0x01ULL)
|
||||
|
||||
struct wlfw_ce_tgt_pipe_cfg_s_v01 {
|
||||
__le32 pipe_num;
|
||||
__le32 pipe_dir;
|
||||
__le32 nentries;
|
||||
__le32 nbytes_max;
|
||||
__le32 flags;
|
||||
};
|
||||
|
||||
struct wlfw_ce_svc_pipe_cfg_s_v01 {
|
||||
__le32 service_id;
|
||||
__le32 pipe_dir;
|
||||
__le32 pipe_num;
|
||||
};
|
||||
|
||||
struct wlfw_shadow_reg_cfg_s_v01 {
|
||||
u16 id;
|
||||
u16 offset;
|
||||
};
|
||||
|
||||
struct wlfw_shadow_reg_v2_cfg_s_v01 {
|
||||
u32 addr;
|
||||
};
|
||||
|
||||
struct wlfw_memory_region_info_s_v01 {
|
||||
u64 region_addr;
|
||||
u32 size;
|
||||
u8 secure_flag;
|
||||
};
|
||||
|
||||
struct wlfw_mem_cfg_s_v01 {
|
||||
u64 offset;
|
||||
u32 size;
|
||||
u8 secure_flag;
|
||||
};
|
||||
|
||||
struct wlfw_mem_seg_s_v01 {
|
||||
u32 size;
|
||||
enum wlfw_mem_type_enum_v01 type;
|
||||
u32 mem_cfg_len;
|
||||
struct wlfw_mem_cfg_s_v01 mem_cfg[QMI_WLFW_MAX_NUM_MEM_CFG_V01];
|
||||
};
|
||||
|
||||
struct wlfw_mem_seg_resp_s_v01 {
|
||||
u64 addr;
|
||||
u32 size;
|
||||
enum wlfw_mem_type_enum_v01 type;
|
||||
};
|
||||
|
||||
struct wlfw_rf_chip_info_s_v01 {
|
||||
u32 chip_id;
|
||||
u32 chip_family;
|
||||
};
|
||||
|
||||
struct wlfw_rf_board_info_s_v01 {
|
||||
u32 board_id;
|
||||
};
|
||||
|
||||
struct wlfw_soc_info_s_v01 {
|
||||
u32 soc_id;
|
||||
};
|
||||
|
||||
struct wlfw_fw_version_info_s_v01 {
|
||||
u32 fw_version;
|
||||
char fw_build_timestamp[QMI_WLFW_MAX_TIMESTAMP_LEN_V01 + 1];
|
||||
};
|
||||
|
||||
struct wlfw_ind_register_req_msg_v01 {
|
||||
u8 fw_ready_enable_valid;
|
||||
u8 fw_ready_enable;
|
||||
u8 initiate_cal_download_enable_valid;
|
||||
u8 initiate_cal_download_enable;
|
||||
u8 initiate_cal_update_enable_valid;
|
||||
u8 initiate_cal_update_enable;
|
||||
u8 msa_ready_enable_valid;
|
||||
u8 msa_ready_enable;
|
||||
u8 pin_connect_result_enable_valid;
|
||||
u8 pin_connect_result_enable;
|
||||
u8 client_id_valid;
|
||||
u32 client_id;
|
||||
u8 request_mem_enable_valid;
|
||||
u8 request_mem_enable;
|
||||
u8 mem_ready_enable_valid;
|
||||
u8 mem_ready_enable;
|
||||
u8 fw_init_done_enable_valid;
|
||||
u8 fw_init_done_enable;
|
||||
u8 rejuvenate_enable_valid;
|
||||
u32 rejuvenate_enable;
|
||||
u8 xo_cal_enable_valid;
|
||||
u8 xo_cal_enable;
|
||||
};
|
||||
|
||||
#define WLFW_IND_REGISTER_REQ_MSG_V01_MAX_MSG_LEN 50
|
||||
extern struct qmi_elem_info wlfw_ind_register_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_ind_register_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u8 fw_status_valid;
|
||||
u64 fw_status;
|
||||
};
|
||||
|
||||
#define WLFW_IND_REGISTER_RESP_MSG_V01_MAX_MSG_LEN 18
|
||||
extern struct qmi_elem_info wlfw_ind_register_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_fw_ready_ind_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_FW_READY_IND_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_fw_ready_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_msa_ready_ind_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_MSA_READY_IND_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_msa_ready_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_pin_connect_result_ind_msg_v01 {
|
||||
u8 pwr_pin_result_valid;
|
||||
u32 pwr_pin_result;
|
||||
u8 phy_io_pin_result_valid;
|
||||
u32 phy_io_pin_result;
|
||||
u8 rf_pin_result_valid;
|
||||
u32 rf_pin_result;
|
||||
};
|
||||
|
||||
#define WLFW_PIN_CONNECT_RESULT_IND_MSG_V01_MAX_MSG_LEN 21
|
||||
extern struct qmi_elem_info wlfw_pin_connect_result_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_wlan_mode_req_msg_v01 {
|
||||
enum wlfw_driver_mode_enum_v01 mode;
|
||||
u8 hw_debug_valid;
|
||||
u8 hw_debug;
|
||||
};
|
||||
|
||||
#define WLFW_WLAN_MODE_REQ_MSG_V01_MAX_MSG_LEN 11
|
||||
extern struct qmi_elem_info wlfw_wlan_mode_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_wlan_mode_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_WLAN_MODE_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_wlan_mode_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_wlan_cfg_req_msg_v01 {
|
||||
u8 host_version_valid;
|
||||
char host_version[QMI_WLFW_MAX_STR_LEN_V01 + 1];
|
||||
u8 tgt_cfg_valid;
|
||||
u32 tgt_cfg_len;
|
||||
struct wlfw_ce_tgt_pipe_cfg_s_v01 tgt_cfg[QMI_WLFW_MAX_NUM_CE_V01];
|
||||
u8 svc_cfg_valid;
|
||||
u32 svc_cfg_len;
|
||||
struct wlfw_ce_svc_pipe_cfg_s_v01 svc_cfg[QMI_WLFW_MAX_NUM_SVC_V01];
|
||||
u8 shadow_reg_valid;
|
||||
u32 shadow_reg_len;
|
||||
struct wlfw_shadow_reg_cfg_s_v01 shadow_reg[QMI_WLFW_MAX_NUM_SHADOW_REG_V01];
|
||||
u8 shadow_reg_v2_valid;
|
||||
u32 shadow_reg_v2_len;
|
||||
struct wlfw_shadow_reg_v2_cfg_s_v01 shadow_reg_v2[QMI_WLFW_MAX_SHADOW_REG_V2];
|
||||
};
|
||||
|
||||
#define WLFW_WLAN_CFG_REQ_MSG_V01_MAX_MSG_LEN 803
|
||||
extern struct qmi_elem_info wlfw_wlan_cfg_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_wlan_cfg_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_WLAN_CFG_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_wlan_cfg_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cap_req_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_CAP_REQ_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_cap_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cap_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u8 chip_info_valid;
|
||||
struct wlfw_rf_chip_info_s_v01 chip_info;
|
||||
u8 board_info_valid;
|
||||
struct wlfw_rf_board_info_s_v01 board_info;
|
||||
u8 soc_info_valid;
|
||||
struct wlfw_soc_info_s_v01 soc_info;
|
||||
u8 fw_version_info_valid;
|
||||
struct wlfw_fw_version_info_s_v01 fw_version_info;
|
||||
u8 fw_build_id_valid;
|
||||
char fw_build_id[QMI_WLFW_MAX_BUILD_ID_LEN_V01 + 1];
|
||||
u8 num_macs_valid;
|
||||
u8 num_macs;
|
||||
};
|
||||
|
||||
#define WLFW_CAP_RESP_MSG_V01_MAX_MSG_LEN 207
|
||||
extern struct qmi_elem_info wlfw_cap_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_bdf_download_req_msg_v01 {
|
||||
u8 valid;
|
||||
u8 file_id_valid;
|
||||
enum wlfw_cal_temp_id_enum_v01 file_id;
|
||||
u8 total_size_valid;
|
||||
u32 total_size;
|
||||
u8 seg_id_valid;
|
||||
u32 seg_id;
|
||||
u8 data_valid;
|
||||
u32 data_len;
|
||||
u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
|
||||
u8 end_valid;
|
||||
u8 end;
|
||||
u8 bdf_type_valid;
|
||||
u8 bdf_type;
|
||||
};
|
||||
|
||||
#define WLFW_BDF_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6182
|
||||
extern struct qmi_elem_info wlfw_bdf_download_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_bdf_download_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_BDF_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_bdf_download_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_report_req_msg_v01 {
|
||||
u32 meta_data_len;
|
||||
enum wlfw_cal_temp_id_enum_v01 meta_data[QMI_WLFW_MAX_NUM_CAL_V01];
|
||||
u8 xo_cal_data_valid;
|
||||
u8 xo_cal_data;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_REPORT_REQ_MSG_V01_MAX_MSG_LEN 28
|
||||
extern struct qmi_elem_info wlfw_cal_report_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_report_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_REPORT_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_cal_report_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_initiate_cal_download_ind_msg_v01 {
|
||||
enum wlfw_cal_temp_id_enum_v01 cal_id;
|
||||
};
|
||||
|
||||
#define WLFW_INITIATE_CAL_DOWNLOAD_IND_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_initiate_cal_download_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_download_req_msg_v01 {
|
||||
u8 valid;
|
||||
u8 file_id_valid;
|
||||
enum wlfw_cal_temp_id_enum_v01 file_id;
|
||||
u8 total_size_valid;
|
||||
u32 total_size;
|
||||
u8 seg_id_valid;
|
||||
u32 seg_id;
|
||||
u8 data_valid;
|
||||
u32 data_len;
|
||||
u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
|
||||
u8 end_valid;
|
||||
u8 end;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_DOWNLOAD_REQ_MSG_V01_MAX_MSG_LEN 6178
|
||||
extern struct qmi_elem_info wlfw_cal_download_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_download_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_DOWNLOAD_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_cal_download_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_initiate_cal_update_ind_msg_v01 {
|
||||
enum wlfw_cal_temp_id_enum_v01 cal_id;
|
||||
u32 total_size;
|
||||
};
|
||||
|
||||
#define WLFW_INITIATE_CAL_UPDATE_IND_MSG_V01_MAX_MSG_LEN 14
|
||||
extern struct qmi_elem_info wlfw_initiate_cal_update_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_update_req_msg_v01 {
|
||||
enum wlfw_cal_temp_id_enum_v01 cal_id;
|
||||
u32 seg_id;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_UPDATE_REQ_MSG_V01_MAX_MSG_LEN 14
|
||||
extern struct qmi_elem_info wlfw_cal_update_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_cal_update_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u8 file_id_valid;
|
||||
enum wlfw_cal_temp_id_enum_v01 file_id;
|
||||
u8 total_size_valid;
|
||||
u32 total_size;
|
||||
u8 seg_id_valid;
|
||||
u32 seg_id;
|
||||
u8 data_valid;
|
||||
u32 data_len;
|
||||
u8 data[QMI_WLFW_MAX_DATA_SIZE_V01];
|
||||
u8 end_valid;
|
||||
u8 end;
|
||||
};
|
||||
|
||||
#define WLFW_CAL_UPDATE_RESP_MSG_V01_MAX_MSG_LEN 6181
|
||||
extern struct qmi_elem_info wlfw_cal_update_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_msa_info_req_msg_v01 {
|
||||
u64 msa_addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
#define WLFW_MSA_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
|
||||
extern struct qmi_elem_info wlfw_msa_info_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_msa_info_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u32 mem_region_info_len;
|
||||
struct wlfw_memory_region_info_s_v01 mem_region_info[QMI_WLFW_MAX_MEM_REG_V01];
|
||||
};
|
||||
|
||||
#define WLFW_MSA_INFO_RESP_MSG_V01_MAX_MSG_LEN 37
|
||||
extern struct qmi_elem_info wlfw_msa_info_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_msa_ready_req_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_MSA_READY_REQ_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_msa_ready_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_msa_ready_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_MSA_READY_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_msa_ready_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_ini_req_msg_v01 {
|
||||
u8 enablefwlog_valid;
|
||||
u8 enablefwlog;
|
||||
};
|
||||
|
||||
#define WLFW_INI_REQ_MSG_V01_MAX_MSG_LEN 4
|
||||
extern struct qmi_elem_info wlfw_ini_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_ini_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_INI_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_ini_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_athdiag_read_req_msg_v01 {
|
||||
u32 offset;
|
||||
u32 mem_type;
|
||||
u32 data_len;
|
||||
};
|
||||
|
||||
#define WLFW_ATHDIAG_READ_REQ_MSG_V01_MAX_MSG_LEN 21
|
||||
extern struct qmi_elem_info wlfw_athdiag_read_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_athdiag_read_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u8 data_valid;
|
||||
u32 data_len;
|
||||
u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
|
||||
};
|
||||
|
||||
#define WLFW_ATHDIAG_READ_RESP_MSG_V01_MAX_MSG_LEN 6156
|
||||
extern struct qmi_elem_info wlfw_athdiag_read_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_athdiag_write_req_msg_v01 {
|
||||
u32 offset;
|
||||
u32 mem_type;
|
||||
u32 data_len;
|
||||
u8 data[QMI_WLFW_MAX_ATHDIAG_DATA_SIZE_V01];
|
||||
};
|
||||
|
||||
#define WLFW_ATHDIAG_WRITE_REQ_MSG_V01_MAX_MSG_LEN 6163
|
||||
extern struct qmi_elem_info wlfw_athdiag_write_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_athdiag_write_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_ATHDIAG_WRITE_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_athdiag_write_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_vbatt_req_msg_v01 {
|
||||
u64 voltage_uv;
|
||||
};
|
||||
|
||||
#define WLFW_VBATT_REQ_MSG_V01_MAX_MSG_LEN 11
|
||||
extern struct qmi_elem_info wlfw_vbatt_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_vbatt_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_VBATT_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_vbatt_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_mac_addr_req_msg_v01 {
|
||||
u8 mac_addr_valid;
|
||||
u8 mac_addr[QMI_WLFW_MAC_ADDR_SIZE_V01];
|
||||
};
|
||||
|
||||
#define WLFW_MAC_ADDR_REQ_MSG_V01_MAX_MSG_LEN 9
|
||||
extern struct qmi_elem_info wlfw_mac_addr_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_mac_addr_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_MAC_ADDR_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_mac_addr_resp_msg_v01_ei[];
|
||||
|
||||
#define QMI_WLFW_MAX_NUM_GPIO_V01 32
|
||||
struct wlfw_host_cap_req_msg_v01 {
|
||||
u8 daemon_support_valid;
|
||||
u32 daemon_support;
|
||||
u8 wake_msi_valid;
|
||||
u32 wake_msi;
|
||||
u8 gpios_valid;
|
||||
u32 gpios_len;
|
||||
u32 gpios[QMI_WLFW_MAX_NUM_GPIO_V01];
|
||||
u8 nm_modem_valid;
|
||||
u8 nm_modem;
|
||||
u8 bdf_support_valid;
|
||||
u8 bdf_support;
|
||||
u8 bdf_cache_support_valid;
|
||||
u8 bdf_cache_support;
|
||||
u8 m3_support_valid;
|
||||
u8 m3_support;
|
||||
u8 m3_cache_support_valid;
|
||||
u8 m3_cache_support;
|
||||
u8 cal_filesys_support_valid;
|
||||
u8 cal_filesys_support;
|
||||
u8 cal_cache_support_valid;
|
||||
u8 cal_cache_support;
|
||||
u8 cal_done_valid;
|
||||
u8 cal_done;
|
||||
u8 mem_bucket_valid;
|
||||
u32 mem_bucket;
|
||||
u8 mem_cfg_mode_valid;
|
||||
u8 mem_cfg_mode;
|
||||
};
|
||||
|
||||
#define WLFW_HOST_CAP_REQ_MSG_V01_MAX_MSG_LEN 189
|
||||
extern struct qmi_elem_info wlfw_host_cap_req_msg_v01_ei[];
|
||||
extern struct qmi_elem_info wlfw_host_cap_8bit_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_host_cap_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_HOST_CAP_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_host_cap_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_request_mem_ind_msg_v01 {
|
||||
u32 mem_seg_len;
|
||||
struct wlfw_mem_seg_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
|
||||
};
|
||||
|
||||
#define WLFW_REQUEST_MEM_IND_MSG_V01_MAX_MSG_LEN 564
|
||||
extern struct qmi_elem_info wlfw_request_mem_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_respond_mem_req_msg_v01 {
|
||||
u32 mem_seg_len;
|
||||
struct wlfw_mem_seg_resp_s_v01 mem_seg[QMI_WLFW_MAX_NUM_MEM_SEG_V01];
|
||||
};
|
||||
|
||||
#define WLFW_RESPOND_MEM_REQ_MSG_V01_MAX_MSG_LEN 260
|
||||
extern struct qmi_elem_info wlfw_respond_mem_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_respond_mem_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_RESPOND_MEM_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_respond_mem_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_mem_ready_ind_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_MEM_READY_IND_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_mem_ready_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_fw_init_done_ind_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_FW_INIT_DONE_IND_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_fw_init_done_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_rejuvenate_ind_msg_v01 {
|
||||
u8 cause_for_rejuvenation_valid;
|
||||
u8 cause_for_rejuvenation;
|
||||
u8 requesting_sub_system_valid;
|
||||
u8 requesting_sub_system;
|
||||
u8 line_number_valid;
|
||||
u16 line_number;
|
||||
u8 function_name_valid;
|
||||
char function_name[QMI_WLFW_FUNCTION_NAME_LEN_V01 + 1];
|
||||
};
|
||||
|
||||
#define WLFW_REJUVENATE_IND_MSG_V01_MAX_MSG_LEN 144
|
||||
extern struct qmi_elem_info wlfw_rejuvenate_ind_msg_v01_ei[];
|
||||
|
||||
struct wlfw_rejuvenate_ack_req_msg_v01 {
|
||||
char placeholder;
|
||||
};
|
||||
|
||||
#define WLFW_REJUVENATE_ACK_REQ_MSG_V01_MAX_MSG_LEN 0
|
||||
extern struct qmi_elem_info wlfw_rejuvenate_ack_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_rejuvenate_ack_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_REJUVENATE_ACK_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_rejuvenate_ack_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_dynamic_feature_mask_req_msg_v01 {
|
||||
u8 mask_valid;
|
||||
u64 mask;
|
||||
};
|
||||
|
||||
#define WLFW_DYNAMIC_FEATURE_MASK_REQ_MSG_V01_MAX_MSG_LEN 11
|
||||
extern struct qmi_elem_info wlfw_dynamic_feature_mask_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_dynamic_feature_mask_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
u8 prev_mask_valid;
|
||||
u64 prev_mask;
|
||||
u8 curr_mask_valid;
|
||||
u64 curr_mask;
|
||||
};
|
||||
|
||||
#define WLFW_DYNAMIC_FEATURE_MASK_RESP_MSG_V01_MAX_MSG_LEN 29
|
||||
extern struct qmi_elem_info wlfw_dynamic_feature_mask_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_m3_info_req_msg_v01 {
|
||||
u64 addr;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
#define WLFW_M3_INFO_REQ_MSG_V01_MAX_MSG_LEN 18
|
||||
extern struct qmi_elem_info wlfw_m3_info_req_msg_v01_ei[];
|
||||
|
||||
struct wlfw_m3_info_resp_msg_v01 {
|
||||
struct qmi_response_type_v01 resp;
|
||||
};
|
||||
|
||||
#define WLFW_M3_INFO_RESP_MSG_V01_MAX_MSG_LEN 7
|
||||
extern struct qmi_elem_info wlfw_m3_info_resp_msg_v01_ei[];
|
||||
|
||||
struct wlfw_xo_cal_ind_msg_v01 {
|
||||
u8 xo_cal_data;
|
||||
};
|
||||
|
||||
#define WLFW_XO_CAL_IND_MSG_V01_MAX_MSG_LEN 4
|
||||
extern struct qmi_elem_info wlfw_xo_cal_ind_msg_v01_ei[];
|
||||
|
||||
#endif
|
1335
sys/contrib/dev/athk/ath10k/rx_desc.h
Normal file
1335
sys/contrib/dev/athk/ath10k/rx_desc.h
Normal file
File diff suppressed because it is too large
Load Diff
2695
sys/contrib/dev/athk/ath10k/sdio.c
Normal file
2695
sys/contrib/dev/athk/ath10k/sdio.c
Normal file
File diff suppressed because it is too large
Load Diff
236
sys/contrib/dev/athk/ath10k/sdio.h
Normal file
236
sys/contrib/dev/athk/ath10k/sdio.h
Normal file
@ -0,0 +1,236 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _SDIO_H_
|
||||
#define _SDIO_H_
|
||||
|
||||
#define ATH10K_HIF_MBOX_BLOCK_SIZE 256
|
||||
|
||||
#define ATH10K_SDIO_MAX_BUFFER_SIZE 4096 /*Unsure of this constant*/
|
||||
|
||||
/* Mailbox address in SDIO address space */
|
||||
#define ATH10K_HIF_MBOX_BASE_ADDR 0x1000
|
||||
#define ATH10K_HIF_MBOX_WIDTH 0x800
|
||||
|
||||
#define ATH10K_HIF_MBOX_TOT_WIDTH \
|
||||
(ATH10K_HIF_MBOX_NUM_MAX * ATH10K_HIF_MBOX_WIDTH)
|
||||
|
||||
#define ATH10K_HIF_MBOX0_EXT_BASE_ADDR 0x5000
|
||||
#define ATH10K_HIF_MBOX0_EXT_WIDTH (36 * 1024)
|
||||
#define ATH10K_HIF_MBOX0_EXT_WIDTH_ROME_2_0 (56 * 1024)
|
||||
#define ATH10K_HIF_MBOX1_EXT_WIDTH (36 * 1024)
|
||||
#define ATH10K_HIF_MBOX_DUMMY_SPACE_SIZE (2 * 1024)
|
||||
|
||||
#define ATH10K_HTC_MBOX_MAX_PAYLOAD_LENGTH \
|
||||
(ATH10K_SDIO_MAX_BUFFER_SIZE - sizeof(struct ath10k_htc_hdr))
|
||||
|
||||
#define ATH10K_HIF_MBOX_NUM_MAX 4
|
||||
#define ATH10K_SDIO_BUS_REQUEST_MAX_NUM 1024
|
||||
|
||||
#define ATH10K_SDIO_HIF_COMMUNICATION_TIMEOUT_HZ (100 * HZ)
|
||||
|
||||
/* HTC runs over mailbox 0 */
|
||||
#define ATH10K_HTC_MAILBOX 0
|
||||
#define ATH10K_HTC_MAILBOX_MASK BIT(ATH10K_HTC_MAILBOX)
|
||||
|
||||
/* GMBOX addresses */
|
||||
#define ATH10K_HIF_GMBOX_BASE_ADDR 0x7000
|
||||
#define ATH10K_HIF_GMBOX_WIDTH 0x4000
|
||||
|
||||
/* Modified versions of the sdio.h macros.
|
||||
* The macros in sdio.h can't be used easily with the FIELD_{PREP|GET}
|
||||
* macros in bitfield.h, so we define our own macros here.
|
||||
*/
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_MASK \
|
||||
(SDIO_DRIVE_DTSx_MASK << SDIO_DRIVE_DTSx_SHIFT)
|
||||
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_B 0
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_A 1
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_C 2
|
||||
#define ATH10K_SDIO_DRIVE_DTSX_TYPE_D 3
|
||||
|
||||
/* SDIO CCCR register definitions */
|
||||
#define CCCR_SDIO_IRQ_MODE_REG 0xF0
|
||||
#define CCCR_SDIO_IRQ_MODE_REG_SDIO3 0x16
|
||||
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_ADDR 0xF2
|
||||
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_A 0x02
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_C 0x04
|
||||
#define CCCR_SDIO_DRIVER_STRENGTH_ENABLE_D 0x08
|
||||
|
||||
#define CCCR_SDIO_ASYNC_INT_DELAY_ADDRESS 0xF0
|
||||
#define CCCR_SDIO_ASYNC_INT_DELAY_MASK 0xC0
|
||||
|
||||
/* mode to enable special 4-bit interrupt assertion without clock */
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ BIT(0)
|
||||
#define SDIO_IRQ_MODE_ASYNC_4BIT_IRQ_SDIO3 BIT(1)
|
||||
|
||||
#define ATH10K_SDIO_TARGET_DEBUG_INTR_MASK 0x01
|
||||
|
||||
/* The theoretical maximum number of RX messages that can be fetched
|
||||
* from the mbox interrupt handler in one loop is derived in the following
|
||||
* way:
|
||||
*
|
||||
* Let's assume that each packet in a bundle of the maximum bundle size
|
||||
* (HTC_HOST_MAX_MSG_PER_RX_BUNDLE) has the HTC header bundle count set
|
||||
* to the maximum value (HTC_HOST_MAX_MSG_PER_RX_BUNDLE).
|
||||
*
|
||||
* in this case the driver must allocate
|
||||
* (HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2) skb's.
|
||||
*/
|
||||
#define ATH10K_SDIO_MAX_RX_MSGS \
|
||||
(HTC_HOST_MAX_MSG_PER_RX_BUNDLE * 2)
|
||||
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL 0x00000868u
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_OFF 0xFFFEFFFF
|
||||
#define ATH10K_FIFO_TIMEOUT_AND_CHIP_CONTROL_DISABLE_SLEEP_ON 0x10000
|
||||
|
||||
enum sdio_mbox_state {
|
||||
SDIO_MBOX_UNKNOWN_STATE = 0,
|
||||
SDIO_MBOX_REQUEST_TO_SLEEP_STATE = 1,
|
||||
SDIO_MBOX_SLEEP_STATE = 2,
|
||||
SDIO_MBOX_AWAKE_STATE = 3,
|
||||
};
|
||||
|
||||
#define ATH10K_CIS_READ_WAIT_4_RTC_CYCLE_IN_US 125
|
||||
#define ATH10K_CIS_RTC_STATE_ADDR 0x1138
|
||||
#define ATH10K_CIS_RTC_STATE_ON 0x01
|
||||
#define ATH10K_CIS_XTAL_SETTLE_DURATION_IN_US 1500
|
||||
#define ATH10K_CIS_READ_RETRY 10
|
||||
#define ATH10K_MIN_SLEEP_INACTIVITY_TIME_MS 50
|
||||
|
||||
/* TODO: remove this and use skb->cb instead, much cleaner approach */
|
||||
struct ath10k_sdio_bus_request {
|
||||
struct list_head list;
|
||||
|
||||
/* sdio address */
|
||||
u32 address;
|
||||
|
||||
struct sk_buff *skb;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
int status;
|
||||
/* Specifies if the current request is an HTC message.
|
||||
* If not, the eid is not applicable an the TX completion handler
|
||||
* associated with the endpoint will not be invoked.
|
||||
*/
|
||||
bool htc_msg;
|
||||
/* Completion that (if set) will be invoked for non HTC requests
|
||||
* (htc_msg == false) when the request has been processed.
|
||||
*/
|
||||
struct completion *comp;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_rx_data {
|
||||
struct sk_buff *skb;
|
||||
size_t alloc_len;
|
||||
size_t act_len;
|
||||
enum ath10k_htc_ep_id eid;
|
||||
bool part_of_bundle;
|
||||
bool last_in_bundle;
|
||||
bool trailer_only;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_proc_regs {
|
||||
u8 host_int_status;
|
||||
u8 cpu_int_status;
|
||||
u8 error_int_status;
|
||||
u8 counter_int_status;
|
||||
u8 mbox_frame;
|
||||
u8 rx_lookahead_valid;
|
||||
u8 host_int_status2;
|
||||
u8 gmbox_rx_avail;
|
||||
__le32 rx_lookahead[2 * ATH10K_HIF_MBOX_NUM_MAX];
|
||||
__le32 int_status_enable;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_enable_regs {
|
||||
u8 int_status_en;
|
||||
u8 cpu_int_status_en;
|
||||
u8 err_int_status_en;
|
||||
u8 cntr_int_status_en;
|
||||
};
|
||||
|
||||
struct ath10k_sdio_irq_data {
|
||||
/* protects irq_proc_reg and irq_en_reg below.
|
||||
* We use a mutex here and not a spinlock since we will have the
|
||||
* mutex locked while calling the sdio_memcpy_ functions.
|
||||
* These function require non atomic context, and hence, spinlocks
|
||||
* can be held while calling these functions.
|
||||
*/
|
||||
struct mutex mtx;
|
||||
struct ath10k_sdio_irq_proc_regs *irq_proc_reg;
|
||||
struct ath10k_sdio_irq_enable_regs *irq_en_reg;
|
||||
};
|
||||
|
||||
struct ath10k_mbox_ext_info {
|
||||
u32 htc_ext_addr;
|
||||
u32 htc_ext_sz;
|
||||
};
|
||||
|
||||
struct ath10k_mbox_info {
|
||||
u32 htc_addr;
|
||||
struct ath10k_mbox_ext_info ext_info[2];
|
||||
u32 block_size;
|
||||
u32 block_mask;
|
||||
u32 gmbox_addr;
|
||||
u32 gmbox_sz;
|
||||
};
|
||||
|
||||
struct ath10k_sdio {
|
||||
struct sdio_func *func;
|
||||
|
||||
struct ath10k_mbox_info mbox_info;
|
||||
bool swap_mbox;
|
||||
u32 mbox_addr[ATH10K_HTC_EP_COUNT];
|
||||
u32 mbox_size[ATH10K_HTC_EP_COUNT];
|
||||
|
||||
/* available bus requests */
|
||||
struct ath10k_sdio_bus_request bus_req[ATH10K_SDIO_BUS_REQUEST_MAX_NUM];
|
||||
/* free list of bus requests */
|
||||
struct list_head bus_req_freeq;
|
||||
|
||||
struct sk_buff_head rx_head;
|
||||
|
||||
/* protects access to bus_req_freeq */
|
||||
spinlock_t lock;
|
||||
|
||||
struct ath10k_sdio_rx_data rx_pkts[ATH10K_SDIO_MAX_RX_MSGS];
|
||||
size_t n_rx_pkts;
|
||||
|
||||
struct ath10k *ar;
|
||||
struct ath10k_sdio_irq_data irq_data;
|
||||
|
||||
/* temporary buffer for sdio read.
|
||||
* It is allocated when probe, and used for receive bundled packets,
|
||||
* the read for bundled packets is not parallel, so it does not need
|
||||
* protected.
|
||||
*/
|
||||
u8 *vsg_buffer;
|
||||
|
||||
/* temporary buffer for BMI requests */
|
||||
u8 *bmi_buf;
|
||||
|
||||
bool is_disabled;
|
||||
|
||||
struct workqueue_struct *workqueue;
|
||||
struct work_struct wr_async_work;
|
||||
struct list_head wr_asyncq;
|
||||
/* protects access to wr_asyncq */
|
||||
spinlock_t wr_async_lock;
|
||||
|
||||
struct work_struct async_work_rx;
|
||||
struct timer_list sleep_timer;
|
||||
enum sdio_mbox_state mbox_state;
|
||||
};
|
||||
|
||||
static inline struct ath10k_sdio *ath10k_sdio_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_sdio *)ar->drv_priv;
|
||||
}
|
||||
|
||||
#endif
|
1889
sys/contrib/dev/athk/ath10k/snoc.c
Normal file
1889
sys/contrib/dev/athk/ath10k/snoc.c
Normal file
File diff suppressed because it is too large
Load Diff
97
sys/contrib/dev/athk/ath10k/snoc.h
Normal file
97
sys/contrib/dev/athk/ath10k/snoc.h
Normal file
@ -0,0 +1,97 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2018 The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#ifndef _SNOC_H_
|
||||
#define _SNOC_H_
|
||||
|
||||
#include <linux/notifier.h>
|
||||
|
||||
#include "hw.h"
|
||||
#include "ce.h"
|
||||
#include "qmi.h"
|
||||
|
||||
struct ath10k_snoc_drv_priv {
|
||||
enum ath10k_hw_rev hw_rev;
|
||||
u64 dma_mask;
|
||||
u32 msa_size;
|
||||
};
|
||||
|
||||
struct snoc_state {
|
||||
u32 pipe_cfg_addr;
|
||||
u32 svc_to_pipe_map;
|
||||
};
|
||||
|
||||
struct ath10k_snoc_pipe {
|
||||
struct ath10k_ce_pipe *ce_hdl;
|
||||
u8 pipe_num;
|
||||
struct ath10k *hif_ce_state;
|
||||
size_t buf_sz;
|
||||
/* protect ce info */
|
||||
spinlock_t pipe_lock;
|
||||
struct ath10k_snoc *ar_snoc;
|
||||
};
|
||||
|
||||
struct ath10k_snoc_target_info {
|
||||
u32 target_version;
|
||||
u32 target_type;
|
||||
u32 target_revision;
|
||||
u32 soc_version;
|
||||
};
|
||||
|
||||
struct ath10k_snoc_ce_irq {
|
||||
u32 irq_line;
|
||||
};
|
||||
|
||||
enum ath10k_snoc_flags {
|
||||
ATH10K_SNOC_FLAG_REGISTERED,
|
||||
ATH10K_SNOC_FLAG_UNREGISTERING,
|
||||
ATH10K_SNOC_FLAG_MODEM_STOPPED,
|
||||
ATH10K_SNOC_FLAG_RECOVERY,
|
||||
ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK,
|
||||
};
|
||||
|
||||
struct clk_bulk_data;
|
||||
struct regulator_bulk_data;
|
||||
|
||||
struct ath10k_snoc {
|
||||
struct platform_device *dev;
|
||||
struct ath10k *ar;
|
||||
unsigned int use_tz;
|
||||
struct ath10k_firmware {
|
||||
struct device *dev;
|
||||
dma_addr_t fw_start_addr;
|
||||
struct iommu_domain *iommu_domain;
|
||||
size_t mapped_mem_size;
|
||||
} fw;
|
||||
void __iomem *mem;
|
||||
dma_addr_t mem_pa;
|
||||
struct ath10k_snoc_target_info target_info;
|
||||
size_t mem_len;
|
||||
struct ath10k_snoc_pipe pipe_info[CE_COUNT_MAX];
|
||||
struct ath10k_snoc_ce_irq ce_irqs[CE_COUNT_MAX];
|
||||
struct ath10k_ce ce;
|
||||
struct timer_list rx_post_retry;
|
||||
struct regulator_bulk_data *vregs;
|
||||
size_t num_vregs;
|
||||
struct clk_bulk_data *clks;
|
||||
size_t num_clks;
|
||||
struct ath10k_qmi *qmi;
|
||||
struct notifier_block nb;
|
||||
void *notifier;
|
||||
unsigned long flags;
|
||||
bool xo_cal_supported;
|
||||
u32 xo_cal_data;
|
||||
DECLARE_BITMAP(pending_ce_irqs, CE_COUNT_MAX);
|
||||
};
|
||||
|
||||
static inline struct ath10k_snoc *ath10k_snoc_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_snoc *)ar->drv_priv;
|
||||
}
|
||||
|
||||
int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type);
|
||||
void ath10k_snoc_fw_crashed_dump(struct ath10k *ar);
|
||||
|
||||
#endif /* _SNOC_H_ */
|
560
sys/contrib/dev/athk/ath10k/spectral.c
Normal file
560
sys/contrib/dev/athk/ath10k/spectral.c
Normal file
@ -0,0 +1,560 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2013-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/relay.h>
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "wmi-ops.h"
|
||||
|
||||
static void send_fft_sample(struct ath10k *ar,
|
||||
const struct fft_sample_tlv *fft_sample_tlv)
|
||||
{
|
||||
int length;
|
||||
|
||||
if (!ar->spectral.rfs_chan_spec_scan)
|
||||
return;
|
||||
|
||||
length = __be16_to_cpu(fft_sample_tlv->length) +
|
||||
sizeof(*fft_sample_tlv);
|
||||
relay_write(ar->spectral.rfs_chan_spec_scan, fft_sample_tlv, length);
|
||||
}
|
||||
|
||||
static uint8_t get_max_exp(s8 max_index, u16 max_magnitude, size_t bin_len,
|
||||
u8 *data)
|
||||
{
|
||||
int dc_pos;
|
||||
u8 max_exp;
|
||||
|
||||
dc_pos = bin_len / 2;
|
||||
|
||||
/* peak index outside of bins */
|
||||
if (dc_pos < max_index || -dc_pos >= max_index)
|
||||
return 0;
|
||||
|
||||
for (max_exp = 0; max_exp < 8; max_exp++) {
|
||||
if (data[dc_pos + max_index] == (max_magnitude >> max_exp))
|
||||
break;
|
||||
}
|
||||
|
||||
/* max_exp not found */
|
||||
if (data[dc_pos + max_index] != (max_magnitude >> max_exp))
|
||||
return 0;
|
||||
|
||||
return max_exp;
|
||||
}
|
||||
|
||||
static inline size_t ath10k_spectral_fix_bin_size(struct ath10k *ar,
|
||||
size_t bin_len)
|
||||
{
|
||||
/* some chipsets reports bin size as 2^n bytes + 'm' bytes in
|
||||
* report mode 2. First 2^n bytes carries inband tones and last
|
||||
* 'm' bytes carries band edge detection data mainly used in
|
||||
* radar detection purpose. Strip last 'm' bytes to make bin size
|
||||
* as a valid one. 'm' can take possible values of 4, 12.
|
||||
*/
|
||||
if (!is_power_of_2(bin_len))
|
||||
bin_len -= ar->hw_params.spectral_bin_discard;
|
||||
|
||||
return bin_len;
|
||||
}
|
||||
|
||||
int ath10k_spectral_process_fft(struct ath10k *ar,
|
||||
struct wmi_phyerr_ev_arg *phyerr,
|
||||
const struct phyerr_fft_report *fftr,
|
||||
size_t bin_len, u64 tsf)
|
||||
{
|
||||
struct fft_sample_ath10k *fft_sample;
|
||||
u8 buf[sizeof(*fft_sample) + SPECTRAL_ATH10K_MAX_NUM_BINS];
|
||||
u16 freq1, freq2, total_gain_db, base_pwr_db, length, peak_mag;
|
||||
u32 reg0, reg1;
|
||||
u8 chain_idx, *bins;
|
||||
int dc_pos;
|
||||
|
||||
fft_sample = (struct fft_sample_ath10k *)&buf;
|
||||
|
||||
bin_len = ath10k_spectral_fix_bin_size(ar, bin_len);
|
||||
|
||||
if (bin_len < 64 || bin_len > SPECTRAL_ATH10K_MAX_NUM_BINS)
|
||||
return -EINVAL;
|
||||
|
||||
reg0 = __le32_to_cpu(fftr->reg0);
|
||||
reg1 = __le32_to_cpu(fftr->reg1);
|
||||
|
||||
length = sizeof(*fft_sample) - sizeof(struct fft_sample_tlv) + bin_len;
|
||||
fft_sample->tlv.type = ATH_FFT_SAMPLE_ATH10K;
|
||||
fft_sample->tlv.length = __cpu_to_be16(length);
|
||||
|
||||
/* TODO: there might be a reason why the hardware reports 20/40/80 MHz,
|
||||
* but the results/plots suggest that its actually 22/44/88 MHz.
|
||||
*/
|
||||
switch (phyerr->chan_width_mhz) {
|
||||
case 20:
|
||||
fft_sample->chan_width_mhz = 22;
|
||||
break;
|
||||
case 40:
|
||||
fft_sample->chan_width_mhz = 44;
|
||||
break;
|
||||
case 80:
|
||||
/* TODO: As experiments with an analogue sender and various
|
||||
* configurations (fft-sizes of 64/128/256 and 20/40/80 Mhz)
|
||||
* show, the particular configuration of 80 MHz/64 bins does
|
||||
* not match with the other samples at all. Until the reason
|
||||
* for that is found, don't report these samples.
|
||||
*/
|
||||
if (bin_len == 64)
|
||||
return -EINVAL;
|
||||
fft_sample->chan_width_mhz = 88;
|
||||
break;
|
||||
default:
|
||||
fft_sample->chan_width_mhz = phyerr->chan_width_mhz;
|
||||
}
|
||||
|
||||
fft_sample->relpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_RELPWR_DB);
|
||||
fft_sample->avgpwr_db = MS(reg1, SEARCH_FFT_REPORT_REG1_AVGPWR_DB);
|
||||
|
||||
peak_mag = MS(reg1, SEARCH_FFT_REPORT_REG1_PEAK_MAG);
|
||||
fft_sample->max_magnitude = __cpu_to_be16(peak_mag);
|
||||
fft_sample->max_index = MS(reg0, SEARCH_FFT_REPORT_REG0_PEAK_SIDX);
|
||||
fft_sample->rssi = phyerr->rssi_combined;
|
||||
|
||||
total_gain_db = MS(reg0, SEARCH_FFT_REPORT_REG0_TOTAL_GAIN_DB);
|
||||
base_pwr_db = MS(reg0, SEARCH_FFT_REPORT_REG0_BASE_PWR_DB);
|
||||
fft_sample->total_gain_db = __cpu_to_be16(total_gain_db);
|
||||
fft_sample->base_pwr_db = __cpu_to_be16(base_pwr_db);
|
||||
|
||||
freq1 = phyerr->freq1;
|
||||
freq2 = phyerr->freq2;
|
||||
fft_sample->freq1 = __cpu_to_be16(freq1);
|
||||
fft_sample->freq2 = __cpu_to_be16(freq2);
|
||||
|
||||
chain_idx = MS(reg0, SEARCH_FFT_REPORT_REG0_FFT_CHN_IDX);
|
||||
|
||||
fft_sample->noise = __cpu_to_be16(phyerr->nf_chains[chain_idx]);
|
||||
|
||||
bins = (u8 *)fftr;
|
||||
bins += sizeof(*fftr) + ar->hw_params.spectral_bin_offset;
|
||||
|
||||
fft_sample->tsf = __cpu_to_be64(tsf);
|
||||
|
||||
/* max_exp has been directly reported by previous hardware (ath9k),
|
||||
* maybe its possible to get it by other means?
|
||||
*/
|
||||
fft_sample->max_exp = get_max_exp(fft_sample->max_index, peak_mag,
|
||||
bin_len, bins);
|
||||
|
||||
memcpy(fft_sample->data, bins, bin_len);
|
||||
|
||||
/* DC value (value in the middle) is the blind spot of the spectral
|
||||
* sample and invalid, interpolate it.
|
||||
*/
|
||||
dc_pos = bin_len / 2;
|
||||
fft_sample->data[dc_pos] = (fft_sample->data[dc_pos + 1] +
|
||||
fft_sample->data[dc_pos - 1]) / 2;
|
||||
|
||||
send_fft_sample(ar, &fft_sample->tlv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ath10k_vif *ath10k_get_spectral_vdev(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (list_empty(&ar->arvifs))
|
||||
return NULL;
|
||||
|
||||
/* if there already is a vif doing spectral, return that. */
|
||||
list_for_each_entry(arvif, &ar->arvifs, list)
|
||||
if (arvif->spectral_enabled)
|
||||
return arvif;
|
||||
|
||||
/* otherwise, return the first vif. */
|
||||
return list_first_entry(&ar->arvifs, typeof(*arvif), list);
|
||||
}
|
||||
|
||||
static int ath10k_spectral_scan_trigger(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int res;
|
||||
int vdev_id;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
arvif = ath10k_get_spectral_vdev(ar);
|
||||
if (!arvif)
|
||||
return -ENODEV;
|
||||
vdev_id = arvif->vdev_id;
|
||||
|
||||
if (ar->spectral.mode == SPECTRAL_DISABLED)
|
||||
return 0;
|
||||
|
||||
res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
|
||||
WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
|
||||
WMI_SPECTRAL_ENABLE_CMD_ENABLE);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
|
||||
WMI_SPECTRAL_TRIGGER_CMD_TRIGGER,
|
||||
WMI_SPECTRAL_ENABLE_CMD_ENABLE);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_spectral_scan_config(struct ath10k *ar,
|
||||
enum ath10k_spectral_mode mode)
|
||||
{
|
||||
struct wmi_vdev_spectral_conf_arg arg;
|
||||
struct ath10k_vif *arvif;
|
||||
int vdev_id, count, res = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
arvif = ath10k_get_spectral_vdev(ar);
|
||||
if (!arvif)
|
||||
return -ENODEV;
|
||||
|
||||
vdev_id = arvif->vdev_id;
|
||||
|
||||
arvif->spectral_enabled = (mode != SPECTRAL_DISABLED);
|
||||
ar->spectral.mode = mode;
|
||||
|
||||
res = ath10k_wmi_vdev_spectral_enable(ar, vdev_id,
|
||||
WMI_SPECTRAL_TRIGGER_CMD_CLEAR,
|
||||
WMI_SPECTRAL_ENABLE_CMD_DISABLE);
|
||||
if (res < 0) {
|
||||
ath10k_warn(ar, "failed to enable spectral scan: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
if (mode == SPECTRAL_DISABLED)
|
||||
return 0;
|
||||
|
||||
if (mode == SPECTRAL_BACKGROUND)
|
||||
count = WMI_SPECTRAL_COUNT_DEFAULT;
|
||||
else
|
||||
count = max_t(u8, 1, ar->spectral.config.count);
|
||||
|
||||
arg.vdev_id = vdev_id;
|
||||
arg.scan_count = count;
|
||||
arg.scan_period = WMI_SPECTRAL_PERIOD_DEFAULT;
|
||||
arg.scan_priority = WMI_SPECTRAL_PRIORITY_DEFAULT;
|
||||
arg.scan_fft_size = ar->spectral.config.fft_size;
|
||||
arg.scan_gc_ena = WMI_SPECTRAL_GC_ENA_DEFAULT;
|
||||
arg.scan_restart_ena = WMI_SPECTRAL_RESTART_ENA_DEFAULT;
|
||||
arg.scan_noise_floor_ref = WMI_SPECTRAL_NOISE_FLOOR_REF_DEFAULT;
|
||||
arg.scan_init_delay = WMI_SPECTRAL_INIT_DELAY_DEFAULT;
|
||||
arg.scan_nb_tone_thr = WMI_SPECTRAL_NB_TONE_THR_DEFAULT;
|
||||
arg.scan_str_bin_thr = WMI_SPECTRAL_STR_BIN_THR_DEFAULT;
|
||||
arg.scan_wb_rpt_mode = WMI_SPECTRAL_WB_RPT_MODE_DEFAULT;
|
||||
arg.scan_rssi_rpt_mode = WMI_SPECTRAL_RSSI_RPT_MODE_DEFAULT;
|
||||
arg.scan_rssi_thr = WMI_SPECTRAL_RSSI_THR_DEFAULT;
|
||||
arg.scan_pwr_format = WMI_SPECTRAL_PWR_FORMAT_DEFAULT;
|
||||
arg.scan_rpt_mode = WMI_SPECTRAL_RPT_MODE_DEFAULT;
|
||||
arg.scan_bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
|
||||
arg.scan_dbm_adj = WMI_SPECTRAL_DBM_ADJ_DEFAULT;
|
||||
arg.scan_chn_mask = WMI_SPECTRAL_CHN_MASK_DEFAULT;
|
||||
|
||||
res = ath10k_wmi_vdev_spectral_conf(ar, &arg);
|
||||
if (res < 0) {
|
||||
ath10k_warn(ar, "failed to configure spectral scan: %d\n", res);
|
||||
return res;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t read_file_spec_scan_ctl(struct file *file, char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char *mode = "";
|
||||
size_t len;
|
||||
enum ath10k_spectral_mode spectral_mode;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
spectral_mode = ar->spectral.mode;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
switch (spectral_mode) {
|
||||
case SPECTRAL_DISABLED:
|
||||
mode = "disable";
|
||||
break;
|
||||
case SPECTRAL_BACKGROUND:
|
||||
mode = "background";
|
||||
break;
|
||||
case SPECTRAL_MANUAL:
|
||||
mode = "manual";
|
||||
break;
|
||||
}
|
||||
|
||||
len = strlen(mode);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, mode, len);
|
||||
}
|
||||
|
||||
static ssize_t write_file_spec_scan_ctl(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
int res;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (strncmp("trigger", buf, 7) == 0) {
|
||||
if (ar->spectral.mode == SPECTRAL_MANUAL ||
|
||||
ar->spectral.mode == SPECTRAL_BACKGROUND) {
|
||||
/* reset the configuration to adopt possibly changed
|
||||
* debugfs parameters
|
||||
*/
|
||||
res = ath10k_spectral_scan_config(ar,
|
||||
ar->spectral.mode);
|
||||
if (res < 0) {
|
||||
ath10k_warn(ar, "failed to reconfigure spectral scan: %d\n",
|
||||
res);
|
||||
}
|
||||
res = ath10k_spectral_scan_trigger(ar);
|
||||
if (res < 0) {
|
||||
ath10k_warn(ar, "failed to trigger spectral scan: %d\n",
|
||||
res);
|
||||
}
|
||||
} else {
|
||||
res = -EINVAL;
|
||||
}
|
||||
} else if (strncmp("background", buf, 10) == 0) {
|
||||
res = ath10k_spectral_scan_config(ar, SPECTRAL_BACKGROUND);
|
||||
} else if (strncmp("manual", buf, 6) == 0) {
|
||||
res = ath10k_spectral_scan_config(ar, SPECTRAL_MANUAL);
|
||||
} else if (strncmp("disable", buf, 7) == 0) {
|
||||
res = ath10k_spectral_scan_config(ar, SPECTRAL_DISABLED);
|
||||
} else {
|
||||
res = -EINVAL;
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_spec_scan_ctl = {
|
||||
.read = read_file_spec_scan_ctl,
|
||||
.write = write_file_spec_scan_ctl,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_spectral_count(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
size_t len;
|
||||
u8 spectral_count;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
spectral_count = ar->spectral.config.count;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
len = sprintf(buf, "%d\n", spectral_count);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t write_file_spectral_count(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned long val;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (kstrtoul(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ar->spectral.config.count = val;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_spectral_count = {
|
||||
.read = read_file_spectral_count,
|
||||
.write = write_file_spectral_count,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static ssize_t read_file_spectral_bins(struct file *file,
|
||||
char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
char buf[32];
|
||||
unsigned int bins, fft_size, bin_scale;
|
||||
size_t len;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
fft_size = ar->spectral.config.fft_size;
|
||||
bin_scale = WMI_SPECTRAL_BIN_SCALE_DEFAULT;
|
||||
bins = 1 << (fft_size - bin_scale);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
len = sprintf(buf, "%d\n", bins);
|
||||
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||
}
|
||||
|
||||
static ssize_t write_file_spectral_bins(struct file *file,
|
||||
const char __user *user_buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct ath10k *ar = file->private_data;
|
||||
unsigned long val;
|
||||
char buf[32];
|
||||
ssize_t len;
|
||||
|
||||
len = min(count, sizeof(buf) - 1);
|
||||
if (copy_from_user(buf, user_buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
buf[len] = '\0';
|
||||
if (kstrtoul(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
|
||||
if (val < 64 || val > SPECTRAL_ATH10K_MAX_NUM_BINS)
|
||||
return -EINVAL;
|
||||
|
||||
if (!is_power_of_2(val))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ar->spectral.config.fft_size = ilog2(val);
|
||||
ar->spectral.config.fft_size += WMI_SPECTRAL_BIN_SCALE_DEFAULT;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations fops_spectral_bins = {
|
||||
.read = read_file_spectral_bins,
|
||||
.write = write_file_spectral_bins,
|
||||
.open = simple_open,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = default_llseek,
|
||||
};
|
||||
|
||||
static struct dentry *create_buf_file_handler(const char *filename,
|
||||
struct dentry *parent,
|
||||
umode_t mode,
|
||||
struct rchan_buf *buf,
|
||||
int *is_global)
|
||||
{
|
||||
struct dentry *buf_file;
|
||||
|
||||
buf_file = debugfs_create_file(filename, mode, parent, buf,
|
||||
&relay_file_operations);
|
||||
if (IS_ERR(buf_file))
|
||||
return NULL;
|
||||
|
||||
*is_global = 1;
|
||||
return buf_file;
|
||||
}
|
||||
|
||||
static int remove_buf_file_handler(struct dentry *dentry)
|
||||
{
|
||||
debugfs_remove(dentry);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rchan_callbacks rfs_spec_scan_cb = {
|
||||
.create_buf_file = create_buf_file_handler,
|
||||
.remove_buf_file = remove_buf_file_handler,
|
||||
};
|
||||
|
||||
int ath10k_spectral_start(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list)
|
||||
arvif->spectral_enabled = 0;
|
||||
|
||||
ar->spectral.mode = SPECTRAL_DISABLED;
|
||||
ar->spectral.config.count = WMI_SPECTRAL_COUNT_DEFAULT;
|
||||
ar->spectral.config.fft_size = WMI_SPECTRAL_FFT_SIZE_DEFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
|
||||
{
|
||||
if (!arvif->spectral_enabled)
|
||||
return 0;
|
||||
|
||||
return ath10k_spectral_scan_config(arvif->ar, SPECTRAL_DISABLED);
|
||||
}
|
||||
|
||||
int ath10k_spectral_create(struct ath10k *ar)
|
||||
{
|
||||
/* The buffer size covers whole channels in dual bands up to 128 bins.
|
||||
* Scan with bigger than 128 bins needs to be run on single band each.
|
||||
*/
|
||||
ar->spectral.rfs_chan_spec_scan = relay_open("spectral_scan",
|
||||
ar->debug.debugfs_phy,
|
||||
1140, 2500,
|
||||
&rfs_spec_scan_cb, NULL);
|
||||
debugfs_create_file("spectral_scan_ctl",
|
||||
0600,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
&fops_spec_scan_ctl);
|
||||
debugfs_create_file("spectral_count",
|
||||
0600,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
&fops_spectral_count);
|
||||
debugfs_create_file("spectral_bins",
|
||||
0600,
|
||||
ar->debug.debugfs_phy, ar,
|
||||
&fops_spectral_bins);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_spectral_destroy(struct ath10k *ar)
|
||||
{
|
||||
if (ar->spectral.rfs_chan_spec_scan) {
|
||||
relay_close(ar->spectral.rfs_chan_spec_scan);
|
||||
ar->spectral.rfs_chan_spec_scan = NULL;
|
||||
}
|
||||
}
|
79
sys/contrib/dev/athk/ath10k/spectral.h
Normal file
79
sys/contrib/dev/athk/ath10k/spectral.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef SPECTRAL_H
|
||||
#define SPECTRAL_H
|
||||
|
||||
#include "../spectral_common.h"
|
||||
|
||||
/**
|
||||
* struct ath10k_spec_scan - parameters for Atheros spectral scan
|
||||
*
|
||||
* @count: number of scan results requested for manual mode
|
||||
* @fft_size: number of bins to be requested = 2^(fft_size - bin_scale)
|
||||
*/
|
||||
struct ath10k_spec_scan {
|
||||
u8 count;
|
||||
u8 fft_size;
|
||||
};
|
||||
|
||||
/* enum ath10k_spectral_mode:
|
||||
*
|
||||
* @SPECTRAL_DISABLED: spectral mode is disabled
|
||||
* @SPECTRAL_BACKGROUND: hardware sends samples when it is not busy with
|
||||
* something else.
|
||||
* @SPECTRAL_MANUAL: spectral scan is enabled, triggering for samples
|
||||
* is performed manually.
|
||||
*/
|
||||
enum ath10k_spectral_mode {
|
||||
SPECTRAL_DISABLED = 0,
|
||||
SPECTRAL_BACKGROUND,
|
||||
SPECTRAL_MANUAL,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ATH10K_SPECTRAL
|
||||
|
||||
int ath10k_spectral_process_fft(struct ath10k *ar,
|
||||
struct wmi_phyerr_ev_arg *phyerr,
|
||||
const struct phyerr_fft_report *fftr,
|
||||
size_t bin_len, u64 tsf);
|
||||
int ath10k_spectral_start(struct ath10k *ar);
|
||||
int ath10k_spectral_vif_stop(struct ath10k_vif *arvif);
|
||||
int ath10k_spectral_create(struct ath10k *ar);
|
||||
void ath10k_spectral_destroy(struct ath10k *ar);
|
||||
|
||||
#else
|
||||
|
||||
static inline int
|
||||
ath10k_spectral_process_fft(struct ath10k *ar,
|
||||
struct wmi_phyerr_ev_arg *phyerr,
|
||||
const struct phyerr_fft_report *fftr,
|
||||
size_t bin_len, u64 tsf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_spectral_start(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_spectral_vif_stop(struct ath10k_vif *arvif)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int ath10k_spectral_create(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_spectral_destroy(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ATH10K_SPECTRAL */
|
||||
|
||||
#endif /* SPECTRAL_H */
|
199
sys/contrib/dev/athk/ath10k/swap.c
Normal file
199
sys/contrib/dev/athk/ath10k/swap.c
Normal file
@ -0,0 +1,199 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
/* This file has implementation for code swap logic. With code swap feature,
|
||||
* target can run the fw binary with even smaller IRAM size by using host
|
||||
* memory to store some of the code segments.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "bmi.h"
|
||||
#include "debug.h"
|
||||
|
||||
static int ath10k_swap_code_seg_fill(struct ath10k *ar,
|
||||
struct ath10k_swap_code_seg_info *seg_info,
|
||||
const void *data, size_t data_len)
|
||||
{
|
||||
u8 *virt_addr = seg_info->virt_address[0];
|
||||
u8 swap_magic[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ] = {};
|
||||
const u8 *fw_data = data;
|
||||
const union ath10k_swap_code_seg_item *swap_item;
|
||||
u32 length = 0;
|
||||
u32 payload_len;
|
||||
u32 total_payload_len = 0;
|
||||
u32 size_left = data_len;
|
||||
|
||||
/* Parse swap bin and copy the content to host allocated memory.
|
||||
* The format is Address, length and value. The last 4-bytes is
|
||||
* target write address. Currently address field is not used.
|
||||
*/
|
||||
seg_info->target_addr = -1;
|
||||
while (size_left >= sizeof(*swap_item)) {
|
||||
swap_item = (const union ath10k_swap_code_seg_item *)fw_data;
|
||||
payload_len = __le32_to_cpu(swap_item->tlv.length);
|
||||
if ((payload_len > size_left) ||
|
||||
(payload_len == 0 &&
|
||||
size_left != sizeof(struct ath10k_swap_code_seg_tail))) {
|
||||
ath10k_err(ar, "refusing to parse invalid tlv length %d\n",
|
||||
payload_len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (payload_len == 0) {
|
||||
if (memcmp(swap_item->tail.magic_signature, swap_magic,
|
||||
ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ)) {
|
||||
ath10k_err(ar, "refusing an invalid swap file\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
seg_info->target_addr =
|
||||
__le32_to_cpu(swap_item->tail.bmi_write_addr);
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(virt_addr, swap_item->tlv.data, payload_len);
|
||||
virt_addr += payload_len;
|
||||
length = payload_len + sizeof(struct ath10k_swap_code_seg_tlv);
|
||||
size_left -= length;
|
||||
fw_data += length;
|
||||
total_payload_len += payload_len;
|
||||
}
|
||||
|
||||
if (seg_info->target_addr == -1) {
|
||||
ath10k_err(ar, "failed to parse invalid swap file\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
seg_info->seg_hw_info.swap_size = __cpu_to_le32(total_payload_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
ath10k_swap_code_seg_free(struct ath10k *ar,
|
||||
struct ath10k_swap_code_seg_info *seg_info)
|
||||
{
|
||||
u32 seg_size;
|
||||
|
||||
if (!seg_info)
|
||||
return;
|
||||
|
||||
if (!seg_info->virt_address[0])
|
||||
return;
|
||||
|
||||
seg_size = __le32_to_cpu(seg_info->seg_hw_info.size);
|
||||
dma_free_coherent(ar->dev, seg_size, seg_info->virt_address[0],
|
||||
seg_info->paddr[0]);
|
||||
}
|
||||
|
||||
static struct ath10k_swap_code_seg_info *
|
||||
ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len)
|
||||
{
|
||||
struct ath10k_swap_code_seg_info *seg_info;
|
||||
void *virt_addr;
|
||||
dma_addr_t paddr;
|
||||
|
||||
swap_bin_len = roundup(swap_bin_len, 2);
|
||||
if (swap_bin_len > ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX) {
|
||||
ath10k_err(ar, "refusing code swap bin because it is too big %zu > %d\n",
|
||||
swap_bin_len, ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
seg_info = devm_kzalloc(ar->dev, sizeof(*seg_info), GFP_KERNEL);
|
||||
if (!seg_info)
|
||||
return NULL;
|
||||
|
||||
virt_addr = dma_alloc_coherent(ar->dev, swap_bin_len, &paddr,
|
||||
GFP_KERNEL);
|
||||
if (!virt_addr)
|
||||
return NULL;
|
||||
|
||||
seg_info->seg_hw_info.bus_addr[0] = __cpu_to_le32(paddr);
|
||||
seg_info->seg_hw_info.size = __cpu_to_le32(swap_bin_len);
|
||||
seg_info->seg_hw_info.swap_size = __cpu_to_le32(swap_bin_len);
|
||||
seg_info->seg_hw_info.num_segs =
|
||||
__cpu_to_le32(ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED);
|
||||
seg_info->seg_hw_info.size_log2 = __cpu_to_le32(ilog2(swap_bin_len));
|
||||
seg_info->virt_address[0] = virt_addr;
|
||||
seg_info->paddr[0] = paddr;
|
||||
|
||||
return seg_info;
|
||||
}
|
||||
|
||||
int ath10k_swap_code_seg_configure(struct ath10k *ar,
|
||||
const struct ath10k_fw_file *fw_file)
|
||||
{
|
||||
int ret;
|
||||
struct ath10k_swap_code_seg_info *seg_info = NULL;
|
||||
|
||||
if (!fw_file->firmware_swap_code_seg_info)
|
||||
return 0;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n");
|
||||
|
||||
seg_info = fw_file->firmware_swap_code_seg_info;
|
||||
|
||||
ret = ath10k_bmi_write_memory(ar, seg_info->target_addr,
|
||||
#if defined(__linux__)
|
||||
&seg_info->seg_hw_info,
|
||||
#elif defined(__FreeBSD__)
|
||||
(void *)&seg_info->seg_hw_info,
|
||||
#endif
|
||||
sizeof(seg_info->seg_hw_info));
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to write Code swap segment information (%d)\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ath10k_swap_code_seg_release(struct ath10k *ar,
|
||||
struct ath10k_fw_file *fw_file)
|
||||
{
|
||||
ath10k_swap_code_seg_free(ar, fw_file->firmware_swap_code_seg_info);
|
||||
|
||||
/* FIXME: these two assignments look to bein wrong place! Shouldn't
|
||||
* they be in ath10k_core_free_firmware_files() like the rest?
|
||||
*/
|
||||
fw_file->codeswap_data = NULL;
|
||||
fw_file->codeswap_len = 0;
|
||||
|
||||
fw_file->firmware_swap_code_seg_info = NULL;
|
||||
}
|
||||
|
||||
int ath10k_swap_code_seg_init(struct ath10k *ar, struct ath10k_fw_file *fw_file)
|
||||
{
|
||||
int ret;
|
||||
struct ath10k_swap_code_seg_info *seg_info;
|
||||
const void *codeswap_data;
|
||||
size_t codeswap_len;
|
||||
|
||||
codeswap_data = fw_file->codeswap_data;
|
||||
codeswap_len = fw_file->codeswap_len;
|
||||
|
||||
if (!codeswap_len || !codeswap_data)
|
||||
return 0;
|
||||
|
||||
seg_info = ath10k_swap_code_seg_alloc(ar, codeswap_len);
|
||||
if (!seg_info) {
|
||||
ath10k_err(ar, "failed to allocate fw code swap segment\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = ath10k_swap_code_seg_fill(ar, seg_info,
|
||||
codeswap_data, codeswap_len);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n",
|
||||
ret);
|
||||
ath10k_swap_code_seg_free(ar, seg_info);
|
||||
return ret;
|
||||
}
|
||||
|
||||
fw_file->firmware_swap_code_seg_info = seg_info;
|
||||
|
||||
return 0;
|
||||
}
|
59
sys/contrib/dev/athk/ath10k/swap.h
Normal file
59
sys/contrib/dev/athk/ath10k/swap.h
Normal file
@ -0,0 +1,59 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2015-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef _SWAP_H_
|
||||
#define _SWAP_H_
|
||||
|
||||
#define ATH10K_SWAP_CODE_SEG_BIN_LEN_MAX (512 * 1024)
|
||||
#define ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ 12
|
||||
#define ATH10K_SWAP_CODE_SEG_NUM_MAX 16
|
||||
/* Currently only one swap segment is supported */
|
||||
#define ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED 1
|
||||
|
||||
struct ath10k_fw_file;
|
||||
|
||||
struct ath10k_swap_code_seg_tlv {
|
||||
__le32 address;
|
||||
__le32 length;
|
||||
u8 data[0];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_swap_code_seg_tail {
|
||||
u8 magic_signature[ATH10K_SWAP_CODE_SEG_MAGIC_BYTES_SZ];
|
||||
__le32 bmi_write_addr;
|
||||
} __packed;
|
||||
|
||||
union ath10k_swap_code_seg_item {
|
||||
struct ath10k_swap_code_seg_tlv tlv;
|
||||
struct ath10k_swap_code_seg_tail tail;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_swap_code_seg_hw_info {
|
||||
/* Swap binary image size */
|
||||
__le32 swap_size;
|
||||
__le32 num_segs;
|
||||
|
||||
/* Swap data size */
|
||||
__le32 size;
|
||||
__le32 size_log2;
|
||||
__le32 bus_addr[ATH10K_SWAP_CODE_SEG_NUM_MAX];
|
||||
__le64 reserved[ATH10K_SWAP_CODE_SEG_NUM_MAX];
|
||||
} __packed;
|
||||
|
||||
struct ath10k_swap_code_seg_info {
|
||||
struct ath10k_swap_code_seg_hw_info seg_hw_info;
|
||||
void *virt_address[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED];
|
||||
u32 target_addr;
|
||||
dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED];
|
||||
};
|
||||
|
||||
int ath10k_swap_code_seg_configure(struct ath10k *ar,
|
||||
const struct ath10k_fw_file *fw_file);
|
||||
void ath10k_swap_code_seg_release(struct ath10k *ar,
|
||||
struct ath10k_fw_file *fw_file);
|
||||
int ath10k_swap_code_seg_init(struct ath10k *ar,
|
||||
struct ath10k_fw_file *fw_file);
|
||||
|
||||
#endif
|
494
sys/contrib/dev/athk/ath10k/targaddrs.h
Normal file
494
sys/contrib/dev/athk/ath10k/targaddrs.h
Normal file
@ -0,0 +1,494 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#ifndef __TARGADDRS_H__
|
||||
#define __TARGADDRS_H__
|
||||
|
||||
#include "hw.h"
|
||||
|
||||
/*
|
||||
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
|
||||
* host_interest structure. It must match the address of the _host_interest
|
||||
* symbol (see linker script).
|
||||
*
|
||||
* Host Interest is shared between Host and Target in order to coordinate
|
||||
* between the two, and is intended to remain constant (with additions only
|
||||
* at the end) across software releases.
|
||||
*
|
||||
* All addresses are available here so that it's possible to
|
||||
* write a single binary that works with all Target Types.
|
||||
* May be used in assembler code as well as C.
|
||||
*/
|
||||
#define QCA988X_HOST_INTEREST_ADDRESS 0x00400800
|
||||
#define HOST_INTEREST_MAX_SIZE 0x200
|
||||
|
||||
/*
|
||||
* These are items that the Host may need to access via BMI or via the
|
||||
* Diagnostic Window. The position of items in this structure must remain
|
||||
* constant across firmware revisions! Types for each item must be fixed
|
||||
* size across target and host platforms. More items may be added at the end.
|
||||
*/
|
||||
struct host_interest {
|
||||
/*
|
||||
* Pointer to application-defined area, if any.
|
||||
* Set by Target application during startup.
|
||||
*/
|
||||
u32 hi_app_host_interest; /* 0x00 */
|
||||
|
||||
/* Pointer to register dump area, valid after Target crash. */
|
||||
u32 hi_failure_state; /* 0x04 */
|
||||
|
||||
/* Pointer to debug logging header */
|
||||
u32 hi_dbglog_hdr; /* 0x08 */
|
||||
|
||||
u32 hi_unused0c; /* 0x0c */
|
||||
|
||||
/*
|
||||
* General-purpose flag bits, similar to SOC_OPTION_* flags.
|
||||
* Can be used by application rather than by OS.
|
||||
*/
|
||||
u32 hi_option_flag; /* 0x10 */
|
||||
|
||||
/*
|
||||
* Boolean that determines whether or not to
|
||||
* display messages on the serial port.
|
||||
*/
|
||||
u32 hi_serial_enable; /* 0x14 */
|
||||
|
||||
/* Start address of DataSet index, if any */
|
||||
u32 hi_dset_list_head; /* 0x18 */
|
||||
|
||||
/* Override Target application start address */
|
||||
u32 hi_app_start; /* 0x1c */
|
||||
|
||||
/* Clock and voltage tuning */
|
||||
u32 hi_skip_clock_init; /* 0x20 */
|
||||
u32 hi_core_clock_setting; /* 0x24 */
|
||||
u32 hi_cpu_clock_setting; /* 0x28 */
|
||||
u32 hi_system_sleep_setting; /* 0x2c */
|
||||
u32 hi_xtal_control_setting; /* 0x30 */
|
||||
u32 hi_pll_ctrl_setting_24ghz; /* 0x34 */
|
||||
u32 hi_pll_ctrl_setting_5ghz; /* 0x38 */
|
||||
u32 hi_ref_voltage_trim_setting; /* 0x3c */
|
||||
u32 hi_clock_info; /* 0x40 */
|
||||
|
||||
/* Host uses BE CPU or not */
|
||||
u32 hi_be; /* 0x44 */
|
||||
|
||||
u32 hi_stack; /* normal stack */ /* 0x48 */
|
||||
u32 hi_err_stack; /* error stack */ /* 0x4c */
|
||||
u32 hi_desired_cpu_speed_hz; /* 0x50 */
|
||||
|
||||
/* Pointer to Board Data */
|
||||
u32 hi_board_data; /* 0x54 */
|
||||
|
||||
/*
|
||||
* Indication of Board Data state:
|
||||
* 0: board data is not yet initialized.
|
||||
* 1: board data is initialized; unknown size
|
||||
* >1: number of bytes of initialized board data
|
||||
*/
|
||||
u32 hi_board_data_initialized; /* 0x58 */
|
||||
|
||||
u32 hi_dset_ram_index_table; /* 0x5c */
|
||||
|
||||
u32 hi_desired_baud_rate; /* 0x60 */
|
||||
u32 hi_dbglog_config; /* 0x64 */
|
||||
u32 hi_end_ram_reserve_sz; /* 0x68 */
|
||||
u32 hi_mbox_io_block_sz; /* 0x6c */
|
||||
|
||||
u32 hi_num_bpatch_streams; /* 0x70 -- unused */
|
||||
u32 hi_mbox_isr_yield_limit; /* 0x74 */
|
||||
|
||||
u32 hi_refclk_hz; /* 0x78 */
|
||||
u32 hi_ext_clk_detected; /* 0x7c */
|
||||
u32 hi_dbg_uart_txpin; /* 0x80 */
|
||||
u32 hi_dbg_uart_rxpin; /* 0x84 */
|
||||
u32 hi_hci_uart_baud; /* 0x88 */
|
||||
u32 hi_hci_uart_pin_assignments; /* 0x8C */
|
||||
|
||||
u32 hi_hci_uart_baud_scale_val; /* 0x90 */
|
||||
u32 hi_hci_uart_baud_step_val; /* 0x94 */
|
||||
|
||||
u32 hi_allocram_start; /* 0x98 */
|
||||
u32 hi_allocram_sz; /* 0x9c */
|
||||
u32 hi_hci_bridge_flags; /* 0xa0 */
|
||||
u32 hi_hci_uart_support_pins; /* 0xa4 */
|
||||
|
||||
u32 hi_hci_uart_pwr_mgmt_params; /* 0xa8 */
|
||||
|
||||
/*
|
||||
* 0xa8 - [1]: 0 = UART FC active low, 1 = UART FC active high
|
||||
* [31:16]: wakeup timeout in ms
|
||||
*/
|
||||
/* Pointer to extended board Data */
|
||||
u32 hi_board_ext_data; /* 0xac */
|
||||
u32 hi_board_ext_data_config; /* 0xb0 */
|
||||
/*
|
||||
* Bit [0] : valid
|
||||
* Bit[31:16: size
|
||||
*/
|
||||
/*
|
||||
* hi_reset_flag is used to do some stuff when target reset.
|
||||
* such as restore app_start after warm reset or
|
||||
* preserve host Interest area, or preserve ROM data, literals etc.
|
||||
*/
|
||||
u32 hi_reset_flag; /* 0xb4 */
|
||||
/* indicate hi_reset_flag is valid */
|
||||
u32 hi_reset_flag_valid; /* 0xb8 */
|
||||
u32 hi_hci_uart_pwr_mgmt_params_ext; /* 0xbc */
|
||||
/* 0xbc - [31:0]: idle timeout in ms */
|
||||
/* ACS flags */
|
||||
u32 hi_acs_flags; /* 0xc0 */
|
||||
u32 hi_console_flags; /* 0xc4 */
|
||||
u32 hi_nvram_state; /* 0xc8 */
|
||||
u32 hi_option_flag2; /* 0xcc */
|
||||
|
||||
/* If non-zero, override values sent to Host in WMI_READY event. */
|
||||
u32 hi_sw_version_override; /* 0xd0 */
|
||||
u32 hi_abi_version_override; /* 0xd4 */
|
||||
|
||||
/*
|
||||
* Percentage of high priority RX traffic to total expected RX traffic
|
||||
* applicable only to ar6004
|
||||
*/
|
||||
u32 hi_hp_rx_traffic_ratio; /* 0xd8 */
|
||||
|
||||
/* test applications flags */
|
||||
u32 hi_test_apps_related; /* 0xdc */
|
||||
/* location of test script */
|
||||
u32 hi_ota_testscript; /* 0xe0 */
|
||||
/* location of CAL data */
|
||||
u32 hi_cal_data; /* 0xe4 */
|
||||
|
||||
/* Number of packet log buffers */
|
||||
u32 hi_pktlog_num_buffers; /* 0xe8 */
|
||||
|
||||
/* wow extension configuration */
|
||||
u32 hi_wow_ext_config; /* 0xec */
|
||||
u32 hi_pwr_save_flags; /* 0xf0 */
|
||||
|
||||
/* Spatial Multiplexing Power Save (SMPS) options */
|
||||
u32 hi_smps_options; /* 0xf4 */
|
||||
|
||||
/* Interconnect-specific state */
|
||||
u32 hi_interconnect_state; /* 0xf8 */
|
||||
|
||||
/* Coex configuration flags */
|
||||
u32 hi_coex_config; /* 0xfc */
|
||||
|
||||
/* Early allocation support */
|
||||
u32 hi_early_alloc; /* 0x100 */
|
||||
/* FW swap field */
|
||||
/*
|
||||
* Bits of this 32bit word will be used to pass specific swap
|
||||
* instruction to FW
|
||||
*/
|
||||
/*
|
||||
* Bit 0 -- AP Nart descriptor no swap. When this bit is set
|
||||
* FW will not swap TX descriptor. Meaning packets are formed
|
||||
* on the target processor.
|
||||
*/
|
||||
/* Bit 1 - unused */
|
||||
u32 hi_fw_swap; /* 0x104 */
|
||||
|
||||
/* global arenas pointer address, used by host driver debug */
|
||||
u32 hi_dynamic_mem_arenas_addr; /* 0x108 */
|
||||
|
||||
/* allocated bytes of DRAM use by allocated */
|
||||
u32 hi_dynamic_mem_allocated; /* 0x10C */
|
||||
|
||||
/* remaining bytes of DRAM */
|
||||
u32 hi_dynamic_mem_remaining; /* 0x110 */
|
||||
|
||||
/* memory track count, configured by host */
|
||||
u32 hi_dynamic_mem_track_max; /* 0x114 */
|
||||
|
||||
/* minidump buffer */
|
||||
u32 hi_minidump; /* 0x118 */
|
||||
|
||||
/* bdata's sig and key addr */
|
||||
u32 hi_bd_sig_key; /* 0x11c */
|
||||
} __packed;
|
||||
|
||||
#define HI_ITEM(item) offsetof(struct host_interest, item)
|
||||
|
||||
/* Bits defined in hi_option_flag */
|
||||
|
||||
/* Enable timer workaround */
|
||||
#define HI_OPTION_TIMER_WAR 0x01
|
||||
/* Limit BMI command credits */
|
||||
#define HI_OPTION_BMI_CRED_LIMIT 0x02
|
||||
/* Relay Dot11 hdr to/from host */
|
||||
#define HI_OPTION_RELAY_DOT11_HDR 0x04
|
||||
/* MAC addr method 0-locally administred 1-globally unique addrs */
|
||||
#define HI_OPTION_MAC_ADDR_METHOD 0x08
|
||||
/* Firmware Bridging */
|
||||
#define HI_OPTION_FW_BRIDGE 0x10
|
||||
/* Enable CPU profiling */
|
||||
#define HI_OPTION_ENABLE_PROFILE 0x20
|
||||
/* Disable debug logging */
|
||||
#define HI_OPTION_DISABLE_DBGLOG 0x40
|
||||
/* Skip Era Tracking */
|
||||
#define HI_OPTION_SKIP_ERA_TRACKING 0x80
|
||||
/* Disable PAPRD (debug) */
|
||||
#define HI_OPTION_PAPRD_DISABLE 0x100
|
||||
#define HI_OPTION_NUM_DEV_LSB 0x200
|
||||
#define HI_OPTION_NUM_DEV_MSB 0x800
|
||||
#define HI_OPTION_DEV_MODE_LSB 0x1000
|
||||
#define HI_OPTION_DEV_MODE_MSB 0x8000000
|
||||
/* Disable LowFreq Timer Stabilization */
|
||||
#define HI_OPTION_NO_LFT_STBL 0x10000000
|
||||
/* Skip regulatory scan */
|
||||
#define HI_OPTION_SKIP_REG_SCAN 0x20000000
|
||||
/*
|
||||
* Do regulatory scan during init before
|
||||
* sending WMI ready event to host
|
||||
*/
|
||||
#define HI_OPTION_INIT_REG_SCAN 0x40000000
|
||||
|
||||
/* REV6: Do not adjust memory map */
|
||||
#define HI_OPTION_SKIP_MEMMAP 0x80000000
|
||||
|
||||
#define HI_OPTION_MAC_ADDR_METHOD_SHIFT 3
|
||||
|
||||
/* 2 bits of hi_option_flag are used to represent 3 modes */
|
||||
#define HI_OPTION_FW_MODE_IBSS 0x0 /* IBSS Mode */
|
||||
#define HI_OPTION_FW_MODE_BSS_STA 0x1 /* STA Mode */
|
||||
#define HI_OPTION_FW_MODE_AP 0x2 /* AP Mode */
|
||||
#define HI_OPTION_FW_MODE_BT30AMP 0x3 /* BT30 AMP Mode */
|
||||
|
||||
/* 2 bits of hi_option flag are usedto represent 4 submodes */
|
||||
#define HI_OPTION_FW_SUBMODE_NONE 0x0 /* Normal mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PDEV 0x1 /* p2p device mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PCLIENT 0x2 /* p2p client mode */
|
||||
#define HI_OPTION_FW_SUBMODE_P2PGO 0x3 /* p2p go mode */
|
||||
|
||||
/* Num dev Mask */
|
||||
#define HI_OPTION_NUM_DEV_MASK 0x7
|
||||
#define HI_OPTION_NUM_DEV_SHIFT 0x9
|
||||
|
||||
/* firmware bridging */
|
||||
#define HI_OPTION_FW_BRIDGE_SHIFT 0x04
|
||||
|
||||
/*
|
||||
* Fw Mode/SubMode Mask
|
||||
*-----------------------------------------------------------------------------
|
||||
* SUB | SUB | SUB | SUB | | | |
|
||||
*MODE[3] | MODE[2] | MODE[1] | MODE[0] | MODE[3] | MODE[2] | MODE[1] | MODE[0]
|
||||
* (2) | (2) | (2) | (2) | (2) | (2) | (2) | (2)
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
#define HI_OPTION_FW_MODE_BITS 0x2
|
||||
#define HI_OPTION_FW_MODE_MASK 0x3
|
||||
#define HI_OPTION_FW_MODE_SHIFT 0xC
|
||||
#define HI_OPTION_ALL_FW_MODE_MASK 0xFF
|
||||
|
||||
#define HI_OPTION_FW_SUBMODE_BITS 0x2
|
||||
#define HI_OPTION_FW_SUBMODE_MASK 0x3
|
||||
#define HI_OPTION_FW_SUBMODE_SHIFT 0x14
|
||||
#define HI_OPTION_ALL_FW_SUBMODE_MASK 0xFF00
|
||||
#define HI_OPTION_ALL_FW_SUBMODE_SHIFT 0x8
|
||||
|
||||
/* hi_option_flag2 options */
|
||||
#define HI_OPTION_OFFLOAD_AMSDU 0x01
|
||||
#define HI_OPTION_DFS_SUPPORT 0x02 /* Enable DFS support */
|
||||
#define HI_OPTION_ENABLE_RFKILL 0x04 /* RFKill Enable Feature*/
|
||||
#define HI_OPTION_RADIO_RETENTION_DISABLE 0x08 /* Disable radio retention */
|
||||
#define HI_OPTION_EARLY_CFG_DONE 0x10 /* Early configuration is complete */
|
||||
|
||||
#define HI_OPTION_RF_KILL_SHIFT 0x2
|
||||
#define HI_OPTION_RF_KILL_MASK 0x1
|
||||
|
||||
/* hi_reset_flag */
|
||||
/* preserve App Start address */
|
||||
#define HI_RESET_FLAG_PRESERVE_APP_START 0x01
|
||||
/* preserve host interest */
|
||||
#define HI_RESET_FLAG_PRESERVE_HOST_INTEREST 0x02
|
||||
/* preserve ROM data */
|
||||
#define HI_RESET_FLAG_PRESERVE_ROMDATA 0x04
|
||||
#define HI_RESET_FLAG_PRESERVE_NVRAM_STATE 0x08
|
||||
#define HI_RESET_FLAG_PRESERVE_BOOT_INFO 0x10
|
||||
#define HI_RESET_FLAG_WARM_RESET 0x20
|
||||
|
||||
/* define hi_fw_swap bits */
|
||||
#define HI_DESC_IN_FW_BIT 0x01
|
||||
|
||||
/* indicate the reset flag is valid */
|
||||
#define HI_RESET_FLAG_IS_VALID 0x12345678
|
||||
|
||||
/* ACS is enabled */
|
||||
#define HI_ACS_FLAGS_ENABLED (1 << 0)
|
||||
/* Use physical WWAN device */
|
||||
#define HI_ACS_FLAGS_USE_WWAN (1 << 1)
|
||||
/* Use test VAP */
|
||||
#define HI_ACS_FLAGS_TEST_VAP (1 << 2)
|
||||
/* SDIO/mailbox ACS flag definitions */
|
||||
#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_SET (1 << 0)
|
||||
#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_SET (1 << 1)
|
||||
#define HI_ACS_FLAGS_ALT_DATA_CREDIT_SIZE (1 << 2)
|
||||
#define HI_ACS_FLAGS_SDIO_SWAP_MAILBOX_FW_ACK (1 << 16)
|
||||
#define HI_ACS_FLAGS_SDIO_REDUCE_TX_COMPL_FW_ACK (1 << 17)
|
||||
|
||||
/*
|
||||
* If both SDIO_CRASH_DUMP_ENHANCEMENT_HOST and SDIO_CRASH_DUMP_ENHANCEMENT_FW
|
||||
* flags are set, then crashdump upload will be done using the BMI host/target
|
||||
* communication channel.
|
||||
*/
|
||||
/* HOST to support using BMI dump FW memory when hit assert */
|
||||
#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_HOST 0x400
|
||||
|
||||
/* FW to support using BMI dump FW memory when hit assert */
|
||||
#define HI_OPTION_SDIO_CRASH_DUMP_ENHANCEMENT_FW 0x800
|
||||
|
||||
/*
|
||||
* CONSOLE FLAGS
|
||||
*
|
||||
* Bit Range Meaning
|
||||
* --------- --------------------------------
|
||||
* 2..0 UART ID (0 = Default)
|
||||
* 3 Baud Select (0 = 9600, 1 = 115200)
|
||||
* 30..4 Reserved
|
||||
* 31 Enable Console
|
||||
*
|
||||
*/
|
||||
|
||||
#define HI_CONSOLE_FLAGS_ENABLE (1 << 31)
|
||||
#define HI_CONSOLE_FLAGS_UART_MASK (0x7)
|
||||
#define HI_CONSOLE_FLAGS_UART_SHIFT 0
|
||||
#define HI_CONSOLE_FLAGS_BAUD_SELECT (1 << 3)
|
||||
|
||||
/* SM power save options */
|
||||
#define HI_SMPS_ALLOW_MASK (0x00000001)
|
||||
#define HI_SMPS_MODE_MASK (0x00000002)
|
||||
#define HI_SMPS_MODE_STATIC (0x00000000)
|
||||
#define HI_SMPS_MODE_DYNAMIC (0x00000002)
|
||||
#define HI_SMPS_DISABLE_AUTO_MODE (0x00000004)
|
||||
#define HI_SMPS_DATA_THRESH_MASK (0x000007f8)
|
||||
#define HI_SMPS_DATA_THRESH_SHIFT (3)
|
||||
#define HI_SMPS_RSSI_THRESH_MASK (0x0007f800)
|
||||
#define HI_SMPS_RSSI_THRESH_SHIFT (11)
|
||||
#define HI_SMPS_LOWPWR_CM_MASK (0x00380000)
|
||||
#define HI_SMPS_LOWPWR_CM_SHIFT (15)
|
||||
#define HI_SMPS_HIPWR_CM_MASK (0x03c00000)
|
||||
#define HI_SMPS_HIPWR_CM_SHIFT (19)
|
||||
|
||||
/*
|
||||
* WOW Extension configuration
|
||||
*
|
||||
* Bit Range Meaning
|
||||
* --------- --------------------------------
|
||||
* 8..0 Size of each WOW pattern (max 511)
|
||||
* 15..9 Number of patterns per list (max 127)
|
||||
* 17..16 Number of lists (max 4)
|
||||
* 30..18 Reserved
|
||||
* 31 Enabled
|
||||
*
|
||||
* set values (except enable) to zeros for default settings
|
||||
*/
|
||||
|
||||
#define HI_WOW_EXT_ENABLED_MASK (1 << 31)
|
||||
#define HI_WOW_EXT_NUM_LIST_SHIFT 16
|
||||
#define HI_WOW_EXT_NUM_LIST_MASK (0x3 << HI_WOW_EXT_NUM_LIST_SHIFT)
|
||||
#define HI_WOW_EXT_NUM_PATTERNS_SHIFT 9
|
||||
#define HI_WOW_EXT_NUM_PATTERNS_MASK (0x7F << HI_WOW_EXT_NUM_PATTERNS_SHIFT)
|
||||
#define HI_WOW_EXT_PATTERN_SIZE_SHIFT 0
|
||||
#define HI_WOW_EXT_PATTERN_SIZE_MASK (0x1FF << HI_WOW_EXT_PATTERN_SIZE_SHIFT)
|
||||
|
||||
#define HI_WOW_EXT_MAKE_CONFIG(num_lists, count, size) \
|
||||
((((num_lists) << HI_WOW_EXT_NUM_LIST_SHIFT) & \
|
||||
HI_WOW_EXT_NUM_LIST_MASK) | \
|
||||
(((count) << HI_WOW_EXT_NUM_PATTERNS_SHIFT) & \
|
||||
HI_WOW_EXT_NUM_PATTERNS_MASK) | \
|
||||
(((size) << HI_WOW_EXT_PATTERN_SIZE_SHIFT) & \
|
||||
HI_WOW_EXT_PATTERN_SIZE_MASK))
|
||||
|
||||
#define HI_WOW_EXT_GET_NUM_LISTS(config) \
|
||||
(((config) & HI_WOW_EXT_NUM_LIST_MASK) >> HI_WOW_EXT_NUM_LIST_SHIFT)
|
||||
#define HI_WOW_EXT_GET_NUM_PATTERNS(config) \
|
||||
(((config) & HI_WOW_EXT_NUM_PATTERNS_MASK) >> \
|
||||
HI_WOW_EXT_NUM_PATTERNS_SHIFT)
|
||||
#define HI_WOW_EXT_GET_PATTERN_SIZE(config) \
|
||||
(((config) & HI_WOW_EXT_PATTERN_SIZE_MASK) >> \
|
||||
HI_WOW_EXT_PATTERN_SIZE_SHIFT)
|
||||
|
||||
/*
|
||||
* Early allocation configuration
|
||||
* Support RAM bank configuration before BMI done and this eases the memory
|
||||
* allocation at very early stage
|
||||
* Bit Range Meaning
|
||||
* --------- ----------------------------------
|
||||
* [0:3] number of bank assigned to be IRAM
|
||||
* [4:15] reserved
|
||||
* [16:31] magic number
|
||||
*
|
||||
* Note:
|
||||
* 1. target firmware would check magic number and if it's a match, firmware
|
||||
* would consider the bits[0:15] are valid and base on that to calculate
|
||||
* the end of DRAM. Early allocation would be located at that area and
|
||||
* may be reclaimed when necessary
|
||||
* 2. if no magic number is found, early allocation would happen at "_end"
|
||||
* symbol of ROM which is located before the app-data and might NOT be
|
||||
* re-claimable. If this is adopted, link script should keep this in
|
||||
* mind to avoid data corruption.
|
||||
*/
|
||||
#define HI_EARLY_ALLOC_MAGIC 0x6d8a
|
||||
#define HI_EARLY_ALLOC_MAGIC_MASK 0xffff0000
|
||||
#define HI_EARLY_ALLOC_MAGIC_SHIFT 16
|
||||
#define HI_EARLY_ALLOC_IRAM_BANKS_MASK 0x0000000f
|
||||
#define HI_EARLY_ALLOC_IRAM_BANKS_SHIFT 0
|
||||
|
||||
#define HI_EARLY_ALLOC_VALID() \
|
||||
((((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_MAGIC_MASK) >> \
|
||||
HI_EARLY_ALLOC_MAGIC_SHIFT) == (HI_EARLY_ALLOC_MAGIC))
|
||||
#define HI_EARLY_ALLOC_GET_IRAM_BANKS() \
|
||||
(((HOST_INTEREST->hi_early_alloc) & HI_EARLY_ALLOC_IRAM_BANKS_MASK) \
|
||||
>> HI_EARLY_ALLOC_IRAM_BANKS_SHIFT)
|
||||
|
||||
/*power save flag bit definitions*/
|
||||
#define HI_PWR_SAVE_LPL_ENABLED 0x1
|
||||
/*b1-b3 reserved*/
|
||||
/*b4-b5 : dev0 LPL type : 0 - none
|
||||
* 1- Reduce Pwr Search
|
||||
* 2- Reduce Pwr Listen
|
||||
*/
|
||||
/*b6-b7 : dev1 LPL type and so on for Max 8 devices*/
|
||||
#define HI_PWR_SAVE_LPL_DEV0_LSB 4
|
||||
#define HI_PWR_SAVE_LPL_DEV_MASK 0x3
|
||||
/*power save related utility macros*/
|
||||
#define HI_LPL_ENABLED() \
|
||||
((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED))
|
||||
#define HI_DEV_LPL_TYPE_GET(_devix) \
|
||||
(HOST_INTEREST->hi_pwr_save_flags & ((HI_PWR_SAVE_LPL_DEV_MASK) << \
|
||||
(HI_PWR_SAVE_LPL_DEV0_LSB + (_devix) * 2)))
|
||||
|
||||
#define HOST_INTEREST_SMPS_IS_ALLOWED() \
|
||||
((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK))
|
||||
|
||||
/* Reserve 1024 bytes for extended board data */
|
||||
#define QCA988X_BOARD_DATA_SZ 7168
|
||||
#define QCA988X_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#define QCA9887_BOARD_DATA_SZ 7168
|
||||
#define QCA9887_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#define QCA6174_BOARD_DATA_SZ 8192
|
||||
#define QCA6174_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#define QCA9377_BOARD_DATA_SZ QCA6174_BOARD_DATA_SZ
|
||||
#define QCA9377_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#define QCA99X0_BOARD_DATA_SZ 12288
|
||||
#define QCA99X0_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
/* Dual band extended board data */
|
||||
#define QCA99X0_EXT_BOARD_DATA_SZ 2048
|
||||
#define EXT_BOARD_ADDRESS_OFFSET 0x3000
|
||||
|
||||
#define QCA4019_BOARD_DATA_SZ 12064
|
||||
#define QCA4019_BOARD_EXT_DATA_SZ 0
|
||||
|
||||
#endif /* __TARGADDRS_H__ */
|
469
sys/contrib/dev/athk/ath10k/testmode.c
Normal file
469
sys/contrib/dev/athk/ath10k/testmode.c
Normal file
@ -0,0 +1,469 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2014-2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include "testmode.h"
|
||||
|
||||
#include <net/netlink.h>
|
||||
#include <linux/firmware.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "wmi.h"
|
||||
#include "hif.h"
|
||||
#include "hw.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "testmode_i.h"
|
||||
|
||||
static const struct nla_policy ath10k_tm_policy[ATH10K_TM_ATTR_MAX + 1] = {
|
||||
[ATH10K_TM_ATTR_CMD] = { .type = NLA_U32 },
|
||||
[ATH10K_TM_ATTR_DATA] = { .type = NLA_BINARY,
|
||||
.len = ATH10K_TM_DATA_MAX_LEN },
|
||||
[ATH10K_TM_ATTR_WMI_CMDID] = { .type = NLA_U32 },
|
||||
[ATH10K_TM_ATTR_VERSION_MAJOR] = { .type = NLA_U32 },
|
||||
[ATH10K_TM_ATTR_VERSION_MINOR] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* Returns true if callee consumes the skb and the skb should be discarded.
|
||||
* Returns false if skb is not used. Does not sleep.
|
||||
*/
|
||||
bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb)
|
||||
{
|
||||
struct sk_buff *nl_skb;
|
||||
bool consumed;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
|
||||
"testmode event wmi cmd_id %d skb %pK skb->len %d\n",
|
||||
cmd_id, skb, skb->len);
|
||||
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", skb->data, skb->len);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
if (!ar->testmode.utf_monitor) {
|
||||
consumed = false;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Only testmode.c should be handling events from utf firmware,
|
||||
* otherwise all sort of problems will arise as mac80211 operations
|
||||
* are not initialised.
|
||||
*/
|
||||
consumed = true;
|
||||
|
||||
nl_skb = cfg80211_testmode_alloc_event_skb(ar->hw->wiphy,
|
||||
2 * sizeof(u32) + skb->len,
|
||||
GFP_ATOMIC);
|
||||
if (!nl_skb) {
|
||||
ath10k_warn(ar,
|
||||
"failed to allocate skb for testmode wmi event\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_CMD, ATH10K_TM_CMD_WMI);
|
||||
if (ret) {
|
||||
ath10k_warn(ar,
|
||||
"failed to put testmode wmi event cmd attribute: %d\n",
|
||||
ret);
|
||||
kfree_skb(nl_skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(nl_skb, ATH10K_TM_ATTR_WMI_CMDID, cmd_id);
|
||||
if (ret) {
|
||||
ath10k_warn(ar,
|
||||
"failed to put testmode wmi event cmd_id: %d\n",
|
||||
ret);
|
||||
kfree_skb(nl_skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = nla_put(nl_skb, ATH10K_TM_ATTR_DATA, skb->len, skb->data);
|
||||
if (ret) {
|
||||
ath10k_warn(ar,
|
||||
"failed to copy skb to testmode wmi event: %d\n",
|
||||
ret);
|
||||
kfree_skb(nl_skb);
|
||||
goto out;
|
||||
}
|
||||
|
||||
cfg80211_testmode_event(nl_skb, GFP_ATOMIC);
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
|
||||
"testmode cmd get version_major %d version_minor %d\n",
|
||||
ATH10K_TESTMODE_VERSION_MAJOR,
|
||||
ATH10K_TESTMODE_VERSION_MINOR);
|
||||
|
||||
skb = cfg80211_testmode_alloc_reply_skb(ar->hw->wiphy,
|
||||
nla_total_size(sizeof(u32)));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MAJOR,
|
||||
ATH10K_TESTMODE_VERSION_MAJOR);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(skb, ATH10K_TM_ATTR_VERSION_MINOR,
|
||||
ATH10K_TESTMODE_VERSION_MINOR);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = nla_put_u32(skb, ATH10K_TM_ATTR_WMI_OP_VERSION,
|
||||
ar->normal_mode_fw.fw_file.wmi_op_version);
|
||||
if (ret) {
|
||||
kfree_skb(skb);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return cfg80211_testmode_reply(skb);
|
||||
}
|
||||
|
||||
static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
|
||||
struct ath10k_fw_file *fw_file)
|
||||
{
|
||||
char filename[100];
|
||||
int ret;
|
||||
|
||||
snprintf(filename, sizeof(filename), "%s/%s",
|
||||
ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
|
||||
|
||||
/* load utf firmware image */
|
||||
ret = firmware_request_nowarn(&fw_file->firmware, filename, ar->dev);
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode fw request '%s': %d\n",
|
||||
filename, ret);
|
||||
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
|
||||
filename, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* We didn't find FW UTF API 1 ("utf.bin") does not advertise
|
||||
* firmware features. Do an ugly hack where we force the firmware
|
||||
* features to match with 10.1 branch so that wmi.c will use the
|
||||
* correct WMI interface.
|
||||
*/
|
||||
|
||||
fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
|
||||
fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
|
||||
fw_file->firmware_data = fw_file->firmware->data;
|
||||
fw_file->firmware_len = fw_file->firmware->size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_tm_fetch_firmware(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_fw_components *utf_mode_fw;
|
||||
int ret;
|
||||
char fw_name[100];
|
||||
int fw_api2 = 2;
|
||||
|
||||
switch (ar->hif.bus) {
|
||||
case ATH10K_BUS_SDIO:
|
||||
case ATH10K_BUS_USB:
|
||||
scnprintf(fw_name, sizeof(fw_name), "%s-%s-%d.bin",
|
||||
ATH10K_FW_UTF_FILE_BASE, ath10k_bus_str(ar->hif.bus),
|
||||
fw_api2);
|
||||
break;
|
||||
default:
|
||||
scnprintf(fw_name, sizeof(fw_name), "%s-%d.bin",
|
||||
ATH10K_FW_UTF_FILE_BASE, fw_api2);
|
||||
break;
|
||||
}
|
||||
|
||||
ret = ath10k_core_fetch_firmware_api_n(ar, fw_name,
|
||||
&ar->testmode.utf_mode_fw.fw_file);
|
||||
if (ret == 0) {
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
|
||||
|
||||
out:
|
||||
utf_mode_fw = &ar->testmode.utf_mode_fw;
|
||||
|
||||
/* Use the same board data file as the normal firmware uses (but
|
||||
* it's still "owned" by normal_mode_fw so we shouldn't free it.
|
||||
*/
|
||||
utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
|
||||
utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
|
||||
|
||||
if (!utf_mode_fw->fw_file.otp_data) {
|
||||
ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
|
||||
utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
|
||||
utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
|
||||
{
|
||||
const char *ver;
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf start\n");
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state == ATH10K_STATE_UTF) {
|
||||
ret = -EALREADY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* start utf only when the driver is not in use */
|
||||
if (ar->state != ATH10K_STATE_OFF) {
|
||||
ret = -EBUSY;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
|
||||
/* utf image is already downloaded, it shouldn't be */
|
||||
ret = -EEXIST;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = ath10k_tm_fetch_firmware(ar);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to fetch UTF firmware: %d", ret);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
|
||||
ar->testmode.utf_mode_fw.fw_file.codeswap_len) {
|
||||
ret = ath10k_swap_code_seg_init(ar,
|
||||
&ar->testmode.utf_mode_fw.fw_file);
|
||||
if (ret) {
|
||||
ath10k_warn(ar,
|
||||
"failed to init utf code swap segment: %d\n",
|
||||
ret);
|
||||
goto err_release_utf_mode_fw;
|
||||
}
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->testmode.utf_monitor = true;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
|
||||
ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
|
||||
|
||||
ret = ath10k_hif_power_up(ar, ATH10K_FIRMWARE_MODE_UTF);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
goto err_release_utf_mode_fw;
|
||||
}
|
||||
|
||||
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
|
||||
&ar->testmode.utf_mode_fw);
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
goto err_power_down;
|
||||
}
|
||||
|
||||
ar->state = ATH10K_STATE_UTF;
|
||||
|
||||
if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
|
||||
ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
|
||||
else
|
||||
ver = "API 1";
|
||||
|
||||
ath10k_info(ar, "UTF firmware %s started\n", ver);
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
err_power_down:
|
||||
ath10k_hif_power_down(ar);
|
||||
|
||||
err_release_utf_mode_fw:
|
||||
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
|
||||
ar->testmode.utf_mode_fw.fw_file.codeswap_len)
|
||||
ath10k_swap_code_seg_release(ar,
|
||||
&ar->testmode.utf_mode_fw.fw_file);
|
||||
|
||||
release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
|
||||
ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
|
||||
|
||||
err:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
|
||||
{
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
ath10k_core_stop(ar);
|
||||
ath10k_hif_power_down(ar);
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
|
||||
ar->testmode.utf_monitor = false;
|
||||
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
if (ar->testmode.utf_mode_fw.fw_file.codeswap_data &&
|
||||
ar->testmode.utf_mode_fw.fw_file.codeswap_len)
|
||||
ath10k_swap_code_seg_release(ar,
|
||||
&ar->testmode.utf_mode_fw.fw_file);
|
||||
|
||||
release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
|
||||
ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
|
||||
|
||||
ar->state = ATH10K_STATE_OFF;
|
||||
}
|
||||
|
||||
static int ath10k_tm_cmd_utf_stop(struct ath10k *ar, struct nlattr *tb[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode cmd utf stop\n");
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_UTF) {
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
__ath10k_tm_cmd_utf_stop(ar);
|
||||
|
||||
ret = 0;
|
||||
|
||||
ath10k_info(ar, "UTF firmware stopped\n");
|
||||
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_tm_cmd_wmi(struct ath10k *ar, struct nlattr *tb[])
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret, buf_len;
|
||||
u32 cmd_id;
|
||||
void *buf;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_UTF) {
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tb[ATH10K_TM_ATTR_DATA]) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!tb[ATH10K_TM_ATTR_WMI_CMDID]) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf = nla_data(tb[ATH10K_TM_ATTR_DATA]);
|
||||
buf_len = nla_len(tb[ATH10K_TM_ATTR_DATA]);
|
||||
cmd_id = nla_get_u32(tb[ATH10K_TM_ATTR_WMI_CMDID]);
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
|
||||
"testmode cmd wmi cmd_id %d buf %pK buf_len %d\n",
|
||||
cmd_id, buf, buf_len);
|
||||
|
||||
ath10k_dbg_dump(ar, ATH10K_DBG_TESTMODE, NULL, "", buf, buf_len);
|
||||
|
||||
skb = ath10k_wmi_alloc_skb(ar, buf_len);
|
||||
if (!skb) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(skb->data, buf, buf_len);
|
||||
|
||||
ret = ath10k_wmi_cmd_send(ar, skb, cmd_id);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to transmit wmi command (testmode): %d\n",
|
||||
ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
struct nlattr *tb[ATH10K_TM_ATTR_MAX + 1];
|
||||
int ret;
|
||||
|
||||
ret = nla_parse_deprecated(tb, ATH10K_TM_ATTR_MAX, data, len,
|
||||
ath10k_tm_policy, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!tb[ATH10K_TM_ATTR_CMD])
|
||||
return -EINVAL;
|
||||
|
||||
switch (nla_get_u32(tb[ATH10K_TM_ATTR_CMD])) {
|
||||
case ATH10K_TM_CMD_GET_VERSION:
|
||||
return ath10k_tm_cmd_get_version(ar, tb);
|
||||
case ATH10K_TM_CMD_UTF_START:
|
||||
return ath10k_tm_cmd_utf_start(ar, tb);
|
||||
case ATH10K_TM_CMD_UTF_STOP:
|
||||
return ath10k_tm_cmd_utf_stop(ar, tb);
|
||||
case ATH10K_TM_CMD_WMI:
|
||||
return ath10k_tm_cmd_wmi(ar, tb);
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
void ath10k_testmode_destroy(struct ath10k *ar)
|
||||
{
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (ar->state != ATH10K_STATE_UTF) {
|
||||
/* utf firmware is not running, nothing to do */
|
||||
goto out;
|
||||
}
|
||||
|
||||
__ath10k_tm_cmd_utf_stop(ar);
|
||||
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
35
sys/contrib/dev/athk/ath10k/testmode.h
Normal file
35
sys/contrib/dev/athk/ath10k/testmode.h
Normal file
@ -0,0 +1,35 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2014 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
|
||||
#ifdef CONFIG_NL80211_TESTMODE
|
||||
|
||||
void ath10k_testmode_destroy(struct ath10k *ar);
|
||||
|
||||
bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id, struct sk_buff *skb);
|
||||
int ath10k_tm_cmd(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||
void *data, int len);
|
||||
|
||||
#else
|
||||
|
||||
static inline void ath10k_testmode_destroy(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline bool ath10k_tm_event_wmi(struct ath10k *ar, u32 cmd_id,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int ath10k_tm_cmd(struct ieee80211_hw *hw,
|
||||
struct ieee80211_vif *vif,
|
||||
void *data, int len)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
60
sys/contrib/dev/athk/ath10k/testmode_i.h
Normal file
60
sys/contrib/dev/athk/ath10k/testmode_i.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
/* "API" level of the ath10k testmode interface. Bump it after every
|
||||
* incompatible interface change.
|
||||
*/
|
||||
#define ATH10K_TESTMODE_VERSION_MAJOR 1
|
||||
|
||||
/* Bump this after every _compatible_ interface change, for example
|
||||
* addition of a new command or an attribute.
|
||||
*/
|
||||
#define ATH10K_TESTMODE_VERSION_MINOR 0
|
||||
|
||||
#define ATH10K_TM_DATA_MAX_LEN 5000
|
||||
|
||||
enum ath10k_tm_attr {
|
||||
__ATH10K_TM_ATTR_INVALID = 0,
|
||||
ATH10K_TM_ATTR_CMD = 1,
|
||||
ATH10K_TM_ATTR_DATA = 2,
|
||||
ATH10K_TM_ATTR_WMI_CMDID = 3,
|
||||
ATH10K_TM_ATTR_VERSION_MAJOR = 4,
|
||||
ATH10K_TM_ATTR_VERSION_MINOR = 5,
|
||||
ATH10K_TM_ATTR_WMI_OP_VERSION = 6,
|
||||
|
||||
/* keep last */
|
||||
__ATH10K_TM_ATTR_AFTER_LAST,
|
||||
ATH10K_TM_ATTR_MAX = __ATH10K_TM_ATTR_AFTER_LAST - 1,
|
||||
};
|
||||
|
||||
/* All ath10k testmode interface commands specified in
|
||||
* ATH10K_TM_ATTR_CMD
|
||||
*/
|
||||
enum ath10k_tm_cmd {
|
||||
/* Returns the supported ath10k testmode interface version in
|
||||
* ATH10K_TM_ATTR_VERSION. Always guaranteed to work. User space
|
||||
* uses this to verify it's using the correct version of the
|
||||
* testmode interface
|
||||
*/
|
||||
ATH10K_TM_CMD_GET_VERSION = 0,
|
||||
|
||||
/* Boots the UTF firmware, the netdev interface must be down at the
|
||||
* time.
|
||||
*/
|
||||
ATH10K_TM_CMD_UTF_START = 1,
|
||||
|
||||
/* Shuts down the UTF firmware and puts the driver back into OFF
|
||||
* state.
|
||||
*/
|
||||
ATH10K_TM_CMD_UTF_STOP = 2,
|
||||
|
||||
/* The command used to transmit a WMI command to the firmware and
|
||||
* the event to receive WMI events from the firmware. Without
|
||||
* struct wmi_cmd_hdr header, only the WMI payload. Command id is
|
||||
* provided with ATH10K_TM_ATTR_WMI_CMDID and payload in
|
||||
* ATH10K_TM_ATTR_DATA.
|
||||
*/
|
||||
ATH10K_TM_CMD_WMI = 3,
|
||||
};
|
219
sys/contrib/dev/athk/ath10k/thermal.c
Normal file
219
sys/contrib/dev/athk/ath10k/thermal.c
Normal file
@ -0,0 +1,219 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/thermal.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "wmi-ops.h"
|
||||
|
||||
static int
|
||||
ath10k_thermal_get_max_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
*state = ATH10K_THERMAL_THROTTLE_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_thermal_get_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long *state)
|
||||
{
|
||||
struct ath10k *ar = cdev->devdata;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
*state = ar->thermal.throttle_state;
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ath10k_thermal_set_cur_throttle_state(struct thermal_cooling_device *cdev,
|
||||
unsigned long throttle_state)
|
||||
{
|
||||
struct ath10k *ar = cdev->devdata;
|
||||
|
||||
if (throttle_state > ATH10K_THERMAL_THROTTLE_MAX) {
|
||||
ath10k_warn(ar, "throttle state %ld is exceeding the limit %d\n",
|
||||
throttle_state, ATH10K_THERMAL_THROTTLE_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
ar->thermal.throttle_state = throttle_state;
|
||||
ath10k_thermal_set_throttling(ar);
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct thermal_cooling_device_ops ath10k_thermal_ops = {
|
||||
.get_max_state = ath10k_thermal_get_max_throttle_state,
|
||||
.get_cur_state = ath10k_thermal_get_cur_throttle_state,
|
||||
.set_cur_state = ath10k_thermal_set_cur_throttle_state,
|
||||
};
|
||||
|
||||
static ssize_t ath10k_thermal_show_temp(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ath10k *ar = dev_get_drvdata(dev);
|
||||
int ret, temperature;
|
||||
unsigned long time_left;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
/* Can't get temperature when the card is off */
|
||||
if (ar->state != ATH10K_STATE_ON) {
|
||||
ret = -ENETDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
reinit_completion(&ar->thermal.wmi_sync);
|
||||
ret = ath10k_wmi_pdev_get_temperature(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to read temperature %d\n", ret);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
|
||||
ret = -ESHUTDOWN;
|
||||
goto out;
|
||||
}
|
||||
|
||||
time_left = wait_for_completion_timeout(&ar->thermal.wmi_sync,
|
||||
ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
|
||||
if (!time_left) {
|
||||
ath10k_warn(ar, "failed to synchronize thermal read\n");
|
||||
ret = -ETIMEDOUT;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
temperature = ar->thermal.temperature;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
/* display in millidegree celcius */
|
||||
ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
|
||||
out:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
|
||||
{
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
ar->thermal.temperature = temperature;
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
complete(&ar->thermal.wmi_sync);
|
||||
}
|
||||
|
||||
static SENSOR_DEVICE_ATTR(temp1_input, 0444, ath10k_thermal_show_temp,
|
||||
NULL, 0);
|
||||
|
||||
static struct attribute *ath10k_hwmon_attrs[] = {
|
||||
&sensor_dev_attr_temp1_input.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(ath10k_hwmon);
|
||||
|
||||
void ath10k_thermal_set_throttling(struct ath10k *ar)
|
||||
{
|
||||
u32 period, duration, enabled;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
|
||||
return;
|
||||
|
||||
if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
|
||||
return;
|
||||
|
||||
if (ar->state != ATH10K_STATE_ON)
|
||||
return;
|
||||
|
||||
period = ar->thermal.quiet_period;
|
||||
duration = (period * ar->thermal.throttle_state) / 100;
|
||||
enabled = duration ? 1 : 0;
|
||||
|
||||
ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
|
||||
ATH10K_QUIET_START_OFFSET,
|
||||
enabled);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
|
||||
period, duration, enabled, ret);
|
||||
}
|
||||
}
|
||||
|
||||
int ath10k_thermal_register(struct ath10k *ar)
|
||||
{
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct device *hwmon_dev;
|
||||
int ret;
|
||||
|
||||
if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
|
||||
return 0;
|
||||
|
||||
cdev = thermal_cooling_device_register("ath10k_thermal", ar,
|
||||
&ath10k_thermal_ops);
|
||||
|
||||
if (IS_ERR(cdev)) {
|
||||
ath10k_err(ar, "failed to setup thermal device result: %ld\n",
|
||||
PTR_ERR(cdev));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
|
||||
"cooling_device");
|
||||
if (ret) {
|
||||
ath10k_err(ar, "failed to create cooling device symlink\n");
|
||||
goto err_cooling_destroy;
|
||||
}
|
||||
|
||||
ar->thermal.cdev = cdev;
|
||||
ar->thermal.quiet_period = ATH10K_QUIET_PERIOD_DEFAULT;
|
||||
|
||||
/* Do not register hwmon device when temperature reading is not
|
||||
* supported by firmware
|
||||
*/
|
||||
if (!(ar->wmi.ops->gen_pdev_get_temperature))
|
||||
return 0;
|
||||
|
||||
/* Avoid linking error on devm_hwmon_device_register_with_groups, I
|
||||
* guess linux/hwmon.h is missing proper stubs.
|
||||
*/
|
||||
if (!IS_REACHABLE(CONFIG_HWMON))
|
||||
return 0;
|
||||
|
||||
hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
|
||||
"ath10k_hwmon", ar,
|
||||
ath10k_hwmon_groups);
|
||||
if (IS_ERR(hwmon_dev)) {
|
||||
ath10k_err(ar, "failed to register hwmon device: %ld\n",
|
||||
PTR_ERR(hwmon_dev));
|
||||
ret = -EINVAL;
|
||||
goto err_remove_link;
|
||||
}
|
||||
return 0;
|
||||
|
||||
err_remove_link:
|
||||
sysfs_remove_link(&ar->dev->kobj, "cooling_device");
|
||||
err_cooling_destroy:
|
||||
thermal_cooling_device_unregister(cdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ath10k_thermal_unregister(struct ath10k *ar)
|
||||
{
|
||||
if (!test_bit(WMI_SERVICE_THERM_THROT, ar->wmi.svc_map))
|
||||
return;
|
||||
|
||||
sysfs_remove_link(&ar->dev->kobj, "cooling_device");
|
||||
thermal_cooling_device_unregister(ar->thermal.cdev);
|
||||
}
|
53
sys/contrib/dev/athk/ath10k/thermal.h
Normal file
53
sys/contrib/dev/athk/ath10k/thermal.h
Normal file
@ -0,0 +1,53 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2014-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
#ifndef _THERMAL_
|
||||
#define _THERMAL_
|
||||
|
||||
#define ATH10K_QUIET_PERIOD_DEFAULT 100
|
||||
#define ATH10K_QUIET_PERIOD_MIN 25
|
||||
#define ATH10K_QUIET_START_OFFSET 10
|
||||
#define ATH10K_HWMON_NAME_LEN 15
|
||||
#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
|
||||
#define ATH10K_THERMAL_THROTTLE_MAX 100
|
||||
|
||||
struct ath10k_thermal {
|
||||
struct thermal_cooling_device *cdev;
|
||||
struct completion wmi_sync;
|
||||
|
||||
/* protected by conf_mutex */
|
||||
u32 throttle_state;
|
||||
u32 quiet_period;
|
||||
/* temperature value in Celcius degree
|
||||
* protected by data_lock
|
||||
*/
|
||||
int temperature;
|
||||
};
|
||||
|
||||
#if IS_REACHABLE(CONFIG_THERMAL)
|
||||
int ath10k_thermal_register(struct ath10k *ar);
|
||||
void ath10k_thermal_unregister(struct ath10k *ar);
|
||||
void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
|
||||
void ath10k_thermal_set_throttling(struct ath10k *ar);
|
||||
#else
|
||||
static inline int ath10k_thermal_register(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ath10k_thermal_unregister(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
|
||||
int temperature)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void ath10k_thermal_set_throttling(struct ath10k *ar)
|
||||
{
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* _THERMAL_ */
|
10
sys/contrib/dev/athk/ath10k/trace.c
Normal file
10
sys/contrib/dev/athk/ath10k/trace.c
Normal file
@ -0,0 +1,10 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2012 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include "trace.h"
|
||||
EXPORT_SYMBOL(__tracepoint_ath10k_log_dbg);
|
537
sys/contrib/dev/athk/ath10k/trace.h
Normal file
537
sys/contrib/dev/athk/ath10k/trace.h
Normal file
@ -0,0 +1,537 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
|
||||
#if !defined(_TRACE_H_) || defined(TRACE_HEADER_MULTI_READ)
|
||||
|
||||
#include <linux/tracepoint.h>
|
||||
#include "core.h"
|
||||
|
||||
#if !defined(_TRACE_H_)
|
||||
static inline u32 ath10k_frm_hdr_len(const void *buf, size_t len)
|
||||
{
|
||||
const struct ieee80211_hdr *hdr = buf;
|
||||
|
||||
/* In some rare cases (e.g. fcs error) device reports frame buffer
|
||||
* shorter than what frame header implies (e.g. len = 0). The buffer
|
||||
* can still be accessed so do a simple min() to guarantee caller
|
||||
* doesn't get value greater than len.
|
||||
*/
|
||||
return min_t(u32, len, ieee80211_hdrlen(hdr->frame_control));
|
||||
}
|
||||
#endif
|
||||
|
||||
#define _TRACE_H_
|
||||
|
||||
/* create empty functions when tracing is disabled */
|
||||
#if !defined(CONFIG_ATH10K_TRACING)
|
||||
#undef TRACE_EVENT
|
||||
#define TRACE_EVENT(name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {} \
|
||||
static inline bool trace_##name##_enabled(void) \
|
||||
{ \
|
||||
return false; \
|
||||
}
|
||||
#undef DECLARE_EVENT_CLASS
|
||||
#define DECLARE_EVENT_CLASS(...)
|
||||
#undef DEFINE_EVENT
|
||||
#define DEFINE_EVENT(evt_class, name, proto, ...) \
|
||||
static inline void trace_ ## name(proto) {}
|
||||
#endif /* !CONFIG_ATH10K_TRACING || __CHECKER__ */
|
||||
|
||||
#undef TRACE_SYSTEM
|
||||
#define TRACE_SYSTEM ath10k
|
||||
|
||||
#define ATH10K_MSG_MAX 400
|
||||
|
||||
DECLARE_EVENT_CLASS(ath10k_log_event,
|
||||
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
|
||||
TP_ARGS(ar, vaf),
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__dynamic_array(char, msg, ATH10K_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
ATH10K_MSG_MAX,
|
||||
vaf->fmt,
|
||||
*vaf->va) >= ATH10K_MSG_MAX);
|
||||
),
|
||||
TP_printk(
|
||||
"%s %s %s",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__get_str(msg)
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_err,
|
||||
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
|
||||
TP_ARGS(ar, vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_warn,
|
||||
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
|
||||
TP_ARGS(ar, vaf)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_log_event, ath10k_log_info,
|
||||
TP_PROTO(struct ath10k *ar, struct va_format *vaf),
|
||||
TP_ARGS(ar, vaf)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_log_dbg,
|
||||
TP_PROTO(struct ath10k *ar, unsigned int level, struct va_format *vaf),
|
||||
TP_ARGS(ar, level, vaf),
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(unsigned int, level)
|
||||
__dynamic_array(char, msg, ATH10K_MSG_MAX)
|
||||
),
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->level = level;
|
||||
WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
|
||||
ATH10K_MSG_MAX,
|
||||
vaf->fmt,
|
||||
*vaf->va) >= ATH10K_MSG_MAX);
|
||||
),
|
||||
TP_printk(
|
||||
"%s %s %s",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__get_str(msg)
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_log_dbg_dump,
|
||||
TP_PROTO(struct ath10k *ar, const char *msg, const char *prefix,
|
||||
const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, msg, prefix, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__string(msg, msg)
|
||||
__string(prefix, prefix)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__assign_str(msg, msg);
|
||||
__assign_str(prefix, prefix);
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s %s/%s\n",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__get_str(prefix),
|
||||
__get_str(msg)
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_cmd,
|
||||
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, id, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(unsigned int, id)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->id = id;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s id %d len %zu",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->id,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_event,
|
||||
TP_PROTO(struct ath10k *ar, int id, const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, id, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(unsigned int, id)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->id = id;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s id %d len %zu",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->id,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_htt_stats,
|
||||
TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s len %zu",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_dbglog,
|
||||
TP_PROTO(struct ath10k *ar, const void *buf, size_t buf_len),
|
||||
|
||||
TP_ARGS(ar, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u8, hw_type)
|
||||
__field(size_t, buf_len)
|
||||
__dynamic_array(u8, buf, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->hw_type = ar->hw_rev;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s %d len %zu",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->hw_type,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_htt_pktlog,
|
||||
TP_PROTO(struct ath10k *ar, const void *buf, u16 buf_len),
|
||||
|
||||
TP_ARGS(ar, buf, buf_len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u8, hw_type)
|
||||
__field(u16, buf_len)
|
||||
__dynamic_array(u8, pktlog, buf_len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->hw_type = ar->hw_rev;
|
||||
__entry->buf_len = buf_len;
|
||||
memcpy(__get_dynamic_array(pktlog), buf, buf_len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s %d size %u",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->hw_type,
|
||||
__entry->buf_len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_htt_tx,
|
||||
TP_PROTO(struct ath10k *ar, u16 msdu_id, u16 msdu_len,
|
||||
u8 vdev_id, u8 tid),
|
||||
|
||||
TP_ARGS(ar, msdu_id, msdu_len, vdev_id, tid),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u16, msdu_id)
|
||||
__field(u16, msdu_len)
|
||||
__field(u8, vdev_id)
|
||||
__field(u8, tid)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->msdu_id = msdu_id;
|
||||
__entry->msdu_len = msdu_len;
|
||||
__entry->vdev_id = vdev_id;
|
||||
__entry->tid = tid;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s msdu_id %d msdu_len %d vdev_id %d tid %d",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->msdu_id,
|
||||
__entry->msdu_len,
|
||||
__entry->vdev_id,
|
||||
__entry->tid
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_txrx_tx_unref,
|
||||
TP_PROTO(struct ath10k *ar, u16 msdu_id),
|
||||
|
||||
TP_ARGS(ar, msdu_id),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u16, msdu_id)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->msdu_id = msdu_id;
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s msdu_id %d",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->msdu_id
|
||||
)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(ath10k_hdr_event,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
|
||||
TP_ARGS(ar, data, len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(size_t, len)
|
||||
__dynamic_array(u8, data, ath10k_frm_hdr_len(data, len))
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->len = ath10k_frm_hdr_len(data, len);
|
||||
memcpy(__get_dynamic_array(data), data, __entry->len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s len %zu\n",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->len
|
||||
)
|
||||
);
|
||||
|
||||
DECLARE_EVENT_CLASS(ath10k_payload_event,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
|
||||
TP_ARGS(ar, data, len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(size_t, len)
|
||||
__dynamic_array(u8, payload, (len -
|
||||
ath10k_frm_hdr_len(data, len)))
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->len = len - ath10k_frm_hdr_len(data, len);
|
||||
memcpy(__get_dynamic_array(payload),
|
||||
data + ath10k_frm_hdr_len(data, len), __entry->len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s len %zu\n",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->len
|
||||
)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_hdr_event, ath10k_tx_hdr,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
TP_ARGS(ar, data, len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_payload_event, ath10k_tx_payload,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
TP_ARGS(ar, data, len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_hdr_event, ath10k_rx_hdr,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
TP_ARGS(ar, data, len)
|
||||
);
|
||||
|
||||
DEFINE_EVENT(ath10k_payload_event, ath10k_rx_payload,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
TP_ARGS(ar, data, len)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_htt_rx_desc,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
|
||||
TP_ARGS(ar, data, len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u8, hw_type)
|
||||
__field(u16, len)
|
||||
__dynamic_array(u8, rxdesc, len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->hw_type = ar->hw_rev;
|
||||
__entry->len = len;
|
||||
memcpy(__get_dynamic_array(rxdesc), data, len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s %d rxdesc len %d",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->hw_type,
|
||||
__entry->len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_diag_container,
|
||||
TP_PROTO(struct ath10k *ar,
|
||||
u8 type,
|
||||
u32 timestamp,
|
||||
u32 code,
|
||||
u16 len,
|
||||
const void *data),
|
||||
|
||||
TP_ARGS(ar, type, timestamp, code, len, data),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u8, type)
|
||||
__field(u32, timestamp)
|
||||
__field(u32, code)
|
||||
__field(u16, len)
|
||||
__dynamic_array(u8, data, len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->type = type;
|
||||
__entry->timestamp = timestamp;
|
||||
__entry->code = code;
|
||||
__entry->len = len;
|
||||
memcpy(__get_dynamic_array(data), data, len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s diag container type %u timestamp %u code %u len %d",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->type,
|
||||
__entry->timestamp,
|
||||
__entry->code,
|
||||
__entry->len
|
||||
)
|
||||
);
|
||||
|
||||
TRACE_EVENT(ath10k_wmi_diag,
|
||||
TP_PROTO(struct ath10k *ar, const void *data, size_t len),
|
||||
|
||||
TP_ARGS(ar, data, len),
|
||||
|
||||
TP_STRUCT__entry(
|
||||
__string(device, dev_name(ar->dev))
|
||||
__string(driver, dev_driver_string(ar->dev))
|
||||
__field(u16, len)
|
||||
__dynamic_array(u8, data, len)
|
||||
),
|
||||
|
||||
TP_fast_assign(
|
||||
__assign_str(device, dev_name(ar->dev));
|
||||
__assign_str(driver, dev_driver_string(ar->dev));
|
||||
__entry->len = len;
|
||||
memcpy(__get_dynamic_array(data), data, len);
|
||||
),
|
||||
|
||||
TP_printk(
|
||||
"%s %s tlv diag len %d",
|
||||
__get_str(driver),
|
||||
__get_str(device),
|
||||
__entry->len
|
||||
)
|
||||
);
|
||||
|
||||
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
|
||||
|
||||
/* we don't want to use include/trace/events */
|
||||
#undef TRACE_INCLUDE_PATH
|
||||
#define TRACE_INCLUDE_PATH .
|
||||
#undef TRACE_INCLUDE_FILE
|
||||
#define TRACE_INCLUDE_FILE trace
|
||||
|
||||
/* This part must be outside protection */
|
||||
#include <trace/define_trace.h>
|
275
sys/contrib/dev/athk/ath10k/txrx.c
Normal file
275
sys/contrib/dev/athk/ath10k/txrx.c
Normal file
@ -0,0 +1,275 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2016 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "core.h"
|
||||
#include "txrx.h"
|
||||
#include "htt.h"
|
||||
#include "mac.h"
|
||||
#include "debug.h"
|
||||
|
||||
static void ath10k_report_offchan_tx(struct ath10k *ar, struct sk_buff *skb)
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
if (likely(!(info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)))
|
||||
return;
|
||||
|
||||
if (ath10k_mac_tx_frm_has_freq(ar))
|
||||
return;
|
||||
|
||||
/* If the original wait_for_completion() timed out before
|
||||
* {data,mgmt}_tx_completed() was called then we could complete
|
||||
* offchan_tx_completed for a different skb. Prevent this by using
|
||||
* offchan_tx_skb.
|
||||
*/
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
if (ar->offchan_tx_skb != skb) {
|
||||
ath10k_warn(ar, "completed old offchannel frame\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
complete(&ar->offchan_tx_completed);
|
||||
ar->offchan_tx_skb = NULL; /* just for sanity */
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "completed offchannel skb %pK\n", skb);
|
||||
out:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct device *dev = ar->dev;
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_txq *txq;
|
||||
struct ath10k_skb_cb *skb_cb;
|
||||
struct ath10k_txq *artxq;
|
||||
struct sk_buff *msdu;
|
||||
u8 flags;
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT,
|
||||
"htt tx completion msdu_id %u status %d\n",
|
||||
tx_done->msdu_id, tx_done->status);
|
||||
|
||||
if (tx_done->msdu_id >= htt->max_num_pending_tx) {
|
||||
ath10k_warn(ar, "warning: msdu_id %d too big, ignoring\n",
|
||||
tx_done->msdu_id);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spin_lock_bh(&htt->tx_lock);
|
||||
msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
|
||||
if (!msdu) {
|
||||
ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
|
||||
tx_done->msdu_id);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
skb_cb = ATH10K_SKB_CB(msdu);
|
||||
txq = skb_cb->txq;
|
||||
|
||||
if (txq) {
|
||||
artxq = (void *)txq->drv_priv;
|
||||
artxq->num_fw_queued--;
|
||||
}
|
||||
|
||||
flags = skb_cb->flags;
|
||||
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
|
||||
ath10k_htt_tx_dec_pending(htt);
|
||||
spin_unlock_bh(&htt->tx_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
if (txq && txq->sta && skb_cb->airtime_est)
|
||||
ieee80211_sta_register_airtime(txq->sta, txq->tid,
|
||||
skb_cb->airtime_est, 0);
|
||||
rcu_read_unlock();
|
||||
|
||||
if (ar->bus_param.dev_type != ATH10K_DEV_TYPE_HL)
|
||||
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
|
||||
|
||||
ath10k_report_offchan_tx(htt->ar, msdu);
|
||||
|
||||
info = IEEE80211_SKB_CB(msdu);
|
||||
memset(&info->status, 0, sizeof(info->status));
|
||||
info->status.rates[0].idx = -1;
|
||||
|
||||
trace_ath10k_txrx_tx_unref(ar, tx_done->msdu_id);
|
||||
|
||||
if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
|
||||
!(flags & ATH10K_SKB_F_NOACK_TID))
|
||||
info->flags |= IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_NOACK)
|
||||
info->flags &= ~IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if ((tx_done->status == HTT_TX_COMPL_STATE_ACK) &&
|
||||
((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
|
||||
(flags & ATH10K_SKB_F_NOACK_TID)))
|
||||
info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_DISCARD) {
|
||||
if ((info->flags & IEEE80211_TX_CTL_NO_ACK) ||
|
||||
(flags & ATH10K_SKB_F_NOACK_TID))
|
||||
info->flags &= ~IEEE80211_TX_STAT_NOACK_TRANSMITTED;
|
||||
else
|
||||
info->flags &= ~IEEE80211_TX_STAT_ACK;
|
||||
}
|
||||
|
||||
if (tx_done->status == HTT_TX_COMPL_STATE_ACK &&
|
||||
tx_done->ack_rssi != ATH10K_INVALID_RSSI) {
|
||||
info->status.ack_signal = ATH10K_DEFAULT_NOISE_FLOOR +
|
||||
tx_done->ack_rssi;
|
||||
info->status.is_valid_ack_signal = true;
|
||||
}
|
||||
|
||||
ieee80211_tx_status(htt->ar->hw, msdu);
|
||||
/* we do not own the msdu anymore */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(peer, &ar->peers, list) {
|
||||
if (peer->vdev_id != vdev_id)
|
||||
continue;
|
||||
if (!ether_addr_equal(peer->addr, addr))
|
||||
continue;
|
||||
|
||||
return peer;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id)
|
||||
{
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
if (peer_id >= BITS_PER_TYPE(peer->peer_ids))
|
||||
return NULL;
|
||||
|
||||
lockdep_assert_held(&ar->data_lock);
|
||||
|
||||
list_for_each_entry(peer, &ar->peers, list)
|
||||
if (test_bit(peer_id, peer->peer_ids))
|
||||
return peer;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr, bool expect_mapped)
|
||||
{
|
||||
long time_left;
|
||||
|
||||
time_left = wait_event_timeout(ar->peer_mapping_wq, ({
|
||||
bool mapped;
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
mapped = !!ath10k_peer_find(ar, vdev_id, addr);
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
|
||||
(mapped == expect_mapped ||
|
||||
test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
|
||||
}), 3 * HZ);
|
||||
|
||||
if (time_left == 0)
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id, const u8 *addr)
|
||||
{
|
||||
return ath10k_wait_for_peer_common(ar, vdev_id, addr, true);
|
||||
}
|
||||
|
||||
int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id, const u8 *addr)
|
||||
{
|
||||
return ath10k_wait_for_peer_common(ar, vdev_id, addr, false);
|
||||
}
|
||||
|
||||
void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_map_event *ev)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
|
||||
ath10k_warn(ar,
|
||||
"received htt peer map event with idx out of bounds: %u\n",
|
||||
ev->peer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
|
||||
if (!peer) {
|
||||
peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
|
||||
if (!peer)
|
||||
goto exit;
|
||||
|
||||
peer->vdev_id = ev->vdev_id;
|
||||
ether_addr_copy(peer->addr, ev->addr);
|
||||
list_add(&peer->list, &ar->peers);
|
||||
wake_up(&ar->peer_mapping_wq);
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer map vdev %d peer %pM id %d\n",
|
||||
ev->vdev_id, ev->addr, ev->peer_id);
|
||||
|
||||
WARN_ON(ar->peer_map[ev->peer_id] && (ar->peer_map[ev->peer_id] != peer));
|
||||
ar->peer_map[ev->peer_id] = peer;
|
||||
set_bit(ev->peer_id, peer->peer_ids);
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
||||
|
||||
void ath10k_peer_unmap_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_unmap_event *ev)
|
||||
{
|
||||
struct ath10k *ar = htt->ar;
|
||||
struct ath10k_peer *peer;
|
||||
|
||||
if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
|
||||
ath10k_warn(ar,
|
||||
"received htt peer unmap event with idx out of bounds: %u\n",
|
||||
ev->peer_id);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_bh(&ar->data_lock);
|
||||
peer = ath10k_peer_find_by_id(ar, ev->peer_id);
|
||||
if (!peer) {
|
||||
ath10k_warn(ar, "peer-unmap-event: unknown peer id %d\n",
|
||||
ev->peer_id);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt peer unmap vdev %d peer %pM id %d\n",
|
||||
peer->vdev_id, peer->addr, ev->peer_id);
|
||||
|
||||
ar->peer_map[ev->peer_id] = NULL;
|
||||
clear_bit(ev->peer_id, peer->peer_ids);
|
||||
|
||||
if (bitmap_empty(peer->peer_ids, ATH10K_MAX_NUM_PEER_IDS)) {
|
||||
list_del(&peer->list);
|
||||
kfree(peer);
|
||||
wake_up(&ar->peer_mapping_wq);
|
||||
}
|
||||
|
||||
exit:
|
||||
spin_unlock_bh(&ar->data_lock);
|
||||
}
|
27
sys/contrib/dev/athk/ath10k/txrx.h
Normal file
27
sys/contrib/dev/athk/ath10k/txrx.h
Normal file
@ -0,0 +1,27 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2005-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2014,2016 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
#ifndef _TXRX_H_
|
||||
#define _TXRX_H_
|
||||
|
||||
#include "htt.h"
|
||||
|
||||
int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
|
||||
const struct htt_tx_done *tx_done);
|
||||
|
||||
struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
struct ath10k_peer *ath10k_peer_find_by_id(struct ath10k *ar, int peer_id);
|
||||
int ath10k_wait_for_peer_created(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
int ath10k_wait_for_peer_deleted(struct ath10k *ar, int vdev_id,
|
||||
const u8 *addr);
|
||||
|
||||
void ath10k_peer_map_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_map_event *ev);
|
||||
void ath10k_peer_unmap_event(struct ath10k_htt *htt,
|
||||
struct htt_peer_unmap_event *ev);
|
||||
|
||||
#endif
|
1104
sys/contrib/dev/athk/ath10k/usb.c
Normal file
1104
sys/contrib/dev/athk/ath10k/usb.c
Normal file
File diff suppressed because it is too large
Load Diff
117
sys/contrib/dev/athk/ath10k/usb.h
Normal file
117
sys/contrib/dev/athk/ath10k/usb.h
Normal file
@ -0,0 +1,117 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2004-2011 Atheros Communications Inc.
|
||||
* Copyright (c) 2011-2012 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2016-2017 Erik Stromdahl <erik.stromdahl@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _USB_H_
|
||||
#define _USB_H_
|
||||
|
||||
/* constants */
|
||||
#define TX_URB_COUNT 32
|
||||
#define RX_URB_COUNT 32
|
||||
#define ATH10K_USB_RX_BUFFER_SIZE 4096
|
||||
|
||||
#define ATH10K_USB_PIPE_INVALID ATH10K_USB_PIPE_MAX
|
||||
|
||||
/* USB endpoint definitions */
|
||||
#define ATH10K_USB_EP_ADDR_APP_CTRL_IN 0x81
|
||||
#define ATH10K_USB_EP_ADDR_APP_DATA_IN 0x82
|
||||
#define ATH10K_USB_EP_ADDR_APP_DATA2_IN 0x83
|
||||
#define ATH10K_USB_EP_ADDR_APP_INT_IN 0x84
|
||||
|
||||
#define ATH10K_USB_EP_ADDR_APP_CTRL_OUT 0x01
|
||||
#define ATH10K_USB_EP_ADDR_APP_DATA_LP_OUT 0x02
|
||||
#define ATH10K_USB_EP_ADDR_APP_DATA_MP_OUT 0x03
|
||||
#define ATH10K_USB_EP_ADDR_APP_DATA_HP_OUT 0x04
|
||||
|
||||
/* diagnostic command defnitions */
|
||||
#define ATH10K_USB_CONTROL_REQ_SEND_BMI_CMD 1
|
||||
#define ATH10K_USB_CONTROL_REQ_RECV_BMI_RESP 2
|
||||
#define ATH10K_USB_CONTROL_REQ_DIAG_CMD 3
|
||||
#define ATH10K_USB_CONTROL_REQ_DIAG_RESP 4
|
||||
|
||||
#define ATH10K_USB_CTRL_DIAG_CC_READ 0
|
||||
#define ATH10K_USB_CTRL_DIAG_CC_WRITE 1
|
||||
|
||||
#define ATH10K_USB_IS_BULK_EP(attr) (((attr) & 3) == 0x02)
|
||||
#define ATH10K_USB_IS_INT_EP(attr) (((attr) & 3) == 0x03)
|
||||
#define ATH10K_USB_IS_ISOC_EP(attr) (((attr) & 3) == 0x01)
|
||||
#define ATH10K_USB_IS_DIR_IN(addr) ((addr) & 0x80)
|
||||
|
||||
struct ath10k_usb_ctrl_diag_cmd_write {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
__le32 value;
|
||||
__le32 padding;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_usb_ctrl_diag_cmd_read {
|
||||
__le32 cmd;
|
||||
__le32 address;
|
||||
} __packed;
|
||||
|
||||
struct ath10k_usb_ctrl_diag_resp_read {
|
||||
u8 value[4];
|
||||
} __packed;
|
||||
|
||||
/* tx/rx pipes for usb */
|
||||
enum ath10k_usb_pipe_id {
|
||||
ATH10K_USB_PIPE_TX_CTRL = 0,
|
||||
ATH10K_USB_PIPE_TX_DATA_LP,
|
||||
ATH10K_USB_PIPE_TX_DATA_MP,
|
||||
ATH10K_USB_PIPE_TX_DATA_HP,
|
||||
ATH10K_USB_PIPE_RX_CTRL,
|
||||
ATH10K_USB_PIPE_RX_DATA,
|
||||
ATH10K_USB_PIPE_RX_DATA2,
|
||||
ATH10K_USB_PIPE_RX_INT,
|
||||
ATH10K_USB_PIPE_MAX
|
||||
};
|
||||
|
||||
struct ath10k_usb_pipe {
|
||||
struct list_head urb_list_head;
|
||||
struct usb_anchor urb_submitted;
|
||||
u32 urb_alloc;
|
||||
u32 urb_cnt;
|
||||
u32 urb_cnt_thresh;
|
||||
unsigned int usb_pipe_handle;
|
||||
u32 flags;
|
||||
u8 ep_address;
|
||||
u8 logical_pipe_num;
|
||||
struct ath10k_usb *ar_usb;
|
||||
u16 max_packet_size;
|
||||
struct work_struct io_complete_work;
|
||||
struct sk_buff_head io_comp_queue;
|
||||
struct usb_endpoint_descriptor *ep_desc;
|
||||
};
|
||||
|
||||
#define ATH10K_USB_PIPE_FLAG_TX BIT(0)
|
||||
|
||||
/* usb device object */
|
||||
struct ath10k_usb {
|
||||
/* protects pipe->urb_list_head and pipe->urb_cnt */
|
||||
spinlock_t cs_lock;
|
||||
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
struct ath10k_usb_pipe pipes[ATH10K_USB_PIPE_MAX];
|
||||
u8 *diag_cmd_buffer;
|
||||
u8 *diag_resp_buffer;
|
||||
struct ath10k *ar;
|
||||
};
|
||||
|
||||
/* usb urb object */
|
||||
struct ath10k_urb_context {
|
||||
struct list_head link;
|
||||
struct ath10k_usb_pipe *pipe;
|
||||
struct sk_buff *skb;
|
||||
struct ath10k *ar;
|
||||
};
|
||||
|
||||
static inline struct ath10k_usb *ath10k_usb_priv(struct ath10k *ar)
|
||||
{
|
||||
return (struct ath10k_usb *)ar->drv_priv;
|
||||
}
|
||||
|
||||
#endif
|
1678
sys/contrib/dev/athk/ath10k/wmi-ops.h
Normal file
1678
sys/contrib/dev/athk/ath10k/wmi-ops.h
Normal file
File diff suppressed because it is too large
Load Diff
5069
sys/contrib/dev/athk/ath10k/wmi-tlv.c
Normal file
5069
sys/contrib/dev/athk/ath10k/wmi-tlv.c
Normal file
File diff suppressed because it is too large
Load Diff
2682
sys/contrib/dev/athk/ath10k/wmi-tlv.h
Normal file
2682
sys/contrib/dev/athk/ath10k/wmi-tlv.h
Normal file
File diff suppressed because it is too large
Load Diff
9736
sys/contrib/dev/athk/ath10k/wmi.c
Normal file
9736
sys/contrib/dev/athk/ath10k/wmi.c
Normal file
File diff suppressed because it is too large
Load Diff
7517
sys/contrib/dev/athk/ath10k/wmi.h
Normal file
7517
sys/contrib/dev/athk/ath10k/wmi.h
Normal file
File diff suppressed because it is too large
Load Diff
641
sys/contrib/dev/athk/ath10k/wow.c
Normal file
641
sys/contrib/dev/athk/ath10k/wow.c
Normal file
@ -0,0 +1,641 @@
|
||||
// SPDX-License-Identifier: ISC
|
||||
/*
|
||||
* Copyright (c) 2015-2017 Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*/
|
||||
|
||||
#include "mac.h"
|
||||
|
||||
#include <net/mac80211.h>
|
||||
#include "hif.h"
|
||||
#include "core.h"
|
||||
#include "debug.h"
|
||||
#include "wmi.h"
|
||||
#include "wmi-ops.h"
|
||||
|
||||
static const struct wiphy_wowlan_support ath10k_wowlan_support = {
|
||||
.flags = WIPHY_WOWLAN_DISCONNECT |
|
||||
WIPHY_WOWLAN_MAGIC_PKT,
|
||||
.pattern_min_len = WOW_MIN_PATTERN_SIZE,
|
||||
.pattern_max_len = WOW_MAX_PATTERN_SIZE,
|
||||
.max_pkt_offset = WOW_MAX_PKT_OFFSET,
|
||||
};
|
||||
|
||||
static int ath10k_wow_vif_cleanup(struct ath10k_vif *arvif)
|
||||
{
|
||||
struct ath10k *ar = arvif->ar;
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < WOW_EVENT_MAX; i++) {
|
||||
ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 0);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to issue wow wakeup for event %s on vdev %i: %d\n",
|
||||
wow_wakeup_event(i), arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ar->wow.max_num_patterns; i++) {
|
||||
ret = ath10k_wmi_wow_del_pattern(ar, arvif->vdev_id, i);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to delete wow pattern %d for vdev %i: %d\n",
|
||||
i, arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wow_cleanup(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ret = ath10k_wow_vif_cleanup(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to clean wow wakeups on vdev %i: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert a 802.3 format to a 802.11 format.
|
||||
* +------------+-----------+--------+----------------+
|
||||
* 802.3: |dest mac(6B)|src mac(6B)|type(2B)| body... |
|
||||
* +------------+-----------+--------+----------------+
|
||||
* |__ |_______ |____________ |________
|
||||
* | | | |
|
||||
* +--+------------+----+-----------+---------------+-----------+
|
||||
* 802.11: |4B|dest mac(6B)| 6B |src mac(6B)| 8B |type(2B)| body... |
|
||||
* +--+------------+----+-----------+---------------+-----------+
|
||||
*/
|
||||
static void ath10k_wow_convert_8023_to_80211(struct cfg80211_pkt_pattern *new,
|
||||
const struct cfg80211_pkt_pattern *old)
|
||||
{
|
||||
u8 hdr_8023_pattern[ETH_HLEN] = {};
|
||||
u8 hdr_8023_bit_mask[ETH_HLEN] = {};
|
||||
u8 hdr_80211_pattern[WOW_HDR_LEN] = {};
|
||||
u8 hdr_80211_bit_mask[WOW_HDR_LEN] = {};
|
||||
|
||||
int total_len = old->pkt_offset + old->pattern_len;
|
||||
int hdr_80211_end_offset;
|
||||
|
||||
struct ieee80211_hdr_3addr *new_hdr_pattern =
|
||||
(struct ieee80211_hdr_3addr *)hdr_80211_pattern;
|
||||
struct ieee80211_hdr_3addr *new_hdr_mask =
|
||||
(struct ieee80211_hdr_3addr *)hdr_80211_bit_mask;
|
||||
struct ethhdr *old_hdr_pattern = (struct ethhdr *)hdr_8023_pattern;
|
||||
struct ethhdr *old_hdr_mask = (struct ethhdr *)hdr_8023_bit_mask;
|
||||
int hdr_len = sizeof(*new_hdr_pattern);
|
||||
|
||||
struct rfc1042_hdr *new_rfc_pattern =
|
||||
(struct rfc1042_hdr *)(hdr_80211_pattern + hdr_len);
|
||||
struct rfc1042_hdr *new_rfc_mask =
|
||||
(struct rfc1042_hdr *)(hdr_80211_bit_mask + hdr_len);
|
||||
int rfc_len = sizeof(*new_rfc_pattern);
|
||||
|
||||
memcpy(hdr_8023_pattern + old->pkt_offset,
|
||||
old->pattern, ETH_HLEN - old->pkt_offset);
|
||||
memcpy(hdr_8023_bit_mask + old->pkt_offset,
|
||||
old->mask, ETH_HLEN - old->pkt_offset);
|
||||
|
||||
/* Copy destination address */
|
||||
memcpy(new_hdr_pattern->addr1, old_hdr_pattern->h_dest, ETH_ALEN);
|
||||
memcpy(new_hdr_mask->addr1, old_hdr_mask->h_dest, ETH_ALEN);
|
||||
|
||||
/* Copy source address */
|
||||
memcpy(new_hdr_pattern->addr3, old_hdr_pattern->h_source, ETH_ALEN);
|
||||
memcpy(new_hdr_mask->addr3, old_hdr_mask->h_source, ETH_ALEN);
|
||||
|
||||
/* Copy logic link type */
|
||||
memcpy(&new_rfc_pattern->snap_type,
|
||||
&old_hdr_pattern->h_proto,
|
||||
sizeof(old_hdr_pattern->h_proto));
|
||||
memcpy(&new_rfc_mask->snap_type,
|
||||
&old_hdr_mask->h_proto,
|
||||
sizeof(old_hdr_mask->h_proto));
|
||||
|
||||
/* Calculate new pkt_offset */
|
||||
if (old->pkt_offset < ETH_ALEN)
|
||||
new->pkt_offset = old->pkt_offset +
|
||||
offsetof(struct ieee80211_hdr_3addr, addr1);
|
||||
else if (old->pkt_offset < offsetof(struct ethhdr, h_proto))
|
||||
new->pkt_offset = old->pkt_offset +
|
||||
offsetof(struct ieee80211_hdr_3addr, addr3) -
|
||||
offsetof(struct ethhdr, h_source);
|
||||
else
|
||||
new->pkt_offset = old->pkt_offset + hdr_len + rfc_len - ETH_HLEN;
|
||||
|
||||
/* Calculate new hdr end offset */
|
||||
if (total_len > ETH_HLEN)
|
||||
hdr_80211_end_offset = hdr_len + rfc_len;
|
||||
else if (total_len > offsetof(struct ethhdr, h_proto))
|
||||
hdr_80211_end_offset = hdr_len + rfc_len + total_len - ETH_HLEN;
|
||||
else if (total_len > ETH_ALEN)
|
||||
hdr_80211_end_offset = total_len - ETH_ALEN +
|
||||
offsetof(struct ieee80211_hdr_3addr, addr3);
|
||||
else
|
||||
hdr_80211_end_offset = total_len +
|
||||
offsetof(struct ieee80211_hdr_3addr, addr1);
|
||||
|
||||
new->pattern_len = hdr_80211_end_offset - new->pkt_offset;
|
||||
|
||||
memcpy((u8 *)new->pattern,
|
||||
hdr_80211_pattern + new->pkt_offset,
|
||||
new->pattern_len);
|
||||
memcpy((u8 *)new->mask,
|
||||
hdr_80211_bit_mask + new->pkt_offset,
|
||||
new->pattern_len);
|
||||
|
||||
if (total_len > ETH_HLEN) {
|
||||
/* Copy frame body */
|
||||
memcpy((u8 *)new->pattern + new->pattern_len,
|
||||
(void *)old->pattern + ETH_HLEN - old->pkt_offset,
|
||||
total_len - ETH_HLEN);
|
||||
memcpy((u8 *)new->mask + new->pattern_len,
|
||||
(void *)old->mask + ETH_HLEN - old->pkt_offset,
|
||||
total_len - ETH_HLEN);
|
||||
|
||||
new->pattern_len += total_len - ETH_HLEN;
|
||||
}
|
||||
}
|
||||
|
||||
static int ath10k_wmi_pno_check(struct ath10k *ar, u32 vdev_id,
|
||||
struct cfg80211_sched_scan_request *nd_config,
|
||||
struct wmi_pno_scan_req *pno)
|
||||
{
|
||||
int i, j, ret = 0;
|
||||
u8 ssid_len;
|
||||
|
||||
pno->enable = 1;
|
||||
pno->vdev_id = vdev_id;
|
||||
pno->uc_networks_count = nd_config->n_match_sets;
|
||||
|
||||
if (!pno->uc_networks_count ||
|
||||
pno->uc_networks_count > WMI_PNO_MAX_SUPP_NETWORKS)
|
||||
return -EINVAL;
|
||||
|
||||
if (nd_config->n_channels > WMI_PNO_MAX_NETW_CHANNELS_EX)
|
||||
return -EINVAL;
|
||||
|
||||
/* Filling per profile params */
|
||||
for (i = 0; i < pno->uc_networks_count; i++) {
|
||||
ssid_len = nd_config->match_sets[i].ssid.ssid_len;
|
||||
|
||||
if (ssid_len == 0 || ssid_len > 32)
|
||||
return -EINVAL;
|
||||
|
||||
pno->a_networks[i].ssid.ssid_len = __cpu_to_le32(ssid_len);
|
||||
|
||||
memcpy(pno->a_networks[i].ssid.ssid,
|
||||
nd_config->match_sets[i].ssid.ssid,
|
||||
nd_config->match_sets[i].ssid.ssid_len);
|
||||
pno->a_networks[i].authentication = 0;
|
||||
pno->a_networks[i].encryption = 0;
|
||||
pno->a_networks[i].bcast_nw_type = 0;
|
||||
|
||||
/*Copying list of valid channel into request */
|
||||
pno->a_networks[i].channel_count = nd_config->n_channels;
|
||||
pno->a_networks[i].rssi_threshold = nd_config->match_sets[i].rssi_thold;
|
||||
|
||||
for (j = 0; j < nd_config->n_channels; j++) {
|
||||
pno->a_networks[i].channels[j] =
|
||||
nd_config->channels[j]->center_freq;
|
||||
}
|
||||
}
|
||||
|
||||
/* set scan to passive if no SSIDs are specified in the request */
|
||||
if (nd_config->n_ssids == 0)
|
||||
pno->do_passive_scan = true;
|
||||
else
|
||||
pno->do_passive_scan = false;
|
||||
|
||||
for (i = 0; i < nd_config->n_ssids; i++) {
|
||||
j = 0;
|
||||
while (j < pno->uc_networks_count) {
|
||||
if (__le32_to_cpu(pno->a_networks[j].ssid.ssid_len) ==
|
||||
nd_config->ssids[i].ssid_len &&
|
||||
(memcmp(pno->a_networks[j].ssid.ssid,
|
||||
nd_config->ssids[i].ssid,
|
||||
__le32_to_cpu(pno->a_networks[j].ssid.ssid_len)) == 0)) {
|
||||
pno->a_networks[j].bcast_nw_type = BCAST_HIDDEN;
|
||||
break;
|
||||
}
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
if (nd_config->n_scan_plans == 2) {
|
||||
pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
|
||||
pno->fast_scan_max_cycles = nd_config->scan_plans[0].iterations;
|
||||
pno->slow_scan_period =
|
||||
nd_config->scan_plans[1].interval * MSEC_PER_SEC;
|
||||
} else if (nd_config->n_scan_plans == 1) {
|
||||
pno->fast_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
|
||||
pno->fast_scan_max_cycles = 1;
|
||||
pno->slow_scan_period = nd_config->scan_plans[0].interval * MSEC_PER_SEC;
|
||||
} else {
|
||||
ath10k_warn(ar, "Invalid number of scan plans %d !!",
|
||||
nd_config->n_scan_plans);
|
||||
}
|
||||
|
||||
if (nd_config->flags & NL80211_SCAN_FLAG_RANDOM_ADDR) {
|
||||
/* enable mac randomization */
|
||||
pno->enable_pno_scan_randomization = 1;
|
||||
memcpy(pno->mac_addr, nd_config->mac_addr, ETH_ALEN);
|
||||
memcpy(pno->mac_addr_mask, nd_config->mac_addr_mask, ETH_ALEN);
|
||||
}
|
||||
|
||||
pno->delay_start_time = nd_config->delay;
|
||||
|
||||
/* Current FW does not support min-max range for dwell time */
|
||||
pno->active_max_time = WMI_ACTIVE_MAX_CHANNEL_TIME;
|
||||
pno->passive_max_time = WMI_PASSIVE_MAX_CHANNEL_TIME;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_vif_wow_set_wakeups(struct ath10k_vif *arvif,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
int ret, i;
|
||||
unsigned long wow_mask = 0;
|
||||
struct ath10k *ar = arvif->ar;
|
||||
const struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
|
||||
int pattern_id = 0;
|
||||
|
||||
/* Setup requested WOW features */
|
||||
switch (arvif->vdev_type) {
|
||||
case WMI_VDEV_TYPE_IBSS:
|
||||
__set_bit(WOW_BEACON_EVENT, &wow_mask);
|
||||
fallthrough;
|
||||
case WMI_VDEV_TYPE_AP:
|
||||
__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
|
||||
__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
|
||||
__set_bit(WOW_PROBE_REQ_WPS_IE_EVENT, &wow_mask);
|
||||
__set_bit(WOW_AUTH_REQ_EVENT, &wow_mask);
|
||||
__set_bit(WOW_ASSOC_REQ_EVENT, &wow_mask);
|
||||
__set_bit(WOW_HTT_EVENT, &wow_mask);
|
||||
__set_bit(WOW_RA_MATCH_EVENT, &wow_mask);
|
||||
break;
|
||||
case WMI_VDEV_TYPE_STA:
|
||||
if (wowlan->disconnect) {
|
||||
__set_bit(WOW_DEAUTH_RECVD_EVENT, &wow_mask);
|
||||
__set_bit(WOW_DISASSOC_RECVD_EVENT, &wow_mask);
|
||||
__set_bit(WOW_BMISS_EVENT, &wow_mask);
|
||||
__set_bit(WOW_CSA_IE_EVENT, &wow_mask);
|
||||
}
|
||||
|
||||
if (wowlan->magic_pkt)
|
||||
__set_bit(WOW_MAGIC_PKT_RECVD_EVENT, &wow_mask);
|
||||
|
||||
if (wowlan->nd_config) {
|
||||
struct wmi_pno_scan_req *pno;
|
||||
int ret;
|
||||
|
||||
pno = kzalloc(sizeof(*pno), GFP_KERNEL);
|
||||
if (!pno)
|
||||
return -ENOMEM;
|
||||
|
||||
ar->nlo_enabled = true;
|
||||
|
||||
ret = ath10k_wmi_pno_check(ar, arvif->vdev_id,
|
||||
wowlan->nd_config, pno);
|
||||
if (!ret) {
|
||||
ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
|
||||
__set_bit(WOW_NLO_DETECTED_EVENT, &wow_mask);
|
||||
}
|
||||
|
||||
kfree(pno);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < wowlan->n_patterns; i++) {
|
||||
u8 bitmask[WOW_MAX_PATTERN_SIZE] = {};
|
||||
u8 ath_pattern[WOW_MAX_PATTERN_SIZE] = {};
|
||||
u8 ath_bitmask[WOW_MAX_PATTERN_SIZE] = {};
|
||||
struct cfg80211_pkt_pattern new_pattern = {};
|
||||
struct cfg80211_pkt_pattern old_pattern = patterns[i];
|
||||
int j;
|
||||
|
||||
new_pattern.pattern = ath_pattern;
|
||||
new_pattern.mask = ath_bitmask;
|
||||
if (patterns[i].pattern_len > WOW_MAX_PATTERN_SIZE)
|
||||
continue;
|
||||
/* convert bytemask to bitmask */
|
||||
for (j = 0; j < patterns[i].pattern_len; j++)
|
||||
if (patterns[i].mask[j / 8] & BIT(j % 8))
|
||||
bitmask[j] = 0xff;
|
||||
old_pattern.mask = bitmask;
|
||||
|
||||
if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {
|
||||
if (patterns[i].pkt_offset < ETH_HLEN) {
|
||||
ath10k_wow_convert_8023_to_80211(&new_pattern,
|
||||
&old_pattern);
|
||||
} else {
|
||||
new_pattern = old_pattern;
|
||||
new_pattern.pkt_offset += WOW_HDR_LEN - ETH_HLEN;
|
||||
}
|
||||
}
|
||||
|
||||
if (WARN_ON(new_pattern.pattern_len > WOW_MAX_PATTERN_SIZE))
|
||||
return -EINVAL;
|
||||
|
||||
ret = ath10k_wmi_wow_add_pattern(ar, arvif->vdev_id,
|
||||
pattern_id,
|
||||
new_pattern.pattern,
|
||||
new_pattern.mask,
|
||||
new_pattern.pattern_len,
|
||||
new_pattern.pkt_offset);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to add pattern %i to vdev %i: %d\n",
|
||||
pattern_id,
|
||||
arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
pattern_id++;
|
||||
__set_bit(WOW_PATTERN_MATCH_EVENT, &wow_mask);
|
||||
}
|
||||
|
||||
for (i = 0; i < WOW_EVENT_MAX; i++) {
|
||||
if (!test_bit(i, &wow_mask))
|
||||
continue;
|
||||
ret = ath10k_wmi_wow_add_wakeup_event(ar, arvif->vdev_id, i, 1);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to enable wakeup event %s on vdev %i: %d\n",
|
||||
wow_wakeup_event(i), arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wow_set_wakeups(struct ath10k *ar,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ret = ath10k_vif_wow_set_wakeups(arvif, wowlan);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set wow wakeups on vdev %i: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_vif_wow_clean_nlo(struct ath10k_vif *arvif)
|
||||
{
|
||||
int ret = 0;
|
||||
struct ath10k *ar = arvif->ar;
|
||||
|
||||
switch (arvif->vdev_type) {
|
||||
case WMI_VDEV_TYPE_STA:
|
||||
if (ar->nlo_enabled) {
|
||||
struct wmi_pno_scan_req *pno;
|
||||
|
||||
pno = kzalloc(sizeof(*pno), GFP_KERNEL);
|
||||
if (!pno)
|
||||
return -ENOMEM;
|
||||
|
||||
pno->enable = 0;
|
||||
ar->nlo_enabled = false;
|
||||
ret = ath10k_wmi_wow_config_pno(ar, arvif->vdev_id, pno);
|
||||
kfree(pno);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ath10k_wow_nlo_cleanup(struct ath10k *ar)
|
||||
{
|
||||
struct ath10k_vif *arvif;
|
||||
int ret = 0;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
list_for_each_entry(arvif, &ar->arvifs, list) {
|
||||
ret = ath10k_vif_wow_clean_nlo(arvif);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to clean nlo settings on vdev %i: %d\n",
|
||||
arvif->vdev_id, ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wow_enable(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
reinit_completion(&ar->target_suspend);
|
||||
|
||||
ret = ath10k_wmi_wow_enable(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to issue wow enable: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->target_suspend, 3 * HZ);
|
||||
if (ret == 0) {
|
||||
ath10k_warn(ar, "timed out while waiting for suspend completion\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ath10k_wow_wakeup(struct ath10k *ar)
|
||||
{
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&ar->conf_mutex);
|
||||
|
||||
reinit_completion(&ar->wow.wakeup_completed);
|
||||
|
||||
ret = ath10k_wmi_wow_host_wakeup_ind(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to send wow wakeup indication: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_for_completion_timeout(&ar->wow.wakeup_completed, 3 * HZ);
|
||||
if (ret == 0) {
|
||||
ath10k_warn(ar, "timed out while waiting for wow wakeup completion\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
|
||||
ar->running_fw->fw_file.fw_features))) {
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_wow_cleanup(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to clear wow wakeup events: %d\n",
|
||||
ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_wow_set_wakeups(ar, wowlan);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to set wow wakeup events: %d\n",
|
||||
ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ath10k_mac_wait_tx_complete(ar);
|
||||
|
||||
ret = ath10k_wow_enable(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to start wow: %d\n", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = ath10k_hif_suspend(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to suspend hif: %d\n", ret);
|
||||
goto wakeup;
|
||||
}
|
||||
|
||||
goto exit;
|
||||
|
||||
wakeup:
|
||||
ath10k_wow_wakeup(ar);
|
||||
|
||||
cleanup:
|
||||
ath10k_wow_cleanup(ar);
|
||||
|
||||
exit:
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret ? 1 : 0;
|
||||
}
|
||||
|
||||
void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
if (test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
|
||||
ar->running_fw->fw_file.fw_features)) {
|
||||
device_set_wakeup_enable(ar->dev, enabled);
|
||||
}
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
}
|
||||
|
||||
int ath10k_wow_op_resume(struct ieee80211_hw *hw)
|
||||
{
|
||||
struct ath10k *ar = hw->priv;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&ar->conf_mutex);
|
||||
|
||||
if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
|
||||
ar->running_fw->fw_file.fw_features))) {
|
||||
ret = 1;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_hif_resume(ar);
|
||||
if (ret) {
|
||||
ath10k_warn(ar, "failed to resume hif: %d\n", ret);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
ret = ath10k_wow_wakeup(ar);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to wakeup from wow: %d\n", ret);
|
||||
|
||||
ret = ath10k_wow_nlo_cleanup(ar);
|
||||
if (ret)
|
||||
ath10k_warn(ar, "failed to cleanup nlo: %d\n", ret);
|
||||
|
||||
exit:
|
||||
if (ret) {
|
||||
switch (ar->state) {
|
||||
case ATH10K_STATE_ON:
|
||||
ar->state = ATH10K_STATE_RESTARTING;
|
||||
ret = 1;
|
||||
break;
|
||||
case ATH10K_STATE_OFF:
|
||||
case ATH10K_STATE_RESTARTING:
|
||||
case ATH10K_STATE_RESTARTED:
|
||||
case ATH10K_STATE_UTF:
|
||||
case ATH10K_STATE_WEDGED:
|
||||
ath10k_warn(ar, "encountered unexpected device state %d on resume, cannot recover\n",
|
||||
ar->state);
|
||||
ret = -EIO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&ar->conf_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int ath10k_wow_init(struct ath10k *ar)
|
||||
{
|
||||
if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
|
||||
ar->running_fw->fw_file.fw_features))
|
||||
return 0;
|
||||
|
||||
if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
|
||||
return -EINVAL;
|
||||
|
||||
ar->wow.wowlan_support = ath10k_wowlan_support;
|
||||
|
||||
if (ar->wmi.rx_decap_mode == ATH10K_HW_TXRX_NATIVE_WIFI) {
|
||||
ar->wow.wowlan_support.pattern_max_len -= WOW_MAX_REDUCE;
|
||||
ar->wow.wowlan_support.max_pkt_offset -= WOW_MAX_REDUCE;
|
||||
}
|
||||
|
||||
if (test_bit(WMI_SERVICE_NLO, ar->wmi.svc_map)) {
|
||||
ar->wow.wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
|
||||
ar->wow.wowlan_support.max_nd_match_sets = WMI_PNO_MAX_SUPP_NETWORKS;
|
||||
}
|
||||
|
||||
ar->wow.wowlan_support.n_patterns = ar->wow.max_num_patterns;
|
||||
ar->hw->wiphy->wowlan = &ar->wow.wowlan_support;
|
||||
|
||||
device_set_wakeup_capable(ar->dev, true);
|
||||
|
||||
return 0;
|
||||
}
|
30
sys/contrib/dev/athk/ath10k/wow.h
Normal file
30
sys/contrib/dev/athk/ath10k/wow.h
Normal file
@ -0,0 +1,30 @@
|
||||
/* SPDX-License-Identifier: ISC */
|
||||
/*
|
||||
* Copyright (c) 2015,2017 Qualcomm Atheros, Inc.
|
||||
*/
|
||||
#ifndef _WOW_H_
|
||||
#define _WOW_H_
|
||||
|
||||
struct ath10k_wow {
|
||||
u32 max_num_patterns;
|
||||
struct completion wakeup_completed;
|
||||
struct wiphy_wowlan_support wowlan_support;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
int ath10k_wow_init(struct ath10k *ar);
|
||||
int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
|
||||
struct cfg80211_wowlan *wowlan);
|
||||
int ath10k_wow_op_resume(struct ieee80211_hw *hw);
|
||||
void ath10k_wow_op_set_wakeup(struct ieee80211_hw *hw, bool enabled);
|
||||
|
||||
#else
|
||||
|
||||
static inline int ath10k_wow_init(struct ath10k *ar)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
#endif /* _WOW_H_ */
|
50
sys/modules/ath10k/Makefile
Normal file
50
sys/modules/ath10k/Makefile
Normal file
@ -0,0 +1,50 @@
|
||||
# $FreeBSD$
|
||||
|
||||
DEVATH10KDIR= ${SRCTOP}/sys/contrib/dev/athk/ath10k
|
||||
|
||||
.PATH: ${DEVATH10KDIR}
|
||||
|
||||
WITH_CONFIG_FWLOG= 1
|
||||
|
||||
KMOD= if_ath10k
|
||||
|
||||
SRCS+= core.c debug.c mac.c ce.c hw.c bmi.c
|
||||
SRCS+= htc.c htt.c htt_rx.c htt_tx.c
|
||||
SRCS+= txrx.c wmi.c wmi-tlv.c
|
||||
SRCS+= p2p.c swap.c
|
||||
|
||||
SRCS+= pci.c
|
||||
|
||||
# Other
|
||||
SRCS+= ${LINUXKPI_GENSRCS}
|
||||
SRCS+= opt_wlan.h opt_inet6.h opt_inet.h opt_acpi.h
|
||||
|
||||
.if defined(WITH_CONFIG_FWLOG) && ${WITH_CONFIG_FWLOG} > 0
|
||||
SRCS+= fwlog.c
|
||||
CFLAGS+= -DCONFIG_FWLOG=${WITH_CONFIG_FWLOG}
|
||||
.endif
|
||||
|
||||
CFLAGS+= -DKBUILD_MODNAME='"ath10k"'
|
||||
|
||||
CFLAGS+= -I${DEVATH10KDIR}
|
||||
CFLAGS+= -I${DEVATH10KDIR}/..
|
||||
CFLAGS+= ${LINUXKPI_INCLUDES}
|
||||
# Helpful after fresh imports.
|
||||
#CFLAGS+= -ferror-limit=0
|
||||
|
||||
CFLAGS+= -DCONFIG_ATH10K_DEBUG
|
||||
|
||||
#CFLAGS+= -DCONFIG_ATH10K_AHB
|
||||
#CFLAGS+= -DCONFIG_ATH10K_DEBUGFS
|
||||
#CFLAGS+= -DCONFIG_ATH10K_DFS_CERTIFIED
|
||||
#CFLAGS+= -DCONFIG_ATH10K_SPECTRAL
|
||||
#CFLAGS+= -DCONFIG_ATH10K_TRACING
|
||||
#CFLAGS+= -DCONFIG_DEV_COREDUMP
|
||||
#CFLAGS+= -DCONFIG_MAC80211_DEBUGFS
|
||||
#CFLAGS+= -DCONFIG_MAC80211_MESH
|
||||
#CFLAGS+= -DCONFIG_NL80211_TESTMODE
|
||||
#CFLAGS+= -DCONFIG_PM
|
||||
#CFLAGS+= -DCONFIG_PM_SLEEP
|
||||
#CFLAGS+= -DCONFIG_THERMAL
|
||||
|
||||
.include <bsd.kmod.mk>
|
Loading…
Reference in New Issue
Block a user