Merge ath-next from ath.git
ath.git patches for 4.6. Major changes: ath10k * dt: add bindings for ipq4019 wifi block * start adding support for qca4019 chip ath9k * add device ID for Toshiba WLM-20U2/GN-1080 * allow more than one interface on DFS channels
This commit is contained in:
commit
89916cc90a
|
@ -1,17 +1,46 @@
|
||||||
* Qualcomm Atheros ath10k wireless devices
|
* Qualcomm Atheros ath10k wireless devices
|
||||||
|
|
||||||
For ath10k devices the calibration data can be provided through Device
|
|
||||||
Tree. The node is a child node of the PCI controller.
|
|
||||||
|
|
||||||
Required properties:
|
Required properties:
|
||||||
-compatible : Should be "qcom,ath10k"
|
- compatible: Should be one of the following:
|
||||||
|
* "qcom,ath10k"
|
||||||
|
* "qcom,ipq4019-wifi"
|
||||||
|
|
||||||
|
PCI based devices uses compatible string "qcom,ath10k" and takes only
|
||||||
|
calibration data via "qcom,ath10k-calibration-data". Rest of the properties
|
||||||
|
are not applicable for PCI based devices.
|
||||||
|
|
||||||
|
AHB based devices (i.e. ipq4019) uses compatible string "qcom,ipq4019-wifi"
|
||||||
|
and also uses most of the properties defined in this doc.
|
||||||
|
|
||||||
Optional properties:
|
Optional properties:
|
||||||
|
- reg: Address and length of the register set for the device.
|
||||||
|
- resets: Must contain an entry for each entry in reset-names.
|
||||||
|
See ../reset/reseti.txt for details.
|
||||||
|
- reset-names: Must include the list of following reset names,
|
||||||
|
"wifi_cpu_init"
|
||||||
|
"wifi_radio_srif"
|
||||||
|
"wifi_radio_warm"
|
||||||
|
"wifi_radio_cold"
|
||||||
|
"wifi_core_warm"
|
||||||
|
"wifi_core_cold"
|
||||||
|
- clocks: List of clock specifiers, must contain an entry for each required
|
||||||
|
entry in clock-names.
|
||||||
|
- clock-names: Should contain the clock names "wifi_wcss_cmd", "wifi_wcss_ref",
|
||||||
|
"wifi_wcss_rtc".
|
||||||
|
- interrupts: List of interrupt lines. Must contain an entry
|
||||||
|
for each entry in the interrupt-names property.
|
||||||
|
- interrupt-names: Must include the entries for MSI interrupt
|
||||||
|
names ("msi0" to "msi15") and legacy interrupt
|
||||||
|
name ("legacy"),
|
||||||
|
- qcom,msi_addr: MSI interrupt address.
|
||||||
|
- qcom,msi_base: Base value to add before writing MSI data into
|
||||||
|
MSI address register.
|
||||||
- qcom,ath10k-calibration-data : calibration data as an array, the
|
- qcom,ath10k-calibration-data : calibration data as an array, the
|
||||||
length can vary between hw versions
|
length can vary between hw versions
|
||||||
|
|
||||||
|
Example (to supply the calibration data alone):
|
||||||
|
|
||||||
Example:
|
In this example, the node is defined as child node of the PCI controller.
|
||||||
|
|
||||||
pci {
|
pci {
|
||||||
pcie@0 {
|
pcie@0 {
|
||||||
|
@ -28,3 +57,53 @@ pci {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Example (to supply ipq4019 SoC wifi block details):
|
||||||
|
|
||||||
|
wifi0: wifi@a000000 {
|
||||||
|
compatible = "qcom,ipq4019-wifi";
|
||||||
|
reg = <0xa000000 0x200000>;
|
||||||
|
resets = <&gcc WIFI0_CPU_INIT_RESET>,
|
||||||
|
<&gcc WIFI0_RADIO_SRIF_RESET>,
|
||||||
|
<&gcc WIFI0_RADIO_WARM_RESET>,
|
||||||
|
<&gcc WIFI0_RADIO_COLD_RESET>,
|
||||||
|
<&gcc WIFI0_CORE_WARM_RESET>,
|
||||||
|
<&gcc WIFI0_CORE_COLD_RESET>;
|
||||||
|
reset-names = "wifi_cpu_init",
|
||||||
|
"wifi_radio_srif",
|
||||||
|
"wifi_radio_warm",
|
||||||
|
"wifi_radio_cold",
|
||||||
|
"wifi_core_warm",
|
||||||
|
"wifi_core_cold";
|
||||||
|
clocks = <&gcc GCC_WCSS2G_CLK>,
|
||||||
|
<&gcc GCC_WCSS2G_REF_CLK>,
|
||||||
|
<&gcc GCC_WCSS2G_RTC_CLK>;
|
||||||
|
clock-names = "wifi_wcss_cmd",
|
||||||
|
"wifi_wcss_ref",
|
||||||
|
"wifi_wcss_rtc";
|
||||||
|
interrupts = <0 0x20 0x1>,
|
||||||
|
<0 0x21 0x1>,
|
||||||
|
<0 0x22 0x1>,
|
||||||
|
<0 0x23 0x1>,
|
||||||
|
<0 0x24 0x1>,
|
||||||
|
<0 0x25 0x1>,
|
||||||
|
<0 0x26 0x1>,
|
||||||
|
<0 0x27 0x1>,
|
||||||
|
<0 0x28 0x1>,
|
||||||
|
<0 0x29 0x1>,
|
||||||
|
<0 0x2a 0x1>,
|
||||||
|
<0 0x2b 0x1>,
|
||||||
|
<0 0x2c 0x1>,
|
||||||
|
<0 0x2d 0x1>,
|
||||||
|
<0 0x2e 0x1>,
|
||||||
|
<0 0x2f 0x1>,
|
||||||
|
<0 0xa8 0x0>;
|
||||||
|
interrupt-names = "msi0", "msi1", "msi2", "msi3",
|
||||||
|
"msi4", "msi5", "msi6", "msi7",
|
||||||
|
"msi8", "msi9", "msi10", "msi11",
|
||||||
|
"msi12", "msi13", "msi14", "msi15",
|
||||||
|
"legacy";
|
||||||
|
qcom,msi_addr = <0x0b006040>;
|
||||||
|
qcom,msi_base = <0x40>;
|
||||||
|
qcom,ath10k-calibration-data = [ 01 02 03 ... ];
|
||||||
|
};
|
||||||
|
|
|
@ -15,6 +15,12 @@ config ATH10K_PCI
|
||||||
---help---
|
---help---
|
||||||
This module adds support for PCIE bus
|
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_DEBUG
|
config ATH10K_DEBUG
|
||||||
bool "Atheros ath10k debugging"
|
bool "Atheros ath10k debugging"
|
||||||
depends on ATH10K
|
depends on ATH10K
|
||||||
|
|
|
@ -25,5 +25,7 @@ obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
|
||||||
ath10k_pci-y += pci.o \
|
ath10k_pci-y += pci.o \
|
||||||
ce.o
|
ce.o
|
||||||
|
|
||||||
|
ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
|
||||||
|
|
||||||
# for tracing framework to find trace.h
|
# for tracing framework to find trace.h
|
||||||
CFLAGS_trace.o := -I$(src)
|
CFLAGS_trace.o := -I$(src)
|
||||||
|
|
|
@ -0,0 +1,933 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#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[] = {
|
||||||
|
/* TODO: enable this entry once everything in place.
|
||||||
|
* { .compatible = "qcom,ipq4019-wifi",
|
||||||
|
* .data = (void *)ATH10K_HW_QCA4019 },
|
||||||
|
*/
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(of, ath10k_ahb_of_match);
|
||||||
|
|
||||||
|
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;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev = &ar_ahb->pdev->dev;
|
||||||
|
|
||||||
|
ar_ahb->cmd_clk = 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));
|
||||||
|
ret = ar_ahb->cmd_clk ? PTR_ERR(ar_ahb->cmd_clk) : -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->ref_clk = 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));
|
||||||
|
ret = ar_ahb->ref_clk ? PTR_ERR(ar_ahb->ref_clk) : -ENODEV;
|
||||||
|
goto err_cmd_clk_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->rtc_clk = 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));
|
||||||
|
ret = ar_ahb->rtc_clk ? PTR_ERR(ar_ahb->rtc_clk) : -ENODEV;
|
||||||
|
goto err_ref_clk_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_ref_clk_put:
|
||||||
|
clk_put(ar_ahb->ref_clk);
|
||||||
|
|
||||||
|
err_cmd_clk_put:
|
||||||
|
clk_put(ar_ahb->cmd_clk);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath10k_ahb_clock_deinit(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk))
|
||||||
|
clk_put(ar_ahb->cmd_clk);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->ref_clk))
|
||||||
|
clk_put(ar_ahb->ref_clk);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->rtc_clk))
|
||||||
|
clk_put(ar_ahb->rtc_clk);
|
||||||
|
|
||||||
|
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);
|
||||||
|
struct device *dev;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev = &ar_ahb->pdev->dev;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->cmd_clk))
|
||||||
|
clk_disable_unprepare(ar_ahb->cmd_clk);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->ref_clk))
|
||||||
|
clk_disable_unprepare(ar_ahb->ref_clk);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->rtc_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;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
dev = &ar_ahb->pdev->dev;
|
||||||
|
|
||||||
|
ar_ahb->core_cold_rst = reset_control_get(dev, "wifi_core_cold");
|
||||||
|
if (IS_ERR_OR_NULL(ar_ahb->core_cold_rst)) {
|
||||||
|
ath10k_err(ar, "failed to get core cold rst ctrl: %ld\n",
|
||||||
|
PTR_ERR(ar_ahb->core_cold_rst));
|
||||||
|
ret = ar_ahb->core_cold_rst ?
|
||||||
|
PTR_ERR(ar_ahb->core_cold_rst) : -ENODEV;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->radio_cold_rst = reset_control_get(dev, "wifi_radio_cold");
|
||||||
|
if (IS_ERR_OR_NULL(ar_ahb->radio_cold_rst)) {
|
||||||
|
ath10k_err(ar, "failed to get radio cold rst ctrl: %ld\n",
|
||||||
|
PTR_ERR(ar_ahb->radio_cold_rst));
|
||||||
|
ret = ar_ahb->radio_cold_rst ?
|
||||||
|
PTR_ERR(ar_ahb->radio_cold_rst) : -ENODEV;
|
||||||
|
goto err_core_cold_rst_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->radio_warm_rst = reset_control_get(dev, "wifi_radio_warm");
|
||||||
|
if (IS_ERR_OR_NULL(ar_ahb->radio_warm_rst)) {
|
||||||
|
ath10k_err(ar, "failed to get radio warm rst ctrl: %ld\n",
|
||||||
|
PTR_ERR(ar_ahb->radio_warm_rst));
|
||||||
|
ret = ar_ahb->radio_warm_rst ?
|
||||||
|
PTR_ERR(ar_ahb->radio_warm_rst) : -ENODEV;
|
||||||
|
goto err_radio_cold_rst_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->radio_srif_rst = reset_control_get(dev, "wifi_radio_srif");
|
||||||
|
if (IS_ERR_OR_NULL(ar_ahb->radio_srif_rst)) {
|
||||||
|
ath10k_err(ar, "failed to get radio srif rst ctrl: %ld\n",
|
||||||
|
PTR_ERR(ar_ahb->radio_srif_rst));
|
||||||
|
ret = ar_ahb->radio_srif_rst ?
|
||||||
|
PTR_ERR(ar_ahb->radio_srif_rst) : -ENODEV;
|
||||||
|
goto err_radio_warm_rst_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->cpu_init_rst = reset_control_get(dev, "wifi_cpu_init");
|
||||||
|
if (IS_ERR_OR_NULL(ar_ahb->cpu_init_rst)) {
|
||||||
|
ath10k_err(ar, "failed to get cpu init rst ctrl: %ld\n",
|
||||||
|
PTR_ERR(ar_ahb->cpu_init_rst));
|
||||||
|
ret = ar_ahb->cpu_init_rst ?
|
||||||
|
PTR_ERR(ar_ahb->cpu_init_rst) : -ENODEV;
|
||||||
|
goto err_radio_srif_rst_put;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_radio_srif_rst_put:
|
||||||
|
reset_control_put(ar_ahb->radio_srif_rst);
|
||||||
|
|
||||||
|
err_radio_warm_rst_put:
|
||||||
|
reset_control_put(ar_ahb->radio_warm_rst);
|
||||||
|
|
||||||
|
err_radio_cold_rst_put:
|
||||||
|
reset_control_put(ar_ahb->radio_cold_rst);
|
||||||
|
|
||||||
|
err_core_cold_rst_put:
|
||||||
|
reset_control_put(ar_ahb->core_cold_rst);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath10k_ahb_rst_ctrl_deinit(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
struct ath10k_ahb *ar_ahb = ath10k_ahb_priv(ar);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->core_cold_rst))
|
||||||
|
reset_control_put(ar_ahb->core_cold_rst);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->radio_cold_rst))
|
||||||
|
reset_control_put(ar_ahb->radio_cold_rst);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->radio_warm_rst))
|
||||||
|
reset_control_put(ar_ahb->radio_warm_rst);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->radio_srif_rst))
|
||||||
|
reset_control_put(ar_ahb->radio_srif_rst);
|
||||||
|
|
||||||
|
if (!IS_ERR_OR_NULL(ar_ahb->cpu_init_rst))
|
||||||
|
reset_control_put(ar_ahb->cpu_init_rst);
|
||||||
|
|
||||||
|
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;
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
|
||||||
|
if (!ath10k_pci_irq_pending(ar))
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
ath10k_pci_disable_and_clear_legacy_irq(ar);
|
||||||
|
tasklet_schedule(&ar_pci->intr_tq);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_ahb_request_irq_legacy(struct ath10k *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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 device *dev;
|
||||||
|
struct resource *res;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pdev = ar_ahb->pdev;
|
||||||
|
dev = &pdev->dev;
|
||||||
|
|
||||||
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
if (!res) {
|
||||||
|
ath10k_err(ar, "failed to get memory resource\n");
|
||||||
|
ret = -ENXIO;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
ar_ahb->mem = devm_ioremap_resource(&pdev->dev, 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_nocache(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_nocache(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);
|
||||||
|
goto err_clock_deinit;
|
||||||
|
}
|
||||||
|
|
||||||
|
ath10k_dbg(ar, ATH10K_DBG_BOOT, "irq: %d\n", ar_ahb->irq);
|
||||||
|
|
||||||
|
ath10k_dbg(ar, ATH10K_DBG_BOOT, "mem: 0x%p mem_len: %lu gcc mem: 0x%p tcsr_mem: 0x%p\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_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_pci_flush(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_ahb_hif_power_up(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
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 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;
|
||||||
|
u32 chip_id;
|
||||||
|
|
||||||
|
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->bus_ops = &ath10k_ahb_bus_ops;
|
||||||
|
|
||||||
|
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_irq_tasklets(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);
|
||||||
|
|
||||||
|
chip_id = ath10k_ahb_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
|
||||||
|
if (chip_id == 0xffffffff) {
|
||||||
|
ath10k_err(ar, "failed to get chip id\n");
|
||||||
|
goto err_halt_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ath10k_core_register(ar, chip_id);
|
||||||
|
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_free_pipes(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;
|
||||||
|
|
||||||
|
printk(KERN_ERR "AHB support is still work in progress\n");
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Qualcomm Atheros, Inc. All rights reserved.
|
||||||
|
* 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 _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_ */
|
|
@ -156,6 +156,11 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||||
.channel_counters_freq_hz = 150000,
|
.channel_counters_freq_hz = 150000,
|
||||||
.max_probe_resp_desc_thres = 24,
|
.max_probe_resp_desc_thres = 24,
|
||||||
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
||||||
|
.num_msdu_desc = 1424,
|
||||||
|
.qcache_active_peers = 50,
|
||||||
|
.tx_chain_mask = 0xf,
|
||||||
|
.rx_chain_mask = 0xf,
|
||||||
|
.max_spatial_stream = 4,
|
||||||
.fw = {
|
.fw = {
|
||||||
.dir = QCA99X0_HW_2_0_FW_DIR,
|
.dir = QCA99X0_HW_2_0_FW_DIR,
|
||||||
.fw = QCA99X0_HW_2_0_FW_FILE,
|
.fw = QCA99X0_HW_2_0_FW_FILE,
|
||||||
|
@ -201,6 +206,31 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
|
||||||
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
|
.board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
.id = QCA4019_HW_1_0_DEV_VERSION,
|
||||||
|
.dev_id = 0,
|
||||||
|
.name = "qca4019 hw1.0",
|
||||||
|
.patch_load_addr = QCA4019_HW_1_0_PATCH_LOAD_ADDR,
|
||||||
|
.uart_pin = 7,
|
||||||
|
.otp_exe_param = 0x0010000,
|
||||||
|
.continuous_frag_desc = true,
|
||||||
|
.channel_counters_freq_hz = 125000,
|
||||||
|
.max_probe_resp_desc_thres = 24,
|
||||||
|
.hw_4addr_pad = ATH10K_HW_4ADDR_PAD_BEFORE,
|
||||||
|
.num_msdu_desc = 2500,
|
||||||
|
.qcache_active_peers = 35,
|
||||||
|
.tx_chain_mask = 0x3,
|
||||||
|
.rx_chain_mask = 0x3,
|
||||||
|
.max_spatial_stream = 2,
|
||||||
|
.fw = {
|
||||||
|
.dir = QCA4019_HW_1_0_FW_DIR,
|
||||||
|
.fw = QCA4019_HW_1_0_FW_FILE,
|
||||||
|
.otp = QCA4019_HW_1_0_OTP_FILE,
|
||||||
|
.board = QCA4019_HW_1_0_BOARD_DATA_FILE,
|
||||||
|
.board_size = QCA4019_BOARD_DATA_SZ,
|
||||||
|
.board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *const ath10k_core_fw_feature_str[] = {
|
static const char *const ath10k_core_fw_feature_str[] = {
|
||||||
|
@ -217,6 +247,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
|
||||||
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
|
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
|
||||||
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
|
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
|
||||||
[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
|
[ATH10K_FW_FEATURE_MFP_SUPPORT] = "mfp",
|
||||||
|
[ATH10K_FW_FEATURE_PEER_FLOW_CONTROL] = "peer-flow-ctrl",
|
||||||
};
|
};
|
||||||
|
|
||||||
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
|
static unsigned int ath10k_core_get_fw_feature_str(char *buf,
|
||||||
|
@ -1478,8 +1509,13 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||||
case ATH10K_FW_WMI_OP_VERSION_10_1:
|
case ATH10K_FW_WMI_OP_VERSION_10_1:
|
||||||
case ATH10K_FW_WMI_OP_VERSION_10_2:
|
case ATH10K_FW_WMI_OP_VERSION_10_2:
|
||||||
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
|
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
|
||||||
ar->max_num_peers = TARGET_10X_NUM_PEERS;
|
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||||
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
|
ar->max_num_peers = TARGET_10X_TX_STATS_NUM_PEERS;
|
||||||
|
ar->max_num_stations = TARGET_10X_TX_STATS_NUM_STATIONS;
|
||||||
|
} else {
|
||||||
|
ar->max_num_peers = TARGET_10X_NUM_PEERS;
|
||||||
|
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
|
||||||
|
}
|
||||||
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
|
ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
|
||||||
ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
|
ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
|
||||||
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
||||||
|
@ -1502,9 +1538,9 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
|
||||||
ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
|
ar->num_active_peers = TARGET_10_4_ACTIVE_PEERS;
|
||||||
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
|
ar->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
|
||||||
ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
|
ar->num_tids = TARGET_10_4_TGT_NUM_TIDS;
|
||||||
ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;
|
ar->htt.max_num_pending_tx = ar->hw_params.num_msdu_desc;
|
||||||
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
ar->fw_stats_req_mask = WMI_STAT_PEER;
|
||||||
ar->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM;
|
ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
|
||||||
break;
|
break;
|
||||||
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
case ATH10K_FW_WMI_OP_VERSION_UNSET:
|
||||||
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
case ATH10K_FW_WMI_OP_VERSION_MAX:
|
||||||
|
@ -1979,6 +2015,10 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
|
||||||
ar->regs = &qca99x0_regs;
|
ar->regs = &qca99x0_regs;
|
||||||
ar->hw_values = &qca99x0_values;
|
ar->hw_values = &qca99x0_values;
|
||||||
break;
|
break;
|
||||||
|
case ATH10K_HW_QCA4019:
|
||||||
|
ar->regs = &qca4019_regs;
|
||||||
|
ar->hw_values = &qca4019_values;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ath10k_err(ar, "unsupported core hardware revision %d\n",
|
ath10k_err(ar, "unsupported core hardware revision %d\n",
|
||||||
hw_rev);
|
hw_rev);
|
||||||
|
|
|
@ -69,6 +69,7 @@ struct ath10k;
|
||||||
|
|
||||||
enum ath10k_bus {
|
enum ath10k_bus {
|
||||||
ATH10K_BUS_PCI,
|
ATH10K_BUS_PCI,
|
||||||
|
ATH10K_BUS_AHB,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
|
static inline const char *ath10k_bus_str(enum ath10k_bus bus)
|
||||||
|
@ -76,6 +77,8 @@ static inline const char *ath10k_bus_str(enum ath10k_bus bus)
|
||||||
switch (bus) {
|
switch (bus) {
|
||||||
case ATH10K_BUS_PCI:
|
case ATH10K_BUS_PCI:
|
||||||
return "pci";
|
return "pci";
|
||||||
|
case ATH10K_BUS_AHB:
|
||||||
|
return "ahb";
|
||||||
}
|
}
|
||||||
|
|
||||||
return "unknown";
|
return "unknown";
|
||||||
|
@ -159,6 +162,7 @@ struct ath10k_fw_stats_peer {
|
||||||
u32 peer_rssi;
|
u32 peer_rssi;
|
||||||
u32 peer_tx_rate;
|
u32 peer_tx_rate;
|
||||||
u32 peer_rx_rate; /* 10x only */
|
u32 peer_rx_rate; /* 10x only */
|
||||||
|
u32 rx_duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath10k_fw_stats_vdev {
|
struct ath10k_fw_stats_vdev {
|
||||||
|
@ -315,6 +319,7 @@ struct ath10k_sta {
|
||||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||||
/* protected by conf_mutex */
|
/* protected by conf_mutex */
|
||||||
bool aggr_mode;
|
bool aggr_mode;
|
||||||
|
u64 rx_duration;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -510,6 +515,15 @@ enum ath10k_fw_features {
|
||||||
/* Firmware supports management frame protection */
|
/* Firmware supports management frame protection */
|
||||||
ATH10K_FW_FEATURE_MFP_SUPPORT = 12,
|
ATH10K_FW_FEATURE_MFP_SUPPORT = 12,
|
||||||
|
|
||||||
|
/* Firmware supports pull-push model where host shares it's software
|
||||||
|
* queue state with firmware and firmware generates fetch requests
|
||||||
|
* telling host which queues to dequeue tx from.
|
||||||
|
*
|
||||||
|
* Primary function of this is improved MU-MIMO performance with
|
||||||
|
* multiple clients.
|
||||||
|
*/
|
||||||
|
ATH10K_FW_FEATURE_PEER_FLOW_CONTROL = 13,
|
||||||
|
|
||||||
/* keep last */
|
/* keep last */
|
||||||
ATH10K_FW_FEATURE_COUNT,
|
ATH10K_FW_FEATURE_COUNT,
|
||||||
};
|
};
|
||||||
|
@ -666,6 +680,12 @@ struct ath10k {
|
||||||
/* The padding bytes's location is different on various chips */
|
/* The padding bytes's location is different on various chips */
|
||||||
enum ath10k_hw_4addr_pad hw_4addr_pad;
|
enum ath10k_hw_4addr_pad hw_4addr_pad;
|
||||||
|
|
||||||
|
u32 num_msdu_desc;
|
||||||
|
u32 qcache_active_peers;
|
||||||
|
u32 tx_chain_mask;
|
||||||
|
u32 rx_chain_mask;
|
||||||
|
u32 max_spatial_stream;
|
||||||
|
|
||||||
struct ath10k_hw_params_fw {
|
struct ath10k_hw_params_fw {
|
||||||
const char *dir;
|
const char *dir;
|
||||||
const char *fw;
|
const char *fw;
|
||||||
|
|
|
@ -276,7 +276,7 @@ static const struct file_operations fops_wmi_services = {
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
|
static void ath10k_fw_stats_pdevs_free(struct list_head *head)
|
||||||
{
|
{
|
||||||
struct ath10k_fw_stats_pdev *i, *tmp;
|
struct ath10k_fw_stats_pdev *i, *tmp;
|
||||||
|
|
||||||
|
@ -286,7 +286,7 @@ static void ath10k_debug_fw_stats_pdevs_free(struct list_head *head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
|
static void ath10k_fw_stats_vdevs_free(struct list_head *head)
|
||||||
{
|
{
|
||||||
struct ath10k_fw_stats_vdev *i, *tmp;
|
struct ath10k_fw_stats_vdev *i, *tmp;
|
||||||
|
|
||||||
|
@ -296,7 +296,7 @@ static void ath10k_debug_fw_stats_vdevs_free(struct list_head *head)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_debug_fw_stats_peers_free(struct list_head *head)
|
static void ath10k_fw_stats_peers_free(struct list_head *head)
|
||||||
{
|
{
|
||||||
struct ath10k_fw_stats_peer *i, *tmp;
|
struct ath10k_fw_stats_peer *i, *tmp;
|
||||||
|
|
||||||
|
@ -310,16 +310,16 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
spin_lock_bh(&ar->data_lock);
|
spin_lock_bh(&ar->data_lock);
|
||||||
ar->debug.fw_stats_done = false;
|
ar->debug.fw_stats_done = false;
|
||||||
ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
|
ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
|
||||||
ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
|
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
|
||||||
ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
|
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
|
||||||
spin_unlock_bh(&ar->data_lock);
|
spin_unlock_bh(&ar->data_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ath10k_fw_stats stats = {};
|
struct ath10k_fw_stats stats = {};
|
||||||
bool is_start, is_started, is_end;
|
bool is_start, is_started, is_end, peer_stats_svc;
|
||||||
size_t num_peers;
|
size_t num_peers;
|
||||||
size_t num_vdevs;
|
size_t num_vdevs;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -347,8 +347,14 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||||
* delivered which is treated as end-of-data and is itself discarded
|
* delivered which is treated as end-of-data and is itself discarded
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
peer_stats_svc = test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map);
|
||||||
|
if (peer_stats_svc)
|
||||||
|
ath10k_sta_update_rx_duration(ar, &stats.peers);
|
||||||
|
|
||||||
if (ar->debug.fw_stats_done) {
|
if (ar->debug.fw_stats_done) {
|
||||||
ath10k_warn(ar, "received unsolicited stats update event\n");
|
if (!peer_stats_svc)
|
||||||
|
ath10k_warn(ar, "received unsolicited stats update event\n");
|
||||||
|
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -372,11 +378,13 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
|
||||||
/* Although this is unlikely impose a sane limit to
|
/* Although this is unlikely impose a sane limit to
|
||||||
* prevent firmware from DoS-ing the host.
|
* prevent firmware from DoS-ing the host.
|
||||||
*/
|
*/
|
||||||
|
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
|
||||||
ath10k_warn(ar, "dropping fw peer stats\n");
|
ath10k_warn(ar, "dropping fw peer stats\n");
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (num_vdevs >= BITS_PER_LONG) {
|
if (num_vdevs >= BITS_PER_LONG) {
|
||||||
|
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
|
||||||
ath10k_warn(ar, "dropping fw vdev stats\n");
|
ath10k_warn(ar, "dropping fw vdev stats\n");
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
@ -391,9 +399,9 @@ free:
|
||||||
/* In some cases lists have been spliced and cleared. Free up
|
/* In some cases lists have been spliced and cleared. Free up
|
||||||
* resources if that is not the case.
|
* resources if that is not the case.
|
||||||
*/
|
*/
|
||||||
ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
|
ath10k_fw_stats_pdevs_free(&stats.pdevs);
|
||||||
ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
|
ath10k_fw_stats_vdevs_free(&stats.vdevs);
|
||||||
ath10k_debug_fw_stats_peers_free(&stats.peers);
|
ath10k_fw_stats_peers_free(&stats.peers);
|
||||||
|
|
||||||
spin_unlock_bh(&ar->data_lock);
|
spin_unlock_bh(&ar->data_lock);
|
||||||
}
|
}
|
||||||
|
@ -2106,6 +2114,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
|
||||||
struct ath10k *ar = file->private_data;
|
struct ath10k *ar = file->private_data;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
size_t buf_size;
|
size_t buf_size;
|
||||||
|
int ret = 0;
|
||||||
bool val;
|
bool val;
|
||||||
|
|
||||||
buf_size = min(count, (sizeof(buf) - 1));
|
buf_size = min(count, (sizeof(buf) - 1));
|
||||||
|
@ -2119,6 +2128,12 @@ static ssize_t ath10k_write_btcoex(struct file *file,
|
||||||
|
|
||||||
mutex_lock(&ar->conf_mutex);
|
mutex_lock(&ar->conf_mutex);
|
||||||
|
|
||||||
|
if (ar->state != ATH10K_STATE_ON &&
|
||||||
|
ar->state != ATH10K_STATE_RESTARTED) {
|
||||||
|
ret = -ENETDOWN;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val))
|
if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val))
|
||||||
goto exit;
|
goto exit;
|
||||||
|
|
||||||
|
@ -2127,17 +2142,15 @@ static ssize_t ath10k_write_btcoex(struct file *file,
|
||||||
else
|
else
|
||||||
clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
|
clear_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
|
||||||
|
|
||||||
if (ar->state != ATH10K_STATE_ON)
|
|
||||||
goto exit;
|
|
||||||
|
|
||||||
ath10k_info(ar, "restarting firmware due to btcoex change");
|
ath10k_info(ar, "restarting firmware due to btcoex change");
|
||||||
|
|
||||||
queue_work(ar->workqueue, &ar->restart_work);
|
queue_work(ar->workqueue, &ar->restart_work);
|
||||||
|
ret = count;
|
||||||
|
|
||||||
exit:
|
exit:
|
||||||
mutex_unlock(&ar->conf_mutex);
|
mutex_unlock(&ar->conf_mutex);
|
||||||
|
|
||||||
return count;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
|
static ssize_t ath10k_read_btcoex(struct file *file, char __user *ubuf,
|
||||||
|
@ -2176,9 +2189,6 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
|
||||||
|
|
||||||
mutex_lock(&ar->conf_mutex);
|
mutex_lock(&ar->conf_mutex);
|
||||||
|
|
||||||
if (len > buf_len)
|
|
||||||
len = buf_len;
|
|
||||||
|
|
||||||
len += scnprintf(buf + len, buf_len - len,
|
len += scnprintf(buf + len, buf_len - len,
|
||||||
"firmware-N.bin\t\t%08x\n",
|
"firmware-N.bin\t\t%08x\n",
|
||||||
crc32_le(0, ar->firmware->data, ar->firmware->size));
|
crc32_le(0, ar->firmware->data, ar->firmware->size));
|
||||||
|
|
|
@ -37,6 +37,7 @@ enum ath10k_debug_mask {
|
||||||
ATH10K_DBG_TESTMODE = 0x00001000,
|
ATH10K_DBG_TESTMODE = 0x00001000,
|
||||||
ATH10K_DBG_WMI_PRINT = 0x00002000,
|
ATH10K_DBG_WMI_PRINT = 0x00002000,
|
||||||
ATH10K_DBG_PCI_PS = 0x00004000,
|
ATH10K_DBG_PCI_PS = 0x00004000,
|
||||||
|
ATH10K_DBG_AHB = 0x00008000,
|
||||||
ATH10K_DBG_ANY = 0xffffffff,
|
ATH10K_DBG_ANY = 0xffffffff,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,6 +154,12 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
|
||||||
#ifdef CONFIG_MAC80211_DEBUGFS
|
#ifdef CONFIG_MAC80211_DEBUGFS
|
||||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta, struct dentry *dir);
|
struct ieee80211_sta *sta, struct dentry *dir);
|
||||||
|
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer);
|
||||||
|
#else
|
||||||
|
static inline void ath10k_sta_update_rx_duration(struct ath10k *ar,
|
||||||
|
struct list_head *peer)
|
||||||
|
{
|
||||||
|
}
|
||||||
#endif /* CONFIG_MAC80211_DEBUGFS */
|
#endif /* CONFIG_MAC80211_DEBUGFS */
|
||||||
|
|
||||||
#ifdef CONFIG_ATH10K_DEBUG
|
#ifdef CONFIG_ATH10K_DEBUG
|
||||||
|
|
|
@ -18,6 +18,23 @@
|
||||||
#include "wmi-ops.h"
|
#include "wmi-ops.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
|
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *head)
|
||||||
|
{ struct ieee80211_sta *sta;
|
||||||
|
struct ath10k_fw_stats_peer *peer;
|
||||||
|
struct ath10k_sta *arsta;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
list_for_each_entry(peer, head, 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 ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
|
static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
|
||||||
char __user *user_buf,
|
char __user *user_buf,
|
||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
|
@ -232,6 +249,28 @@ static const struct file_operations fops_delba = {
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static ssize_t ath10k_dbg_sta_read_rx_duration(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;
|
||||||
|
char buf[100];
|
||||||
|
int len = 0;
|
||||||
|
|
||||||
|
len = scnprintf(buf, sizeof(buf),
|
||||||
|
"%llu usecs\n", arsta->rx_duration);
|
||||||
|
|
||||||
|
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations fops_rx_duration = {
|
||||||
|
.read = ath10k_dbg_sta_read_rx_duration,
|
||||||
|
.open = simple_open,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = default_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta, struct dentry *dir)
|
struct ieee80211_sta *sta, struct dentry *dir)
|
||||||
{
|
{
|
||||||
|
@ -240,4 +279,6 @@ void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
|
debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
|
||||||
debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
|
debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
|
||||||
debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
|
debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
|
||||||
|
debugfs_create_file("rx_duration", S_IRUGO, dir, sta,
|
||||||
|
&fops_rx_duration);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,12 +131,12 @@ static const enum htt_t2h_msg_type htt_10_4_t2h_msg_types[] = {
|
||||||
[HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
|
[HTT_10_4_T2H_MSG_TYPE_AGGR_CONF] = HTT_T2H_MSG_TYPE_AGGR_CONF,
|
||||||
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] =
|
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND] =
|
||||||
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
|
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
|
||||||
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] =
|
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM] =
|
||||||
HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
|
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
|
||||||
[HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] =
|
[HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] =
|
||||||
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
|
||||||
[HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] =
|
[HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
|
||||||
HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
|
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
|
||||||
};
|
};
|
||||||
|
|
||||||
int ath10k_htt_connect(struct ath10k_htt *htt)
|
int ath10k_htt_connect(struct ath10k_htt *htt)
|
||||||
|
|
|
@ -52,6 +52,7 @@ enum htt_h2t_msg_type { /* host-to-target */
|
||||||
/* This command is used for sending management frames in HTT < 3.0.
|
/* This command is used for sending management frames in HTT < 3.0.
|
||||||
* HTT >= 3.0 uses TX_FRM for everything. */
|
* HTT >= 3.0 uses TX_FRM for everything. */
|
||||||
HTT_H2T_MSG_TYPE_MGMT_TX = 7,
|
HTT_H2T_MSG_TYPE_MGMT_TX = 7,
|
||||||
|
HTT_H2T_MSG_TYPE_TX_FETCH_RESP = 11,
|
||||||
|
|
||||||
HTT_H2T_NUM_MSGS /* keep this last */
|
HTT_H2T_NUM_MSGS /* keep this last */
|
||||||
};
|
};
|
||||||
|
@ -413,10 +414,10 @@ enum htt_10_4_t2h_msg_type {
|
||||||
HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14,
|
HTT_10_4_T2H_MSG_TYPE_EN_STATS = 0x14,
|
||||||
HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15,
|
HTT_10_4_T2H_MSG_TYPE_AGGR_CONF = 0x15,
|
||||||
HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16,
|
HTT_10_4_T2H_MSG_TYPE_TX_FETCH_IND = 0x16,
|
||||||
HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF = 0x17,
|
HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM = 0x17,
|
||||||
HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18,
|
HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD = 0x18,
|
||||||
/* 0x19 to 0x2f are reserved */
|
/* 0x19 to 0x2f are reserved */
|
||||||
HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND = 0x30,
|
HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND = 0x30,
|
||||||
/* keep this last */
|
/* keep this last */
|
||||||
HTT_10_4_T2H_NUM_MSGS
|
HTT_10_4_T2H_NUM_MSGS
|
||||||
};
|
};
|
||||||
|
@ -449,8 +450,8 @@ enum htt_t2h_msg_type {
|
||||||
HTT_T2H_MSG_TYPE_TEST,
|
HTT_T2H_MSG_TYPE_TEST,
|
||||||
HTT_T2H_MSG_TYPE_EN_STATS,
|
HTT_T2H_MSG_TYPE_EN_STATS,
|
||||||
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
|
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
|
||||||
HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
|
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
|
||||||
HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
|
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
|
||||||
/* keep this last */
|
/* keep this last */
|
||||||
HTT_T2H_NUM_MSGS
|
HTT_T2H_NUM_MSGS
|
||||||
};
|
};
|
||||||
|
@ -1306,9 +1307,43 @@ struct htt_frag_desc_bank_id {
|
||||||
* so we use a conservatively safe value for now */
|
* so we use a conservatively safe value for now */
|
||||||
#define HTT_FRAG_DESC_BANK_MAX 4
|
#define HTT_FRAG_DESC_BANK_MAX 4
|
||||||
|
|
||||||
#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_MASK 0x03
|
||||||
#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB 0
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_PDEV_ID_LSB 0
|
||||||
#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP (1 << 2)
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP BIT(2)
|
||||||
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID BIT(3)
|
||||||
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_MASK BIT(4)
|
||||||
|
#define HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE_LSB 4
|
||||||
|
|
||||||
|
enum htt_q_depth_type {
|
||||||
|
HTT_Q_DEPTH_TYPE_BYTES = 0,
|
||||||
|
HTT_Q_DEPTH_TYPE_MSDUS = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HTT_TX_Q_STATE_NUM_PEERS (TARGET_10_4_NUM_QCACHE_PEERS_MAX + \
|
||||||
|
TARGET_10_4_NUM_VDEVS)
|
||||||
|
#define HTT_TX_Q_STATE_NUM_TIDS 8
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_SIZE 1
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_MULTIPLIER 0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* htt_q_state_conf - part of htt_frag_desc_bank_cfg for host q state config
|
||||||
|
*
|
||||||
|
* Defines host q state format and behavior. See htt_q_state.
|
||||||
|
*
|
||||||
|
* @record_size: Defines the size of each host q entry in bytes. In practice
|
||||||
|
* however firmware (at least 10.4.3-00191) ignores this host
|
||||||
|
* configuration value and uses hardcoded value of 1.
|
||||||
|
* @record_multiplier: This is valid only when q depth type is MSDUs. It
|
||||||
|
* defines the exponent for the power of 2 multiplication.
|
||||||
|
*/
|
||||||
|
struct htt_q_state_conf {
|
||||||
|
__le32 paddr;
|
||||||
|
__le16 num_peers;
|
||||||
|
__le16 num_tids;
|
||||||
|
u8 record_size;
|
||||||
|
u8 record_multiplier;
|
||||||
|
u8 pad[2];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
struct htt_frag_desc_bank_cfg {
|
struct htt_frag_desc_bank_cfg {
|
||||||
u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
|
u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
|
||||||
|
@ -1316,6 +1351,114 @@ struct htt_frag_desc_bank_cfg {
|
||||||
u8 desc_size;
|
u8 desc_size;
|
||||||
__le32 bank_base_addrs[HTT_FRAG_DESC_BANK_MAX];
|
__le32 bank_base_addrs[HTT_FRAG_DESC_BANK_MAX];
|
||||||
struct htt_frag_desc_bank_id bank_id[HTT_FRAG_DESC_BANK_MAX];
|
struct htt_frag_desc_bank_id bank_id[HTT_FRAG_DESC_BANK_MAX];
|
||||||
|
struct htt_q_state_conf q_state;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_COEFFICIENT 128
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_FACTOR_MASK 0x3f
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_FACTOR_LSB 0
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_EXP_MASK 0xc0
|
||||||
|
#define HTT_TX_Q_STATE_ENTRY_EXP_LSB 6
|
||||||
|
|
||||||
|
/**
|
||||||
|
* htt_q_state - shared between host and firmware via DMA
|
||||||
|
*
|
||||||
|
* This structure is used for the host to expose it's software queue state to
|
||||||
|
* firmware so that its rate control can schedule fetch requests for optimized
|
||||||
|
* performance. This is most notably used for MU-MIMO aggregation when multiple
|
||||||
|
* MU clients are connected.
|
||||||
|
*
|
||||||
|
* @count: Each element defines the host queue depth. When q depth type was
|
||||||
|
* configured as HTT_Q_DEPTH_TYPE_BYTES then each entry is defined as:
|
||||||
|
* FACTOR * 128 * 8^EXP (see HTT_TX_Q_STATE_ENTRY_FACTOR_MASK and
|
||||||
|
* HTT_TX_Q_STATE_ENTRY_EXP_MASK). When q depth type was configured as
|
||||||
|
* HTT_Q_DEPTH_TYPE_MSDUS the number of packets is scaled by 2 **
|
||||||
|
* record_multiplier (see htt_q_state_conf).
|
||||||
|
* @map: Used by firmware to quickly check which host queues are not empty. It
|
||||||
|
* is a bitmap simply saying.
|
||||||
|
* @seq: Used by firmware to quickly check if the host queues were updated
|
||||||
|
* since it last checked.
|
||||||
|
*
|
||||||
|
* FIXME: Is the q_state map[] size calculation really correct?
|
||||||
|
*/
|
||||||
|
struct htt_q_state {
|
||||||
|
u8 count[HTT_TX_Q_STATE_NUM_TIDS][HTT_TX_Q_STATE_NUM_PEERS];
|
||||||
|
u32 map[HTT_TX_Q_STATE_NUM_TIDS][(HTT_TX_Q_STATE_NUM_PEERS + 31) / 32];
|
||||||
|
__le32 seq;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_MASK 0x0fff
|
||||||
|
#define HTT_TX_FETCH_RECORD_INFO_PEER_ID_LSB 0
|
||||||
|
#define HTT_TX_FETCH_RECORD_INFO_TID_MASK 0xf000
|
||||||
|
#define HTT_TX_FETCH_RECORD_INFO_TID_LSB 12
|
||||||
|
|
||||||
|
struct htt_tx_fetch_record {
|
||||||
|
__le16 info; /* HTT_TX_FETCH_IND_RECORD_INFO_ */
|
||||||
|
__le16 num_msdus;
|
||||||
|
__le32 num_bytes;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct htt_tx_fetch_ind {
|
||||||
|
u8 pad0;
|
||||||
|
__le16 fetch_seq_num;
|
||||||
|
__le32 token;
|
||||||
|
__le16 num_resp_ids;
|
||||||
|
__le16 num_records;
|
||||||
|
struct htt_tx_fetch_record records[0];
|
||||||
|
__le32 resp_ids[0]; /* ath10k_htt_get_tx_fetch_ind_resp_ids() */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
static inline void *
|
||||||
|
ath10k_htt_get_tx_fetch_ind_resp_ids(struct htt_tx_fetch_ind *ind)
|
||||||
|
{
|
||||||
|
return (void *)&ind->records[le16_to_cpu(ind->num_records)];
|
||||||
|
}
|
||||||
|
|
||||||
|
struct htt_tx_fetch_resp {
|
||||||
|
u8 pad0;
|
||||||
|
__le16 resp_id;
|
||||||
|
__le16 fetch_seq_num;
|
||||||
|
__le16 num_records;
|
||||||
|
__le32 token;
|
||||||
|
struct htt_tx_fetch_record records[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct htt_tx_fetch_confirm {
|
||||||
|
u8 pad0;
|
||||||
|
__le16 num_resp_ids;
|
||||||
|
__le32 resp_ids[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
enum htt_tx_mode_switch_mode {
|
||||||
|
HTT_TX_MODE_SWITCH_PUSH = 0,
|
||||||
|
HTT_TX_MODE_SWITCH_PUSH_PULL = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO0_ENABLE BIT(0)
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_MASK 0xfffe
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO0_NUM_RECORDS_LSB 1
|
||||||
|
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_MASK 0x0003
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO1_MODE_LSB 0
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_MASK 0xfffc
|
||||||
|
#define HTT_TX_MODE_SWITCH_IND_INFO1_THRESHOLD_LSB 2
|
||||||
|
|
||||||
|
#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_MASK 0x0fff
|
||||||
|
#define HTT_TX_MODE_SWITCH_RECORD_INFO0_PEER_ID_LSB 0
|
||||||
|
#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_MASK 0xf000
|
||||||
|
#define HTT_TX_MODE_SWITCH_RECORD_INFO0_TID_LSB 12
|
||||||
|
|
||||||
|
struct htt_tx_mode_switch_record {
|
||||||
|
__le16 info0; /* HTT_TX_MODE_SWITCH_RECORD_INFO0_ */
|
||||||
|
__le16 num_max_msdus;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct htt_tx_mode_switch_ind {
|
||||||
|
u8 pad0;
|
||||||
|
__le16 info0; /* HTT_TX_MODE_SWITCH_IND_INFO0_ */
|
||||||
|
__le16 info1; /* HTT_TX_MODE_SWITCH_IND_INFO1_ */
|
||||||
|
u8 pad1[2];
|
||||||
|
struct htt_tx_mode_switch_record records[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
union htt_rx_pn_t {
|
union htt_rx_pn_t {
|
||||||
|
@ -1340,6 +1483,7 @@ struct htt_cmd {
|
||||||
struct htt_oob_sync_req oob_sync_req;
|
struct htt_oob_sync_req oob_sync_req;
|
||||||
struct htt_aggr_conf aggr_conf;
|
struct htt_aggr_conf aggr_conf;
|
||||||
struct htt_frag_desc_bank_cfg frag_desc_bank_cfg;
|
struct htt_frag_desc_bank_cfg frag_desc_bank_cfg;
|
||||||
|
struct htt_tx_fetch_resp tx_fetch_resp;
|
||||||
};
|
};
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@ -1364,6 +1508,9 @@ struct htt_resp {
|
||||||
struct htt_rx_pn_ind rx_pn_ind;
|
struct htt_rx_pn_ind rx_pn_ind;
|
||||||
struct htt_rx_offload_ind rx_offload_ind;
|
struct htt_rx_offload_ind rx_offload_ind;
|
||||||
struct htt_rx_in_ord_ind rx_in_ord_ind;
|
struct htt_rx_in_ord_ind rx_in_ord_ind;
|
||||||
|
struct htt_tx_fetch_ind tx_fetch_ind;
|
||||||
|
struct htt_tx_fetch_confirm tx_fetch_confirm;
|
||||||
|
struct htt_tx_mode_switch_ind tx_mode_switch_ind;
|
||||||
};
|
};
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
@ -1518,6 +1665,14 @@ struct ath10k_htt {
|
||||||
dma_addr_t paddr;
|
dma_addr_t paddr;
|
||||||
struct ath10k_htt_txbuf *vaddr;
|
struct ath10k_htt_txbuf *vaddr;
|
||||||
} txbuf;
|
} txbuf;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct htt_q_state *vaddr;
|
||||||
|
dma_addr_t paddr;
|
||||||
|
u16 num_peers;
|
||||||
|
u16 num_tids;
|
||||||
|
enum htt_q_depth_type type;
|
||||||
|
} tx_q_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define RX_HTT_HDR_STATUS_LEN 64
|
#define RX_HTT_HDR_STATUS_LEN 64
|
||||||
|
|
|
@ -2011,9 +2011,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HTT_T2H_MSG_TYPE_RX_IND:
|
case HTT_T2H_MSG_TYPE_RX_IND:
|
||||||
spin_lock_bh(&htt->rx_ring.lock);
|
skb_queue_tail(&htt->rx_compl_q, skb);
|
||||||
__skb_queue_tail(&htt->rx_compl_q, skb);
|
|
||||||
spin_unlock_bh(&htt->rx_ring.lock);
|
|
||||||
tasklet_schedule(&htt->txrx_compl_task);
|
tasklet_schedule(&htt->txrx_compl_task);
|
||||||
return;
|
return;
|
||||||
case HTT_T2H_MSG_TYPE_PEER_MAP: {
|
case HTT_T2H_MSG_TYPE_PEER_MAP: {
|
||||||
|
@ -2111,9 +2109,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
|
case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
|
||||||
spin_lock_bh(&htt->rx_ring.lock);
|
skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
|
||||||
__skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
|
|
||||||
spin_unlock_bh(&htt->rx_ring.lock);
|
|
||||||
tasklet_schedule(&htt->txrx_compl_task);
|
tasklet_schedule(&htt->txrx_compl_task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2123,10 +2119,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
|
||||||
break;
|
break;
|
||||||
case HTT_T2H_MSG_TYPE_AGGR_CONF:
|
case HTT_T2H_MSG_TYPE_AGGR_CONF:
|
||||||
break;
|
break;
|
||||||
case HTT_T2H_MSG_TYPE_EN_STATS:
|
|
||||||
case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
|
case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
|
||||||
case HTT_T2H_MSG_TYPE_TX_FETCH_CONF:
|
case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
|
||||||
case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND:
|
case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
|
||||||
|
/* TODO: Implement pull-push logic */
|
||||||
|
break;
|
||||||
|
case HTT_T2H_MSG_TYPE_EN_STATS:
|
||||||
default:
|
default:
|
||||||
ath10k_warn(ar, "htt event (%d) not handled\n",
|
ath10k_warn(ar, "htt event (%d) not handled\n",
|
||||||
resp->hdr.msg_type);
|
resp->hdr.msg_type);
|
||||||
|
@ -2143,11 +2141,7 @@ EXPORT_SYMBOL(ath10k_htt_t2h_msg_handler);
|
||||||
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
|
void ath10k_htt_rx_pktlog_completion_handler(struct ath10k *ar,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ath10k_pktlog_10_4_hdr *hdr =
|
trace_ath10k_htt_pktlog(ar, skb->data, skb->len);
|
||||||
(struct ath10k_pktlog_10_4_hdr *)skb->data;
|
|
||||||
|
|
||||||
trace_ath10k_htt_pktlog(ar, hdr->payload,
|
|
||||||
sizeof(*hdr) + __le16_to_cpu(hdr->size));
|
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
|
EXPORT_SYMBOL(ath10k_htt_rx_pktlog_completion_handler);
|
||||||
|
@ -2156,24 +2150,46 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
|
||||||
{
|
{
|
||||||
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
|
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
|
||||||
struct ath10k *ar = htt->ar;
|
struct ath10k *ar = htt->ar;
|
||||||
|
struct sk_buff_head tx_q;
|
||||||
|
struct sk_buff_head rx_q;
|
||||||
|
struct sk_buff_head rx_ind_q;
|
||||||
struct htt_resp *resp;
|
struct htt_resp *resp;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
while ((skb = skb_dequeue(&htt->tx_compl_q))) {
|
__skb_queue_head_init(&tx_q);
|
||||||
|
__skb_queue_head_init(&rx_q);
|
||||||
|
__skb_queue_head_init(&rx_ind_q);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&htt->tx_compl_q.lock, flags);
|
||||||
|
skb_queue_splice_init(&htt->tx_compl_q, &tx_q);
|
||||||
|
spin_unlock_irqrestore(&htt->tx_compl_q.lock, flags);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&htt->rx_compl_q.lock, flags);
|
||||||
|
skb_queue_splice_init(&htt->rx_compl_q, &rx_q);
|
||||||
|
spin_unlock_irqrestore(&htt->rx_compl_q.lock, flags);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&htt->rx_in_ord_compl_q.lock, flags);
|
||||||
|
skb_queue_splice_init(&htt->rx_in_ord_compl_q, &rx_ind_q);
|
||||||
|
spin_unlock_irqrestore(&htt->rx_in_ord_compl_q.lock, flags);
|
||||||
|
|
||||||
|
while ((skb = __skb_dequeue(&tx_q))) {
|
||||||
ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
|
ath10k_htt_rx_frm_tx_compl(htt->ar, skb);
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock_bh(&htt->rx_ring.lock);
|
while ((skb = __skb_dequeue(&rx_q))) {
|
||||||
while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
|
|
||||||
resp = (struct htt_resp *)skb->data;
|
resp = (struct htt_resp *)skb->data;
|
||||||
|
spin_lock_bh(&htt->rx_ring.lock);
|
||||||
ath10k_htt_rx_handler(htt, &resp->rx_ind);
|
ath10k_htt_rx_handler(htt, &resp->rx_ind);
|
||||||
|
spin_unlock_bh(&htt->rx_ring.lock);
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
|
while ((skb = __skb_dequeue(&rx_ind_q))) {
|
||||||
|
spin_lock_bh(&htt->rx_ring.lock);
|
||||||
ath10k_htt_rx_in_ord_ind(ar, skb);
|
ath10k_htt_rx_in_ord_ind(ar, skb);
|
||||||
|
spin_unlock_bh(&htt->rx_ring.lock);
|
||||||
dev_kfree_skb_any(skb);
|
dev_kfree_skb_any(skb);
|
||||||
}
|
}
|
||||||
spin_unlock_bh(&htt->rx_ring.lock);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,6 +97,85 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
|
||||||
idr_remove(&htt->pending_tx, msdu_id);
|
idr_remove(&htt->pending_tx, msdu_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ath10k_htt_tx_free_cont_frag_desc(struct ath10k_htt *htt)
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!htt->frag_desc.vaddr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
|
||||||
|
|
||||||
|
dma_free_coherent(htt->ar->dev,
|
||||||
|
size,
|
||||||
|
htt->frag_desc.vaddr,
|
||||||
|
htt->frag_desc.paddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_htt_tx_alloc_cont_frag_desc(struct ath10k_htt *htt)
|
||||||
|
{
|
||||||
|
struct ath10k *ar = htt->ar;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!ar->hw_params.continuous_frag_desc)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
|
||||||
|
htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size,
|
||||||
|
&htt->frag_desc.paddr,
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (!htt->frag_desc.vaddr) {
|
||||||
|
ath10k_err(ar, "failed to alloc fragment desc memory\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt)
|
||||||
|
{
|
||||||
|
struct ath10k *ar = htt->ar;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
|
||||||
|
return;
|
||||||
|
|
||||||
|
size = sizeof(*htt->tx_q_state.vaddr);
|
||||||
|
|
||||||
|
dma_unmap_single(ar->dev, htt->tx_q_state.paddr, size, DMA_TO_DEVICE);
|
||||||
|
kfree(htt->tx_q_state.vaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt)
|
||||||
|
{
|
||||||
|
struct ath10k *ar = htt->ar;
|
||||||
|
size_t size;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS;
|
||||||
|
htt->tx_q_state.num_tids = HTT_TX_Q_STATE_NUM_TIDS;
|
||||||
|
htt->tx_q_state.type = HTT_Q_DEPTH_TYPE_BYTES;
|
||||||
|
|
||||||
|
size = sizeof(*htt->tx_q_state.vaddr);
|
||||||
|
htt->tx_q_state.vaddr = kzalloc(size, GFP_KERNEL);
|
||||||
|
if (!htt->tx_q_state.vaddr)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
htt->tx_q_state.paddr = dma_map_single(ar->dev, htt->tx_q_state.vaddr,
|
||||||
|
size, DMA_TO_DEVICE);
|
||||||
|
ret = dma_mapping_error(ar->dev, htt->tx_q_state.paddr);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_warn(ar, "failed to dma map tx_q_state: %d\n", ret);
|
||||||
|
kfree(htt->tx_q_state.vaddr);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||||
{
|
{
|
||||||
struct ath10k *ar = htt->ar;
|
struct ath10k *ar = htt->ar;
|
||||||
|
@ -118,29 +197,32 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
|
||||||
goto free_idr_pending_tx;
|
goto free_idr_pending_tx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ar->hw_params.continuous_frag_desc)
|
ret = ath10k_htt_tx_alloc_cont_frag_desc(htt);
|
||||||
goto skip_frag_desc_alloc;
|
if (ret) {
|
||||||
|
ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret);
|
||||||
size = htt->max_num_pending_tx * sizeof(struct htt_msdu_ext_desc);
|
|
||||||
htt->frag_desc.vaddr = dma_alloc_coherent(ar->dev, size,
|
|
||||||
&htt->frag_desc.paddr,
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!htt->frag_desc.vaddr) {
|
|
||||||
ath10k_warn(ar, "failed to alloc fragment desc memory\n");
|
|
||||||
ret = -ENOMEM;
|
|
||||||
goto free_txbuf;
|
goto free_txbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
skip_frag_desc_alloc:
|
ret = ath10k_htt_tx_alloc_txq(htt);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_err(ar, "failed to alloc txq: %d\n", ret);
|
||||||
|
goto free_frag_desc;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
free_frag_desc:
|
||||||
|
ath10k_htt_tx_free_cont_frag_desc(htt);
|
||||||
|
|
||||||
free_txbuf:
|
free_txbuf:
|
||||||
size = htt->max_num_pending_tx *
|
size = htt->max_num_pending_tx *
|
||||||
sizeof(struct ath10k_htt_txbuf);
|
sizeof(struct ath10k_htt_txbuf);
|
||||||
dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
|
dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
|
||||||
htt->txbuf.paddr);
|
htt->txbuf.paddr);
|
||||||
|
|
||||||
free_idr_pending_tx:
|
free_idr_pending_tx:
|
||||||
idr_destroy(&htt->pending_tx);
|
idr_destroy(&htt->pending_tx);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,12 +256,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
|
||||||
htt->txbuf.paddr);
|
htt->txbuf.paddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (htt->frag_desc.vaddr) {
|
ath10k_htt_tx_free_txq(htt);
|
||||||
size = htt->max_num_pending_tx *
|
ath10k_htt_tx_free_cont_frag_desc(htt);
|
||||||
sizeof(struct htt_msdu_ext_desc);
|
|
||||||
dma_free_coherent(htt->ar->dev, size, htt->frag_desc.vaddr,
|
|
||||||
htt->frag_desc.paddr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
|
||||||
|
@ -268,7 +346,9 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
|
||||||
struct ath10k *ar = htt->ar;
|
struct ath10k *ar = htt->ar;
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct htt_cmd *cmd;
|
struct htt_cmd *cmd;
|
||||||
|
struct htt_frag_desc_bank_cfg *cfg;
|
||||||
int ret, size;
|
int ret, size;
|
||||||
|
u8 info;
|
||||||
|
|
||||||
if (!ar->hw_params.continuous_frag_desc)
|
if (!ar->hw_params.continuous_frag_desc)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -286,14 +366,30 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
|
||||||
skb_put(skb, size);
|
skb_put(skb, size);
|
||||||
cmd = (struct htt_cmd *)skb->data;
|
cmd = (struct htt_cmd *)skb->data;
|
||||||
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG;
|
cmd->hdr.msg_type = HTT_H2T_MSG_TYPE_FRAG_DESC_BANK_CFG;
|
||||||
cmd->frag_desc_bank_cfg.info = 0;
|
|
||||||
cmd->frag_desc_bank_cfg.num_banks = 1;
|
info = 0;
|
||||||
cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc);
|
info |= SM(htt->tx_q_state.type,
|
||||||
cmd->frag_desc_bank_cfg.bank_base_addrs[0] =
|
HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE);
|
||||||
__cpu_to_le32(htt->frag_desc.paddr);
|
|
||||||
cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0;
|
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
|
||||||
cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id =
|
info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID;
|
||||||
__cpu_to_le16(htt->max_num_pending_tx - 1);
|
|
||||||
|
cfg = &cmd->frag_desc_bank_cfg;
|
||||||
|
cfg->info = info;
|
||||||
|
cfg->num_banks = 1;
|
||||||
|
cfg->desc_size = sizeof(struct htt_msdu_ext_desc);
|
||||||
|
cfg->bank_base_addrs[0] = __cpu_to_le32(htt->frag_desc.paddr);
|
||||||
|
cfg->bank_id[0].bank_min_id = 0;
|
||||||
|
cfg->bank_id[0].bank_max_id = __cpu_to_le16(htt->max_num_pending_tx -
|
||||||
|
1);
|
||||||
|
|
||||||
|
cfg->q_state.paddr = cpu_to_le32(htt->tx_q_state.paddr);
|
||||||
|
cfg->q_state.num_peers = cpu_to_le16(htt->tx_q_state.num_peers);
|
||||||
|
cfg->q_state.num_tids = cpu_to_le16(htt->tx_q_state.num_tids);
|
||||||
|
cfg->q_state.record_size = HTT_TX_Q_STATE_ENTRY_SIZE;
|
||||||
|
cfg->q_state.record_multiplier = HTT_TX_Q_STATE_ENTRY_MULTIPLIER;
|
||||||
|
|
||||||
|
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt frag desc bank cmd\n");
|
||||||
|
|
||||||
ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
|
ret = ath10k_htc_send(&htt->ar->htc, htt->eid, skb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -109,6 +109,38 @@ const struct ath10k_hw_regs qca99x0_regs = {
|
||||||
.pcie_intr_clr_address = 0x00000010,
|
.pcie_intr_clr_address = 0x00000010,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct ath10k_hw_regs qca4019_regs = {
|
||||||
|
.rtc_soc_base_address = 0x00080000,
|
||||||
|
.soc_core_base_address = 0x00082000,
|
||||||
|
.ce_wrapper_base_address = 0x0004d000,
|
||||||
|
.ce0_base_address = 0x0004a000,
|
||||||
|
.ce1_base_address = 0x0004a400,
|
||||||
|
.ce2_base_address = 0x0004a800,
|
||||||
|
.ce3_base_address = 0x0004ac00,
|
||||||
|
.ce4_base_address = 0x0004b000,
|
||||||
|
.ce5_base_address = 0x0004b400,
|
||||||
|
.ce6_base_address = 0x0004b800,
|
||||||
|
.ce7_base_address = 0x0004bc00,
|
||||||
|
/* qca4019 supports upto 12 copy engines. Since base address
|
||||||
|
* of ce8 to ce11 are not directly referred in the code,
|
||||||
|
* no need have them in separate members in this table.
|
||||||
|
* Copy Engine Address
|
||||||
|
* CE8 0x0004c000
|
||||||
|
* CE9 0x0004c400
|
||||||
|
* CE10 0x0004c800
|
||||||
|
* CE11 0x0004cc00
|
||||||
|
*/
|
||||||
|
.soc_reset_control_si0_rst_mask = 0x00000001,
|
||||||
|
.soc_reset_control_ce_rst_mask = 0x00000100,
|
||||||
|
.soc_chip_id_address = 0x000000ec,
|
||||||
|
.fw_indicator_address = 0x0004f00c,
|
||||||
|
.ce_wrap_intr_sum_host_msi_lsb = 0x0000000c,
|
||||||
|
.ce_wrap_intr_sum_host_msi_mask = 0x00fff000,
|
||||||
|
.pcie_intr_fw_mask = 0x00100000,
|
||||||
|
.pcie_intr_ce_mask_all = 0x000fff00,
|
||||||
|
.pcie_intr_clr_address = 0x00000010,
|
||||||
|
};
|
||||||
|
|
||||||
const struct ath10k_hw_values qca988x_values = {
|
const struct ath10k_hw_values qca988x_values = {
|
||||||
.rtc_state_val_on = 3,
|
.rtc_state_val_on = 3,
|
||||||
.ce_count = 8,
|
.ce_count = 8,
|
||||||
|
@ -136,6 +168,13 @@ const struct ath10k_hw_values qca99x0_values = {
|
||||||
.ce_desc_meta_data_lsb = 4,
|
.ce_desc_meta_data_lsb = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const struct ath10k_hw_values qca4019_values = {
|
||||||
|
.ce_count = 12,
|
||||||
|
.num_target_ce_config_wlan = 10,
|
||||||
|
.ce_desc_meta_data_mask = 0xFFF0,
|
||||||
|
.ce_desc_meta_data_lsb = 4,
|
||||||
|
};
|
||||||
|
|
||||||
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||||
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
|
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
|
||||||
{
|
{
|
||||||
|
|
|
@ -106,6 +106,14 @@ enum qca9377_chip_id_rev {
|
||||||
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
|
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||||
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
#define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||||
|
|
||||||
|
/* QCA4019 1.0 definitions */
|
||||||
|
#define QCA4019_HW_1_0_DEV_VERSION 0x01000000
|
||||||
|
#define QCA4019_HW_1_0_FW_DIR ATH10K_FW_DIR "/QCA4019/hw1.0"
|
||||||
|
#define QCA4019_HW_1_0_FW_FILE "firmware.bin"
|
||||||
|
#define QCA4019_HW_1_0_OTP_FILE "otp.bin"
|
||||||
|
#define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
|
||||||
|
#define QCA4019_HW_1_0_PATCH_LOAD_ADDR 0x1234
|
||||||
|
|
||||||
#define ATH10K_FW_API2_FILE "firmware-2.bin"
|
#define ATH10K_FW_API2_FILE "firmware-2.bin"
|
||||||
#define ATH10K_FW_API3_FILE "firmware-3.bin"
|
#define ATH10K_FW_API3_FILE "firmware-3.bin"
|
||||||
|
|
||||||
|
@ -200,6 +208,7 @@ enum ath10k_hw_rev {
|
||||||
ATH10K_HW_QCA6174,
|
ATH10K_HW_QCA6174,
|
||||||
ATH10K_HW_QCA99X0,
|
ATH10K_HW_QCA99X0,
|
||||||
ATH10K_HW_QCA9377,
|
ATH10K_HW_QCA9377,
|
||||||
|
ATH10K_HW_QCA4019,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ath10k_hw_regs {
|
struct ath10k_hw_regs {
|
||||||
|
@ -232,6 +241,7 @@ struct ath10k_hw_regs {
|
||||||
extern const struct ath10k_hw_regs qca988x_regs;
|
extern const struct ath10k_hw_regs qca988x_regs;
|
||||||
extern const struct ath10k_hw_regs qca6174_regs;
|
extern const struct ath10k_hw_regs qca6174_regs;
|
||||||
extern const struct ath10k_hw_regs qca99x0_regs;
|
extern const struct ath10k_hw_regs qca99x0_regs;
|
||||||
|
extern const struct ath10k_hw_regs qca4019_regs;
|
||||||
|
|
||||||
struct ath10k_hw_values {
|
struct ath10k_hw_values {
|
||||||
u32 rtc_state_val_on;
|
u32 rtc_state_val_on;
|
||||||
|
@ -245,6 +255,7 @@ struct ath10k_hw_values {
|
||||||
extern const struct ath10k_hw_values qca988x_values;
|
extern const struct ath10k_hw_values qca988x_values;
|
||||||
extern const struct ath10k_hw_values qca6174_values;
|
extern const struct ath10k_hw_values qca6174_values;
|
||||||
extern const struct ath10k_hw_values qca99x0_values;
|
extern const struct ath10k_hw_values qca99x0_values;
|
||||||
|
extern const struct ath10k_hw_values qca4019_values;
|
||||||
|
|
||||||
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||||
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
|
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev);
|
||||||
|
@ -253,6 +264,7 @@ void ath10k_hw_fill_survey_time(struct ath10k *ar, struct survey_info *survey,
|
||||||
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
|
#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
|
||||||
#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
|
#define QCA_REV_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
|
||||||
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
|
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
|
||||||
|
#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
|
||||||
|
|
||||||
/* Known pecularities:
|
/* Known pecularities:
|
||||||
* - raw appears in nwifi decap, raw and nwifi appear in ethernet decap
|
* - raw appears in nwifi decap, raw and nwifi appear in ethernet decap
|
||||||
|
@ -363,14 +375,19 @@ enum ath10k_hw_4addr_pad {
|
||||||
#define TARGET_10X_MAC_AGGR_DELIM 0
|
#define TARGET_10X_MAC_AGGR_DELIM 0
|
||||||
#define TARGET_10X_AST_SKID_LIMIT 128
|
#define TARGET_10X_AST_SKID_LIMIT 128
|
||||||
#define TARGET_10X_NUM_STATIONS 128
|
#define TARGET_10X_NUM_STATIONS 128
|
||||||
|
#define TARGET_10X_TX_STATS_NUM_STATIONS 118
|
||||||
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
|
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
|
||||||
(TARGET_10X_NUM_VDEVS))
|
(TARGET_10X_NUM_VDEVS))
|
||||||
|
#define TARGET_10X_TX_STATS_NUM_PEERS ((TARGET_10X_TX_STATS_NUM_STATIONS) + \
|
||||||
|
(TARGET_10X_NUM_VDEVS))
|
||||||
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
|
#define TARGET_10X_NUM_OFFLOAD_PEERS 0
|
||||||
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
|
#define TARGET_10X_NUM_OFFLOAD_REORDER_BUFS 0
|
||||||
#define TARGET_10X_NUM_PEER_KEYS 2
|
#define TARGET_10X_NUM_PEER_KEYS 2
|
||||||
#define TARGET_10X_NUM_TIDS_MAX 256
|
#define TARGET_10X_NUM_TIDS_MAX 256
|
||||||
#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
|
#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
|
||||||
(TARGET_10X_NUM_PEERS) * 2)
|
(TARGET_10X_NUM_PEERS) * 2)
|
||||||
|
#define TARGET_10X_TX_STATS_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
|
||||||
|
(TARGET_10X_TX_STATS_NUM_PEERS) * 2)
|
||||||
#define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
#define TARGET_10X_TX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||||
#define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
#define TARGET_10X_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||||
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100
|
#define TARGET_10X_RX_TIMEOUT_LO_PRI 100
|
||||||
|
@ -414,16 +431,11 @@ enum ath10k_hw_4addr_pad {
|
||||||
#define TARGET_10_4_ACTIVE_PEERS 0
|
#define TARGET_10_4_ACTIVE_PEERS 0
|
||||||
|
|
||||||
#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512
|
#define TARGET_10_4_NUM_QCACHE_PEERS_MAX 512
|
||||||
#define TARGET_10_4_QCACHE_ACTIVE_PEERS 50
|
|
||||||
#define TARGET_10_4_NUM_OFFLOAD_PEERS 0
|
#define TARGET_10_4_NUM_OFFLOAD_PEERS 0
|
||||||
#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0
|
#define TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS 0
|
||||||
#define TARGET_10_4_NUM_PEER_KEYS 2
|
#define TARGET_10_4_NUM_PEER_KEYS 2
|
||||||
#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2)
|
#define TARGET_10_4_TGT_NUM_TIDS ((TARGET_10_4_NUM_PEERS) * 2)
|
||||||
#define TARGET_10_4_AST_SKID_LIMIT 32
|
#define TARGET_10_4_AST_SKID_LIMIT 32
|
||||||
#define TARGET_10_4_TX_CHAIN_MASK (BIT(0) | BIT(1) | \
|
|
||||||
BIT(2) | BIT(3))
|
|
||||||
#define TARGET_10_4_RX_CHAIN_MASK (BIT(0) | BIT(1) | \
|
|
||||||
BIT(2) | BIT(3))
|
|
||||||
|
|
||||||
/* 100 ms for video, best-effort, and background */
|
/* 100 ms for video, best-effort, and background */
|
||||||
#define TARGET_10_4_RX_TIMEOUT_LO_PRI 100
|
#define TARGET_10_4_RX_TIMEOUT_LO_PRI 100
|
||||||
|
@ -449,7 +461,6 @@ enum ath10k_hw_4addr_pad {
|
||||||
#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
|
#define TARGET_10_4_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK 1
|
||||||
#define TARGET_10_4_VOW_CONFIG 0
|
#define TARGET_10_4_VOW_CONFIG 0
|
||||||
#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3
|
#define TARGET_10_4_GTK_OFFLOAD_MAX_VDEV 3
|
||||||
#define TARGET_10_4_NUM_MSDU_DESC (1024 + 400)
|
|
||||||
#define TARGET_10_4_11AC_TX_MAX_FRAGS 2
|
#define TARGET_10_4_11AC_TX_MAX_FRAGS 2
|
||||||
#define TARGET_10_4_MAX_PEER_EXT_STATS 16
|
#define TARGET_10_4_MAX_PEER_EXT_STATS 16
|
||||||
#define TARGET_10_4_SMART_ANT_CAP 0
|
#define TARGET_10_4_SMART_ANT_CAP 0
|
||||||
|
@ -601,6 +612,7 @@ enum ath10k_hw_4addr_pad {
|
||||||
#define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address
|
#define FW_INDICATOR_ADDRESS ar->regs->fw_indicator_address
|
||||||
#define FW_IND_EVENT_PENDING 1
|
#define FW_IND_EVENT_PENDING 1
|
||||||
#define FW_IND_INITIALIZED 2
|
#define FW_IND_INITIALIZED 2
|
||||||
|
#define FW_IND_HOST_READY 0x80000000
|
||||||
|
|
||||||
/* HOST_REG interrupt from firmware */
|
/* HOST_REG interrupt from firmware */
|
||||||
#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask
|
#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask
|
||||||
|
|
|
@ -1358,10 +1358,7 @@ static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
|
||||||
const u8 *p2p_ie;
|
const u8 *p2p_ie;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
|
if (arvif->vif->type != NL80211_IFTYPE_AP || !arvif->vif->p2p)
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
mgmt = (void *)bcn->data;
|
mgmt = (void *)bcn->data;
|
||||||
|
@ -3259,8 +3256,7 @@ static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
|
||||||
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
|
||||||
|
|
||||||
/* This is case only for P2P_GO */
|
/* This is case only for P2P_GO */
|
||||||
if (arvif->vdev_type != WMI_VDEV_TYPE_AP ||
|
if (vif->type != NL80211_IFTYPE_AP || !vif->p2p)
|
||||||
arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
|
if (unlikely(ieee80211_is_probe_resp(hdr->frame_control))) {
|
||||||
|
@ -3988,7 +3984,7 @@ static int ath10k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant)
|
||||||
static int ath10k_start(struct ieee80211_hw *hw)
|
static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
{
|
{
|
||||||
struct ath10k *ar = hw->priv;
|
struct ath10k *ar = hw->priv;
|
||||||
u32 burst_enable;
|
u32 param;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4031,13 +4027,15 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
goto err_power_down;
|
goto err_power_down;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->pmf_qos, 1);
|
param = ar->wmi.pdev_param->pmf_qos;
|
||||||
|
ret = ath10k_wmi_pdev_set_param(ar, param, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
|
ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
|
||||||
goto err_core_stop;
|
goto err_core_stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->dynamic_bw, 1);
|
param = ar->wmi.pdev_param->dynamic_bw;
|
||||||
|
ret = ath10k_wmi_pdev_set_param(ar, param, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
|
ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
|
||||||
goto err_core_stop;
|
goto err_core_stop;
|
||||||
|
@ -4053,8 +4051,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) {
|
if (test_bit(WMI_SERVICE_BURST, ar->wmi.svc_map)) {
|
||||||
burst_enable = ar->wmi.pdev_param->burst_enable;
|
param = ar->wmi.pdev_param->burst_enable;
|
||||||
ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0);
|
ret = ath10k_wmi_pdev_set_param(ar, param, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to disable burst: %d\n", ret);
|
ath10k_warn(ar, "failed to disable burst: %d\n", ret);
|
||||||
goto err_core_stop;
|
goto err_core_stop;
|
||||||
|
@ -4072,8 +4070,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
* this problem.
|
* this problem.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = ath10k_wmi_pdev_set_param(ar,
|
param = ar->wmi.pdev_param->arp_ac_override;
|
||||||
ar->wmi.pdev_param->arp_ac_override, 0);
|
ret = ath10k_wmi_pdev_set_param(ar, param, 0);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
|
ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
@ -4092,8 +4090,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath10k_wmi_pdev_set_param(ar,
|
param = ar->wmi.pdev_param->ani_enable;
|
||||||
ar->wmi.pdev_param->ani_enable, 1);
|
ret = ath10k_wmi_pdev_set_param(ar, param, 1);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to enable ani by default: %d\n",
|
ath10k_warn(ar, "failed to enable ani by default: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
@ -4102,6 +4100,18 @@ static int ath10k_start(struct ieee80211_hw *hw)
|
||||||
|
|
||||||
ar->ani_enabled = true;
|
ar->ani_enabled = true;
|
||||||
|
|
||||||
|
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||||
|
param = ar->wmi.pdev_param->peer_stats_update_period;
|
||||||
|
ret = ath10k_wmi_pdev_set_param(ar, param,
|
||||||
|
PEER_DEFAULT_STATS_UPDATE_PERIOD);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_warn(ar,
|
||||||
|
"failed to set peer stats period : %d\n",
|
||||||
|
ret);
|
||||||
|
goto err_core_stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ar->num_started_vdevs = 0;
|
ar->num_started_vdevs = 0;
|
||||||
ath10k_regd_update(ar);
|
ath10k_regd_update(ar);
|
||||||
|
|
||||||
|
@ -4349,25 +4359,29 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
bit, ar->free_vdev_map);
|
bit, ar->free_vdev_map);
|
||||||
|
|
||||||
arvif->vdev_id = bit;
|
arvif->vdev_id = bit;
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
|
arvif->vdev_subtype =
|
||||||
|
ath10k_wmi_get_vdev_subtype(ar, WMI_VDEV_SUBTYPE_NONE);
|
||||||
|
|
||||||
switch (vif->type) {
|
switch (vif->type) {
|
||||||
case NL80211_IFTYPE_P2P_DEVICE:
|
case NL80211_IFTYPE_P2P_DEVICE:
|
||||||
arvif->vdev_type = WMI_VDEV_TYPE_STA;
|
arvif->vdev_type = WMI_VDEV_TYPE_STA;
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
|
arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
|
||||||
|
(ar, WMI_VDEV_SUBTYPE_P2P_DEVICE);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_UNSPECIFIED:
|
case NL80211_IFTYPE_UNSPECIFIED:
|
||||||
case NL80211_IFTYPE_STATION:
|
case NL80211_IFTYPE_STATION:
|
||||||
arvif->vdev_type = WMI_VDEV_TYPE_STA;
|
arvif->vdev_type = WMI_VDEV_TYPE_STA;
|
||||||
if (vif->p2p)
|
if (vif->p2p)
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_CLIENT;
|
arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
|
||||||
|
(ar, WMI_VDEV_SUBTYPE_P2P_CLIENT);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_ADHOC:
|
case NL80211_IFTYPE_ADHOC:
|
||||||
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
|
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_MESH_POINT:
|
case NL80211_IFTYPE_MESH_POINT:
|
||||||
if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
|
if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) {
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
|
arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
|
||||||
|
(ar, WMI_VDEV_SUBTYPE_MESH_11S);
|
||||||
} else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
} else if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags)) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
|
ath10k_warn(ar, "must load driver with rawmode=1 to add mesh interfaces\n");
|
||||||
|
@ -4379,7 +4393,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
|
||||||
arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
arvif->vdev_type = WMI_VDEV_TYPE_AP;
|
||||||
|
|
||||||
if (vif->p2p)
|
if (vif->p2p)
|
||||||
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_GO;
|
arvif->vdev_subtype = ath10k_wmi_get_vdev_subtype
|
||||||
|
(ar, WMI_VDEV_SUBTYPE_P2P_GO);
|
||||||
break;
|
break;
|
||||||
case NL80211_IFTYPE_MONITOR:
|
case NL80211_IFTYPE_MONITOR:
|
||||||
arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
|
arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;
|
||||||
|
|
|
@ -94,7 +94,6 @@ static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
|
||||||
static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
|
static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
|
||||||
static int ath10k_pci_cold_reset(struct ath10k *ar);
|
static int ath10k_pci_cold_reset(struct ath10k *ar);
|
||||||
static int ath10k_pci_safe_chip_reset(struct ath10k *ar);
|
static int ath10k_pci_safe_chip_reset(struct ath10k *ar);
|
||||||
static int ath10k_pci_wait_for_target_init(struct ath10k *ar);
|
|
||||||
static int ath10k_pci_init_irq(struct ath10k *ar);
|
static int ath10k_pci_init_irq(struct ath10k *ar);
|
||||||
static int ath10k_pci_deinit_irq(struct ath10k *ar);
|
static int ath10k_pci_deinit_irq(struct ath10k *ar);
|
||||||
static int ath10k_pci_request_irq(struct ath10k *ar);
|
static int ath10k_pci_request_irq(struct ath10k *ar);
|
||||||
|
@ -620,7 +619,7 @@ static void ath10k_pci_sleep_sync(struct ath10k *ar)
|
||||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
|
static void ath10k_bus_pci_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -642,7 +641,7 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||||
ath10k_pci_sleep(ar);
|
ath10k_pci_sleep(ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
static u32 ath10k_bus_pci_read32(struct ath10k *ar, u32 offset)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
u32 val;
|
u32 val;
|
||||||
|
@ -667,6 +666,20 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
|
||||||
|
{
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
|
||||||
|
ar_pci->bus_ops->write32(ar, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
|
||||||
|
{
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
|
||||||
|
return ar_pci->bus_ops->read32(ar, offset);
|
||||||
|
}
|
||||||
|
|
||||||
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
|
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr)
|
||||||
{
|
{
|
||||||
return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
|
return ath10k_pci_read32(ar, RTC_SOC_BASE_ADDRESS + addr);
|
||||||
|
@ -687,7 +700,7 @@ void ath10k_pci_reg_write32(struct ath10k *ar, u32 addr, u32 val)
|
||||||
ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
|
ath10k_pci_write32(ar, PCIE_LOCAL_BASE_ADDRESS + addr, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ath10k_pci_irq_pending(struct ath10k *ar)
|
bool ath10k_pci_irq_pending(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
u32 cause;
|
u32 cause;
|
||||||
|
|
||||||
|
@ -700,7 +713,7 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
|
void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
/* IMPORTANT: INTR_CLR register has to be set after
|
/* IMPORTANT: INTR_CLR register has to be set after
|
||||||
* INTR_ENABLE is set to 0, otherwise interrupt can not be
|
* INTR_ENABLE is set to 0, otherwise interrupt can not be
|
||||||
|
@ -716,7 +729,7 @@ static void ath10k_pci_disable_and_clear_legacy_irq(struct ath10k *ar)
|
||||||
PCIE_INTR_ENABLE_ADDRESS);
|
PCIE_INTR_ENABLE_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
|
void ath10k_pci_enable_legacy_irq(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
|
ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS +
|
||||||
PCIE_INTR_ENABLE_ADDRESS,
|
PCIE_INTR_ENABLE_ADDRESS,
|
||||||
|
@ -809,7 +822,7 @@ static void ath10k_pci_rx_post_pipe(struct ath10k_pci_pipe *pipe)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_rx_post(struct ath10k *ar)
|
void ath10k_pci_rx_post(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
int i;
|
int i;
|
||||||
|
@ -818,7 +831,7 @@ static void ath10k_pci_rx_post(struct ath10k *ar)
|
||||||
ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
|
ath10k_pci_rx_post_pipe(&ar_pci->pipe_info[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
|
void ath10k_pci_rx_replenish_retry(unsigned long ptr)
|
||||||
{
|
{
|
||||||
struct ath10k *ar = (void *)ptr;
|
struct ath10k *ar = (void *)ptr;
|
||||||
|
|
||||||
|
@ -838,6 +851,7 @@ static u32 ath10k_pci_targ_cpu_to_ce_addr(struct ath10k *ar, u32 addr)
|
||||||
0x7ff) << 21;
|
0x7ff) << 21;
|
||||||
break;
|
break;
|
||||||
case ATH10K_HW_QCA99X0:
|
case ATH10K_HW_QCA99X0:
|
||||||
|
case ATH10K_HW_QCA4019:
|
||||||
val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
|
val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1007,8 +1021,8 @@ static int __ath10k_pci_diag_read_hi(struct ath10k *ar, void *dest,
|
||||||
#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
|
#define ath10k_pci_diag_read_hi(ar, dest, src, len) \
|
||||||
__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
|
__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
|
||||||
|
|
||||||
static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
|
||||||
const void *data, int nbytes)
|
const void *data, int nbytes)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
@ -1263,8 +1277,8 @@ static void ath10k_pci_htt_rx_cb(struct ath10k_ce_pipe *ce_state)
|
||||||
ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
|
ath10k_pci_process_rx_cb(ce_state, ath10k_pci_htt_rx_deliver);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
|
||||||
struct ath10k_hif_sg_item *items, int n_items)
|
struct ath10k_hif_sg_item *items, int n_items)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
|
struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
|
||||||
|
@ -1332,13 +1346,13 @@ err:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
|
||||||
size_t buf_len)
|
size_t buf_len)
|
||||||
{
|
{
|
||||||
return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
|
return ath10k_pci_diag_read_mem(ar, address, buf, buf_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
|
u16 ath10k_pci_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
|
||||||
|
@ -1406,8 +1420,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
|
||||||
queue_work(ar->workqueue, &ar->restart_work);
|
queue_work(ar->workqueue, &ar->restart_work);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||||
int force)
|
int force)
|
||||||
{
|
{
|
||||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
|
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif send complete check\n");
|
||||||
|
|
||||||
|
@ -1432,7 +1446,7 @@ static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
|
||||||
ath10k_ce_per_engine_service(ar, pipe);
|
ath10k_ce_per_engine_service(ar, pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
int i;
|
int i;
|
||||||
|
@ -1446,8 +1460,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
|
||||||
del_timer_sync(&ar_pci->rx_post_retry);
|
del_timer_sync(&ar_pci->rx_post_retry);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
||||||
u8 *ul_pipe, u8 *dl_pipe)
|
u8 *ul_pipe, u8 *dl_pipe)
|
||||||
{
|
{
|
||||||
const struct service_to_pipe *entry;
|
const struct service_to_pipe *entry;
|
||||||
bool ul_set = false, dl_set = false;
|
bool ul_set = false, dl_set = false;
|
||||||
|
@ -1491,8 +1505,8 @@ static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
|
void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
|
||||||
u8 *ul_pipe, u8 *dl_pipe)
|
u8 *ul_pipe, u8 *dl_pipe)
|
||||||
{
|
{
|
||||||
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
|
ath10k_dbg(ar, ATH10K_DBG_PCI, "pci hif get default pipe\n");
|
||||||
|
|
||||||
|
@ -1516,6 +1530,7 @@ static void ath10k_pci_irq_msi_fw_mask(struct ath10k *ar)
|
||||||
CORE_CTRL_ADDRESS, val);
|
CORE_CTRL_ADDRESS, val);
|
||||||
break;
|
break;
|
||||||
case ATH10K_HW_QCA99X0:
|
case ATH10K_HW_QCA99X0:
|
||||||
|
case ATH10K_HW_QCA4019:
|
||||||
/* TODO: Find appropriate register configuration for QCA99X0
|
/* TODO: Find appropriate register configuration for QCA99X0
|
||||||
* to mask irq/MSI.
|
* to mask irq/MSI.
|
||||||
*/
|
*/
|
||||||
|
@ -1538,6 +1553,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
|
||||||
CORE_CTRL_ADDRESS, val);
|
CORE_CTRL_ADDRESS, val);
|
||||||
break;
|
break;
|
||||||
case ATH10K_HW_QCA99X0:
|
case ATH10K_HW_QCA99X0:
|
||||||
|
case ATH10K_HW_QCA4019:
|
||||||
/* TODO: Find appropriate register configuration for QCA99X0
|
/* TODO: Find appropriate register configuration for QCA99X0
|
||||||
* to unmask irq/MSI.
|
* to unmask irq/MSI.
|
||||||
*/
|
*/
|
||||||
|
@ -1668,7 +1684,7 @@ static void ath10k_pci_buffer_cleanup(struct ath10k *ar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_ce_deinit(struct ath10k *ar)
|
void ath10k_pci_ce_deinit(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -1676,7 +1692,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
|
||||||
ath10k_ce_deinit_pipe(ar, i);
|
ath10k_ce_deinit_pipe(ar, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_flush(struct ath10k *ar)
|
void ath10k_pci_flush(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
ath10k_pci_kill_tasklet(ar);
|
ath10k_pci_kill_tasklet(ar);
|
||||||
ath10k_pci_buffer_cleanup(ar);
|
ath10k_pci_buffer_cleanup(ar);
|
||||||
|
@ -1711,9 +1727,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
|
||||||
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
||||||
void *req, u32 req_len,
|
void *req, u32 req_len,
|
||||||
void *resp, u32 *resp_len)
|
void *resp, u32 *resp_len)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
|
struct ath10k_pci_pipe *pci_tx = &ar_pci->pipe_info[BMI_CE_NUM_TO_TARG];
|
||||||
|
@ -1756,7 +1772,7 @@ static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
|
||||||
DMA_FROM_DEVICE);
|
DMA_FROM_DEVICE);
|
||||||
ret = dma_mapping_error(ar->dev, resp_paddr);
|
ret = dma_mapping_error(ar->dev, resp_paddr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = EIO;
|
ret = -EIO;
|
||||||
goto err_req;
|
goto err_req;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1907,7 +1923,14 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_init_config(struct ath10k *ar)
|
static int ath10k_bus_get_num_banks(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
|
||||||
|
return ar_pci->bus_ops->get_num_banks(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ath10k_pci_init_config(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
u32 interconnect_targ_addr;
|
u32 interconnect_targ_addr;
|
||||||
u32 pcie_state_targ_addr = 0;
|
u32 pcie_state_targ_addr = 0;
|
||||||
|
@ -2018,7 +2041,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
|
||||||
/* first bank is switched to IRAM */
|
/* first bank is switched to IRAM */
|
||||||
ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
|
ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
|
||||||
HI_EARLY_ALLOC_MAGIC_MASK);
|
HI_EARLY_ALLOC_MAGIC_MASK);
|
||||||
ealloc_value |= ((ath10k_pci_get_num_banks(ar) <<
|
ealloc_value |= ((ath10k_bus_get_num_banks(ar) <<
|
||||||
HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
|
HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
|
||||||
HI_EARLY_ALLOC_IRAM_BANKS_MASK);
|
HI_EARLY_ALLOC_IRAM_BANKS_MASK);
|
||||||
|
|
||||||
|
@ -2071,7 +2094,7 @@ static void ath10k_pci_override_ce_config(struct ath10k *ar)
|
||||||
target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
|
target_service_to_ce_map_wlan[15].pipenum = __cpu_to_le32(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
struct ath10k_pci_pipe *pipe;
|
struct ath10k_pci_pipe *pipe;
|
||||||
|
@ -2102,7 +2125,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_free_pipes(struct ath10k *ar)
|
void ath10k_pci_free_pipes(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -2110,7 +2133,7 @@ static void ath10k_pci_free_pipes(struct ath10k *ar)
|
||||||
ath10k_ce_free_pipe(ar, i);
|
ath10k_ce_free_pipe(ar, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_init_pipes(struct ath10k *ar)
|
int ath10k_pci_init_pipes(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
|
@ -2453,7 +2476,7 @@ err_sleep:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_hif_power_down(struct ath10k *ar)
|
void ath10k_pci_hif_power_down(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
|
ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");
|
||||||
|
|
||||||
|
@ -2722,7 +2745,7 @@ static void ath10k_pci_free_irq(struct ath10k *ar)
|
||||||
free_irq(ar_pci->pdev->irq + i, ar);
|
free_irq(ar_pci->pdev->irq + i, ar);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
|
void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
int i;
|
int i;
|
||||||
|
@ -2808,7 +2831,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
int ath10k_pci_wait_for_target_init(struct ath10k *ar)
|
||||||
{
|
{
|
||||||
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
unsigned long timeout;
|
unsigned long timeout;
|
||||||
|
@ -2989,6 +3012,43 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath10k_pci_setup_resource(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
spin_lock_init(&ar_pci->ce_lock);
|
||||||
|
spin_lock_init(&ar_pci->ps_lock);
|
||||||
|
|
||||||
|
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
|
||||||
|
(unsigned long)ar);
|
||||||
|
|
||||||
|
if (QCA_REV_6174(ar))
|
||||||
|
ath10k_pci_override_ce_config(ar);
|
||||||
|
|
||||||
|
ret = ath10k_pci_alloc_pipes(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
|
||||||
|
ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ath10k_pci_release_resource(struct ath10k *ar)
|
||||||
|
{
|
||||||
|
ath10k_pci_kill_tasklet(ar);
|
||||||
|
ath10k_pci_ce_deinit(ar);
|
||||||
|
ath10k_pci_free_pipes(ar);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct ath10k_bus_ops ath10k_pci_bus_ops = {
|
||||||
|
.read32 = ath10k_bus_pci_read32,
|
||||||
|
.write32 = ath10k_bus_pci_write32,
|
||||||
|
.get_num_banks = ath10k_pci_get_num_banks,
|
||||||
|
};
|
||||||
|
|
||||||
static int ath10k_pci_probe(struct pci_dev *pdev,
|
static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||||
const struct pci_device_id *pci_dev)
|
const struct pci_device_id *pci_dev)
|
||||||
{
|
{
|
||||||
|
@ -3039,40 +3099,32 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||||
ar_pci->ar = ar;
|
ar_pci->ar = ar;
|
||||||
ar->dev_id = pci_dev->device;
|
ar->dev_id = pci_dev->device;
|
||||||
ar_pci->pci_ps = pci_ps;
|
ar_pci->pci_ps = pci_ps;
|
||||||
|
ar_pci->bus_ops = &ath10k_pci_bus_ops;
|
||||||
|
|
||||||
ar->id.vendor = pdev->vendor;
|
ar->id.vendor = pdev->vendor;
|
||||||
ar->id.device = pdev->device;
|
ar->id.device = pdev->device;
|
||||||
ar->id.subsystem_vendor = pdev->subsystem_vendor;
|
ar->id.subsystem_vendor = pdev->subsystem_vendor;
|
||||||
ar->id.subsystem_device = pdev->subsystem_device;
|
ar->id.subsystem_device = pdev->subsystem_device;
|
||||||
|
|
||||||
spin_lock_init(&ar_pci->ce_lock);
|
|
||||||
spin_lock_init(&ar_pci->ps_lock);
|
|
||||||
|
|
||||||
setup_timer(&ar_pci->rx_post_retry, ath10k_pci_rx_replenish_retry,
|
|
||||||
(unsigned long)ar);
|
|
||||||
setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
|
setup_timer(&ar_pci->ps_timer, ath10k_pci_ps_timer,
|
||||||
(unsigned long)ar);
|
(unsigned long)ar);
|
||||||
|
|
||||||
|
ret = ath10k_pci_setup_resource(ar);
|
||||||
|
if (ret) {
|
||||||
|
ath10k_err(ar, "failed to setup resource: %d\n", ret);
|
||||||
|
goto err_core_destroy;
|
||||||
|
}
|
||||||
|
|
||||||
ret = ath10k_pci_claim(ar);
|
ret = ath10k_pci_claim(ar);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_err(ar, "failed to claim device: %d\n", ret);
|
ath10k_err(ar, "failed to claim device: %d\n", ret);
|
||||||
goto err_core_destroy;
|
goto err_free_pipes;
|
||||||
}
|
|
||||||
|
|
||||||
if (QCA_REV_6174(ar))
|
|
||||||
ath10k_pci_override_ce_config(ar);
|
|
||||||
|
|
||||||
ret = ath10k_pci_alloc_pipes(ar);
|
|
||||||
if (ret) {
|
|
||||||
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
|
|
||||||
ret);
|
|
||||||
goto err_sleep;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ath10k_pci_force_wake(ar);
|
ret = ath10k_pci_force_wake(ar);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
|
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
|
||||||
goto err_free_pipes;
|
goto err_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
ath10k_pci_ce_deinit(ar);
|
ath10k_pci_ce_deinit(ar);
|
||||||
|
@ -3081,7 +3133,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
|
||||||
ret = ath10k_pci_init_irq(ar);
|
ret = ath10k_pci_init_irq(ar);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ath10k_err(ar, "failed to init irqs: %d\n", ret);
|
ath10k_err(ar, "failed to init irqs: %d\n", ret);
|
||||||
goto err_free_pipes;
|
goto err_sleep;
|
||||||
}
|
}
|
||||||
|
|
||||||
ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
|
ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
|
||||||
|
@ -3127,13 +3179,13 @@ err_free_irq:
|
||||||
err_deinit_irq:
|
err_deinit_irq:
|
||||||
ath10k_pci_deinit_irq(ar);
|
ath10k_pci_deinit_irq(ar);
|
||||||
|
|
||||||
err_free_pipes:
|
|
||||||
ath10k_pci_free_pipes(ar);
|
|
||||||
|
|
||||||
err_sleep:
|
err_sleep:
|
||||||
ath10k_pci_sleep_sync(ar);
|
ath10k_pci_sleep_sync(ar);
|
||||||
ath10k_pci_release(ar);
|
ath10k_pci_release(ar);
|
||||||
|
|
||||||
|
err_free_pipes:
|
||||||
|
ath10k_pci_free_pipes(ar);
|
||||||
|
|
||||||
err_core_destroy:
|
err_core_destroy:
|
||||||
ath10k_core_destroy(ar);
|
ath10k_core_destroy(ar);
|
||||||
|
|
||||||
|
@ -3157,10 +3209,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
|
||||||
|
|
||||||
ath10k_core_unregister(ar);
|
ath10k_core_unregister(ar);
|
||||||
ath10k_pci_free_irq(ar);
|
ath10k_pci_free_irq(ar);
|
||||||
ath10k_pci_kill_tasklet(ar);
|
|
||||||
ath10k_pci_deinit_irq(ar);
|
ath10k_pci_deinit_irq(ar);
|
||||||
ath10k_pci_ce_deinit(ar);
|
ath10k_pci_release_resource(ar);
|
||||||
ath10k_pci_free_pipes(ar);
|
|
||||||
ath10k_pci_sleep_sync(ar);
|
ath10k_pci_sleep_sync(ar);
|
||||||
ath10k_pci_release(ar);
|
ath10k_pci_release(ar);
|
||||||
ath10k_core_destroy(ar);
|
ath10k_core_destroy(ar);
|
||||||
|
@ -3184,6 +3234,10 @@ static int __init ath10k_pci_init(void)
|
||||||
printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
|
printk(KERN_ERR "failed to register ath10k pci driver: %d\n",
|
||||||
ret);
|
ret);
|
||||||
|
|
||||||
|
ret = ath10k_ahb_init();
|
||||||
|
if (ret)
|
||||||
|
printk(KERN_ERR "ahb init failed: %d\n", ret);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
module_init(ath10k_pci_init);
|
module_init(ath10k_pci_init);
|
||||||
|
@ -3191,6 +3245,7 @@ module_init(ath10k_pci_init);
|
||||||
static void __exit ath10k_pci_exit(void)
|
static void __exit ath10k_pci_exit(void)
|
||||||
{
|
{
|
||||||
pci_unregister_driver(&ath10k_pci_driver);
|
pci_unregister_driver(&ath10k_pci_driver);
|
||||||
|
ath10k_ahb_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
module_exit(ath10k_pci_exit);
|
module_exit(ath10k_pci_exit);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "hw.h"
|
#include "hw.h"
|
||||||
#include "ce.h"
|
#include "ce.h"
|
||||||
|
#include "ahb.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
|
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
|
||||||
|
@ -157,6 +158,12 @@ struct ath10k_pci_supp_chip {
|
||||||
u32 rev_id;
|
u32 rev_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
|
||||||
struct ath10k_pci {
|
struct ath10k_pci {
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
@ -225,6 +232,14 @@ struct ath10k_pci {
|
||||||
* on MMIO read/write.
|
* on MMIO read/write.
|
||||||
*/
|
*/
|
||||||
bool pci_ps;
|
bool pci_ps;
|
||||||
|
|
||||||
|
const struct ath10k_bus_ops *bus_ops;
|
||||||
|
|
||||||
|
/* 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[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
|
||||||
|
@ -253,6 +268,40 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset);
|
||||||
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
|
u32 ath10k_pci_soc_read32(struct ath10k *ar, u32 addr);
|
||||||
u32 ath10k_pci_reg_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_free_pipes(struct ath10k *ar);
|
||||||
|
void ath10k_pci_rx_replenish_retry(unsigned long ptr);
|
||||||
|
void ath10k_pci_ce_deinit(struct ath10k *ar);
|
||||||
|
void ath10k_pci_init_irq_tasklets(struct ath10k *ar);
|
||||||
|
void ath10k_pci_kill_tasklet(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);
|
||||||
|
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
|
/* 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
|
* frequently. To avoid this put SoC to sleep after a very conservative grace
|
||||||
* period. Adjust with great care.
|
* period. Adjust with great care.
|
||||||
|
|
|
@ -456,4 +456,7 @@ Fw Mode/SubMode Mask
|
||||||
#define QCA99X0_BOARD_DATA_SZ 12288
|
#define QCA99X0_BOARD_DATA_SZ 12288
|
||||||
#define QCA99X0_BOARD_EXT_DATA_SZ 0
|
#define QCA99X0_BOARD_EXT_DATA_SZ 0
|
||||||
|
|
||||||
|
#define QCA4019_BOARD_DATA_SZ 12064
|
||||||
|
#define QCA4019_BOARD_EXT_DATA_SZ 0
|
||||||
|
|
||||||
#endif /* __TARGADDRS_H__ */
|
#endif /* __TARGADDRS_H__ */
|
||||||
|
|
|
@ -250,6 +250,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string(device, dev_name(ar->dev))
|
__string(device, dev_name(ar->dev))
|
||||||
__string(driver, dev_driver_string(ar->dev))
|
__string(driver, dev_driver_string(ar->dev))
|
||||||
|
__field(u8, hw_type);
|
||||||
__field(size_t, buf_len)
|
__field(size_t, buf_len)
|
||||||
__dynamic_array(u8, buf, buf_len)
|
__dynamic_array(u8, buf, buf_len)
|
||||||
),
|
),
|
||||||
|
@ -257,14 +258,16 @@ TRACE_EVENT(ath10k_wmi_dbglog,
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__assign_str(device, dev_name(ar->dev));
|
__assign_str(device, dev_name(ar->dev));
|
||||||
__assign_str(driver, dev_driver_string(ar->dev));
|
__assign_str(driver, dev_driver_string(ar->dev));
|
||||||
|
__entry->hw_type = ar->hw_rev;
|
||||||
__entry->buf_len = buf_len;
|
__entry->buf_len = buf_len;
|
||||||
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
memcpy(__get_dynamic_array(buf), buf, buf_len);
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
"%s %s len %zu",
|
"%s %s %d len %zu",
|
||||||
__get_str(driver),
|
__get_str(driver),
|
||||||
__get_str(device),
|
__get_str(device),
|
||||||
|
__entry->hw_type,
|
||||||
__entry->buf_len
|
__entry->buf_len
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -277,6 +280,7 @@ TRACE_EVENT(ath10k_htt_pktlog,
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string(device, dev_name(ar->dev))
|
__string(device, dev_name(ar->dev))
|
||||||
__string(driver, dev_driver_string(ar->dev))
|
__string(driver, dev_driver_string(ar->dev))
|
||||||
|
__field(u8, hw_type);
|
||||||
__field(u16, buf_len)
|
__field(u16, buf_len)
|
||||||
__dynamic_array(u8, pktlog, buf_len)
|
__dynamic_array(u8, pktlog, buf_len)
|
||||||
),
|
),
|
||||||
|
@ -284,14 +288,16 @@ TRACE_EVENT(ath10k_htt_pktlog,
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__assign_str(device, dev_name(ar->dev));
|
__assign_str(device, dev_name(ar->dev));
|
||||||
__assign_str(driver, dev_driver_string(ar->dev));
|
__assign_str(driver, dev_driver_string(ar->dev));
|
||||||
|
__entry->hw_type = ar->hw_rev;
|
||||||
__entry->buf_len = buf_len;
|
__entry->buf_len = buf_len;
|
||||||
memcpy(__get_dynamic_array(pktlog), buf, buf_len);
|
memcpy(__get_dynamic_array(pktlog), buf, buf_len);
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
"%s %s size %hu",
|
"%s %s %d size %hu",
|
||||||
__get_str(driver),
|
__get_str(driver),
|
||||||
__get_str(device),
|
__get_str(device),
|
||||||
|
__entry->hw_type,
|
||||||
__entry->buf_len
|
__entry->buf_len
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -440,6 +446,7 @@ TRACE_EVENT(ath10k_htt_rx_desc,
|
||||||
TP_STRUCT__entry(
|
TP_STRUCT__entry(
|
||||||
__string(device, dev_name(ar->dev))
|
__string(device, dev_name(ar->dev))
|
||||||
__string(driver, dev_driver_string(ar->dev))
|
__string(driver, dev_driver_string(ar->dev))
|
||||||
|
__field(u8, hw_type);
|
||||||
__field(u16, len)
|
__field(u16, len)
|
||||||
__dynamic_array(u8, rxdesc, len)
|
__dynamic_array(u8, rxdesc, len)
|
||||||
),
|
),
|
||||||
|
@ -447,14 +454,16 @@ TRACE_EVENT(ath10k_htt_rx_desc,
|
||||||
TP_fast_assign(
|
TP_fast_assign(
|
||||||
__assign_str(device, dev_name(ar->dev));
|
__assign_str(device, dev_name(ar->dev));
|
||||||
__assign_str(driver, dev_driver_string(ar->dev));
|
__assign_str(driver, dev_driver_string(ar->dev));
|
||||||
|
__entry->hw_type = ar->hw_rev;
|
||||||
__entry->len = len;
|
__entry->len = len;
|
||||||
memcpy(__get_dynamic_array(rxdesc), data, len);
|
memcpy(__get_dynamic_array(rxdesc), data, len);
|
||||||
),
|
),
|
||||||
|
|
||||||
TP_printk(
|
TP_printk(
|
||||||
"%s %s rxdesc len %d",
|
"%s %s %d rxdesc len %d",
|
||||||
__get_str(driver),
|
__get_str(driver),
|
||||||
__get_str(device),
|
__get_str(device),
|
||||||
|
__entry->hw_type,
|
||||||
__entry->len
|
__entry->len
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -186,6 +186,8 @@ struct wmi_ops {
|
||||||
u8 enable,
|
u8 enable,
|
||||||
u32 detect_level,
|
u32 detect_level,
|
||||||
u32 detect_margin);
|
u32 detect_margin);
|
||||||
|
int (*get_vdev_subtype)(struct ath10k *ar,
|
||||||
|
enum wmi_vdev_subtype subtype);
|
||||||
};
|
};
|
||||||
|
|
||||||
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
|
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
|
||||||
|
@ -1327,4 +1329,13 @@ ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
|
||||||
ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid);
|
ar->wmi.cmd->pdev_enable_adaptive_cca_cmdid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int
|
||||||
|
ath10k_wmi_get_vdev_subtype(struct ath10k *ar, enum wmi_vdev_subtype subtype)
|
||||||
|
{
|
||||||
|
if (!ar->wmi.ops->get_vdev_subtype)
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
|
return ar->wmi.ops->get_vdev_subtype(ar, subtype);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -3483,6 +3483,7 @@ static const struct wmi_ops wmi_tlv_ops = {
|
||||||
.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
|
.gen_tdls_peer_update = ath10k_wmi_tlv_op_gen_tdls_peer_update,
|
||||||
.gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
|
.gen_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
|
||||||
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
|
static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = {
|
||||||
|
|
|
@ -2862,11 +2862,20 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
|
||||||
/* fw doesn't implement vdev stats */
|
/* fw doesn't implement vdev stats */
|
||||||
|
|
||||||
for (i = 0; i < num_peer_stats; i++) {
|
for (i = 0; i < num_peer_stats; i++) {
|
||||||
const struct wmi_10_2_4_peer_stats *src;
|
const struct wmi_10_2_4_ext_peer_stats *src;
|
||||||
struct ath10k_fw_stats_peer *dst;
|
struct ath10k_fw_stats_peer *dst;
|
||||||
|
int stats_len;
|
||||||
|
bool ext_peer_stats_support;
|
||||||
|
|
||||||
|
ext_peer_stats_support = test_bit(WMI_SERVICE_PEER_STATS,
|
||||||
|
ar->wmi.svc_map);
|
||||||
|
if (ext_peer_stats_support)
|
||||||
|
stats_len = sizeof(struct wmi_10_2_4_ext_peer_stats);
|
||||||
|
else
|
||||||
|
stats_len = sizeof(struct wmi_10_2_4_peer_stats);
|
||||||
|
|
||||||
src = (void *)skb->data;
|
src = (void *)skb->data;
|
||||||
if (!skb_pull(skb, sizeof(*src)))
|
if (!skb_pull(skb, stats_len))
|
||||||
return -EPROTO;
|
return -EPROTO;
|
||||||
|
|
||||||
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
|
dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
|
||||||
|
@ -2876,6 +2885,9 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
|
||||||
ath10k_wmi_pull_peer_stats(&src->common.old, dst);
|
ath10k_wmi_pull_peer_stats(&src->common.old, dst);
|
||||||
|
|
||||||
dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
|
dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
|
||||||
|
|
||||||
|
if (ext_peer_stats_support)
|
||||||
|
dst->rx_duration = __le32_to_cpu(src->rx_duration);
|
||||||
/* FIXME: expose 10.2 specific values */
|
/* FIXME: expose 10.2 specific values */
|
||||||
|
|
||||||
list_add_tail(&dst->list, &stats->peers);
|
list_add_tail(&dst->list, &stats->peers);
|
||||||
|
@ -3184,7 +3196,7 @@ static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
|
||||||
struct sk_buff *bcn,
|
struct sk_buff *bcn,
|
||||||
const struct wmi_p2p_noa_info *noa)
|
const struct wmi_p2p_noa_info *noa)
|
||||||
{
|
{
|
||||||
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
|
if (!arvif->vif->p2p)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
|
ath10k_dbg(ar, ATH10K_DBG_MGMT, "noa changed: %d\n", noa->changed);
|
||||||
|
@ -3244,6 +3256,50 @@ static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ath10k_wmi_10_2_4_op_pull_swba_ev(struct ath10k *ar,
|
||||||
|
struct sk_buff *skb,
|
||||||
|
struct wmi_swba_ev_arg *arg)
|
||||||
|
{
|
||||||
|
struct wmi_10_2_4_host_swba_event *ev = (void *)skb->data;
|
||||||
|
u32 map;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (skb->len < sizeof(*ev))
|
||||||
|
return -EPROTO;
|
||||||
|
|
||||||
|
skb_pull(skb, sizeof(*ev));
|
||||||
|
arg->vdev_map = ev->vdev_map;
|
||||||
|
|
||||||
|
for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) {
|
||||||
|
if (!(map & BIT(0)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If this happens there were some changes in firmware and
|
||||||
|
* ath10k should update the max size of tim_info array.
|
||||||
|
*/
|
||||||
|
if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (__le32_to_cpu(ev->bcn_info[i].tim_info.tim_len) >
|
||||||
|
sizeof(ev->bcn_info[i].tim_info.tim_bitmap)) {
|
||||||
|
ath10k_warn(ar, "refusing to parse invalid swba structure\n");
|
||||||
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg->tim_info[i].tim_len = ev->bcn_info[i].tim_info.tim_len;
|
||||||
|
arg->tim_info[i].tim_mcast = ev->bcn_info[i].tim_info.tim_mcast;
|
||||||
|
arg->tim_info[i].tim_bitmap =
|
||||||
|
ev->bcn_info[i].tim_info.tim_bitmap;
|
||||||
|
arg->tim_info[i].tim_changed =
|
||||||
|
ev->bcn_info[i].tim_info.tim_changed;
|
||||||
|
arg->tim_info[i].tim_num_ps_pending =
|
||||||
|
ev->bcn_info[i].tim_info.tim_num_ps_pending;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar,
|
static int ath10k_wmi_10_4_op_pull_swba_ev(struct ath10k *ar,
|
||||||
struct sk_buff *skb,
|
struct sk_buff *skb,
|
||||||
struct wmi_swba_ev_arg *arg)
|
struct wmi_swba_ev_arg *arg)
|
||||||
|
@ -4562,9 +4618,9 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
|
||||||
|
|
||||||
if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
|
if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
|
||||||
ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX +
|
ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX +
|
||||||
TARGET_10_4_NUM_VDEVS;
|
ar->max_num_vdevs;
|
||||||
ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS +
|
ar->num_active_peers = ar->hw_params.qcache_active_peers +
|
||||||
TARGET_10_4_NUM_VDEVS;
|
ar->max_num_vdevs;
|
||||||
ar->num_tids = ar->num_active_peers * 2;
|
ar->num_tids = ar->num_active_peers * 2;
|
||||||
ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX;
|
ar->max_num_stations = TARGET_10_4_NUM_QCACHE_PEERS_MAX;
|
||||||
}
|
}
|
||||||
|
@ -5460,9 +5516,15 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
|
||||||
u32 len, val, features;
|
u32 len, val, features;
|
||||||
|
|
||||||
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
|
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
|
||||||
config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
|
|
||||||
config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
|
config.num_peer_keys = __cpu_to_le32(TARGET_10X_NUM_PEER_KEYS);
|
||||||
config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
|
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
|
||||||
|
config.num_peers = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_PEERS);
|
||||||
|
config.num_tids = __cpu_to_le32(TARGET_10X_TX_STATS_NUM_TIDS);
|
||||||
|
} else {
|
||||||
|
config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
|
||||||
|
config.num_tids = __cpu_to_le32(TARGET_10X_NUM_TIDS);
|
||||||
|
}
|
||||||
|
|
||||||
config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
|
config.ast_skid_limit = __cpu_to_le32(TARGET_10X_AST_SKID_LIMIT);
|
||||||
config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
|
config.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_CHAIN_MASK);
|
||||||
config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
|
config.rx_chain_mask = __cpu_to_le32(TARGET_10X_RX_CHAIN_MASK);
|
||||||
|
@ -5517,6 +5579,9 @@ static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
|
||||||
test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
|
test_bit(WMI_SERVICE_COEX_GPIO, ar->wmi.svc_map))
|
||||||
features |= WMI_10_2_COEX_GPIO;
|
features |= WMI_10_2_COEX_GPIO;
|
||||||
|
|
||||||
|
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map))
|
||||||
|
features |= WMI_10_2_PEER_STATS;
|
||||||
|
|
||||||
cmd->resource_config.feature_mask = __cpu_to_le32(features);
|
cmd->resource_config.feature_mask = __cpu_to_le32(features);
|
||||||
|
|
||||||
memcpy(&cmd->resource_config.common, &config, sizeof(config));
|
memcpy(&cmd->resource_config.common, &config, sizeof(config));
|
||||||
|
@ -5543,8 +5608,8 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar)
|
||||||
__cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS);
|
__cpu_to_le32(TARGET_10_4_NUM_OFFLOAD_REORDER_BUFFS);
|
||||||
config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS);
|
config.num_peer_keys = __cpu_to_le32(TARGET_10_4_NUM_PEER_KEYS);
|
||||||
config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT);
|
config.ast_skid_limit = __cpu_to_le32(TARGET_10_4_AST_SKID_LIMIT);
|
||||||
config.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK);
|
config.tx_chain_mask = __cpu_to_le32(ar->hw_params.tx_chain_mask);
|
||||||
config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK);
|
config.rx_chain_mask = __cpu_to_le32(ar->hw_params.rx_chain_mask);
|
||||||
|
|
||||||
config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
|
config.rx_timeout_pri[0] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
|
||||||
config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
|
config.rx_timeout_pri[1] = __cpu_to_le32(TARGET_10_4_RX_TIMEOUT_LO_PRI);
|
||||||
|
@ -5575,7 +5640,7 @@ static struct sk_buff *ath10k_wmi_10_4_op_gen_init(struct ath10k *ar)
|
||||||
config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG);
|
config.vow_config = __cpu_to_le32(TARGET_10_4_VOW_CONFIG);
|
||||||
config.gtk_offload_max_vdev =
|
config.gtk_offload_max_vdev =
|
||||||
__cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV);
|
__cpu_to_le32(TARGET_10_4_GTK_OFFLOAD_MAX_VDEV);
|
||||||
config.num_msdu_desc = __cpu_to_le32(TARGET_10_4_NUM_MSDU_DESC);
|
config.num_msdu_desc = __cpu_to_le32(ar->htt.max_num_pending_tx);
|
||||||
config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS);
|
config.max_frag_entries = __cpu_to_le32(TARGET_10_4_11AC_TX_MAX_FRAGS);
|
||||||
config.max_peer_ext_stats =
|
config.max_peer_ext_stats =
|
||||||
__cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS);
|
__cpu_to_le32(TARGET_10_4_MAX_PEER_EXT_STATS);
|
||||||
|
@ -7126,6 +7191,9 @@ ath10k_wmi_fw_peer_stats_fill(const struct ath10k_fw_stats_peer *peer,
|
||||||
"Peer TX rate", peer->peer_tx_rate);
|
"Peer TX rate", peer->peer_tx_rate);
|
||||||
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||||
"Peer RX rate", peer->peer_rx_rate);
|
"Peer RX rate", peer->peer_rx_rate);
|
||||||
|
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
|
||||||
|
"Peer RX duration", peer->rx_duration);
|
||||||
|
|
||||||
len += scnprintf(buf + len, buf_len - len, "\n");
|
len += scnprintf(buf + len, buf_len - len, "\n");
|
||||||
*length = len;
|
*length = len;
|
||||||
}
|
}
|
||||||
|
@ -7351,6 +7419,71 @@ unlock:
|
||||||
buf[len] = 0;
|
buf[len] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
|
||||||
|
enum wmi_vdev_subtype subtype)
|
||||||
|
{
|
||||||
|
switch (subtype) {
|
||||||
|
case WMI_VDEV_SUBTYPE_NONE:
|
||||||
|
return WMI_VDEV_SUBTYPE_LEGACY_NONE;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_DEVICE:
|
||||||
|
return WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_CLIENT:
|
||||||
|
return WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_GO:
|
||||||
|
return WMI_VDEV_SUBTYPE_LEGACY_P2P_GO;
|
||||||
|
case WMI_VDEV_SUBTYPE_PROXY_STA:
|
||||||
|
return WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA;
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_11S:
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_NON_11S:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_wmi_10_2_4_op_get_vdev_subtype(struct ath10k *ar,
|
||||||
|
enum wmi_vdev_subtype subtype)
|
||||||
|
{
|
||||||
|
switch (subtype) {
|
||||||
|
case WMI_VDEV_SUBTYPE_NONE:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_NONE;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_DEVICE:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_CLIENT:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_GO:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_P2P_GO;
|
||||||
|
case WMI_VDEV_SUBTYPE_PROXY_STA:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA;
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_11S:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_2_4_MESH_11S;
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_NON_11S:
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ath10k_wmi_10_4_op_get_vdev_subtype(struct ath10k *ar,
|
||||||
|
enum wmi_vdev_subtype subtype)
|
||||||
|
{
|
||||||
|
switch (subtype) {
|
||||||
|
case WMI_VDEV_SUBTYPE_NONE:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_NONE;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_DEVICE:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_P2P_DEV;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_CLIENT:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_P2P_CLI;
|
||||||
|
case WMI_VDEV_SUBTYPE_P2P_GO:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_P2P_GO;
|
||||||
|
case WMI_VDEV_SUBTYPE_PROXY_STA:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_PROXY_STA;
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_11S:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_MESH_11S;
|
||||||
|
case WMI_VDEV_SUBTYPE_MESH_NON_11S:
|
||||||
|
return WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S;
|
||||||
|
}
|
||||||
|
return -ENOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct wmi_ops wmi_ops = {
|
static const struct wmi_ops wmi_ops = {
|
||||||
.rx = ath10k_wmi_op_rx,
|
.rx = ath10k_wmi_op_rx,
|
||||||
.map_svc = wmi_main_svc_map,
|
.map_svc = wmi_main_svc_map,
|
||||||
|
@ -7410,6 +7543,7 @@ static const struct wmi_ops wmi_ops = {
|
||||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||||
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
.fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
|
||||||
/* .gen_bcn_tmpl not implemented */
|
/* .gen_bcn_tmpl not implemented */
|
||||||
/* .gen_prb_tmpl not implemented */
|
/* .gen_prb_tmpl not implemented */
|
||||||
/* .gen_p2p_go_bcn_ie not implemented */
|
/* .gen_p2p_go_bcn_ie not implemented */
|
||||||
|
@ -7477,6 +7611,7 @@ static const struct wmi_ops wmi_10_1_ops = {
|
||||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
|
||||||
/* .gen_bcn_tmpl not implemented */
|
/* .gen_bcn_tmpl not implemented */
|
||||||
/* .gen_prb_tmpl not implemented */
|
/* .gen_prb_tmpl not implemented */
|
||||||
/* .gen_p2p_go_bcn_ie not implemented */
|
/* .gen_p2p_go_bcn_ie not implemented */
|
||||||
|
@ -7545,6 +7680,7 @@ static const struct wmi_ops wmi_10_2_ops = {
|
||||||
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
.gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
|
||||||
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
.gen_delba_send = ath10k_wmi_op_gen_delba_send,
|
||||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype,
|
||||||
/* .gen_pdev_enable_adaptive_cca not implemented */
|
/* .gen_pdev_enable_adaptive_cca not implemented */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -7566,7 +7702,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
|
||||||
.pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
|
.pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
|
||||||
.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
|
.pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
|
||||||
.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
|
.pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
|
||||||
.pull_swba = ath10k_wmi_op_pull_swba_ev,
|
.pull_swba = ath10k_wmi_10_2_4_op_pull_swba_ev,
|
||||||
.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,
|
.pull_phyerr_hdr = ath10k_wmi_op_pull_phyerr_ev_hdr,
|
||||||
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
|
.pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
|
||||||
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
|
.pull_rdy = ath10k_wmi_op_pull_rdy_ev,
|
||||||
|
@ -7611,6 +7747,7 @@ static const struct wmi_ops wmi_10_2_4_ops = {
|
||||||
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
.fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill,
|
||||||
.gen_pdev_enable_adaptive_cca =
|
.gen_pdev_enable_adaptive_cca =
|
||||||
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
|
ath10k_wmi_op_gen_pdev_enable_adaptive_cca,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype,
|
||||||
/* .gen_bcn_tmpl not implemented */
|
/* .gen_bcn_tmpl not implemented */
|
||||||
/* .gen_prb_tmpl not implemented */
|
/* .gen_prb_tmpl not implemented */
|
||||||
/* .gen_p2p_go_bcn_ie not implemented */
|
/* .gen_p2p_go_bcn_ie not implemented */
|
||||||
|
@ -7677,6 +7814,7 @@ static const struct wmi_ops wmi_10_4_ops = {
|
||||||
/* shared with 10.2 */
|
/* shared with 10.2 */
|
||||||
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
|
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
|
||||||
.gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
|
.gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
|
||||||
|
.get_vdev_subtype = ath10k_wmi_10_4_op_get_vdev_subtype,
|
||||||
};
|
};
|
||||||
|
|
||||||
int ath10k_wmi_attach(struct ath10k *ar)
|
int ath10k_wmi_attach(struct ath10k *ar)
|
||||||
|
|
|
@ -176,7 +176,10 @@ enum wmi_service {
|
||||||
WMI_SERVICE_AUX_CHAN_LOAD_INTF,
|
WMI_SERVICE_AUX_CHAN_LOAD_INTF,
|
||||||
WMI_SERVICE_BSS_CHANNEL_INFO_64,
|
WMI_SERVICE_BSS_CHANNEL_INFO_64,
|
||||||
WMI_SERVICE_EXT_RES_CFG_SUPPORT,
|
WMI_SERVICE_EXT_RES_CFG_SUPPORT,
|
||||||
WMI_SERVICE_MESH,
|
WMI_SERVICE_MESH_11S,
|
||||||
|
WMI_SERVICE_MESH_NON_11S,
|
||||||
|
WMI_SERVICE_PEER_STATS,
|
||||||
|
WMI_SERVICE_RESTRT_CHNL_SUPPORT,
|
||||||
|
|
||||||
/* keep last */
|
/* keep last */
|
||||||
WMI_SERVICE_MAX,
|
WMI_SERVICE_MAX,
|
||||||
|
@ -213,6 +216,7 @@ enum wmi_10x_service {
|
||||||
WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
|
WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
|
||||||
WMI_10X_SERVICE_MESH,
|
WMI_10X_SERVICE_MESH,
|
||||||
WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
|
WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
|
||||||
|
WMI_10X_SERVICE_PEER_STATS,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wmi_main_service {
|
enum wmi_main_service {
|
||||||
|
@ -294,7 +298,10 @@ enum wmi_10_4_service {
|
||||||
WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF,
|
WMI_10_4_SERVICE_AUX_CHAN_LOAD_INTF,
|
||||||
WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
|
WMI_10_4_SERVICE_BSS_CHANNEL_INFO_64,
|
||||||
WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
|
WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
|
||||||
WMI_10_4_SERVICE_MESH,
|
WMI_10_4_SERVICE_MESH_NON_11S,
|
||||||
|
WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
|
||||||
|
WMI_10_4_SERVICE_PEER_STATS,
|
||||||
|
WMI_10_4_SERVICE_MESH_11S,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline char *wmi_service_name(int service_id)
|
static inline char *wmi_service_name(int service_id)
|
||||||
|
@ -385,7 +392,10 @@ static inline char *wmi_service_name(int service_id)
|
||||||
SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
|
SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
|
||||||
SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
|
SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
|
||||||
SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT);
|
SVCSTR(WMI_SERVICE_EXT_RES_CFG_SUPPORT);
|
||||||
SVCSTR(WMI_SERVICE_MESH);
|
SVCSTR(WMI_SERVICE_MESH_11S);
|
||||||
|
SVCSTR(WMI_SERVICE_MESH_NON_11S);
|
||||||
|
SVCSTR(WMI_SERVICE_PEER_STATS);
|
||||||
|
SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT);
|
||||||
default:
|
default:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -460,9 +470,11 @@ static inline void wmi_10x_svc_map(const __le32 *in, unsigned long *out,
|
||||||
SVCMAP(WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
|
SVCMAP(WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
|
||||||
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
|
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
|
||||||
SVCMAP(WMI_10X_SERVICE_MESH,
|
SVCMAP(WMI_10X_SERVICE_MESH,
|
||||||
WMI_SERVICE_MESH, len);
|
WMI_SERVICE_MESH_11S, len);
|
||||||
SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
|
SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
|
||||||
WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
|
WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
|
||||||
|
SVCMAP(WMI_10X_SERVICE_PEER_STATS,
|
||||||
|
WMI_SERVICE_PEER_STATS, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
|
static inline void wmi_main_svc_map(const __le32 *in, unsigned long *out,
|
||||||
|
@ -623,8 +635,14 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
|
||||||
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
|
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
|
||||||
SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
|
SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
|
||||||
WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
|
WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
|
||||||
SVCMAP(WMI_10_4_SERVICE_MESH,
|
SVCMAP(WMI_10_4_SERVICE_MESH_NON_11S,
|
||||||
WMI_SERVICE_MESH, len);
|
WMI_SERVICE_MESH_NON_11S, len);
|
||||||
|
SVCMAP(WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
|
||||||
|
WMI_SERVICE_RESTRT_CHNL_SUPPORT, len);
|
||||||
|
SVCMAP(WMI_10_4_SERVICE_PEER_STATS,
|
||||||
|
WMI_SERVICE_PEER_STATS, len);
|
||||||
|
SVCMAP(WMI_10_4_SERVICE_MESH_11S,
|
||||||
|
WMI_SERVICE_MESH_11S, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef SVCMAP
|
#undef SVCMAP
|
||||||
|
@ -1800,7 +1818,6 @@ enum wmi_channel_change_cause {
|
||||||
#define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
|
#define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
|
||||||
|
|
||||||
#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */
|
#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */
|
||||||
#define WMI_10_4_MAX_SPATIAL_STREAM 4
|
|
||||||
|
|
||||||
/* HT Capabilities*/
|
/* HT Capabilities*/
|
||||||
#define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */
|
#define WMI_HT_CAP_ENABLED 0x0001 /* HT Enabled/ disabled */
|
||||||
|
@ -2417,6 +2434,7 @@ enum wmi_10_2_feature_mask {
|
||||||
WMI_10_2_RX_BATCH_MODE = BIT(0),
|
WMI_10_2_RX_BATCH_MODE = BIT(0),
|
||||||
WMI_10_2_ATF_CONFIG = BIT(1),
|
WMI_10_2_ATF_CONFIG = BIT(1),
|
||||||
WMI_10_2_COEX_GPIO = BIT(3),
|
WMI_10_2_COEX_GPIO = BIT(3),
|
||||||
|
WMI_10_2_PEER_STATS = BIT(7),
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wmi_resource_config_10_2 {
|
struct wmi_resource_config_10_2 {
|
||||||
|
@ -4227,7 +4245,13 @@ struct wmi_10_2_peer_stats {
|
||||||
|
|
||||||
struct wmi_10_2_4_peer_stats {
|
struct wmi_10_2_4_peer_stats {
|
||||||
struct wmi_10_2_peer_stats common;
|
struct wmi_10_2_peer_stats common;
|
||||||
__le32 unknown_value; /* FIXME: what is this word? */
|
__le32 peer_rssi_changed;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_10_2_4_ext_peer_stats {
|
||||||
|
struct wmi_10_2_peer_stats common;
|
||||||
|
__le32 peer_rssi_changed;
|
||||||
|
__le32 rx_duration;
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
struct wmi_10_4_peer_stats {
|
struct wmi_10_4_peer_stats {
|
||||||
|
@ -4270,12 +4294,40 @@ enum wmi_vdev_type {
|
||||||
};
|
};
|
||||||
|
|
||||||
enum wmi_vdev_subtype {
|
enum wmi_vdev_subtype {
|
||||||
WMI_VDEV_SUBTYPE_NONE = 0,
|
WMI_VDEV_SUBTYPE_NONE,
|
||||||
WMI_VDEV_SUBTYPE_P2P_DEVICE = 1,
|
WMI_VDEV_SUBTYPE_P2P_DEVICE,
|
||||||
WMI_VDEV_SUBTYPE_P2P_CLIENT = 2,
|
WMI_VDEV_SUBTYPE_P2P_CLIENT,
|
||||||
WMI_VDEV_SUBTYPE_P2P_GO = 3,
|
WMI_VDEV_SUBTYPE_P2P_GO,
|
||||||
WMI_VDEV_SUBTYPE_PROXY_STA = 4,
|
WMI_VDEV_SUBTYPE_PROXY_STA,
|
||||||
WMI_VDEV_SUBTYPE_MESH = 5,
|
WMI_VDEV_SUBTYPE_MESH_11S,
|
||||||
|
WMI_VDEV_SUBTYPE_MESH_NON_11S,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_vdev_subtype_legacy {
|
||||||
|
WMI_VDEV_SUBTYPE_LEGACY_NONE = 0,
|
||||||
|
WMI_VDEV_SUBTYPE_LEGACY_P2P_DEV = 1,
|
||||||
|
WMI_VDEV_SUBTYPE_LEGACY_P2P_CLI = 2,
|
||||||
|
WMI_VDEV_SUBTYPE_LEGACY_P2P_GO = 3,
|
||||||
|
WMI_VDEV_SUBTYPE_LEGACY_PROXY_STA = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_vdev_subtype_10_2_4 {
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_NONE = 0,
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_P2P_DEV = 1,
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_P2P_CLI = 2,
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_P2P_GO = 3,
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_PROXY_STA = 4,
|
||||||
|
WMI_VDEV_SUBTYPE_10_2_4_MESH_11S = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum wmi_vdev_subtype_10_4 {
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_NONE = 0,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_P2P_DEV = 1,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_P2P_CLI = 2,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_P2P_GO = 3,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_PROXY_STA = 4,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_MESH_NON_11S = 5,
|
||||||
|
WMI_VDEV_SUBTYPE_10_4_MESH_11S = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* values for vdev_subtype */
|
/* values for vdev_subtype */
|
||||||
|
@ -5442,6 +5494,16 @@ struct wmi_host_swba_event {
|
||||||
struct wmi_bcn_info bcn_info[0];
|
struct wmi_bcn_info bcn_info[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_10_2_4_bcn_info {
|
||||||
|
struct wmi_tim_info tim_info;
|
||||||
|
/* The 10.2.4 FW doesn't have p2p NOA info */
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct wmi_10_2_4_host_swba_event {
|
||||||
|
__le32 vdev_map;
|
||||||
|
struct wmi_10_2_4_bcn_info bcn_info[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
/* 16 words = 512 client + 1 word = for guard */
|
/* 16 words = 512 client + 1 word = for guard */
|
||||||
#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17
|
#define WMI_10_4_TIM_BITMAP_ARRAY_SIZE 17
|
||||||
|
|
||||||
|
@ -6436,5 +6498,7 @@ size_t ath10k_wmi_fw_stats_num_vdevs(struct list_head *head);
|
||||||
void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
|
void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
|
||||||
struct ath10k_fw_stats *fw_stats,
|
struct ath10k_fw_stats *fw_stats,
|
||||||
char *buf);
|
char *buf);
|
||||||
|
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
|
||||||
|
enum wmi_vdev_subtype subtype);
|
||||||
|
|
||||||
#endif /* _WMI_H_ */
|
#endif /* _WMI_H_ */
|
||||||
|
|
|
@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah,
|
||||||
|
|
||||||
static void ath9k_ani_restart(struct ath_hw *ah)
|
static void ath9k_ani_restart(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ar5416AniState *aniState;
|
struct ar5416AniState *aniState = &ah->ani;
|
||||||
|
|
||||||
if (!ah->curchan)
|
|
||||||
return;
|
|
||||||
|
|
||||||
aniState = &ah->ani;
|
|
||||||
aniState->listenTime = 0;
|
aniState->listenTime = 0;
|
||||||
|
|
||||||
ENABLE_REGWRITE_BUFFER(ah);
|
ENABLE_REGWRITE_BUFFER(ah);
|
||||||
|
@ -221,12 +217,7 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel,
|
||||||
|
|
||||||
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ar5416AniState *aniState;
|
struct ar5416AniState *aniState = &ah->ani;
|
||||||
|
|
||||||
if (!ah->curchan)
|
|
||||||
return;
|
|
||||||
|
|
||||||
aniState = &ah->ani;
|
|
||||||
|
|
||||||
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
|
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
|
||||||
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
|
ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false);
|
||||||
|
@ -281,12 +272,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
|
||||||
|
|
||||||
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ar5416AniState *aniState;
|
struct ar5416AniState *aniState = &ah->ani;
|
||||||
|
|
||||||
if (!ah->curchan)
|
|
||||||
return;
|
|
||||||
|
|
||||||
aniState = &ah->ani;
|
|
||||||
|
|
||||||
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
|
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
|
||||||
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
|
ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1,
|
||||||
|
@ -299,9 +285,7 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah)
|
||||||
*/
|
*/
|
||||||
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ar5416AniState *aniState;
|
struct ar5416AniState *aniState = &ah->ani;
|
||||||
|
|
||||||
aniState = &ah->ani;
|
|
||||||
|
|
||||||
/* lower OFDM noise immunity */
|
/* lower OFDM noise immunity */
|
||||||
if (aniState->ofdmNoiseImmunityLevel > 0 &&
|
if (aniState->ofdmNoiseImmunityLevel > 0 &&
|
||||||
|
@ -329,7 +313,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
int ofdm_nil, cck_nil;
|
int ofdm_nil, cck_nil;
|
||||||
|
|
||||||
if (!ah->curchan)
|
if (!chan)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
BUG_ON(aniState == NULL);
|
BUG_ON(aniState == NULL);
|
||||||
|
@ -416,14 +400,10 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah)
|
||||||
|
|
||||||
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
|
void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
{
|
{
|
||||||
struct ar5416AniState *aniState;
|
struct ar5416AniState *aniState = &ah->ani;
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
u32 ofdmPhyErrRate, cckPhyErrRate;
|
u32 ofdmPhyErrRate, cckPhyErrRate;
|
||||||
|
|
||||||
if (!ah->curchan)
|
|
||||||
return;
|
|
||||||
|
|
||||||
aniState = &ah->ani;
|
|
||||||
if (!ath9k_hw_ani_read_counters(ah))
|
if (!ath9k_hw_ani_read_counters(ah))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -450,7 +430,9 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
} else if (cckPhyErrRate > ah->config.cck_trig_high) {
|
} else if (cckPhyErrRate > ah->config.cck_trig_high) {
|
||||||
ath9k_hw_ani_cck_err_trigger(ah);
|
ath9k_hw_ani_cck_err_trigger(ah);
|
||||||
aniState->ofdmsTurn = true;
|
aniState->ofdmsTurn = true;
|
||||||
}
|
} else
|
||||||
|
return;
|
||||||
|
|
||||||
ath9k_ani_restart(ah);
|
ath9k_ani_restart(ah);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,19 +53,19 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int16_t ar9003_aic_find_valid(struct ath_aic_sram_info *cal_sram,
|
static int16_t ar9003_aic_find_valid(bool *cal_sram_valid,
|
||||||
bool dir, u8 index)
|
bool dir, u8 index)
|
||||||
{
|
{
|
||||||
int16_t i;
|
int16_t i;
|
||||||
|
|
||||||
if (dir) {
|
if (dir) {
|
||||||
for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
||||||
if (cal_sram[i].valid)
|
if (cal_sram_valid[i])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (i = index - 1; i >= 0; i--) {
|
for (i = index - 1; i >= 0; i--) {
|
||||||
if (cal_sram[i].valid)
|
if (cal_sram_valid[i])
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -264,7 +264,7 @@ static u8 ar9003_aic_cal_start(struct ath_hw *ah, u8 min_valid_count)
|
||||||
static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
{
|
{
|
||||||
struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
|
struct ath9k_hw_aic *aic = &ah->btcoex_hw.aic;
|
||||||
struct ath_aic_sram_info cal_sram[ATH_AIC_MAX_BT_CHANNEL];
|
bool cal_sram_valid[ATH_AIC_MAX_BT_CHANNEL];
|
||||||
struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL];
|
struct ath_aic_out_info aic_sram[ATH_AIC_MAX_BT_CHANNEL];
|
||||||
u32 dir_path_gain_idx, quad_path_gain_idx, value;
|
u32 dir_path_gain_idx, quad_path_gain_idx, value;
|
||||||
u32 fixed_com_att_db;
|
u32 fixed_com_att_db;
|
||||||
|
@ -272,33 +272,34 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
int16_t i;
|
int16_t i;
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
memset(&cal_sram, 0, sizeof(cal_sram));
|
memset(&cal_sram_valid, 0, sizeof(cal_sram_valid));
|
||||||
memset(&aic_sram, 0, sizeof(aic_sram));
|
memset(&aic_sram, 0, sizeof(aic_sram));
|
||||||
|
|
||||||
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
||||||
|
struct ath_aic_sram_info sram;
|
||||||
value = aic->aic_sram[i];
|
value = aic->aic_sram[i];
|
||||||
|
|
||||||
cal_sram[i].valid =
|
cal_sram_valid[i] = sram.valid =
|
||||||
MS(value, AR_PHY_AIC_SRAM_VALID);
|
MS(value, AR_PHY_AIC_SRAM_VALID);
|
||||||
cal_sram[i].rot_quad_att_db =
|
sram.rot_quad_att_db =
|
||||||
MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB);
|
MS(value, AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB);
|
||||||
cal_sram[i].vga_quad_sign =
|
sram.vga_quad_sign =
|
||||||
MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN);
|
MS(value, AR_PHY_AIC_SRAM_VGA_QUAD_SIGN);
|
||||||
cal_sram[i].rot_dir_att_db =
|
sram.rot_dir_att_db =
|
||||||
MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB);
|
MS(value, AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB);
|
||||||
cal_sram[i].vga_dir_sign =
|
sram.vga_dir_sign =
|
||||||
MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN);
|
MS(value, AR_PHY_AIC_SRAM_VGA_DIR_SIGN);
|
||||||
cal_sram[i].com_att_6db =
|
sram.com_att_6db =
|
||||||
MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB);
|
MS(value, AR_PHY_AIC_SRAM_COM_ATT_6DB);
|
||||||
|
|
||||||
if (cal_sram[i].valid) {
|
if (sram.valid) {
|
||||||
dir_path_gain_idx = cal_sram[i].rot_dir_att_db +
|
dir_path_gain_idx = sram.rot_dir_att_db +
|
||||||
com_att_db_table[cal_sram[i].com_att_6db];
|
com_att_db_table[sram.com_att_6db];
|
||||||
quad_path_gain_idx = cal_sram[i].rot_quad_att_db +
|
quad_path_gain_idx = sram.rot_quad_att_db +
|
||||||
com_att_db_table[cal_sram[i].com_att_6db];
|
com_att_db_table[sram.com_att_6db];
|
||||||
|
|
||||||
dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1;
|
dir_path_sign = (sram.vga_dir_sign) ? 1 : -1;
|
||||||
quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1;
|
quad_path_sign = (sram.vga_quad_sign) ? 1 : -1;
|
||||||
|
|
||||||
aic_sram[i].dir_path_gain_lin = dir_path_sign *
|
aic_sram[i].dir_path_gain_lin = dir_path_sign *
|
||||||
aic_lin_table[dir_path_gain_idx];
|
aic_lin_table[dir_path_gain_idx];
|
||||||
|
@ -310,16 +311,16 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
||||||
int16_t start_idx, end_idx;
|
int16_t start_idx, end_idx;
|
||||||
|
|
||||||
if (cal_sram[i].valid)
|
if (cal_sram_valid[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
start_idx = ar9003_aic_find_valid(cal_sram, 0, i);
|
start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i);
|
||||||
end_idx = ar9003_aic_find_valid(cal_sram, 1, i);
|
end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i);
|
||||||
|
|
||||||
if (start_idx < 0) {
|
if (start_idx < 0) {
|
||||||
/* extrapolation */
|
/* extrapolation */
|
||||||
start_idx = end_idx;
|
start_idx = end_idx;
|
||||||
end_idx = ar9003_aic_find_valid(cal_sram, 1, start_idx);
|
end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, start_idx);
|
||||||
|
|
||||||
if (end_idx < 0) {
|
if (end_idx < 0) {
|
||||||
ret = false;
|
ret = false;
|
||||||
|
@ -342,7 +343,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
|
|
||||||
if (end_idx < 0) {
|
if (end_idx < 0) {
|
||||||
/* extrapolation */
|
/* extrapolation */
|
||||||
end_idx = ar9003_aic_find_valid(cal_sram, 0, start_idx);
|
end_idx = ar9003_aic_find_valid(cal_sram_valid, 0, start_idx);
|
||||||
|
|
||||||
if (end_idx < 0) {
|
if (end_idx < 0) {
|
||||||
ret = false;
|
ret = false;
|
||||||
|
@ -378,19 +379,21 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* From dir/quad_path_gain_lin to sram. */
|
/* From dir/quad_path_gain_lin to sram. */
|
||||||
i = ar9003_aic_find_valid(cal_sram, 1, 0);
|
i = ar9003_aic_find_valid(cal_sram_valid, 1, 0);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
i = 0;
|
i = 0;
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
fixed_com_att_db = com_att_db_table[cal_sram[i].com_att_6db];
|
fixed_com_att_db = com_att_db_table[MS(aic->aic_sram[i],
|
||||||
|
AR_PHY_AIC_SRAM_COM_ATT_6DB)];
|
||||||
|
|
||||||
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
||||||
int16_t rot_dir_path_att_db, rot_quad_path_att_db;
|
int16_t rot_dir_path_att_db, rot_quad_path_att_db;
|
||||||
|
struct ath_aic_sram_info sram;
|
||||||
|
|
||||||
aic_sram[i].sram.vga_dir_sign =
|
sram.vga_dir_sign =
|
||||||
(aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0;
|
(aic_sram[i].dir_path_gain_lin >= 0) ? 1 : 0;
|
||||||
aic_sram[i].sram.vga_quad_sign=
|
sram.vga_quad_sign =
|
||||||
(aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
|
(aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
|
||||||
|
|
||||||
rot_dir_path_att_db =
|
rot_dir_path_att_db =
|
||||||
|
@ -400,33 +403,31 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
|
||||||
ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) -
|
ar9003_aic_find_index(0, abs(aic_sram[i].quad_path_gain_lin)) -
|
||||||
fixed_com_att_db;
|
fixed_com_att_db;
|
||||||
|
|
||||||
aic_sram[i].sram.com_att_6db =
|
sram.com_att_6db =
|
||||||
ar9003_aic_find_index(1, fixed_com_att_db);
|
ar9003_aic_find_index(1, fixed_com_att_db);
|
||||||
|
|
||||||
aic_sram[i].sram.valid = 1;
|
sram.valid = 1;
|
||||||
|
|
||||||
aic_sram[i].sram.rot_dir_att_db =
|
sram.rot_dir_att_db =
|
||||||
min(max(rot_dir_path_att_db,
|
min(max(rot_dir_path_att_db,
|
||||||
(int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
|
(int16_t)ATH_AIC_MIN_ROT_DIR_ATT_DB),
|
||||||
ATH_AIC_MAX_ROT_DIR_ATT_DB);
|
ATH_AIC_MAX_ROT_DIR_ATT_DB);
|
||||||
aic_sram[i].sram.rot_quad_att_db =
|
sram.rot_quad_att_db =
|
||||||
min(max(rot_quad_path_att_db,
|
min(max(rot_quad_path_att_db,
|
||||||
(int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
|
(int16_t)ATH_AIC_MIN_ROT_QUAD_ATT_DB),
|
||||||
ATH_AIC_MAX_ROT_QUAD_ATT_DB);
|
ATH_AIC_MAX_ROT_QUAD_ATT_DB);
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
|
aic->aic_sram[i] = (SM(sram.vga_dir_sign,
|
||||||
aic->aic_sram[i] = (SM(aic_sram[i].sram.vga_dir_sign,
|
|
||||||
AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
|
AR_PHY_AIC_SRAM_VGA_DIR_SIGN) |
|
||||||
SM(aic_sram[i].sram.vga_quad_sign,
|
SM(sram.vga_quad_sign,
|
||||||
AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) |
|
AR_PHY_AIC_SRAM_VGA_QUAD_SIGN) |
|
||||||
SM(aic_sram[i].sram.com_att_6db,
|
SM(sram.com_att_6db,
|
||||||
AR_PHY_AIC_SRAM_COM_ATT_6DB) |
|
AR_PHY_AIC_SRAM_COM_ATT_6DB) |
|
||||||
SM(aic_sram[i].sram.valid,
|
SM(sram.valid,
|
||||||
AR_PHY_AIC_SRAM_VALID) |
|
AR_PHY_AIC_SRAM_VALID) |
|
||||||
SM(aic_sram[i].sram.rot_dir_att_db,
|
SM(sram.rot_dir_att_db,
|
||||||
AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) |
|
AR_PHY_AIC_SRAM_ROT_DIR_ATT_DB) |
|
||||||
SM(aic_sram[i].sram.rot_quad_att_db,
|
SM(sram.rot_quad_att_db,
|
||||||
AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB));
|
AR_PHY_AIC_SRAM_ROT_QUAD_ATT_DB));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ struct ath_aic_sram_info {
|
||||||
struct ath_aic_out_info {
|
struct ath_aic_out_info {
|
||||||
int16_t dir_path_gain_lin;
|
int16_t dir_path_gain_lin;
|
||||||
int16_t quad_path_gain_lin;
|
int16_t quad_path_gain_lin;
|
||||||
struct ath_aic_sram_info sram;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
u8 ar9003_aic_calibration(struct ath_hw *ah);
|
u8 ar9003_aic_calibration(struct ath_hw *ah);
|
||||||
|
|
|
@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
|
||||||
AR9300_PAPRD_SCALE_1);
|
AR9300_PAPRD_SCALE_1);
|
||||||
else {
|
else {
|
||||||
if (chan->channel >= 5700)
|
if (chan->channel >= 5700)
|
||||||
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
|
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
|
||||||
AR9300_PAPRD_SCALE_1);
|
AR9300_PAPRD_SCALE_1);
|
||||||
else if (chan->channel >= 5400)
|
else if (chan->channel >= 5400)
|
||||||
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
||||||
AR9300_PAPRD_SCALE_2);
|
AR9300_PAPRD_SCALE_2);
|
||||||
else
|
else
|
||||||
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
|
||||||
AR9300_PAPRD_SCALE_1);
|
AR9300_PAPRD_SCALE_1);
|
||||||
|
|
|
@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
|
||||||
else if (AR_SREV_9340(ah))
|
else if (AR_SREV_9340(ah))
|
||||||
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||||
ar9340Modes_low_ob_db_tx_gain_table_1p0);
|
ar9340Modes_low_ob_db_tx_gain_table_1p0);
|
||||||
|
else if (AR_SREV_9531_11(ah))
|
||||||
|
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||||
|
qca953x_1p1_modes_no_xpa_low_power_tx_gain_table);
|
||||||
else if (AR_SREV_9485_11_OR_LATER(ah))
|
else if (AR_SREV_9485_11_OR_LATER(ah))
|
||||||
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
INIT_INI_ARRAY(&ah->iniModesTxGain,
|
||||||
ar9485Modes_low_ob_db_tx_gain_1_1);
|
ar9485Modes_low_ob_db_tx_gain_1_1);
|
||||||
|
|
|
@ -976,9 +976,14 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
|
||||||
/*
|
/*
|
||||||
* JAPAN regulatory.
|
* JAPAN regulatory.
|
||||||
*/
|
*/
|
||||||
if (chan->channel == 2484)
|
if (chan->channel == 2484) {
|
||||||
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
|
ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
|
||||||
|
|
||||||
|
if (AR_SREV_9531(ah))
|
||||||
|
REG_RMW_FIELD(ah, AR_PHY_FCAL_2_0,
|
||||||
|
AR_PHY_FLC_PWR_THRESH, 0);
|
||||||
|
}
|
||||||
|
|
||||||
ah->modes_index = modesIndex;
|
ah->modes_index = modesIndex;
|
||||||
ar9003_hw_override_ini(ah);
|
ar9003_hw_override_ini(ah);
|
||||||
ar9003_hw_set_channel_regs(ah, chan);
|
ar9003_hw_set_channel_regs(ah, chan);
|
||||||
|
@ -2071,7 +2076,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
|
||||||
* to be disabled.
|
* to be disabled.
|
||||||
*
|
*
|
||||||
* 0x04000409: Packet stuck on receive.
|
* 0x04000409: Packet stuck on receive.
|
||||||
* Full chip reset is required for all chips except AR9340.
|
* Full chip reset is required for all chips except
|
||||||
|
* AR9340, AR9531 and AR9561.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2100,7 +2106,7 @@ bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
|
||||||
case 0x04000b09:
|
case 0x04000b09:
|
||||||
return true;
|
return true;
|
||||||
case 0x04000409:
|
case 0x04000409:
|
||||||
if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
|
if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah))
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -487,6 +487,9 @@
|
||||||
#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150)
|
#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150)
|
||||||
#define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158)
|
#define AR_PHY_XPA_CFG (AR_SM_BASE + 0x158)
|
||||||
|
|
||||||
|
#define AR_PHY_FLC_PWR_THRESH 7
|
||||||
|
#define AR_PHY_FLC_PWR_THRESH_S 0
|
||||||
|
|
||||||
#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3
|
#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW 3
|
||||||
#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0
|
#define AR_PHY_FRAME_CTL_CF_OVERLAP_WINDOW_S 0
|
||||||
|
|
||||||
|
|
|
@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = {
|
||||||
{0x00016448, 0x6c927a70},
|
{0x00016448, 0x6c927a70},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const u32 qca953x_1p1_modes_no_xpa_low_power_tx_gain_table[][2] = {
|
||||||
|
/* Addr allmodes */
|
||||||
|
{0x0000a2dc, 0xfff55592},
|
||||||
|
{0x0000a2e0, 0xfff99924},
|
||||||
|
{0x0000a2e4, 0xfffe1e00},
|
||||||
|
{0x0000a2e8, 0xffffe000},
|
||||||
|
{0x0000a410, 0x000050d6},
|
||||||
|
{0x0000a500, 0x00000069},
|
||||||
|
{0x0000a504, 0x0400006b},
|
||||||
|
{0x0000a508, 0x0800006d},
|
||||||
|
{0x0000a50c, 0x0c000269},
|
||||||
|
{0x0000a510, 0x1000026b},
|
||||||
|
{0x0000a514, 0x1400026d},
|
||||||
|
{0x0000a518, 0x18000669},
|
||||||
|
{0x0000a51c, 0x1c00066b},
|
||||||
|
{0x0000a520, 0x1d000a68},
|
||||||
|
{0x0000a524, 0x21000a6a},
|
||||||
|
{0x0000a528, 0x25000a6c},
|
||||||
|
{0x0000a52c, 0x29000a6e},
|
||||||
|
{0x0000a530, 0x2d0012a9},
|
||||||
|
{0x0000a534, 0x310012ab},
|
||||||
|
{0x0000a538, 0x350012ad},
|
||||||
|
{0x0000a53c, 0x39001b0a},
|
||||||
|
{0x0000a540, 0x3d001b0c},
|
||||||
|
{0x0000a544, 0x41001b0e},
|
||||||
|
{0x0000a548, 0x43001bae},
|
||||||
|
{0x0000a54c, 0x45001914},
|
||||||
|
{0x0000a550, 0x47001916},
|
||||||
|
{0x0000a554, 0x49001b96},
|
||||||
|
{0x0000a558, 0x49001b96},
|
||||||
|
{0x0000a55c, 0x49001b96},
|
||||||
|
{0x0000a560, 0x49001b96},
|
||||||
|
{0x0000a564, 0x49001b96},
|
||||||
|
{0x0000a568, 0x49001b96},
|
||||||
|
{0x0000a56c, 0x49001b96},
|
||||||
|
{0x0000a570, 0x49001b96},
|
||||||
|
{0x0000a574, 0x49001b96},
|
||||||
|
{0x0000a578, 0x49001b96},
|
||||||
|
{0x0000a57c, 0x49001b96},
|
||||||
|
{0x0000a600, 0x00000000},
|
||||||
|
{0x0000a604, 0x00000000},
|
||||||
|
{0x0000a608, 0x00000000},
|
||||||
|
{0x0000a60c, 0x00000000},
|
||||||
|
{0x0000a610, 0x00000000},
|
||||||
|
{0x0000a614, 0x00000000},
|
||||||
|
{0x0000a618, 0x00804201},
|
||||||
|
{0x0000a61c, 0x01408201},
|
||||||
|
{0x0000a620, 0x01408502},
|
||||||
|
{0x0000a624, 0x01408502},
|
||||||
|
{0x0000a628, 0x01408502},
|
||||||
|
{0x0000a62c, 0x01408502},
|
||||||
|
{0x0000a630, 0x01408502},
|
||||||
|
{0x0000a634, 0x01408502},
|
||||||
|
{0x0000a638, 0x01408502},
|
||||||
|
{0x0000a63c, 0x01408502},
|
||||||
|
{0x0000b2dc, 0xfff55592},
|
||||||
|
{0x0000b2e0, 0xfff99924},
|
||||||
|
{0x0000b2e4, 0xfffe1e00},
|
||||||
|
{0x0000b2e8, 0xffffe000},
|
||||||
|
{0x00016044, 0x044922db},
|
||||||
|
{0x00016048, 0x6c927a70},
|
||||||
|
{0x00016444, 0x044922db},
|
||||||
|
{0x00016448, 0x6c927a70},
|
||||||
|
};
|
||||||
|
|
||||||
static const u32 qca953x_2p0_baseband_core[][2] = {
|
static const u32 qca953x_2p0_baseband_core[][2] = {
|
||||||
/* Addr allmodes */
|
/* Addr allmodes */
|
||||||
{0x00009800, 0xafe68e30},
|
{0x00009800, 0xafe68e30},
|
||||||
|
|
|
@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
|
||||||
struct ath_common *common = ath9k_hw_common(ah);
|
struct ath_common *common = ath9k_hw_common(ah);
|
||||||
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
|
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
|
||||||
|
u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
|
||||||
|
|
||||||
if (ah->caldata)
|
if (ah->caldata)
|
||||||
h = ah->caldata->nfCalHist;
|
h = ah->caldata->nfCalHist;
|
||||||
|
@ -263,6 +264,16 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* stop NF cal if ongoing to ensure NF load completes immediately
|
||||||
|
* (or after end rx/tx frame if ongoing)
|
||||||
|
*/
|
||||||
|
if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
|
||||||
|
REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||||
|
REG_RMW_BUFFER_FLUSH(ah);
|
||||||
|
ENABLE_REG_RMW_BUFFER(ah);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load software filtered NF value into baseband internal minCCApwr
|
* Load software filtered NF value into baseband internal minCCApwr
|
||||||
* variable.
|
* variable.
|
||||||
|
@ -276,17 +287,32 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for load to complete, should be fast, a few 10s of us.
|
* Wait for load to complete, should be fast, a few 10s of us.
|
||||||
* The max delay was changed from an original 250us to 10000us
|
* The max delay was changed from an original 250us to 22.2 msec.
|
||||||
* since 250us often results in NF load timeout and causes deaf
|
* This would increase timeout to the longest possible frame
|
||||||
* condition during stress testing 12/12/2009
|
* (11n max length 22.1 msec)
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < 10000; j++) {
|
for (j = 0; j < 22200; j++) {
|
||||||
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
|
if ((REG_READ(ah, AR_PHY_AGC_CONTROL) &
|
||||||
AR_PHY_AGC_CONTROL_NF) == 0)
|
AR_PHY_AGC_CONTROL_NF) == 0)
|
||||||
break;
|
break;
|
||||||
udelay(10);
|
udelay(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Restart NF so it can continue.
|
||||||
|
*/
|
||||||
|
if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NF) {
|
||||||
|
ENABLE_REG_RMW_BUFFER(ah);
|
||||||
|
if (bb_agc_ctl & AR_PHY_AGC_CONTROL_ENABLE_NF)
|
||||||
|
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||||
|
AR_PHY_AGC_CONTROL_ENABLE_NF);
|
||||||
|
if (bb_agc_ctl & AR_PHY_AGC_CONTROL_NO_UPDATE_NF)
|
||||||
|
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
|
||||||
|
AR_PHY_AGC_CONTROL_NO_UPDATE_NF);
|
||||||
|
REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF);
|
||||||
|
REG_RMW_BUFFER_FLUSH(ah);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We timed out waiting for the noisefloor to load, probably due to an
|
* We timed out waiting for the noisefloor to load, probably due to an
|
||||||
* in-progress rx. Simply return here and allow the load plenty of time
|
* in-progress rx. Simply return here and allow the load plenty of time
|
||||||
|
@ -296,7 +322,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
|
||||||
* here, the baseband nf cal will just be capped by our present
|
* here, the baseband nf cal will just be capped by our present
|
||||||
* noisefloor until the next calibration timer.
|
* noisefloor until the next calibration timer.
|
||||||
*/
|
*/
|
||||||
if (j == 10000) {
|
if (j == 22200) {
|
||||||
ath_dbg(common, ANY,
|
ath_dbg(common, ANY,
|
||||||
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
|
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
|
||||||
REG_READ(ah, AR_PHY_AGC_CONTROL));
|
REG_READ(ah, AR_PHY_AGC_CONTROL));
|
||||||
|
|
|
@ -226,7 +226,7 @@ static const char *chanctx_state_string(enum ath_chanctx_state state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const u32 chanctx_event_delta(struct ath_softc *sc)
|
static u32 chanctx_event_delta(struct ath_softc *sc)
|
||||||
{
|
{
|
||||||
u64 ms;
|
u64 ms;
|
||||||
struct timespec ts, *old;
|
struct timespec ts, *old;
|
||||||
|
@ -1454,7 +1454,7 @@ static void ath9k_update_p2p_ps(struct ath_softc *sc, struct ieee80211_vif *vif)
|
||||||
if (!sc->p2p_ps_timer)
|
if (!sc->p2p_ps_timer)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
|
if (vif->type != NL80211_IFTYPE_STATION)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
sc->p2p_ps_vif = avp;
|
sc->p2p_ps_vif = avp;
|
||||||
|
|
|
@ -55,6 +55,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
|
||||||
.driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */
|
.driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */
|
||||||
{ USB_DEVICE(0x04da, 0x3904),
|
{ USB_DEVICE(0x04da, 0x3904),
|
||||||
.driver_info = AR9280_USB },
|
.driver_info = AR9280_USB },
|
||||||
|
{ USB_DEVICE(0x0930, 0x0a08),
|
||||||
|
.driver_info = AR9280_USB }, /* Toshiba WLM-20U2 and GN-1080 */
|
||||||
|
|
||||||
{ USB_DEVICE(0x0cf3, 0x20ff),
|
{ USB_DEVICE(0x0cf3, 0x20ff),
|
||||||
.driver_info = STORAGE_DEVICE },
|
.driver_info = STORAGE_DEVICE },
|
||||||
|
|
|
@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
|
||||||
if (ath9k_hw_mci_is_enabled(ah))
|
if (ath9k_hw_mci_is_enabled(ah))
|
||||||
ar9003_mci_check_gpm_offset(ah);
|
ar9003_mci_check_gpm_offset(ah);
|
||||||
|
|
||||||
|
/* DMA HALT added to resolve ar9300 and ar9580 bus error during
|
||||||
|
* RTC_RC reg read
|
||||||
|
*/
|
||||||
|
if (AR_SREV_9300(ah) || AR_SREV_9580(ah)) {
|
||||||
|
REG_SET_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
|
||||||
|
ath9k_hw_wait(ah, AR_CFG, AR_CFG_HALT_ACK, AR_CFG_HALT_ACK,
|
||||||
|
20 * AH_WAIT_TIMEOUT);
|
||||||
|
REG_CLR_BIT(ah, AR_CFG, AR_CFG_HALT_REQ);
|
||||||
|
}
|
||||||
|
|
||||||
REG_WRITE(ah, AR_RTC_RC, rst_flags);
|
REG_WRITE(ah, AR_RTC_RC, rst_flags);
|
||||||
|
|
||||||
REGWRITE_BUFFER_FLUSH(ah);
|
REGWRITE_BUFFER_FLUSH(ah);
|
||||||
|
|
|
@ -751,14 +751,6 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
|
||||||
|
|
||||||
#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
|
#endif /* CONFIG_ATH9K_CHANNEL_CONTEXT */
|
||||||
|
|
||||||
static const struct ieee80211_iface_limit if_dfs_limits[] = {
|
|
||||||
{ .max = 1, .types = BIT(NL80211_IFTYPE_AP) |
|
|
||||||
#ifdef CONFIG_MAC80211_MESH
|
|
||||||
BIT(NL80211_IFTYPE_MESH_POINT) |
|
|
||||||
#endif
|
|
||||||
BIT(NL80211_IFTYPE_ADHOC) },
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct ieee80211_iface_combination if_comb[] = {
|
static const struct ieee80211_iface_combination if_comb[] = {
|
||||||
{
|
{
|
||||||
.limits = if_limits,
|
.limits = if_limits,
|
||||||
|
@ -766,6 +758,11 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
||||||
.max_interfaces = 2048,
|
.max_interfaces = 2048,
|
||||||
.num_different_channels = 1,
|
.num_different_channels = 1,
|
||||||
.beacon_int_infra_match = true,
|
.beacon_int_infra_match = true,
|
||||||
|
#ifdef CONFIG_ATH9K_DFS_CERTIFIED
|
||||||
|
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
||||||
|
BIT(NL80211_CHAN_WIDTH_20) |
|
||||||
|
BIT(NL80211_CHAN_WIDTH_40),
|
||||||
|
#endif
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
.limits = wds_limits,
|
.limits = wds_limits,
|
||||||
|
@ -774,18 +771,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
|
||||||
.num_different_channels = 1,
|
.num_different_channels = 1,
|
||||||
.beacon_int_infra_match = true,
|
.beacon_int_infra_match = true,
|
||||||
},
|
},
|
||||||
#ifdef CONFIG_ATH9K_DFS_CERTIFIED
|
|
||||||
{
|
|
||||||
.limits = if_dfs_limits,
|
|
||||||
.n_limits = ARRAY_SIZE(if_dfs_limits),
|
|
||||||
.max_interfaces = 1,
|
|
||||||
.num_different_channels = 1,
|
|
||||||
.beacon_int_infra_match = true,
|
|
||||||
.radar_detect_widths = BIT(NL80211_CHAN_WIDTH_20_NOHT) |
|
|
||||||
BIT(NL80211_CHAN_WIDTH_20) |
|
|
||||||
BIT(NL80211_CHAN_WIDTH_40),
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
|
#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
|
||||||
|
|
|
@ -978,7 +978,7 @@ static void ath9k_update_bssid_mask(struct ath_softc *sc,
|
||||||
if (ctx->nvifs_assigned != 1)
|
if (ctx->nvifs_assigned != 1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!avp->vif->p2p || !iter_data->has_hw_macaddr)
|
if (!iter_data->has_hw_macaddr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ether_addr_copy(common->curbssid, avp->bssid);
|
ether_addr_copy(common->curbssid, avp->bssid);
|
||||||
|
@ -1255,6 +1255,9 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
|
||||||
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
|
ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type);
|
||||||
sc->cur_chan->nvifs++;
|
sc->cur_chan->nvifs++;
|
||||||
|
|
||||||
|
if (vif->type == NL80211_IFTYPE_STATION && ath9k_is_chanctx_enabled())
|
||||||
|
vif->driver_flags |= IEEE80211_VIF_GET_NOA_UPDATE;
|
||||||
|
|
||||||
if (ath9k_uses_beacons(vif->type))
|
if (ath9k_uses_beacons(vif->type))
|
||||||
ath9k_beacon_assign_slot(sc, vif);
|
ath9k_beacon_assign_slot(sc, vif);
|
||||||
|
|
||||||
|
|
|
@ -34,8 +34,10 @@
|
||||||
#define AR_CFG_SWRG 0x00000010
|
#define AR_CFG_SWRG 0x00000010
|
||||||
#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
|
#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
|
||||||
#define AR_CFG_PHOK 0x00000100
|
#define AR_CFG_PHOK 0x00000100
|
||||||
#define AR_CFG_CLK_GATE_DIS 0x00000400
|
|
||||||
#define AR_CFG_EEBS 0x00000200
|
#define AR_CFG_EEBS 0x00000200
|
||||||
|
#define AR_CFG_CLK_GATE_DIS 0x00000400
|
||||||
|
#define AR_CFG_HALT_REQ 0x00000800
|
||||||
|
#define AR_CFG_HALT_ACK 0x00001000
|
||||||
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000
|
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH 0x00060000
|
||||||
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17
|
#define AR_CFG_PCI_MASTER_REQ_Q_THRESH_S 17
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -535,7 +535,18 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
|
||||||
|
|
||||||
wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
|
wil_dbg_misc(wil, "%s(reason=%d)\n", __func__, reason_code);
|
||||||
|
|
||||||
rc = wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
|
if (!(test_bit(wil_status_fwconnecting, wil->status) ||
|
||||||
|
test_bit(wil_status_fwconnected, wil->status))) {
|
||||||
|
wil_err(wil, "%s: Disconnect was called while disconnected\n",
|
||||||
|
__func__);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
|
||||||
|
WMI_DISCONNECT_EVENTID, NULL, 0,
|
||||||
|
WIL6210_DISCONNECT_TO_MS);
|
||||||
|
if (rc)
|
||||||
|
wil_err(wil, "%s: disconnect error %d\n", __func__, rc);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -696,6 +707,79 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* find a specific IE in a list of IEs
|
||||||
|
* return a pointer to the beginning of IE in the list
|
||||||
|
* or NULL if not found
|
||||||
|
*/
|
||||||
|
static const u8 *_wil_cfg80211_find_ie(const u8 *ies, u16 ies_len, const u8 *ie,
|
||||||
|
u16 ie_len)
|
||||||
|
{
|
||||||
|
struct ieee80211_vendor_ie *vie;
|
||||||
|
u32 oui;
|
||||||
|
|
||||||
|
/* IE tag at offset 0, length at offset 1 */
|
||||||
|
if (ie_len < 2 || 2 + ie[1] > ie_len)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (ie[0] != WLAN_EID_VENDOR_SPECIFIC)
|
||||||
|
return cfg80211_find_ie(ie[0], ies, ies_len);
|
||||||
|
|
||||||
|
/* make sure there is room for 3 bytes OUI + 1 byte OUI type */
|
||||||
|
if (ie[1] < 4)
|
||||||
|
return NULL;
|
||||||
|
vie = (struct ieee80211_vendor_ie *)ie;
|
||||||
|
oui = vie->oui[0] << 16 | vie->oui[1] << 8 | vie->oui[2];
|
||||||
|
return cfg80211_find_vendor_ie(oui, vie->oui_type, ies,
|
||||||
|
ies_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* merge the IEs in two lists into a single list.
|
||||||
|
* do not include IEs from the second list which exist in the first list.
|
||||||
|
* add only vendor specific IEs from second list to keep
|
||||||
|
* the merged list sorted (since vendor-specific IE has the
|
||||||
|
* highest tag number)
|
||||||
|
* caller must free the allocated memory for merged IEs
|
||||||
|
*/
|
||||||
|
static int _wil_cfg80211_merge_extra_ies(const u8 *ies1, u16 ies1_len,
|
||||||
|
const u8 *ies2, u16 ies2_len,
|
||||||
|
u8 **merged_ies, u16 *merged_len)
|
||||||
|
{
|
||||||
|
u8 *buf, *dpos;
|
||||||
|
const u8 *spos;
|
||||||
|
|
||||||
|
if (ies1_len == 0 && ies2_len == 0) {
|
||||||
|
*merged_ies = NULL;
|
||||||
|
*merged_len = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = kmalloc(ies1_len + ies2_len, GFP_KERNEL);
|
||||||
|
if (!buf)
|
||||||
|
return -ENOMEM;
|
||||||
|
memcpy(buf, ies1, ies1_len);
|
||||||
|
dpos = buf + ies1_len;
|
||||||
|
spos = ies2;
|
||||||
|
while (spos + 1 < ies2 + ies2_len) {
|
||||||
|
/* IE tag at offset 0, length at offset 1 */
|
||||||
|
u16 ielen = 2 + spos[1];
|
||||||
|
|
||||||
|
if (spos + ielen > ies2 + ies2_len)
|
||||||
|
break;
|
||||||
|
if (spos[0] == WLAN_EID_VENDOR_SPECIFIC &&
|
||||||
|
!_wil_cfg80211_find_ie(ies1, ies1_len, spos, ielen)) {
|
||||||
|
memcpy(dpos, spos, ielen);
|
||||||
|
dpos += ielen;
|
||||||
|
}
|
||||||
|
spos += ielen;
|
||||||
|
}
|
||||||
|
|
||||||
|
*merged_ies = buf;
|
||||||
|
*merged_len = dpos - buf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
|
static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
|
||||||
{
|
{
|
||||||
print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET,
|
print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET,
|
||||||
|
@ -712,49 +796,49 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
|
||||||
b->assocresp_ies, b->assocresp_ies_len);
|
b->assocresp_ies, b->assocresp_ies_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int wil_fix_bcon(struct wil6210_priv *wil,
|
|
||||||
struct cfg80211_beacon_data *bcon)
|
|
||||||
{
|
|
||||||
struct ieee80211_mgmt *f = (struct ieee80211_mgmt *)bcon->probe_resp;
|
|
||||||
size_t hlen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
|
|
||||||
|
|
||||||
if (bcon->probe_resp_len <= hlen)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* always use IE's from full probe frame, they has more info
|
|
||||||
* notable RSN
|
|
||||||
*/
|
|
||||||
bcon->proberesp_ies = f->u.probe_resp.variable;
|
|
||||||
bcon->proberesp_ies_len = bcon->probe_resp_len - hlen;
|
|
||||||
if (!bcon->assocresp_ies) {
|
|
||||||
bcon->assocresp_ies = bcon->proberesp_ies;
|
|
||||||
bcon->assocresp_ies_len = bcon->proberesp_ies_len;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* internal functions for device reset and starting AP */
|
/* internal functions for device reset and starting AP */
|
||||||
static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
|
static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
|
||||||
struct cfg80211_beacon_data *bcon)
|
struct cfg80211_beacon_data *bcon)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
|
||||||
|
u16 len = 0, proberesp_len = 0;
|
||||||
|
u8 *ies = NULL, *proberesp = NULL;
|
||||||
|
|
||||||
|
if (bcon->probe_resp) {
|
||||||
|
struct ieee80211_mgmt *f =
|
||||||
|
(struct ieee80211_mgmt *)bcon->probe_resp;
|
||||||
|
size_t hlen = offsetof(struct ieee80211_mgmt,
|
||||||
|
u.probe_resp.variable);
|
||||||
|
proberesp = f->u.probe_resp.variable;
|
||||||
|
proberesp_len = bcon->probe_resp_len - hlen;
|
||||||
|
}
|
||||||
|
rc = _wil_cfg80211_merge_extra_ies(proberesp,
|
||||||
|
proberesp_len,
|
||||||
|
bcon->proberesp_ies,
|
||||||
|
bcon->proberesp_ies_len,
|
||||||
|
&ies, &len);
|
||||||
|
|
||||||
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, bcon->proberesp_ies_len,
|
|
||||||
bcon->proberesp_ies);
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
goto out;
|
||||||
|
|
||||||
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
|
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, ies);
|
||||||
bcon->assocresp_ies);
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
if (bcon->assocresp_ies)
|
||||||
|
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP,
|
||||||
|
bcon->assocresp_ies_len, bcon->assocresp_ies);
|
||||||
|
else
|
||||||
|
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, len, ies);
|
||||||
#if 0 /* to use beacon IE's, remove this #if 0 */
|
#if 0 /* to use beacon IE's, remove this #if 0 */
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
goto out;
|
||||||
|
|
||||||
rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
|
rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
|
||||||
#endif
|
#endif
|
||||||
|
out:
|
||||||
|
kfree(ies);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,14 +907,9 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
|
||||||
wil_dbg_misc(wil, "%s()\n", __func__);
|
wil_dbg_misc(wil, "%s()\n", __func__);
|
||||||
wil_print_bcon_data(bcon);
|
wil_print_bcon_data(bcon);
|
||||||
|
|
||||||
if (wil_fix_bcon(wil, bcon)) {
|
if (bcon->tail &&
|
||||||
wil_dbg_misc(wil, "Fixed bcon\n");
|
cfg80211_find_ie(WLAN_EID_RSN, bcon->tail,
|
||||||
wil_print_bcon_data(bcon);
|
bcon->tail_len))
|
||||||
}
|
|
||||||
|
|
||||||
if (bcon->proberesp_ies &&
|
|
||||||
cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies,
|
|
||||||
bcon->proberesp_ies_len))
|
|
||||||
privacy = 1;
|
privacy = 1;
|
||||||
|
|
||||||
/* in case privacy has changed, need to restart the AP */
|
/* in case privacy has changed, need to restart the AP */
|
||||||
|
@ -900,11 +979,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
|
||||||
wil_print_bcon_data(bcon);
|
wil_print_bcon_data(bcon);
|
||||||
wil_print_crypto(wil, crypto);
|
wil_print_crypto(wil, crypto);
|
||||||
|
|
||||||
if (wil_fix_bcon(wil, bcon)) {
|
|
||||||
wil_dbg_misc(wil, "Fixed bcon\n");
|
|
||||||
wil_print_bcon_data(bcon);
|
|
||||||
}
|
|
||||||
|
|
||||||
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
rc = _wil_cfg80211_start_ap(wiphy, ndev,
|
||||||
info->ssid, info->ssid_len, info->privacy,
|
info->ssid, info->ssid_len, info->privacy,
|
||||||
info->beacon_interval, channel->hw_value,
|
info->beacon_interval, channel->hw_value,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -68,13 +68,13 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
|
||||||
seq_puts(s, "???\n");
|
seq_puts(s, "???\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vring->va && (vring->size < 1025)) {
|
if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
|
||||||
uint i;
|
uint i;
|
||||||
|
|
||||||
for (i = 0; i < vring->size; i++) {
|
for (i = 0; i < vring->size; i++) {
|
||||||
volatile struct vring_tx_desc *d = &vring->va[i].tx;
|
volatile struct vring_tx_desc *d = &vring->va[i].tx;
|
||||||
|
|
||||||
if ((i % 64) == 0 && (i != 0))
|
if ((i % 128) == 0 && (i != 0))
|
||||||
seq_puts(s, "\n");
|
seq_puts(s, "\n");
|
||||||
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
|
seq_printf(s, "%c", (d->dma.status & BIT(0)) ?
|
||||||
_s : (vring->ctx[i].skb ? _h : 'h'));
|
_s : (vring->ctx[i].skb ? _h : 'h'));
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -23,9 +23,6 @@
|
||||||
#include "wmi.h"
|
#include "wmi.h"
|
||||||
#include "boot_loader.h"
|
#include "boot_loader.h"
|
||||||
|
|
||||||
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
|
|
||||||
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
|
|
||||||
|
|
||||||
bool debug_fw; /* = false; */
|
bool debug_fw; /* = false; */
|
||||||
module_param(debug_fw, bool, S_IRUGO);
|
module_param(debug_fw, bool, S_IRUGO);
|
||||||
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
|
MODULE_PARM_DESC(debug_fw, " do not perform card reset. For FW debug");
|
||||||
|
@ -155,7 +152,7 @@ __acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
|
||||||
|
|
||||||
if (sta->status != wil_sta_unused) {
|
if (sta->status != wil_sta_unused) {
|
||||||
if (!from_event)
|
if (!from_event)
|
||||||
wmi_disconnect_sta(wil, sta->addr, reason_code);
|
wmi_disconnect_sta(wil, sta->addr, reason_code, true);
|
||||||
|
|
||||||
switch (wdev->iftype) {
|
switch (wdev->iftype) {
|
||||||
case NL80211_IFTYPE_AP:
|
case NL80211_IFTYPE_AP:
|
||||||
|
@ -195,8 +192,8 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
|
||||||
struct wireless_dev *wdev = wil->wdev;
|
struct wireless_dev *wdev = wil->wdev;
|
||||||
|
|
||||||
might_sleep();
|
might_sleep();
|
||||||
wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
|
wil_info(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
|
||||||
reason_code, from_event ? "+" : "-");
|
reason_code, from_event ? "+" : "-");
|
||||||
|
|
||||||
/* Cases are:
|
/* Cases are:
|
||||||
* - disconnect single STA, still connected
|
* - disconnect single STA, still connected
|
||||||
|
@ -258,13 +255,16 @@ static void wil_disconnect_worker(struct work_struct *work)
|
||||||
static void wil_connect_timer_fn(ulong x)
|
static void wil_connect_timer_fn(ulong x)
|
||||||
{
|
{
|
||||||
struct wil6210_priv *wil = (void *)x;
|
struct wil6210_priv *wil = (void *)x;
|
||||||
|
bool q;
|
||||||
|
|
||||||
wil_dbg_misc(wil, "Connect timeout\n");
|
wil_err(wil, "Connect timeout detected, disconnect station\n");
|
||||||
|
|
||||||
/* reschedule to thread context - disconnect won't
|
/* reschedule to thread context - disconnect won't
|
||||||
* run from atomic context
|
* run from atomic context.
|
||||||
|
* queue on wmi_wq to prevent race with connect event.
|
||||||
*/
|
*/
|
||||||
schedule_work(&wil->disconnect_worker);
|
q = queue_work(wil->wmi_wq, &wil->disconnect_worker);
|
||||||
|
wil_dbg_wmi(wil, "queue_work of disconnect_worker -> %d\n", q);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wil_scan_timer_fn(ulong x)
|
static void wil_scan_timer_fn(ulong x)
|
||||||
|
@ -369,6 +369,32 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int wil_tx_init(struct wil6210_priv *wil, int cid)
|
||||||
|
{
|
||||||
|
int rc = -EINVAL, ringid;
|
||||||
|
|
||||||
|
if (cid < 0) {
|
||||||
|
wil_err(wil, "No connection pending\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
ringid = wil_find_free_vring(wil);
|
||||||
|
if (ringid < 0) {
|
||||||
|
wil_err(wil, "No free vring found\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
|
||||||
|
cid, ringid);
|
||||||
|
|
||||||
|
rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
|
||||||
|
if (rc)
|
||||||
|
wil_err(wil, "wil_vring_init_tx for CID %d vring %d failed\n",
|
||||||
|
cid, ringid);
|
||||||
|
|
||||||
|
out:
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
int wil_bcast_init(struct wil6210_priv *wil)
|
int wil_bcast_init(struct wil6210_priv *wil)
|
||||||
{
|
{
|
||||||
int ri = wil->bcast_vring, rc;
|
int ri = wil->bcast_vring, rc;
|
||||||
|
@ -399,41 +425,6 @@ void wil_bcast_fini(struct wil6210_priv *wil)
|
||||||
wil_vring_fini_tx(wil, ri);
|
wil_vring_fini_tx(wil, ri);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wil_connect_worker(struct work_struct *work)
|
|
||||||
{
|
|
||||||
int rc, cid, ringid;
|
|
||||||
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
|
|
||||||
connect_worker);
|
|
||||||
struct net_device *ndev = wil_to_ndev(wil);
|
|
||||||
|
|
||||||
mutex_lock(&wil->mutex);
|
|
||||||
|
|
||||||
cid = wil->pending_connect_cid;
|
|
||||||
if (cid < 0) {
|
|
||||||
wil_err(wil, "No connection pending\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
ringid = wil_find_free_vring(wil);
|
|
||||||
if (ringid < 0) {
|
|
||||||
wil_err(wil, "No free vring found\n");
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
wil_dbg_wmi(wil, "Configure for connection CID %d vring %d\n",
|
|
||||||
cid, ringid);
|
|
||||||
|
|
||||||
rc = wil_vring_init_tx(wil, ringid, 1 << tx_ring_order, cid, 0);
|
|
||||||
wil->pending_connect_cid = -1;
|
|
||||||
if (rc == 0) {
|
|
||||||
wil->sta[cid].status = wil_sta_connected;
|
|
||||||
netif_tx_wake_all_queues(ndev);
|
|
||||||
} else {
|
|
||||||
wil_disconnect_cid(wil, cid, WLAN_REASON_UNSPECIFIED, true);
|
|
||||||
}
|
|
||||||
out:
|
|
||||||
mutex_unlock(&wil->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
int wil_priv_init(struct wil6210_priv *wil)
|
int wil_priv_init(struct wil6210_priv *wil)
|
||||||
{
|
{
|
||||||
uint i;
|
uint i;
|
||||||
|
@ -444,6 +435,9 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||||
for (i = 0; i < WIL6210_MAX_CID; i++)
|
for (i = 0; i < WIL6210_MAX_CID; i++)
|
||||||
spin_lock_init(&wil->sta[i].tid_rx_lock);
|
spin_lock_init(&wil->sta[i].tid_rx_lock);
|
||||||
|
|
||||||
|
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++)
|
||||||
|
spin_lock_init(&wil->vring_tx_data[i].lock);
|
||||||
|
|
||||||
mutex_init(&wil->mutex);
|
mutex_init(&wil->mutex);
|
||||||
mutex_init(&wil->wmi_mutex);
|
mutex_init(&wil->wmi_mutex);
|
||||||
mutex_init(&wil->back_rx_mutex);
|
mutex_init(&wil->back_rx_mutex);
|
||||||
|
@ -453,12 +447,10 @@ int wil_priv_init(struct wil6210_priv *wil)
|
||||||
init_completion(&wil->wmi_ready);
|
init_completion(&wil->wmi_ready);
|
||||||
init_completion(&wil->wmi_call);
|
init_completion(&wil->wmi_call);
|
||||||
|
|
||||||
wil->pending_connect_cid = -1;
|
|
||||||
wil->bcast_vring = -1;
|
wil->bcast_vring = -1;
|
||||||
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
setup_timer(&wil->connect_timer, wil_connect_timer_fn, (ulong)wil);
|
||||||
setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
|
setup_timer(&wil->scan_timer, wil_scan_timer_fn, (ulong)wil);
|
||||||
|
|
||||||
INIT_WORK(&wil->connect_worker, wil_connect_worker);
|
|
||||||
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
|
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
|
||||||
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
|
||||||
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
|
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
|
||||||
|
@ -844,7 +836,6 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* init after reset */
|
/* init after reset */
|
||||||
wil->pending_connect_cid = -1;
|
|
||||||
wil->ap_isolate = 0;
|
wil->ap_isolate = 0;
|
||||||
reinit_completion(&wil->wmi_ready);
|
reinit_completion(&wil->wmi_ready);
|
||||||
reinit_completion(&wil->wmi_call);
|
reinit_completion(&wil->wmi_call);
|
||||||
|
@ -948,8 +939,7 @@ int wil_up(struct wil6210_priv *wil)
|
||||||
|
|
||||||
int __wil_down(struct wil6210_priv *wil)
|
int __wil_down(struct wil6210_priv *wil)
|
||||||
{
|
{
|
||||||
int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
|
int rc;
|
||||||
WAIT_FOR_DISCONNECT_INTERVAL_MS;
|
|
||||||
|
|
||||||
WARN_ON(!mutex_is_locked(&wil->mutex));
|
WARN_ON(!mutex_is_locked(&wil->mutex));
|
||||||
|
|
||||||
|
@ -973,22 +963,16 @@ int __wil_down(struct wil6210_priv *wil)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (test_bit(wil_status_fwconnected, wil->status) ||
|
if (test_bit(wil_status_fwconnected, wil->status) ||
|
||||||
test_bit(wil_status_fwconnecting, wil->status))
|
test_bit(wil_status_fwconnecting, wil->status)) {
|
||||||
wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
|
|
||||||
|
|
||||||
/* make sure wil is idle (not connected) */
|
mutex_unlock(&wil->mutex);
|
||||||
mutex_unlock(&wil->mutex);
|
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
|
||||||
while (iter--) {
|
WMI_DISCONNECT_EVENTID, NULL, 0,
|
||||||
int idle = !test_bit(wil_status_fwconnected, wil->status) &&
|
WIL6210_DISCONNECT_TO_MS);
|
||||||
!test_bit(wil_status_fwconnecting, wil->status);
|
mutex_lock(&wil->mutex);
|
||||||
if (idle)
|
if (rc)
|
||||||
break;
|
wil_err(wil, "timeout waiting for disconnect\n");
|
||||||
msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
|
|
||||||
}
|
}
|
||||||
mutex_lock(&wil->mutex);
|
|
||||||
|
|
||||||
if (iter < 0)
|
|
||||||
wil_err(wil, "timeout waiting for idle FW/HW\n");
|
|
||||||
|
|
||||||
wil_reset(wil, false);
|
wil_reset(wil, false);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -108,8 +108,9 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
|
||||||
/* always process ALL Tx complete, regardless budget - it is fast */
|
/* always process ALL Tx complete, regardless budget - it is fast */
|
||||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||||
struct vring *vring = &wil->vring_tx[i];
|
struct vring *vring = &wil->vring_tx[i];
|
||||||
|
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
|
||||||
|
|
||||||
if (!vring->va)
|
if (!vring->va || !txdata->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
tx_done += wil_tx_complete(wil, i);
|
tx_done += wil_tx_complete(wil, i);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -717,6 +717,21 @@ void wil_rx_fini(struct wil6210_priv *wil)
|
||||||
wil_vring_free(wil, vring, 0);
|
wil_vring_free(wil, vring, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline void wil_tx_data_init(struct vring_tx_data *txdata)
|
||||||
|
{
|
||||||
|
spin_lock_bh(&txdata->lock);
|
||||||
|
txdata->dot1x_open = 0;
|
||||||
|
txdata->enabled = 0;
|
||||||
|
txdata->idle = 0;
|
||||||
|
txdata->last_idle = 0;
|
||||||
|
txdata->begin = 0;
|
||||||
|
txdata->agg_wsize = 0;
|
||||||
|
txdata->agg_timeout = 0;
|
||||||
|
txdata->agg_amsdu = 0;
|
||||||
|
txdata->addba_in_progress = false;
|
||||||
|
spin_unlock_bh(&txdata->lock);
|
||||||
|
}
|
||||||
|
|
||||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||||
int cid, int tid)
|
int cid, int tid)
|
||||||
{
|
{
|
||||||
|
@ -758,8 +773,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(txdata, 0, sizeof(*txdata));
|
wil_tx_data_init(txdata);
|
||||||
spin_lock_init(&txdata->lock);
|
|
||||||
vring->size = size;
|
vring->size = size;
|
||||||
rc = wil_vring_alloc(wil, vring);
|
rc = wil_vring_alloc(wil, vring);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -791,9 +805,14 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_free:
|
out_free:
|
||||||
|
spin_lock_bh(&txdata->lock);
|
||||||
txdata->dot1x_open = false;
|
txdata->dot1x_open = false;
|
||||||
txdata->enabled = 0;
|
txdata->enabled = 0;
|
||||||
|
spin_unlock_bh(&txdata->lock);
|
||||||
wil_vring_free(wil, vring, 1);
|
wil_vring_free(wil, vring, 1);
|
||||||
|
wil->vring2cid_tid[id][0] = WIL6210_MAX_CID;
|
||||||
|
wil->vring2cid_tid[id][1] = 0;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -831,8 +850,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
memset(txdata, 0, sizeof(*txdata));
|
wil_tx_data_init(txdata);
|
||||||
spin_lock_init(&txdata->lock);
|
|
||||||
vring->size = size;
|
vring->size = size;
|
||||||
rc = wil_vring_alloc(wil, vring);
|
rc = wil_vring_alloc(wil, vring);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -862,8 +880,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
out_free:
|
out_free:
|
||||||
|
spin_lock_bh(&txdata->lock);
|
||||||
txdata->enabled = 0;
|
txdata->enabled = 0;
|
||||||
txdata->dot1x_open = false;
|
txdata->dot1x_open = false;
|
||||||
|
spin_unlock_bh(&txdata->lock);
|
||||||
wil_vring_free(wil, vring, 1);
|
wil_vring_free(wil, vring, 1);
|
||||||
out:
|
out:
|
||||||
|
|
||||||
|
@ -891,7 +911,6 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
|
||||||
napi_synchronize(&wil->napi_tx);
|
napi_synchronize(&wil->napi_tx);
|
||||||
|
|
||||||
wil_vring_free(wil, vring, 1);
|
wil_vring_free(wil, vring, 1);
|
||||||
memset(txdata, 0, sizeof(*txdata));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
||||||
|
@ -911,10 +930,11 @@ static struct vring *wil_find_tx_ucast(struct wil6210_priv *wil,
|
||||||
continue;
|
continue;
|
||||||
if (wil->vring2cid_tid[i][0] == cid) {
|
if (wil->vring2cid_tid[i][0] == cid) {
|
||||||
struct vring *v = &wil->vring_tx[i];
|
struct vring *v = &wil->vring_tx[i];
|
||||||
|
struct vring_tx_data *txdata = &wil->vring_tx_data[i];
|
||||||
|
|
||||||
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
|
wil_dbg_txrx(wil, "%s(%pM) -> [%d]\n",
|
||||||
__func__, eth->h_dest, i);
|
__func__, eth->h_dest, i);
|
||||||
if (v->va) {
|
if (v->va && txdata->enabled) {
|
||||||
return v;
|
return v;
|
||||||
} else {
|
} else {
|
||||||
wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
|
wil_dbg_txrx(wil, "vring[%d] not valid\n", i);
|
||||||
|
@ -935,6 +955,7 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||||
struct vring *v;
|
struct vring *v;
|
||||||
int i;
|
int i;
|
||||||
u8 cid;
|
u8 cid;
|
||||||
|
struct vring_tx_data *txdata;
|
||||||
|
|
||||||
/* In the STA mode, it is expected to have only 1 VRING
|
/* In the STA mode, it is expected to have only 1 VRING
|
||||||
* for the AP we connected to.
|
* for the AP we connected to.
|
||||||
|
@ -942,7 +963,8 @@ static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||||
v = &wil->vring_tx[i];
|
v = &wil->vring_tx[i];
|
||||||
if (!v->va)
|
txdata = &wil->vring_tx_data[i];
|
||||||
|
if (!v->va || !txdata->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cid = wil->vring2cid_tid[i][0];
|
cid = wil->vring2cid_tid[i][0];
|
||||||
|
@ -978,12 +1000,14 @@ static struct vring *wil_find_tx_bcast_1(struct wil6210_priv *wil,
|
||||||
struct sk_buff *skb)
|
struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct vring *v;
|
struct vring *v;
|
||||||
|
struct vring_tx_data *txdata;
|
||||||
int i = wil->bcast_vring;
|
int i = wil->bcast_vring;
|
||||||
|
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
v = &wil->vring_tx[i];
|
v = &wil->vring_tx[i];
|
||||||
if (!v->va)
|
txdata = &wil->vring_tx_data[i];
|
||||||
|
if (!v->va || !txdata->enabled)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!wil->vring_tx_data[i].dot1x_open &&
|
if (!wil->vring_tx_data[i].dot1x_open &&
|
||||||
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
(skb->protocol != cpu_to_be16(ETH_P_PAE)))
|
||||||
|
@ -1010,11 +1034,13 @@ static struct vring *wil_find_tx_bcast_2(struct wil6210_priv *wil,
|
||||||
u8 cid;
|
u8 cid;
|
||||||
struct ethhdr *eth = (void *)skb->data;
|
struct ethhdr *eth = (void *)skb->data;
|
||||||
char *src = eth->h_source;
|
char *src = eth->h_source;
|
||||||
|
struct vring_tx_data *txdata;
|
||||||
|
|
||||||
/* find 1-st vring eligible for data */
|
/* find 1-st vring eligible for data */
|
||||||
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
|
||||||
v = &wil->vring_tx[i];
|
v = &wil->vring_tx[i];
|
||||||
if (!v->va)
|
txdata = &wil->vring_tx_data[i];
|
||||||
|
if (!v->va || !txdata->enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
cid = wil->vring2cid_tid[i][0];
|
cid = wil->vring2cid_tid[i][0];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -51,7 +51,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
|
||||||
|
|
||||||
#define WIL_TX_Q_LEN_DEFAULT (4000)
|
#define WIL_TX_Q_LEN_DEFAULT (4000)
|
||||||
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
|
#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
|
||||||
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
|
#define WIL_TX_RING_SIZE_ORDER_DEFAULT (12)
|
||||||
#define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7)
|
#define WIL_BCAST_RING_SIZE_ORDER_DEFAULT (7)
|
||||||
#define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */
|
#define WIL_BCAST_MCS0_LIMIT (1024) /* limit for MCS0 frame size */
|
||||||
/* limit ring size in range [32..32k] */
|
/* limit ring size in range [32..32k] */
|
||||||
|
@ -92,6 +92,7 @@ static inline u32 wil_mtu2macbuf(u32 mtu)
|
||||||
#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */
|
#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */
|
||||||
#define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000)
|
#define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000)
|
||||||
#define WIL6210_SCAN_TO msecs_to_jiffies(10000)
|
#define WIL6210_SCAN_TO msecs_to_jiffies(10000)
|
||||||
|
#define WIL6210_DISCONNECT_TO_MS (2000)
|
||||||
#define WIL6210_RX_HIGH_TRSH_INIT (0)
|
#define WIL6210_RX_HIGH_TRSH_INIT (0)
|
||||||
#define WIL6210_RX_HIGH_TRSH_DEFAULT \
|
#define WIL6210_RX_HIGH_TRSH_DEFAULT \
|
||||||
(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
|
(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
|
||||||
|
@ -581,12 +582,10 @@ struct wil6210_priv {
|
||||||
struct workqueue_struct *wmi_wq; /* for deferred calls */
|
struct workqueue_struct *wmi_wq; /* for deferred calls */
|
||||||
struct work_struct wmi_event_worker;
|
struct work_struct wmi_event_worker;
|
||||||
struct workqueue_struct *wq_service;
|
struct workqueue_struct *wq_service;
|
||||||
struct work_struct connect_worker;
|
|
||||||
struct work_struct disconnect_worker;
|
struct work_struct disconnect_worker;
|
||||||
struct work_struct fw_error_worker; /* for FW error recovery */
|
struct work_struct fw_error_worker; /* for FW error recovery */
|
||||||
struct timer_list connect_timer;
|
struct timer_list connect_timer;
|
||||||
struct timer_list scan_timer; /* detect scan timeout */
|
struct timer_list scan_timer; /* detect scan timeout */
|
||||||
int pending_connect_cid;
|
|
||||||
struct list_head pending_wmi_ev;
|
struct list_head pending_wmi_ev;
|
||||||
/*
|
/*
|
||||||
* protect pending_wmi_ev
|
* protect pending_wmi_ev
|
||||||
|
@ -756,7 +755,8 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring);
|
||||||
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
|
int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
|
||||||
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
int wmi_rxon(struct wil6210_priv *wil, bool on);
|
||||||
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
|
||||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
|
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
|
||||||
|
bool full_disconnect);
|
||||||
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
|
int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
|
||||||
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
|
int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
|
||||||
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
|
int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
|
||||||
|
@ -807,6 +807,7 @@ void wil_rx_fini(struct wil6210_priv *wil);
|
||||||
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
|
||||||
int cid, int tid);
|
int cid, int tid);
|
||||||
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
|
void wil_vring_fini_tx(struct wil6210_priv *wil, int id);
|
||||||
|
int wil_tx_init(struct wil6210_priv *wil, int cid);
|
||||||
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
|
int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size);
|
||||||
int wil_bcast_init(struct wil6210_priv *wil);
|
int wil_bcast_init(struct wil6210_priv *wil);
|
||||||
void wil_bcast_fini(struct wil6210_priv *wil);
|
void wil_bcast_fini(struct wil6210_priv *wil);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
|
* Copyright (c) 2012-2016 Qualcomm Atheros, Inc.
|
||||||
*
|
*
|
||||||
* Permission to use, copy, modify, and/or distribute this software for any
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
@ -426,6 +426,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||||
const size_t assoc_req_ie_offset = sizeof(u16) * 2;
|
const size_t assoc_req_ie_offset = sizeof(u16) * 2;
|
||||||
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
|
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
|
||||||
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
|
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
|
||||||
|
int rc;
|
||||||
|
|
||||||
if (len < sizeof(*evt)) {
|
if (len < sizeof(*evt)) {
|
||||||
wil_err(wil, "Connect event too short : %d bytes\n", len);
|
wil_err(wil, "Connect event too short : %d bytes\n", len);
|
||||||
|
@ -445,8 +446,8 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
ch = evt->channel + 1;
|
ch = evt->channel + 1;
|
||||||
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
|
wil_info(wil, "Connect %pM channel [%d] cid %d\n",
|
||||||
evt->bssid, ch, evt->cid);
|
evt->bssid, ch, evt->cid);
|
||||||
wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
|
wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
|
||||||
evt->assoc_info, len - sizeof(*evt), true);
|
evt->assoc_info, len - sizeof(*evt), true);
|
||||||
|
|
||||||
|
@ -468,20 +469,67 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||||
assoc_resp_ielen = 0;
|
assoc_resp_ielen = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_lock(&wil->mutex);
|
||||||
|
if (test_bit(wil_status_resetting, wil->status) ||
|
||||||
|
!test_bit(wil_status_fwready, wil->status)) {
|
||||||
|
wil_err(wil, "status_resetting, cancel connect event, CID %d\n",
|
||||||
|
evt->cid);
|
||||||
|
mutex_unlock(&wil->mutex);
|
||||||
|
/* no need for cleanup, wil_reset will do that */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
|
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
|
||||||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
||||||
if (!test_bit(wil_status_fwconnecting, wil->status)) {
|
if (!test_bit(wil_status_fwconnecting, wil->status)) {
|
||||||
wil_err(wil, "Not in connecting state\n");
|
wil_err(wil, "Not in connecting state\n");
|
||||||
|
mutex_unlock(&wil->mutex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
del_timer_sync(&wil->connect_timer);
|
del_timer_sync(&wil->connect_timer);
|
||||||
cfg80211_connect_result(ndev, evt->bssid,
|
}
|
||||||
assoc_req_ie, assoc_req_ielen,
|
|
||||||
assoc_resp_ie, assoc_resp_ielen,
|
|
||||||
WLAN_STATUS_SUCCESS, GFP_KERNEL);
|
|
||||||
|
|
||||||
|
/* FIXME FW can transmit only ucast frames to peer */
|
||||||
|
/* FIXME real ring_id instead of hard coded 0 */
|
||||||
|
ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
|
||||||
|
wil->sta[evt->cid].status = wil_sta_conn_pending;
|
||||||
|
|
||||||
|
rc = wil_tx_init(wil, evt->cid);
|
||||||
|
if (rc) {
|
||||||
|
wil_err(wil, "%s: config tx vring failed for CID %d, rc (%d)\n",
|
||||||
|
__func__, evt->cid, rc);
|
||||||
|
wmi_disconnect_sta(wil, wil->sta[evt->cid].addr,
|
||||||
|
WLAN_REASON_UNSPECIFIED, false);
|
||||||
|
} else {
|
||||||
|
wil_info(wil, "%s: successful connection to CID %d\n",
|
||||||
|
__func__, evt->cid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
|
||||||
|
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
|
||||||
|
if (rc) {
|
||||||
|
netif_tx_stop_all_queues(ndev);
|
||||||
|
netif_carrier_off(ndev);
|
||||||
|
wil_err(wil,
|
||||||
|
"%s: cfg80211_connect_result with failure\n",
|
||||||
|
__func__);
|
||||||
|
cfg80211_connect_result(ndev, evt->bssid, NULL, 0,
|
||||||
|
NULL, 0,
|
||||||
|
WLAN_STATUS_UNSPECIFIED_FAILURE,
|
||||||
|
GFP_KERNEL);
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
cfg80211_connect_result(ndev, evt->bssid,
|
||||||
|
assoc_req_ie, assoc_req_ielen,
|
||||||
|
assoc_resp_ie, assoc_resp_ielen,
|
||||||
|
WLAN_STATUS_SUCCESS,
|
||||||
|
GFP_KERNEL);
|
||||||
|
}
|
||||||
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
|
} else if ((wdev->iftype == NL80211_IFTYPE_AP) ||
|
||||||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
memset(&sinfo, 0, sizeof(sinfo));
|
memset(&sinfo, 0, sizeof(sinfo));
|
||||||
|
|
||||||
sinfo.generation = wil->sinfo_gen++;
|
sinfo.generation = wil->sinfo_gen++;
|
||||||
|
@ -492,17 +540,21 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
|
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
|
||||||
|
} else {
|
||||||
|
wil_err(wil, "%s: unhandled iftype %d for CID %d\n",
|
||||||
|
__func__, wdev->iftype, evt->cid);
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
clear_bit(wil_status_fwconnecting, wil->status);
|
|
||||||
|
wil->sta[evt->cid].status = wil_sta_connected;
|
||||||
set_bit(wil_status_fwconnected, wil->status);
|
set_bit(wil_status_fwconnected, wil->status);
|
||||||
|
netif_tx_wake_all_queues(ndev);
|
||||||
|
|
||||||
/* FIXME FW can transmit only ucast frames to peer */
|
out:
|
||||||
/* FIXME real ring_id instead of hard coded 0 */
|
if (rc)
|
||||||
ether_addr_copy(wil->sta[evt->cid].addr, evt->bssid);
|
wil->sta[evt->cid].status = wil_sta_unused;
|
||||||
wil->sta[evt->cid].status = wil_sta_conn_pending;
|
clear_bit(wil_status_fwconnecting, wil->status);
|
||||||
|
mutex_unlock(&wil->mutex);
|
||||||
wil->pending_connect_cid = evt->cid;
|
|
||||||
queue_work(wil->wq_service, &wil->connect_worker);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
||||||
|
@ -511,8 +563,8 @@ static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
|
||||||
struct wmi_disconnect_event *evt = d;
|
struct wmi_disconnect_event *evt = d;
|
||||||
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
|
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
|
||||||
|
|
||||||
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
||||||
evt->bssid, reason_code, evt->disconnect_reason);
|
evt->bssid, reason_code, evt->disconnect_reason);
|
||||||
|
|
||||||
wil->sinfo_gen++;
|
wil->sinfo_gen++;
|
||||||
|
|
||||||
|
@ -727,6 +779,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||||
void __iomem *src;
|
void __iomem *src;
|
||||||
ulong flags;
|
ulong flags;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
unsigned int num_immed_reply = 0;
|
||||||
|
|
||||||
if (!test_bit(wil_status_mbox_ready, wil->status)) {
|
if (!test_bit(wil_status_mbox_ready, wil->status)) {
|
||||||
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
|
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
|
||||||
|
@ -736,6 +789,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||||
for (n = 0;; n++) {
|
for (n = 0;; n++) {
|
||||||
u16 len;
|
u16 len;
|
||||||
bool q;
|
bool q;
|
||||||
|
bool immed_reply = false;
|
||||||
|
|
||||||
r->head = wil_r(wil, RGF_MBOX +
|
r->head = wil_r(wil, RGF_MBOX +
|
||||||
offsetof(struct wil6210_mbox_ctl, rx.head));
|
offsetof(struct wil6210_mbox_ctl, rx.head));
|
||||||
|
@ -784,6 +838,15 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||||
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
|
struct wil6210_mbox_hdr_wmi *wmi = &evt->event.wmi;
|
||||||
u16 id = le16_to_cpu(wmi->id);
|
u16 id = le16_to_cpu(wmi->id);
|
||||||
u32 tstamp = le32_to_cpu(wmi->timestamp);
|
u32 tstamp = le32_to_cpu(wmi->timestamp);
|
||||||
|
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||||
|
if (wil->reply_id && wil->reply_id == id) {
|
||||||
|
if (wil->reply_buf) {
|
||||||
|
memcpy(wil->reply_buf, wmi,
|
||||||
|
min(len, wil->reply_size));
|
||||||
|
immed_reply = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||||
|
|
||||||
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
|
wil_dbg_wmi(wil, "WMI event 0x%04x MID %d @%d msec\n",
|
||||||
id, wmi->mid, tstamp);
|
id, wmi->mid, tstamp);
|
||||||
|
@ -799,15 +862,24 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
|
||||||
wil_w(wil, RGF_MBOX +
|
wil_w(wil, RGF_MBOX +
|
||||||
offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
|
offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
|
||||||
|
|
||||||
/* add to the pending list */
|
if (immed_reply) {
|
||||||
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
|
||||||
list_add_tail(&evt->list, &wil->pending_wmi_ev);
|
__func__, wil->reply_id);
|
||||||
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
kfree(evt);
|
||||||
q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
|
num_immed_reply++;
|
||||||
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
|
complete(&wil->wmi_call);
|
||||||
|
} else {
|
||||||
|
/* add to the pending list */
|
||||||
|
spin_lock_irqsave(&wil->wmi_ev_lock, flags);
|
||||||
|
list_add_tail(&evt->list, &wil->pending_wmi_ev);
|
||||||
|
spin_unlock_irqrestore(&wil->wmi_ev_lock, flags);
|
||||||
|
q = queue_work(wil->wmi_wq, &wil->wmi_event_worker);
|
||||||
|
wil_dbg_wmi(wil, "queue_work -> %d\n", q);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* normally, 1 event per IRQ should be processed */
|
/* normally, 1 event per IRQ should be processed */
|
||||||
wil_dbg_wmi(wil, "%s -> %d events queued\n", __func__, n);
|
wil_dbg_wmi(wil, "%s -> %d events queued, %d completed\n", __func__,
|
||||||
|
n - num_immed_reply, num_immed_reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||||
|
@ -818,13 +890,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||||
|
|
||||||
mutex_lock(&wil->wmi_mutex);
|
mutex_lock(&wil->wmi_mutex);
|
||||||
|
|
||||||
|
spin_lock(&wil->wmi_ev_lock);
|
||||||
|
wil->reply_id = reply_id;
|
||||||
|
wil->reply_buf = reply;
|
||||||
|
wil->reply_size = reply_size;
|
||||||
|
spin_unlock(&wil->wmi_ev_lock);
|
||||||
|
|
||||||
rc = __wmi_send(wil, cmdid, buf, len);
|
rc = __wmi_send(wil, cmdid, buf, len);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
wil->reply_id = reply_id;
|
|
||||||
wil->reply_buf = reply;
|
|
||||||
wil->reply_size = reply_size;
|
|
||||||
remain = wait_for_completion_timeout(&wil->wmi_call,
|
remain = wait_for_completion_timeout(&wil->wmi_call,
|
||||||
msecs_to_jiffies(to_msec));
|
msecs_to_jiffies(to_msec));
|
||||||
if (0 == remain) {
|
if (0 == remain) {
|
||||||
|
@ -837,10 +912,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
|
||||||
cmdid, reply_id,
|
cmdid, reply_id,
|
||||||
to_msec - jiffies_to_msecs(remain));
|
to_msec - jiffies_to_msecs(remain));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
spin_lock(&wil->wmi_ev_lock);
|
||||||
wil->reply_id = 0;
|
wil->reply_id = 0;
|
||||||
wil->reply_buf = NULL;
|
wil->reply_buf = NULL;
|
||||||
wil->reply_size = 0;
|
wil->reply_size = 0;
|
||||||
out:
|
spin_unlock(&wil->wmi_ev_lock);
|
||||||
|
|
||||||
mutex_unlock(&wil->wmi_mutex);
|
mutex_unlock(&wil->wmi_mutex);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -1184,7 +1263,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
|
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason,
|
||||||
|
bool full_disconnect)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
u16 reason_code;
|
u16 reason_code;
|
||||||
|
@ -1208,19 +1288,20 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call event handler manually after processing wmi_call,
|
if (full_disconnect) {
|
||||||
* to avoid deadlock - disconnect event handler acquires wil->mutex
|
/* call event handler manually after processing wmi_call,
|
||||||
* while it is already held here
|
* to avoid deadlock - disconnect event handler acquires
|
||||||
*/
|
* wil->mutex while it is already held here
|
||||||
reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
|
*/
|
||||||
|
reason_code = le16_to_cpu(reply.evt.protocol_reason_status);
|
||||||
|
|
||||||
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
|
||||||
reply.evt.bssid, reason_code,
|
reply.evt.bssid, reason_code,
|
||||||
reply.evt.disconnect_reason);
|
reply.evt.disconnect_reason);
|
||||||
|
|
||||||
wil->sinfo_gen++;
|
|
||||||
wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
|
|
||||||
|
|
||||||
|
wil->sinfo_gen++;
|
||||||
|
wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1348,14 +1429,11 @@ static void wmi_event_handle(struct wil6210_priv *wil,
|
||||||
id, wil->reply_id);
|
id, wil->reply_id);
|
||||||
/* check if someone waits for this event */
|
/* check if someone waits for this event */
|
||||||
if (wil->reply_id && wil->reply_id == id) {
|
if (wil->reply_id && wil->reply_id == id) {
|
||||||
if (wil->reply_buf) {
|
WARN_ON(wil->reply_buf);
|
||||||
memcpy(wil->reply_buf, wmi,
|
wmi_evt_call_handler(wil, id, evt_data,
|
||||||
min(len, wil->reply_size));
|
len - sizeof(*wmi));
|
||||||
} else {
|
wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
|
||||||
wmi_evt_call_handler(wil, id, evt_data,
|
__func__, id);
|
||||||
len - sizeof(*wmi));
|
|
||||||
}
|
|
||||||
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
|
|
||||||
complete(&wil->wmi_call);
|
complete(&wil->wmi_call);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue