wireless-drivers 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
 
 bcma
 
 * move flash detection code to ChipCommon core driver
 
 brcmfmac
 
 * IPv6 Neighbor discovery offload
 * driver settings that can be populated from different sources
 * country code setting in firmware
 * length checks to validate firmware events
 * new way to determine device memory size needed for BCM4366
 * various offloads during Wake on Wireless LAN (WoWLAN)
 * full Management Frame Protection (MFP) support
 
 iwlwifi
 
 * add support for thermal device / cooling device
 * improvements in scheduled scan without profiles
 * new firmware support (-21.ucode)
 * add MSIX support for 9000 devices
 * enable MU-MIMO and take care of firmware restart
 * add support for large SKBs in mvm to reach A-MSDU
 * add support for filtering frames from a BA session
 * start implementing the new Rx path for 9000 devices
 * enable the new Radio Resource Management (RRM) nl80211 feature flag
 * add a new module paramater to disable VHT
 * build infrastructure for Dynamic Queue Allocation
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQEcBAABAgAGBQJW4HwrAAoJEG4XJFUm622bvFUH/ArZD53Jh8btu8ukmkgKOPkc
 hCnvR639TURCNkC/e1lR0MFjO1QLLZ2m1tdRoZQfLiZm63HUuQzPDmaVnTeVfjrI
 4p3LmYriTECvgLoqVJgmBjNWiC61fMbWTJ91YqQiw2ZhvuKbcsu6oz/jU9MyCLyJ
 7WSk+HUqAnwtj7z515vAYQYapdUbxU1u7m/NgYdiYKTXfBR2ozUbfDR18Ey2EBWC
 KkDpFXyxo7ZByXzVA1B1UogB9NteV7IV1+WHphIX/XGdVQPpwRV3KxmLqKjIWW5E
 1Cv3q05vWapev9V5ZYghLpAGUQTu8h0nH2v0bJa9nSiQX23/Vkz7xxA/hi5gBOo=
 =aqji
 -----END PGP SIGNATURE-----

Merge tag 'wireless-drivers-next-for-davem-2016-03-09' of git://git.kernel.org/pub/scm/linux/kernel/git/kvalo/wireless-drivers-next

Kalle Valo says:

====================
wireless-drivers 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

bcma

* move flash detection code to ChipCommon core driver

brcmfmac

* IPv6 Neighbor discovery offload
* driver settings that can be populated from different sources
* country code setting in firmware
* length checks to validate firmware events
* new way to determine device memory size needed for BCM4366
* various offloads during Wake on Wireless LAN (WoWLAN)
* full Management Frame Protection (MFP) support

iwlwifi

* add support for thermal device / cooling device
* improvements in scheduled scan without profiles
* new firmware support (-21.ucode)
* add MSIX support for 9000 devices
* enable MU-MIMO and take care of firmware restart
* add support for large SKBs in mvm to reach A-MSDU
* add support for filtering frames from a BA session
* start implementing the new Rx path for 9000 devices
* enable the new Radio Resource Management (RRM) nl80211 feature flag
* add a new module paramater to disable VHT
* build infrastructure for Dynamic Queue Allocation
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2016-03-13 15:03:34 -04:00
commit 00e3d2ef18
162 changed files with 6425 additions and 1822 deletions

View File

@ -1,17 +1,46 @@
* 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:
-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:
- 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
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 {
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 ... ];
};

View File

@ -70,6 +70,11 @@ config BCMA_DRIVER_MIPS
If unsure, say N
config BCMA_PFLASH
bool
depends on BCMA_DRIVER_MIPS
default y
config BCMA_SFLASH
bool
depends on BCMA_DRIVER_MIPS

View File

@ -1,6 +1,7 @@
bcma-y += main.o scan.o core.o sprom.o
bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
bcma-y += driver_chipcommon_b.o
bcma-$(CONFIG_BCMA_PFLASH) += driver_chipcommon_pflash.o
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o

View File

@ -47,9 +47,6 @@ int bcma_sprom_get(struct bcma_bus *bus);
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
#ifdef CONFIG_BCMA_DRIVER_MIPS
extern struct platform_device bcma_pflash_dev;
#endif /* CONFIG_BCMA_DRIVER_MIPS */
/* driver_chipcommon_b.c */
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
@ -61,6 +58,21 @@ void bcma_pmu_init(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
/**************************************************
* driver_chipcommon_sflash.c
**************************************************/
#ifdef CONFIG_BCMA_PFLASH
extern struct platform_device bcma_pflash_dev;
int bcma_pflash_init(struct bcma_drv_cc *cc);
#else
static inline int bcma_pflash_init(struct bcma_drv_cc *cc)
{
bcma_err(cc->core->bus, "Parallel flash not supported\n");
return 0;
}
#endif /* CONFIG_BCMA_PFLASH */
#ifdef CONFIG_BCMA_SFLASH
/* driver_chipcommon_sflash.c */
int bcma_sflash_init(struct bcma_drv_cc *cc);

View File

@ -115,6 +115,33 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
return 0;
}
static void bcma_core_chipcommon_flash_detect(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
case BCMA_CC_FLASHT_ATSER:
bcma_debug(bus, "Found serial flash\n");
bcma_sflash_init(cc);
break;
case BCMA_CC_FLASHT_PARA:
bcma_debug(bus, "Found parallel flash\n");
bcma_pflash_init(cc);
break;
default:
bcma_err(bus, "Flash type not supported\n");
}
if (cc->core->id.rev == 38 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
bcma_debug(bus, "Found NAND flash\n");
bcma_nflash_init(cc);
}
}
}
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
{
struct bcma_bus *bus = cc->core->bus;
@ -136,6 +163,9 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
bcma_chipco_serial_init(cc);
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
bcma_core_chipcommon_flash_detect(cc);
cc->early_setup_done = true;
}

View File

@ -0,0 +1,49 @@
/*
* Broadcom specific AMBA
* ChipCommon parallel flash
*
* Licensed under the GNU/GPL. See COPYING for details.
*/
#include "bcma_private.h"
#include <linux/bcma/bcma.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
static const char * const part_probes[] = { "bcm47xxpart", NULL };
static struct physmap_flash_data bcma_pflash_data = {
.part_probe_types = part_probes,
};
static struct resource bcma_pflash_resource = {
.name = "bcma_pflash",
.flags = IORESOURCE_MEM,
};
struct platform_device bcma_pflash_dev = {
.name = "physmap-flash",
.dev = {
.platform_data = &bcma_pflash_data,
},
.resource = &bcma_pflash_resource,
.num_resources = 1,
};
int bcma_pflash_init(struct bcma_drv_cc *cc)
{
struct bcma_pflash *pflash = &cc->pflash;
pflash->present = true;
if (!(bcma_read32(cc->core, BCMA_CC_FLASH_CFG) & BCMA_CC_FLASH_CFG_DS))
bcma_pflash_data.width = 1;
else
bcma_pflash_data.width = 2;
bcma_pflash_resource.start = BCMA_SOC_FLASH2;
bcma_pflash_resource.end = BCMA_SOC_FLASH2 + BCMA_SOC_FLASH2_SZ;
return 0;
}

View File

@ -14,8 +14,6 @@
#include <linux/bcma/bcma.h>
#include <linux/mtd/physmap.h>
#include <linux/platform_device.h>
#include <linux/serial.h>
#include <linux/serial_core.h>
#include <linux/serial_reg.h>
@ -32,26 +30,6 @@ enum bcma_boot_dev {
BCMA_BOOT_DEV_NAND,
};
static const char * const part_probes[] = { "bcm47xxpart", NULL };
static struct physmap_flash_data bcma_pflash_data = {
.part_probe_types = part_probes,
};
static struct resource bcma_pflash_resource = {
.name = "bcma_pflash",
.flags = IORESOURCE_MEM,
};
struct platform_device bcma_pflash_dev = {
.name = "physmap-flash",
.dev = {
.platform_data = &bcma_pflash_data,
},
.resource = &bcma_pflash_resource,
.num_resources = 1,
};
/* The 47162a0 hangs when reading MIPS DMP registers registers */
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
{
@ -272,48 +250,11 @@ static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
return BCMA_BOOT_DEV_SERIAL;
}
static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
{
struct bcma_bus *bus = mcore->core->bus;
struct bcma_drv_cc *cc = &bus->drv_cc;
struct bcma_pflash *pflash = &cc->pflash;
enum bcma_boot_dev boot_dev;
switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
case BCMA_CC_FLASHT_ATSER:
bcma_debug(bus, "Found serial flash\n");
bcma_sflash_init(cc);
break;
case BCMA_CC_FLASHT_PARA:
bcma_debug(bus, "Found parallel flash\n");
pflash->present = true;
pflash->window = BCMA_SOC_FLASH2;
pflash->window_size = BCMA_SOC_FLASH2_SZ;
if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
BCMA_CC_FLASH_CFG_DS) == 0)
pflash->buswidth = 1;
else
pflash->buswidth = 2;
bcma_pflash_data.width = pflash->buswidth;
bcma_pflash_resource.start = pflash->window;
bcma_pflash_resource.end = pflash->window + pflash->window_size;
break;
default:
bcma_err(bus, "Flash type not supported\n");
}
if (cc->core->id.rev == 38 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
bcma_debug(bus, "Found NAND flash\n");
bcma_nflash_init(cc);
}
}
/* Determine flash type this SoC boots from */
boot_dev = bcma_boot_dev(bus);
switch (boot_dev) {
@ -340,7 +281,7 @@ void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
if (mcore->early_setup_done)
return;
bcma_core_mips_flash_detect(mcore);
bcma_core_mips_nvram_init(mcore);
mcore->early_setup_done = true;
}

View File

@ -350,7 +350,7 @@ static int bcma_register_devices(struct bcma_bus *bus)
bcma_register_core(bus, core);
}
#ifdef CONFIG_BCMA_DRIVER_MIPS
#ifdef CONFIG_BCMA_PFLASH
if (bus->drv_cc.pflash.present) {
err = platform_device_register(&bcma_pflash_dev);
if (err)

View File

@ -15,6 +15,12 @@ config ATH10K_PCI
---help---
This module adds support for PCIE bus
config ATH10K_AHB
bool "Atheros ath10k AHB support"
depends on ATH10K_PCI && OF && RESET_CONTROLLER
---help---
This module adds support for AHB bus
config ATH10K_DEBUG
bool "Atheros ath10k debugging"
depends on ATH10K

View File

@ -25,5 +25,7 @@ obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
ce.o
ath10k_pci-$(CONFIG_ATH10K_AHB) += ahb.o
# for tracing framework to find trace.h
CFLAGS_trace.o := -I$(src)

View File

@ -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);
}

View File

@ -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_ */

View File

@ -156,6 +156,11 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.channel_counters_freq_hz = 150000,
.max_probe_resp_desc_thres = 24,
.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 = {
.dir = QCA99X0_HW_2_0_FW_DIR,
.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,
},
},
{
.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[] = {
@ -217,6 +247,7 @@ static const char *const ath10k_core_fw_feature_str[] = {
[ATH10K_FW_FEATURE_RAW_MODE_SUPPORT] = "raw-mode",
[ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA] = "adaptive-cca",
[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,
@ -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_2:
case ATH10K_FW_WMI_OP_VERSION_10_2_4:
ar->max_num_peers = TARGET_10X_NUM_PEERS;
ar->max_num_stations = TARGET_10X_NUM_STATIONS;
if (test_bit(WMI_SERVICE_PEER_STATS, ar->wmi.svc_map)) {
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->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
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->max_num_vdevs = TARGET_10_4_NUM_VDEVS;
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->max_spatial_stream = WMI_10_4_MAX_SPATIAL_STREAM;
ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
break;
case ATH10K_FW_WMI_OP_VERSION_UNSET:
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->hw_values = &qca99x0_values;
break;
case ATH10K_HW_QCA4019:
ar->regs = &qca4019_regs;
ar->hw_values = &qca4019_values;
break;
default:
ath10k_err(ar, "unsupported core hardware revision %d\n",
hw_rev);

View File

@ -69,6 +69,7 @@ struct ath10k;
enum ath10k_bus {
ATH10K_BUS_PCI,
ATH10K_BUS_AHB,
};
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) {
case ATH10K_BUS_PCI:
return "pci";
case ATH10K_BUS_AHB:
return "ahb";
}
return "unknown";
@ -159,6 +162,7 @@ struct ath10k_fw_stats_peer {
u32 peer_rssi;
u32 peer_tx_rate;
u32 peer_rx_rate; /* 10x only */
u32 rx_duration;
};
struct ath10k_fw_stats_vdev {
@ -315,6 +319,7 @@ struct ath10k_sta {
#ifdef CONFIG_MAC80211_DEBUGFS
/* protected by conf_mutex */
bool aggr_mode;
u64 rx_duration;
#endif
};
@ -510,6 +515,15 @@ enum ath10k_fw_features {
/* Firmware supports management frame protection */
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 */
ATH10K_FW_FEATURE_COUNT,
};
@ -666,6 +680,12 @@ struct ath10k {
/* The padding bytes's location is different on various chips */
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 {
const char *dir;
const char *fw;

View File

@ -276,7 +276,7 @@ static const struct file_operations fops_wmi_services = {
.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;
@ -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;
@ -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;
@ -310,16 +310,16 @@ static void ath10k_debug_fw_stats_reset(struct ath10k *ar)
{
spin_lock_bh(&ar->data_lock);
ar->debug.fw_stats_done = false;
ath10k_debug_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_debug_fw_stats_peers_free(&ar->debug.fw_stats.peers);
ath10k_fw_stats_pdevs_free(&ar->debug.fw_stats.pdevs);
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_fw_stats_peers_free(&ar->debug.fw_stats.peers);
spin_unlock_bh(&ar->data_lock);
}
void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
{
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_vdevs;
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
*/
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) {
ath10k_warn(ar, "received unsolicited stats update event\n");
if (!peer_stats_svc)
ath10k_warn(ar, "received unsolicited stats update event\n");
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
* 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");
goto free;
}
if (num_vdevs >= BITS_PER_LONG) {
ath10k_fw_stats_vdevs_free(&ar->debug.fw_stats.vdevs);
ath10k_warn(ar, "dropping fw vdev stats\n");
goto free;
}
@ -391,9 +399,9 @@ void ath10k_debug_fw_stats_process(struct ath10k *ar, struct sk_buff *skb)
/* In some cases lists have been spliced and cleared. Free up
* resources if that is not the case.
*/
ath10k_debug_fw_stats_pdevs_free(&stats.pdevs);
ath10k_debug_fw_stats_vdevs_free(&stats.vdevs);
ath10k_debug_fw_stats_peers_free(&stats.peers);
ath10k_fw_stats_pdevs_free(&stats.pdevs);
ath10k_fw_stats_vdevs_free(&stats.vdevs);
ath10k_fw_stats_peers_free(&stats.peers);
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;
char buf[32];
size_t buf_size;
int ret = 0;
bool val;
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);
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))
goto exit;
@ -2127,17 +2142,15 @@ static ssize_t ath10k_write_btcoex(struct file *file,
else
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");
queue_work(ar->workqueue, &ar->restart_work);
ret = count;
exit:
mutex_unlock(&ar->conf_mutex);
return count;
return ret;
}
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);
if (len > buf_len)
len = buf_len;
len += scnprintf(buf + len, buf_len - len,
"firmware-N.bin\t\t%08x\n",
crc32_le(0, ar->firmware->data, ar->firmware->size));

View File

@ -37,6 +37,7 @@ enum ath10k_debug_mask {
ATH10K_DBG_TESTMODE = 0x00001000,
ATH10K_DBG_WMI_PRINT = 0x00002000,
ATH10K_DBG_PCI_PS = 0x00004000,
ATH10K_DBG_AHB = 0x00008000,
ATH10K_DBG_ANY = 0xffffffff,
};
@ -153,6 +154,12 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
#ifdef CONFIG_MAC80211_DEBUGFS
void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct ieee80211_sta *sta, struct dentry *dir);
void ath10k_sta_update_rx_duration(struct ath10k *ar, struct list_head *peer);
#else
static inline void ath10k_sta_update_rx_duration(struct ath10k *ar,
struct list_head *peer)
{
}
#endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG

View File

@ -18,6 +18,23 @@
#include "wmi-ops.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,
char __user *user_buf,
size_t count, loff_t *ppos)
@ -232,6 +249,28 @@ static const struct file_operations fops_delba = {
.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,
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_resp", S_IWUSR, dir, sta, &fops_addba_resp);
debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
debugfs_create_file("rx_duration", S_IRUGO, dir, sta,
&fops_rx_duration);
}

View File

@ -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_TX_FETCH_IND] =
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONF] =
HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
[HTT_10_4_T2H_MSG_TYPE_TX_FETCH_CONFIRM] =
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
[HTT_10_4_T2H_MSG_TYPE_STATS_NOUPLOAD] =
HTT_T2H_MSG_TYPE_STATS_NOUPLOAD,
[HTT_10_4_T2H_MSG_TYPE_TX_LOW_LATENCY_IND] =
HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
[HTT_10_4_T2H_MSG_TYPE_TX_MODE_SWITCH_IND] =
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
};
int ath10k_htt_connect(struct ath10k_htt *htt)

View File

@ -52,6 +52,7 @@ enum htt_h2t_msg_type { /* host-to-target */
/* This command is used for sending management frames in HTT < 3.0.
* HTT >= 3.0 uses TX_FRM for everything. */
HTT_H2T_MSG_TYPE_MGMT_TX = 7,
HTT_H2T_MSG_TYPE_TX_FETCH_RESP = 11,
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_AGGR_CONF = 0x15,
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,
/* 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 */
HTT_10_4_T2H_NUM_MSGS
};
@ -449,8 +450,8 @@ enum htt_t2h_msg_type {
HTT_T2H_MSG_TYPE_TEST,
HTT_T2H_MSG_TYPE_EN_STATS,
HTT_T2H_MSG_TYPE_TX_FETCH_IND,
HTT_T2H_MSG_TYPE_TX_FETCH_CONF,
HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND,
HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM,
HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND,
/* keep this last */
HTT_T2H_NUM_MSGS
};
@ -1306,9 +1307,43 @@ struct htt_frag_desc_bank_id {
* so we use a conservatively safe value for now */
#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_LSB 0
#define HTT_FRAG_DESC_BANK_CFG_INFO_SWAP (1 << 2)
#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_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 {
u8 info; /* HTT_FRAG_DESC_BANK_CFG_INFO_ */
@ -1316,6 +1351,114 @@ struct htt_frag_desc_bank_cfg {
u8 desc_size;
__le32 bank_base_addrs[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;
union htt_rx_pn_t {
@ -1340,6 +1483,7 @@ struct htt_cmd {
struct htt_oob_sync_req oob_sync_req;
struct htt_aggr_conf aggr_conf;
struct htt_frag_desc_bank_cfg frag_desc_bank_cfg;
struct htt_tx_fetch_resp tx_fetch_resp;
};
} __packed;
@ -1364,6 +1508,9 @@ struct htt_resp {
struct htt_rx_pn_ind rx_pn_ind;
struct htt_rx_offload_ind rx_offload_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;
@ -1518,6 +1665,14 @@ struct ath10k_htt {
dma_addr_t paddr;
struct ath10k_htt_txbuf *vaddr;
} 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

View File

@ -2011,9 +2011,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
}
case HTT_T2H_MSG_TYPE_RX_IND:
spin_lock_bh(&htt->rx_ring.lock);
__skb_queue_tail(&htt->rx_compl_q, skb);
spin_unlock_bh(&htt->rx_ring.lock);
skb_queue_tail(&htt->rx_compl_q, skb);
tasklet_schedule(&htt->txrx_compl_task);
return;
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;
}
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);
spin_unlock_bh(&htt->rx_ring.lock);
skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
tasklet_schedule(&htt->txrx_compl_task);
return;
}
@ -2123,10 +2119,12 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
break;
case HTT_T2H_MSG_TYPE_AGGR_CONF:
break;
case HTT_T2H_MSG_TYPE_EN_STATS:
case HTT_T2H_MSG_TYPE_TX_FETCH_IND:
case HTT_T2H_MSG_TYPE_TX_FETCH_CONF:
case HTT_T2H_MSG_TYPE_TX_LOW_LATENCY_IND:
case HTT_T2H_MSG_TYPE_TX_FETCH_CONFIRM:
case HTT_T2H_MSG_TYPE_TX_MODE_SWITCH_IND:
/* TODO: Implement pull-push logic */
break;
case HTT_T2H_MSG_TYPE_EN_STATS:
default:
ath10k_warn(ar, "htt event (%d) not handled\n",
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,
struct sk_buff *skb)
{
struct ath10k_pktlog_10_4_hdr *hdr =
(struct ath10k_pktlog_10_4_hdr *)skb->data;
trace_ath10k_htt_pktlog(ar, hdr->payload,
sizeof(*hdr) + __le16_to_cpu(hdr->size));
trace_ath10k_htt_pktlog(ar, skb->data, skb->len);
dev_kfree_skb_any(skb);
}
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 *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 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);
dev_kfree_skb_any(skb);
}
spin_lock_bh(&htt->rx_ring.lock);
while ((skb = __skb_dequeue(&htt->rx_compl_q))) {
while ((skb = __skb_dequeue(&rx_q))) {
resp = (struct htt_resp *)skb->data;
spin_lock_bh(&htt->rx_ring.lock);
ath10k_htt_rx_handler(htt, &resp->rx_ind);
spin_unlock_bh(&htt->rx_ring.lock);
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);
spin_unlock_bh(&htt->rx_ring.lock);
dev_kfree_skb_any(skb);
}
spin_unlock_bh(&htt->rx_ring.lock);
}

View File

@ -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);
}
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)
{
struct ath10k *ar = htt->ar;
@ -118,29 +197,32 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
goto free_idr_pending_tx;
}
if (!ar->hw_params.continuous_frag_desc)
goto skip_frag_desc_alloc;
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;
ret = ath10k_htt_tx_alloc_cont_frag_desc(htt);
if (ret) {
ath10k_err(ar, "failed to alloc cont frag desc: %d\n", ret);
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;
free_frag_desc:
ath10k_htt_tx_free_cont_frag_desc(htt);
free_txbuf:
size = htt->max_num_pending_tx *
sizeof(struct ath10k_htt_txbuf);
dma_free_coherent(htt->ar->dev, size, htt->txbuf.vaddr,
htt->txbuf.paddr);
free_idr_pending_tx:
idr_destroy(&htt->pending_tx);
return ret;
}
@ -174,12 +256,8 @@ void ath10k_htt_tx_free(struct ath10k_htt *htt)
htt->txbuf.paddr);
}
if (htt->frag_desc.vaddr) {
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);
}
ath10k_htt_tx_free_txq(htt);
ath10k_htt_tx_free_cont_frag_desc(htt);
}
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 sk_buff *skb;
struct htt_cmd *cmd;
struct htt_frag_desc_bank_cfg *cfg;
int ret, size;
u8 info;
if (!ar->hw_params.continuous_frag_desc)
return 0;
@ -286,14 +366,30 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
skb_put(skb, size);
cmd = (struct htt_cmd *)skb->data;
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;
cmd->frag_desc_bank_cfg.desc_size = sizeof(struct htt_msdu_ext_desc);
cmd->frag_desc_bank_cfg.bank_base_addrs[0] =
__cpu_to_le32(htt->frag_desc.paddr);
cmd->frag_desc_bank_cfg.bank_id[0].bank_min_id = 0;
cmd->frag_desc_bank_cfg.bank_id[0].bank_max_id =
__cpu_to_le16(htt->max_num_pending_tx - 1);
info = 0;
info |= SM(htt->tx_q_state.type,
HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE);
if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID;
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);
if (ret) {

View File

@ -109,6 +109,38 @@ const struct ath10k_hw_regs qca99x0_regs = {
.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 = {
.rtc_state_val_on = 3,
.ce_count = 8,
@ -136,6 +168,13 @@ const struct ath10k_hw_values qca99x0_values = {
.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,
u32 cc, u32 rcc, u32 cc_prev, u32 rcc_prev)
{

View File

@ -106,6 +106,14 @@ enum qca9377_chip_id_rev {
#define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
#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_API3_FILE "firmware-3.bin"
@ -200,6 +208,7 @@ enum ath10k_hw_rev {
ATH10K_HW_QCA6174,
ATH10K_HW_QCA99X0,
ATH10K_HW_QCA9377,
ATH10K_HW_QCA4019,
};
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 qca6174_regs;
extern const struct ath10k_hw_regs qca99x0_regs;
extern const struct ath10k_hw_regs qca4019_regs;
struct ath10k_hw_values {
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 qca6174_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,
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_99X0(ar) ((ar)->hw_rev == ATH10K_HW_QCA99X0)
#define QCA_REV_9377(ar) ((ar)->hw_rev == ATH10K_HW_QCA9377)
#define QCA_REV_40XX(ar) ((ar)->hw_rev == ATH10K_HW_QCA4019)
/* Known pecularities:
* - 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_AST_SKID_LIMIT 128
#define TARGET_10X_NUM_STATIONS 128
#define TARGET_10X_TX_STATS_NUM_STATIONS 118
#define TARGET_10X_NUM_PEERS ((TARGET_10X_NUM_STATIONS) + \
(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_REORDER_BUFS 0
#define TARGET_10X_NUM_PEER_KEYS 2
#define TARGET_10X_NUM_TIDS_MAX 256
#define TARGET_10X_NUM_TIDS min((TARGET_10X_NUM_TIDS_MAX), \
(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_RX_CHAIN_MASK (BIT(0) | BIT(1) | BIT(2))
#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_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_REORDER_BUFFS 0
#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_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 */
#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_VOW_CONFIG 0
#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_MAX_PEER_EXT_STATS 16
#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_IND_EVENT_PENDING 1
#define FW_IND_INITIALIZED 2
#define FW_IND_HOST_READY 0x80000000
/* HOST_REG interrupt from firmware */
#define PCIE_INTR_FIRMWARE_MASK ar->regs->pcie_intr_fw_mask

View File

@ -1358,10 +1358,7 @@ static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
const u8 *p2p_ie;
int ret;
if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
return 0;
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
if (arvif->vif->type != NL80211_IFTYPE_AP || !arvif->vif->p2p)
return 0;
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);
/* This is case only for P2P_GO */
if (arvif->vdev_type != WMI_VDEV_TYPE_AP ||
arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
if (vif->type != NL80211_IFTYPE_AP || !vif->p2p)
return;
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)
{
struct ath10k *ar = hw->priv;
u32 burst_enable;
u32 param;
int ret = 0;
/*
@ -4031,13 +4027,15 @@ static int ath10k_start(struct ieee80211_hw *hw)
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) {
ath10k_warn(ar, "failed to enable PMF QOS: %d\n", ret);
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) {
ath10k_warn(ar, "failed to enable dynamic BW: %d\n", ret);
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)) {
burst_enable = ar->wmi.pdev_param->burst_enable;
ret = ath10k_wmi_pdev_set_param(ar, burst_enable, 0);
param = ar->wmi.pdev_param->burst_enable;
ret = ath10k_wmi_pdev_set_param(ar, param, 0);
if (ret) {
ath10k_warn(ar, "failed to disable burst: %d\n", ret);
goto err_core_stop;
@ -4072,8 +4070,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
* this problem.
*/
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->arp_ac_override, 0);
param = ar->wmi.pdev_param->arp_ac_override;
ret = ath10k_wmi_pdev_set_param(ar, param, 0);
if (ret) {
ath10k_warn(ar, "failed to set arp ac override parameter: %d\n",
ret);
@ -4092,8 +4090,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
}
}
ret = ath10k_wmi_pdev_set_param(ar,
ar->wmi.pdev_param->ani_enable, 1);
param = ar->wmi.pdev_param->ani_enable;
ret = ath10k_wmi_pdev_set_param(ar, param, 1);
if (ret) {
ath10k_warn(ar, "failed to enable ani by default: %d\n",
ret);
@ -4102,6 +4100,18 @@ static int ath10k_start(struct ieee80211_hw *hw)
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;
ath10k_regd_update(ar);
@ -4349,25 +4359,29 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
bit, ar->free_vdev_map);
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) {
case NL80211_IFTYPE_P2P_DEVICE:
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;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
arvif->vdev_type = WMI_VDEV_TYPE_STA;
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;
case NL80211_IFTYPE_ADHOC:
arvif->vdev_type = WMI_VDEV_TYPE_IBSS;
break;
case NL80211_IFTYPE_MESH_POINT:
if (test_bit(WMI_SERVICE_MESH, ar->wmi.svc_map)) {
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_MESH;
if (test_bit(WMI_SERVICE_MESH_11S, ar->wmi.svc_map)) {
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)) {
ret = -EINVAL;
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;
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;
case NL80211_IFTYPE_MONITOR:
arvif->vdev_type = WMI_VDEV_TYPE_MONITOR;

View File

@ -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 int ath10k_pci_cold_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_deinit_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);
}
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);
int ret;
@ -642,7 +641,7 @@ void ath10k_pci_write32(struct ath10k *ar, u32 offset, u32 value)
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);
u32 val;
@ -667,6 +666,20 @@ u32 ath10k_pci_read32(struct ath10k *ar, u32 offset)
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)
{
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);
}
static bool ath10k_pci_irq_pending(struct ath10k *ar)
bool ath10k_pci_irq_pending(struct ath10k *ar)
{
u32 cause;
@ -700,7 +713,7 @@ static bool ath10k_pci_irq_pending(struct ath10k *ar)
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
* 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);
}
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 +
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);
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]);
}
static void ath10k_pci_rx_replenish_retry(unsigned long ptr)
void ath10k_pci_rx_replenish_retry(unsigned long 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;
break;
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA4019:
val = ath10k_pci_read32(ar, PCIE_BAR_REG_ADDRESS);
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) \
__ath10k_pci_diag_read_hi(ar, dest, HI_ITEM(src), len)
static int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
const void *data, int nbytes)
int ath10k_pci_diag_write_mem(struct ath10k *ar, u32 address,
const void *data, int nbytes)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
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);
}
static 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_tx_sg(struct ath10k *ar, u8 pipe_id,
struct ath10k_hif_sg_item *items, int n_items)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_pci_pipe *pci_pipe = &ar_pci->pipe_info[pipe_id];
@ -1332,13 +1346,13 @@ static int ath10k_pci_hif_tx_sg(struct ath10k *ar, u8 pipe_id,
return err;
}
static int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
size_t buf_len)
int ath10k_pci_hif_diag_read(struct ath10k *ar, u32 address, void *buf,
size_t 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);
@ -1406,8 +1420,8 @@ static void ath10k_pci_fw_crashed_dump(struct ath10k *ar)
queue_work(ar->workqueue, &ar->restart_work);
}
static void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
int force)
{
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);
}
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);
int i;
@ -1446,8 +1460,8 @@ static void ath10k_pci_kill_tasklet(struct ath10k *ar)
del_timer_sync(&ar_pci->rx_post_retry);
}
static int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
int ath10k_pci_hif_map_service_to_pipe(struct ath10k *ar, u16 service_id,
u8 *ul_pipe, u8 *dl_pipe)
{
const struct service_to_pipe *entry;
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;
}
static void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
u8 *ul_pipe, u8 *dl_pipe)
void ath10k_pci_hif_get_default_pipe(struct ath10k *ar,
u8 *ul_pipe, u8 *dl_pipe)
{
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);
break;
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0
* to mask irq/MSI.
*/
@ -1538,6 +1553,7 @@ static void ath10k_pci_irq_msi_fw_unmask(struct ath10k *ar)
CORE_CTRL_ADDRESS, val);
break;
case ATH10K_HW_QCA99X0:
case ATH10K_HW_QCA4019:
/* TODO: Find appropriate register configuration for QCA99X0
* 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;
@ -1676,7 +1692,7 @@ static void ath10k_pci_ce_deinit(struct ath10k *ar)
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_buffer_cleanup(ar);
@ -1711,9 +1727,9 @@ static void ath10k_pci_hif_stop(struct ath10k *ar)
spin_unlock_irqrestore(&ar_pci->ps_lock, flags);
}
static int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
void *req, u32 req_len,
void *resp, u32 *resp_len)
int ath10k_pci_hif_exchange_bmi_msg(struct ath10k *ar,
void *req, u32 req_len,
void *resp, u32 *resp_len)
{
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
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);
ret = dma_mapping_error(ar->dev, resp_paddr);
if (ret) {
ret = EIO;
ret = -EIO;
goto err_req;
}
@ -1907,7 +1923,14 @@ static int ath10k_pci_get_num_banks(struct ath10k *ar)
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 pcie_state_targ_addr = 0;
@ -2018,7 +2041,7 @@ static int ath10k_pci_init_config(struct ath10k *ar)
/* first bank is switched to IRAM */
ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
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_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);
}
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_pipe *pipe;
@ -2102,7 +2125,7 @@ static int ath10k_pci_alloc_pipes(struct ath10k *ar)
return 0;
}
static void ath10k_pci_free_pipes(struct ath10k *ar)
void ath10k_pci_free_pipes(struct ath10k *ar)
{
int i;
@ -2110,7 +2133,7 @@ static void ath10k_pci_free_pipes(struct ath10k *ar)
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;
@ -2453,7 +2476,7 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
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");
@ -2722,7 +2745,7 @@ static void ath10k_pci_free_irq(struct ath10k *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);
int i;
@ -2808,7 +2831,7 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
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);
unsigned long timeout;
@ -2989,6 +3012,43 @@ static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
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,
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->dev_id = pci_dev->device;
ar_pci->pci_ps = pci_ps;
ar_pci->bus_ops = &ath10k_pci_bus_ops;
ar->id.vendor = pdev->vendor;
ar->id.device = pdev->device;
ar->id.subsystem_vendor = pdev->subsystem_vendor;
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,
(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);
if (ret) {
ath10k_err(ar, "failed to claim device: %d\n", ret);
goto err_core_destroy;
}
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;
goto err_free_pipes;
}
ret = ath10k_pci_force_wake(ar);
if (ret) {
ath10k_warn(ar, "failed to wake up device : %d\n", ret);
goto err_free_pipes;
goto err_sleep;
}
ath10k_pci_ce_deinit(ar);
@ -3081,7 +3133,7 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
ret = ath10k_pci_init_irq(ar);
if (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",
@ -3127,13 +3179,13 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
err_deinit_irq:
ath10k_pci_deinit_irq(ar);
err_free_pipes:
ath10k_pci_free_pipes(ar);
err_sleep:
ath10k_pci_sleep_sync(ar);
ath10k_pci_release(ar);
err_free_pipes:
ath10k_pci_free_pipes(ar);
err_core_destroy:
ath10k_core_destroy(ar);
@ -3157,10 +3209,8 @@ static void ath10k_pci_remove(struct pci_dev *pdev)
ath10k_core_unregister(ar);
ath10k_pci_free_irq(ar);
ath10k_pci_kill_tasklet(ar);
ath10k_pci_deinit_irq(ar);
ath10k_pci_ce_deinit(ar);
ath10k_pci_free_pipes(ar);
ath10k_pci_release_resource(ar);
ath10k_pci_sleep_sync(ar);
ath10k_pci_release(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",
ret);
ret = ath10k_ahb_init();
if (ret)
printk(KERN_ERR "ahb init failed: %d\n", ret);
return ret;
}
module_init(ath10k_pci_init);
@ -3191,6 +3245,7 @@ module_init(ath10k_pci_init);
static void __exit ath10k_pci_exit(void)
{
pci_unregister_driver(&ath10k_pci_driver);
ath10k_ahb_exit();
}
module_exit(ath10k_pci_exit);

View File

@ -22,6 +22,7 @@
#include "hw.h"
#include "ce.h"
#include "ahb.h"
/*
* maximum number of bytes that can be handled atomically by DiagRead/DiagWrite
@ -157,6 +158,12 @@ struct ath10k_pci_supp_chip {
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 pci_dev *pdev;
struct device *dev;
@ -225,6 +232,14 @@ struct ath10k_pci {
* on MMIO read/write.
*/
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)
@ -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_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
* frequently. To avoid this put SoC to sleep after a very conservative grace
* period. Adjust with great care.

View File

@ -456,4 +456,7 @@ Fw Mode/SubMode Mask
#define QCA99X0_BOARD_DATA_SZ 12288
#define QCA99X0_BOARD_EXT_DATA_SZ 0
#define QCA4019_BOARD_DATA_SZ 12064
#define QCA4019_BOARD_EXT_DATA_SZ 0
#endif /* __TARGADDRS_H__ */

View File

@ -250,6 +250,7 @@ TRACE_EVENT(ath10k_wmi_dbglog,
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u8, hw_type);
__field(size_t, buf_len)
__dynamic_array(u8, buf, buf_len)
),
@ -257,14 +258,16 @@ TRACE_EVENT(ath10k_wmi_dbglog,
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->hw_type = ar->hw_rev;
__entry->buf_len = buf_len;
memcpy(__get_dynamic_array(buf), buf, buf_len);
),
TP_printk(
"%s %s len %zu",
"%s %s %d len %zu",
__get_str(driver),
__get_str(device),
__entry->hw_type,
__entry->buf_len
)
);
@ -277,6 +280,7 @@ TRACE_EVENT(ath10k_htt_pktlog,
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u8, hw_type);
__field(u16, buf_len)
__dynamic_array(u8, pktlog, buf_len)
),
@ -284,14 +288,16 @@ TRACE_EVENT(ath10k_htt_pktlog,
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->hw_type = ar->hw_rev;
__entry->buf_len = buf_len;
memcpy(__get_dynamic_array(pktlog), buf, buf_len);
),
TP_printk(
"%s %s size %hu",
"%s %s %d size %hu",
__get_str(driver),
__get_str(device),
__entry->hw_type,
__entry->buf_len
)
);
@ -440,6 +446,7 @@ TRACE_EVENT(ath10k_htt_rx_desc,
TP_STRUCT__entry(
__string(device, dev_name(ar->dev))
__string(driver, dev_driver_string(ar->dev))
__field(u8, hw_type);
__field(u16, len)
__dynamic_array(u8, rxdesc, len)
),
@ -447,14 +454,16 @@ TRACE_EVENT(ath10k_htt_rx_desc,
TP_fast_assign(
__assign_str(device, dev_name(ar->dev));
__assign_str(driver, dev_driver_string(ar->dev));
__entry->hw_type = ar->hw_rev;
__entry->len = len;
memcpy(__get_dynamic_array(rxdesc), data, len);
),
TP_printk(
"%s %s rxdesc len %d",
"%s %s %d rxdesc len %d",
__get_str(driver),
__get_str(device),
__entry->hw_type,
__entry->len
)
);

View File

@ -186,6 +186,8 @@ struct wmi_ops {
u8 enable,
u32 detect_level,
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);
@ -1327,4 +1329,13 @@ ath10k_wmi_pdev_enable_adaptive_cca(struct ath10k *ar, u8 enable,
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

View File

@ -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_adaptive_qcs = ath10k_wmi_tlv_op_gen_adaptive_qcs,
.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 = {

View File

@ -2862,11 +2862,20 @@ static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
/* fw doesn't implement vdev stats */
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;
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;
if (!skb_pull(skb, sizeof(*src)))
if (!skb_pull(skb, stats_len))
return -EPROTO;
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);
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 */
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,
const struct wmi_p2p_noa_info *noa)
{
if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
if (!arvif->vif->p2p)
return;
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;
}
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,
struct sk_buff *skb,
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)) {
ar->max_num_peers = TARGET_10_4_NUM_QCACHE_PEERS_MAX +
TARGET_10_4_NUM_VDEVS;
ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS +
TARGET_10_4_NUM_VDEVS;
ar->max_num_vdevs;
ar->num_active_peers = ar->hw_params.qcache_active_peers +
ar->max_num_vdevs;
ar->num_tids = ar->num_active_peers * 2;
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;
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_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.tx_chain_mask = __cpu_to_le32(TARGET_10X_TX_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))
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);
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);
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.tx_chain_mask = __cpu_to_le32(TARGET_10_4_TX_CHAIN_MASK);
config.rx_chain_mask = __cpu_to_le32(TARGET_10_4_RX_CHAIN_MASK);
config.tx_chain_mask = __cpu_to_le32(ar->hw_params.tx_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[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.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_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);
len += scnprintf(buf + len, buf_len - len, "%30s %u\n",
"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");
*length = len;
}
@ -7351,6 +7419,71 @@ void ath10k_wmi_10_4_op_fw_stats_fill(struct ath10k *ar,
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 = {
.rx = ath10k_wmi_op_rx,
.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_delba_send = ath10k_wmi_op_gen_delba_send,
.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_prb_tmpl 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_delba_send = ath10k_wmi_op_gen_delba_send,
.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_prb_tmpl 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_delba_send = ath10k_wmi_op_gen_delba_send,
.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 */
};
@ -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_vdev_start = ath10k_wmi_op_pull_vdev_start_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 = ath10k_wmi_op_pull_phyerr_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,
.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_prb_tmpl 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 */
.gen_request_stats = ath10k_wmi_op_gen_request_stats,
.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)

View File

@ -176,7 +176,10 @@ enum wmi_service {
WMI_SERVICE_AUX_CHAN_LOAD_INTF,
WMI_SERVICE_BSS_CHANNEL_INFO_64,
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 */
WMI_SERVICE_MAX,
@ -213,6 +216,7 @@ enum wmi_10x_service {
WMI_10X_SERVICE_BSS_CHANNEL_INFO_64,
WMI_10X_SERVICE_MESH,
WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
WMI_10X_SERVICE_PEER_STATS,
};
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_BSS_CHANNEL_INFO_64,
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)
@ -385,7 +392,10 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_AUX_CHAN_LOAD_INTF);
SVCSTR(WMI_SERVICE_BSS_CHANNEL_INFO_64);
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:
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,
WMI_SERVICE_BSS_CHANNEL_INFO_64, len);
SVCMAP(WMI_10X_SERVICE_MESH,
WMI_SERVICE_MESH, len);
WMI_SERVICE_MESH_11S, len);
SVCMAP(WMI_10X_SERVICE_EXT_RES_CFG_SUPPORT,
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,
@ -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);
SVCMAP(WMI_10_4_SERVICE_EXT_RES_CFG_SUPPORT,
WMI_SERVICE_EXT_RES_CFG_SUPPORT, len);
SVCMAP(WMI_10_4_SERVICE_MESH,
WMI_SERVICE_MESH, len);
SVCMAP(WMI_10_4_SERVICE_MESH_NON_11S,
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
@ -1800,7 +1818,6 @@ enum wmi_channel_change_cause {
#define WMI_CHANNEL_CHANGE_CAUSE_CSA (1 << 13)
#define WMI_MAX_SPATIAL_STREAM 3 /* default max ss */
#define WMI_10_4_MAX_SPATIAL_STREAM 4
/* HT Capabilities*/
#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_ATF_CONFIG = BIT(1),
WMI_10_2_COEX_GPIO = BIT(3),
WMI_10_2_PEER_STATS = BIT(7),
};
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_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;
struct wmi_10_4_peer_stats {
@ -4270,12 +4294,40 @@ enum wmi_vdev_type {
};
enum wmi_vdev_subtype {
WMI_VDEV_SUBTYPE_NONE = 0,
WMI_VDEV_SUBTYPE_P2P_DEVICE = 1,
WMI_VDEV_SUBTYPE_P2P_CLIENT = 2,
WMI_VDEV_SUBTYPE_P2P_GO = 3,
WMI_VDEV_SUBTYPE_PROXY_STA = 4,
WMI_VDEV_SUBTYPE_MESH = 5,
WMI_VDEV_SUBTYPE_NONE,
WMI_VDEV_SUBTYPE_P2P_DEVICE,
WMI_VDEV_SUBTYPE_P2P_CLIENT,
WMI_VDEV_SUBTYPE_P2P_GO,
WMI_VDEV_SUBTYPE_PROXY_STA,
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 */
@ -5442,6 +5494,16 @@ struct wmi_host_swba_event {
struct wmi_bcn_info bcn_info[0];
} __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 */
#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,
struct ath10k_fw_stats *fw_stats,
char *buf);
int ath10k_wmi_op_get_vdev_subtype(struct ath10k *ar,
enum wmi_vdev_subtype subtype);
#endif /* _WMI_H_ */

View File

@ -126,12 +126,8 @@ static void ath9k_hw_update_mibstats(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;
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)
{
struct ar5416AniState *aniState;
if (!ah->curchan)
return;
aniState = &ah->ani;
struct ar5416AniState *aniState = &ah->ani;
if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL)
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)
{
struct ar5416AniState *aniState;
if (!ah->curchan)
return;
aniState = &ah->ani;
struct ar5416AniState *aniState = &ah->ani;
if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL)
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)
{
struct ar5416AniState *aniState;
aniState = &ah->ani;
struct ar5416AniState *aniState = &ah->ani;
/* lower OFDM noise immunity */
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);
int ofdm_nil, cck_nil;
if (!ah->curchan)
if (!chan)
return;
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)
{
struct ar5416AniState *aniState;
struct ar5416AniState *aniState = &ah->ani;
struct ath_common *common = ath9k_hw_common(ah);
u32 ofdmPhyErrRate, cckPhyErrRate;
if (!ah->curchan)
return;
aniState = &ah->ani;
if (!ath9k_hw_ani_read_counters(ah))
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) {
ath9k_hw_ani_cck_err_trigger(ah);
aniState->ofdmsTurn = true;
}
} else
return;
ath9k_ani_restart(ah);
}
}

View File

@ -53,19 +53,19 @@ static bool ar9003_hw_is_aic_enabled(struct ath_hw *ah)
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)
{
int16_t i;
if (dir) {
for (i = index + 1; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
if (cal_sram[i].valid)
if (cal_sram_valid[i])
break;
}
} else {
for (i = index - 1; i >= 0; i--) {
if (cal_sram[i].valid)
if (cal_sram_valid[i])
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)
{
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];
u32 dir_path_gain_idx, quad_path_gain_idx, value;
u32 fixed_com_att_db;
@ -272,33 +272,34 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
int16_t i;
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));
for (i = 0; i < ATH_AIC_MAX_BT_CHANNEL; i++) {
struct ath_aic_sram_info sram;
value = aic->aic_sram[i];
cal_sram[i].valid =
cal_sram_valid[i] = 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);
cal_sram[i].vga_quad_sign =
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);
cal_sram[i].vga_dir_sign =
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);
if (cal_sram[i].valid) {
dir_path_gain_idx = cal_sram[i].rot_dir_att_db +
com_att_db_table[cal_sram[i].com_att_6db];
quad_path_gain_idx = cal_sram[i].rot_quad_att_db +
com_att_db_table[cal_sram[i].com_att_6db];
if (sram.valid) {
dir_path_gain_idx = sram.rot_dir_att_db +
com_att_db_table[sram.com_att_6db];
quad_path_gain_idx = sram.rot_quad_att_db +
com_att_db_table[sram.com_att_6db];
dir_path_sign = (cal_sram[i].vga_dir_sign) ? 1 : -1;
quad_path_sign = (cal_sram[i].vga_quad_sign) ? 1 : -1;
dir_path_sign = (sram.vga_dir_sign) ? 1 : -1;
quad_path_sign = (sram.vga_quad_sign) ? 1 : -1;
aic_sram[i].dir_path_gain_lin = dir_path_sign *
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++) {
int16_t start_idx, end_idx;
if (cal_sram[i].valid)
if (cal_sram_valid[i])
continue;
start_idx = ar9003_aic_find_valid(cal_sram, 0, i);
end_idx = ar9003_aic_find_valid(cal_sram, 1, i);
start_idx = ar9003_aic_find_valid(cal_sram_valid, 0, i);
end_idx = ar9003_aic_find_valid(cal_sram_valid, 1, i);
if (start_idx < 0) {
/* extrapolation */
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) {
ret = false;
@ -342,7 +343,7 @@ static bool ar9003_aic_cal_post_process(struct ath_hw *ah)
if (end_idx < 0) {
/* 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) {
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. */
i = ar9003_aic_find_valid(cal_sram, 1, 0);
i = ar9003_aic_find_valid(cal_sram_valid, 1, 0);
if (i < 0) {
i = 0;
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++) {
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].sram.vga_quad_sign=
sram.vga_quad_sign =
(aic_sram[i].quad_path_gain_lin >= 0) ? 1 : 0;
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)) -
fixed_com_att_db;
aic_sram[i].sram.com_att_6db =
sram.com_att_6db =
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,
(int16_t)ATH_AIC_MIN_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,
(int16_t)ATH_AIC_MIN_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(aic_sram[i].sram.vga_dir_sign,
aic->aic_sram[i] = (SM(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) |
SM(aic_sram[i].sram.com_att_6db,
SM(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) |
SM(aic_sram[i].sram.rot_dir_att_db,
SM(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));
}

View File

@ -50,7 +50,6 @@ struct ath_aic_sram_info {
struct ath_aic_out_info {
int16_t dir_path_gain_lin;
int16_t quad_path_gain_lin;
struct ath_aic_sram_info sram;
};
u8 ar9003_aic_calibration(struct ath_hw *ah);

View File

@ -5485,11 +5485,11 @@ unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah,
AR9300_PAPRD_SCALE_1);
else {
if (chan->channel >= 5700)
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
AR9300_PAPRD_SCALE_1);
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt20),
AR9300_PAPRD_SCALE_1);
else if (chan->channel >= 5400)
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
AR9300_PAPRD_SCALE_2);
AR9300_PAPRD_SCALE_2);
else
return MS(le32_to_cpu(eep->modalHeader5G.papdRateMaskHt40),
AR9300_PAPRD_SCALE_1);

View File

@ -698,6 +698,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
else if (AR_SREV_9340(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
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))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9485Modes_low_ob_db_tx_gain_1_1);

View File

@ -976,9 +976,14 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
/*
* JAPAN regulatory.
*/
if (chan->channel == 2484)
if (chan->channel == 2484) {
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;
ar9003_hw_override_ini(ah);
ar9003_hw_set_channel_regs(ah, chan);
@ -2071,7 +2076,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
* to be disabled.
*
* 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:
return true;
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;
else
return true;

View File

@ -487,6 +487,9 @@
#define AR_PHY_ADDAC_PARA_CTL (AR_SM_BASE + 0x150)
#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_S 0

View File

@ -757,6 +757,71 @@ static const u32 qca953x_1p1_modes_xpa_tx_gain_table[][2] = {
{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] = {
/* Addr allmodes */
{0x00009800, 0xafe68e30},

View File

@ -241,6 +241,7 @@ int ath9k_hw_loadnf(struct ath_hw *ah, struct ath9k_channel *chan)
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
struct ath_common *common = ath9k_hw_common(ah);
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
u32 bb_agc_ctl = REG_READ(ah, AR_PHY_AGC_CONTROL);
if (ah->caldata)
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
* 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.
* The max delay was changed from an original 250us to 10000us
* since 250us often results in NF load timeout and causes deaf
* condition during stress testing 12/12/2009
* The max delay was changed from an original 250us to 22.2 msec.
* This would increase timeout to the longest possible frame
* (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) &
AR_PHY_AGC_CONTROL_NF) == 0)
AR_PHY_AGC_CONTROL_NF) == 0)
break;
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
* 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
* noisefloor until the next calibration timer.
*/
if (j == 10000) {
if (j == 22200) {
ath_dbg(common, ANY,
"Timeout while waiting for nf to load: AR_PHY_AGC_CONTROL=0x%x\n",
REG_READ(ah, AR_PHY_AGC_CONTROL));

View File

@ -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;
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)
return;
if (vif->type != NL80211_IFTYPE_STATION || !vif->p2p)
if (vif->type != NL80211_IFTYPE_STATION)
return;
sc->p2p_ps_vif = avp;

View File

@ -55,6 +55,8 @@ static struct usb_device_id ath9k_hif_usb_ids[] = {
.driver_info = AR9280_USB }, /* Buffalo WLI-UV-AG300P */
{ USB_DEVICE(0x04da, 0x3904),
.driver_info = AR9280_USB },
{ USB_DEVICE(0x0930, 0x0a08),
.driver_info = AR9280_USB }, /* Toshiba WLM-20U2 and GN-1080 */
{ USB_DEVICE(0x0cf3, 0x20ff),
.driver_info = STORAGE_DEVICE },

View File

@ -1368,6 +1368,16 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
if (ath9k_hw_mci_is_enabled(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);
REGWRITE_BUFFER_FLUSH(ah);

View File

@ -751,14 +751,6 @@ static const struct ieee80211_iface_combination if_comb_multi[] = {
#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[] = {
{
.limits = if_limits,
@ -766,6 +758,11 @@ static const struct ieee80211_iface_combination if_comb[] = {
.max_interfaces = 2048,
.num_different_channels = 1,
.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,
@ -774,18 +771,6 @@ static const struct ieee80211_iface_combination if_comb[] = {
.num_different_channels = 1,
.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

View File

@ -978,7 +978,7 @@ static void ath9k_update_bssid_mask(struct ath_softc *sc,
if (ctx->nvifs_assigned != 1)
continue;
if (!avp->vif->p2p || !iter_data->has_hw_macaddr)
if (!iter_data->has_hw_macaddr)
continue;
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);
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))
ath9k_beacon_assign_slot(sc, vif);

View File

@ -34,8 +34,10 @@
#define AR_CFG_SWRG 0x00000010
#define AR_CFG_AP_ADHOC_INDICATION 0x00000020
#define AR_CFG_PHOK 0x00000100
#define AR_CFG_CLK_GATE_DIS 0x00000400
#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_S 17

View File

@ -56,6 +56,7 @@ enum carl9170_cmd_oids {
CARL9170_CMD_RX_FILTER = 0x07,
CARL9170_CMD_WOL = 0x08,
CARL9170_CMD_TALLY = 0x09,
CARL9170_CMD_WREGB = 0x0a,
/* CAM */
CARL9170_CMD_EKEY = 0x10,
@ -123,6 +124,12 @@ struct carl9170_write_reg {
} regs[0] __packed;
} __packed;
struct carl9170_write_reg_byte {
__le32 addr;
__le32 count;
u8 val[0];
} __packed;
#define CARL9170FW_PHY_HT_ENABLE 0x4
#define CARL9170FW_PHY_HT_DYN2040 0x8
#define CARL9170FW_PHY_HT_EXT_CHAN_OFF 0x3
@ -226,6 +233,7 @@ struct carl9170_cmd {
struct carl9170_u32_list echo;
struct carl9170_reg_list rreg;
struct carl9170_write_reg wreg;
struct carl9170_write_reg_byte wregb;
struct carl9170_rf_init rf_init;
struct carl9170_psm psm;
struct carl9170_wol_cmd wol;

View File

@ -81,6 +81,12 @@ enum carl9170fw_feature_list {
/* Firmware will pass BA when BARs are queued */
CARL9170FW_RX_BA_FILTER,
/* Firmware has support to write a byte at a time */
CARL9170FW_HAS_WREGB_CMD,
/* Pattern generator */
CARL9170FW_PATTERN_GENERATOR,
/* KEEP LAST */
__CARL9170FW_FEATURE_NUM
};

View File

@ -453,9 +453,74 @@
#define AR9170_MC_REG_BASE 0x1d1000
#define AR9170_MC_REG_FLASH_WAIT_STATE (AR9170_MC_REG_BASE + 0x000)
#define AR9170_MC_REG_SEEPROM_WP0 (AR9170_MC_REG_BASE + 0x400)
#define AR9170_MC_REG_SEEPROM_WP1 (AR9170_MC_REG_BASE + 0x404)
#define AR9170_MC_REG_SEEPROM_WP2 (AR9170_MC_REG_BASE + 0x408)
#define AR9170_SPI_REG_BASE (AR9170_MC_REG_BASE + 0x200)
#define AR9170_SPI_REG_CONTROL0 (AR9170_SPI_REG_BASE + 0x000)
#define AR9170_SPI_CONTROL0_BUSY BIT(0)
#define AR9170_SPI_CONTROL0_CMD_GO BIT(1)
#define AR9170_SPI_CONTROL0_PAGE_WR BIT(2)
#define AR9170_SPI_CONTROL0_SEQ_RD BIT(3)
#define AR9170_SPI_CONTROL0_CMD_ABORT BIT(4)
#define AR9170_SPI_CONTROL0_CMD_LEN_S 8
#define AR9170_SPI_CONTROL0_CMD_LEN 0x00000f00
#define AR9170_SPI_CONTROL0_RD_LEN_S 12
#define AR9170_SPI_CONTROL0_RD_LEN 0x00007000
#define AR9170_SPI_REG_CONTROL1 (AR9170_SPI_REG_BASE + 0x004)
#define AR9170_SPI_CONTROL1_SCK_RATE BIT(0)
#define AR9170_SPI_CONTROL1_DRIVE_SDO BIT(1)
#define AR9170_SPI_CONTROL1_MODE_SEL_S 2
#define AR9170_SPI_CONTROL1_MODE_SEL 0x000000c0
#define AR9170_SPI_CONTROL1_WRITE_PROTECT BIT(4)
#define AR9170_SPI_REG_COMMAND_PORT0 (AR9170_SPI_REG_BASE + 0x008)
#define AR9170_SPI_COMMAND_PORT0_CMD0_S 0
#define AR9170_SPI_COMMAND_PORT0_CMD0 0x000000ff
#define AR9170_SPI_COMMAND_PORT0_CMD1_S 8
#define AR9170_SPI_COMMAND_PORT0_CMD1 0x0000ff00
#define AR9170_SPI_COMMAND_PORT0_CMD2_S 16
#define AR9170_SPI_COMMAND_PORT0_CMD2 0x00ff0000
#define AR9170_SPI_COMMAND_PORT0_CMD3_S 24
#define AR9170_SPI_COMMAND_PORT0_CMD3 0xff000000
#define AR9170_SPI_REG_COMMAND_PORT1 (AR9170_SPI_REG_BASE + 0x00C)
#define AR9170_SPI_COMMAND_PORT1_CMD4_S 0
#define AR9170_SPI_COMMAND_PORT1_CMD4 0x000000ff
#define AR9170_SPI_COMMAND_PORT1_CMD5_S 8
#define AR9170_SPI_COMMAND_PORT1_CMD5 0x0000ff00
#define AR9170_SPI_COMMAND_PORT1_CMD6_S 16
#define AR9170_SPI_COMMAND_PORT1_CMD6 0x00ff0000
#define AR9170_SPI_COMMAND_PORT1_CMD7_S 24
#define AR9170_SPI_COMMAND_PORT1_CMD7 0xff000000
#define AR9170_SPI_REG_DATA_PORT (AR9170_SPI_REG_BASE + 0x010)
#define AR9170_SPI_REG_PAGE_WRITE_LEN (AR9170_SPI_REG_BASE + 0x014)
#define AR9170_EEPROM_REG_BASE (AR9170_MC_REG_BASE + 0x400)
#define AR9170_EEPROM_REG_WP_MAGIC1 (AR9170_EEPROM_REG_BASE + 0x000)
#define AR9170_EEPROM_WP_MAGIC1 0x12345678
#define AR9170_EEPROM_REG_WP_MAGIC2 (AR9170_EEPROM_REG_BASE + 0x004)
#define AR9170_EEPROM_WP_MAGIC2 0x55aa00ff
#define AR9170_EEPROM_REG_WP_MAGIC3 (AR9170_EEPROM_REG_BASE + 0x008)
#define AR9170_EEPROM_WP_MAGIC3 0x13579ace
#define AR9170_EEPROM_REG_CLOCK_DIV (AR9170_EEPROM_REG_BASE + 0x00C)
#define AR9170_EEPROM_CLOCK_DIV_FAC_S 0
#define AR9170_EEPROM_CLOCK_DIV_FAC 0x000001ff
#define AR9170_EEPROM_CLOCK_DIV_FAC_39KHZ 0xff
#define AR9170_EEPROM_CLOCK_DIV_FAC_78KHZ 0x7f
#define AR9170_EEPROM_CLOCK_DIV_FAC_312KHZ 0x1f
#define AR9170_EEPROM_CLOCK_DIV_FAC_10MHZ 0x0
#define AR9170_EEPROM_CLOCK_DIV_SOFT_RST BIT(9)
#define AR9170_EEPROM_REG_MODE (AR9170_EEPROM_REG_BASE + 0x010)
#define AR9170_EEPROM_MODE_EEPROM_SIZE_16K_PLUS BIT(31)
#define AR9170_EEPROM_REG_WRITE_PROTECT (AR9170_EEPROM_REG_BASE + 0x014)
#define AR9170_EEPROM_WRITE_PROTECT_WP_STATUS BIT(0)
#define AR9170_EEPROM_WRITE_PROTECT_WP_SET BIT(8)
/* Interrupt Controller */
#define AR9170_MAX_INT_SRC 9
@ -589,11 +654,13 @@
#define AR9170_USB_REG_EP10_MAP (AR9170_USB_REG_BASE + 0x039)
#define AR9170_USB_REG_EP_IN_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x03f)
#define AR9170_USB_EP_IN_STALL 0x8
#define AR9170_USB_EP_IN_TOGGLE 0x10
#define AR9170_USB_REG_EP_IN_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x03e)
#define AR9170_USB_REG_EP_OUT_MAX_SIZE_HIGH (AR9170_USB_REG_BASE + 0x05f)
#define AR9170_USB_EP_OUT_STALL 0x8
#define AR9170_USB_EP_OUT_TOGGLE 0x10
#define AR9170_USB_REG_EP_OUT_MAX_SIZE_LOW (AR9170_USB_REG_BASE + 0x05e)

View File

@ -1,7 +1,7 @@
#ifndef __CARL9170_SHARED_VERSION_H
#define __CARL9170_SHARED_VERSION_H
#define CARL9170FW_VERSION_YEAR 12
#define CARL9170FW_VERSION_MONTH 12
#define CARL9170FW_VERSION_YEAR 16
#define CARL9170FW_VERSION_MONTH 2
#define CARL9170FW_VERSION_DAY 15
#define CARL9170FW_VERSION_GIT "1.9.7"
#define CARL9170FW_VERSION_GIT "1.9.9"
#endif /* __CARL9170_SHARED_VERSION_H */

View File

@ -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
* purpose with or without fee is hereby granted, provided that the above
@ -540,7 +540,18 @@ static int wil_cfg80211_disconnect(struct wiphy *wiphy,
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;
}
@ -701,6 +712,79 @@ static int wil_cancel_remain_on_channel(struct wiphy *wiphy,
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)
{
print_hex_dump_bytes("head ", DUMP_PREFIX_OFFSET,
@ -717,49 +801,49 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
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 */
static int _wil_cfg80211_set_ies(struct wiphy *wiphy,
struct cfg80211_beacon_data *bcon)
{
int rc;
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)
return rc;
goto out;
rc = wmi_set_ie(wil, WMI_FRAME_ASSOC_RESP, bcon->assocresp_ies_len,
bcon->assocresp_ies);
rc = wmi_set_ie(wil, WMI_FRAME_PROBE_RESP, len, 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 (rc)
return rc;
goto out;
rc = wmi_set_ie(wil, WMI_FRAME_BEACON, bcon->tail_len, bcon->tail);
#endif
out:
kfree(ies);
return rc;
}
@ -828,14 +912,9 @@ static int wil_cfg80211_change_beacon(struct wiphy *wiphy,
wil_dbg_misc(wil, "%s()\n", __func__);
wil_print_bcon_data(bcon);
if (wil_fix_bcon(wil, bcon)) {
wil_dbg_misc(wil, "Fixed bcon\n");
wil_print_bcon_data(bcon);
}
if (bcon->proberesp_ies &&
cfg80211_find_ie(WLAN_EID_RSN, bcon->proberesp_ies,
bcon->proberesp_ies_len))
if (bcon->tail &&
cfg80211_find_ie(WLAN_EID_RSN, bcon->tail,
bcon->tail_len))
privacy = 1;
/* in case privacy has changed, need to restart the AP */
@ -910,11 +989,6 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil_print_bcon_data(bcon);
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,
info->ssid, info->ssid_len, info->privacy,
info->beacon_interval, channel->hw_value,

View File

@ -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
* 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");
}
if (vring->va && (vring->size < 1025)) {
if (vring->va && (vring->size <= (1 << WIL_RING_SIZE_ORDER_MAX))) {
uint i;
for (i = 0; i < vring->size; i++) {
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_printf(s, "%c", (d->dma.status & BIT(0)) ?
_s : (vring->ctx[i].skb ? _h : 'h'));

View File

@ -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
* purpose with or without fee is hereby granted, provided that the above
@ -23,9 +23,6 @@
#include "wmi.h"
#include "boot_loader.h"
#define WAIT_FOR_DISCONNECT_TIMEOUT_MS 2000
#define WAIT_FOR_DISCONNECT_INTERVAL_MS 10
bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
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 (!from_event)
wmi_disconnect_sta(wil, sta->addr, reason_code);
wmi_disconnect_sta(wil, sta->addr, reason_code, true);
switch (wdev->iftype) {
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;
might_sleep();
wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
reason_code, from_event ? "+" : "-");
wil_info(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
reason_code, from_event ? "+" : "-");
/* Cases are:
* - 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)
{
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
* 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)
@ -369,6 +369,32 @@ static int wil_find_free_vring(struct wil6210_priv *wil)
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 ri = wil->bcast_vring, rc;
@ -399,41 +425,6 @@ void wil_bcast_fini(struct wil6210_priv *wil)
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)
{
uint i;
@ -444,6 +435,9 @@ int wil_priv_init(struct wil6210_priv *wil)
for (i = 0; i < WIL6210_MAX_CID; i++)
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->wmi_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_call);
wil->pending_connect_cid = -1;
wil->bcast_vring = -1;
setup_timer(&wil->connect_timer, wil_connect_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->wmi_event_worker, wmi_event_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 */
wil->pending_connect_cid = -1;
wil->ap_isolate = 0;
reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call);
@ -948,8 +939,7 @@ int wil_up(struct wil6210_priv *wil)
int __wil_down(struct wil6210_priv *wil)
{
int iter = WAIT_FOR_DISCONNECT_TIMEOUT_MS /
WAIT_FOR_DISCONNECT_INTERVAL_MS;
int rc;
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) ||
test_bit(wil_status_fwconnecting, wil->status))
wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
test_bit(wil_status_fwconnecting, wil->status)) {
/* make sure wil is idle (not connected) */
mutex_unlock(&wil->mutex);
while (iter--) {
int idle = !test_bit(wil_status_fwconnected, wil->status) &&
!test_bit(wil_status_fwconnecting, wil->status);
if (idle)
break;
msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
mutex_unlock(&wil->mutex);
rc = wmi_call(wil, WMI_DISCONNECT_CMDID, NULL, 0,
WMI_DISCONNECT_EVENTID, NULL, 0,
WIL6210_DISCONNECT_TO_MS);
mutex_lock(&wil->mutex);
if (rc)
wil_err(wil, "timeout waiting for disconnect\n");
}
mutex_lock(&wil->mutex);
if (iter < 0)
wil_err(wil, "timeout waiting for idle FW/HW\n");
wil_reset(wil, false);

View File

@ -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
* 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 */
for (i = 0; i < WIL6210_MAX_TX_RINGS; 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;
tx_done += wil_tx_complete(wil, i);

View File

@ -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
* 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);
}
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 cid, int tid)
{
@ -758,8 +773,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
goto out;
}
memset(txdata, 0, sizeof(*txdata));
spin_lock_init(&txdata->lock);
wil_tx_data_init(txdata);
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
@ -791,9 +805,14 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
return 0;
out_free:
spin_lock_bh(&txdata->lock);
txdata->dot1x_open = false;
txdata->enabled = 0;
spin_unlock_bh(&txdata->lock);
wil_vring_free(wil, vring, 1);
wil->vring2cid_tid[id][0] = WIL6210_MAX_CID;
wil->vring2cid_tid[id][1] = 0;
out:
return rc;
@ -831,8 +850,7 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
goto out;
}
memset(txdata, 0, sizeof(*txdata));
spin_lock_init(&txdata->lock);
wil_tx_data_init(txdata);
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
@ -862,8 +880,10 @@ int wil_vring_init_bcast(struct wil6210_priv *wil, int id, int size)
return 0;
out_free:
spin_lock_bh(&txdata->lock);
txdata->enabled = 0;
txdata->dot1x_open = false;
spin_unlock_bh(&txdata->lock);
wil_vring_free(wil, vring, 1);
out:
@ -891,7 +911,6 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
napi_synchronize(&wil->napi_tx);
wil_vring_free(wil, vring, 1);
memset(txdata, 0, sizeof(*txdata));
}
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;
if (wil->vring2cid_tid[i][0] == cid) {
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",
__func__, eth->h_dest, i);
if (v->va) {
if (v->va && txdata->enabled) {
return v;
} else {
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;
int i;
u8 cid;
struct vring_tx_data *txdata;
/* In the STA mode, it is expected to have only 1 VRING
* 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++) {
v = &wil->vring_tx[i];
if (!v->va)
txdata = &wil->vring_tx_data[i];
if (!v->va || !txdata->enabled)
continue;
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 vring *v;
struct vring_tx_data *txdata;
int i = wil->bcast_vring;
if (i < 0)
return NULL;
v = &wil->vring_tx[i];
if (!v->va)
txdata = &wil->vring_tx_data[i];
if (!v->va || !txdata->enabled)
return NULL;
if (!wil->vring_tx_data[i].dot1x_open &&
(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;
struct ethhdr *eth = (void *)skb->data;
char *src = eth->h_source;
struct vring_tx_data *txdata;
/* find 1-st vring eligible for data */
for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
v = &wil->vring_tx[i];
if (!v->va)
txdata = &wil->vring_tx_data[i];
if (!v->va || !txdata->enabled)
continue;
cid = wil->vring2cid_tid[i][0];

View File

@ -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
* 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_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_MCS0_LIMIT (1024) /* limit for MCS0 frame size */
/* 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_TO msecs_to_jiffies(5000)
#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_DEFAULT \
(1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
@ -581,12 +582,10 @@ struct wil6210_priv {
struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker;
struct workqueue_struct *wq_service;
struct work_struct connect_worker;
struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
struct timer_list connect_timer;
struct timer_list scan_timer; /* detect scan timeout */
int pending_connect_cid;
struct list_head 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_rxon(struct wil6210_priv *wil, bool on);
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_delba_tx(struct wil6210_priv *wil, u8 ringid, 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 cid, int tid);
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_bcast_init(struct wil6210_priv *wil);
void wil_bcast_fini(struct wil6210_priv *wil);

View File

@ -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
* 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;
/* capinfo(u16) + status_code(u16) + associd(u16) + IEs */
const size_t assoc_resp_ie_offset = sizeof(u16) * 3;
int rc;
if (len < sizeof(*evt)) {
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;
wil_dbg_wmi(wil, "Connect %pM channel [%d] cid %d\n",
evt->bssid, ch, evt->cid);
wil_info(wil, "Connect %pM channel [%d] cid %d\n",
evt->bssid, ch, evt->cid);
wil_hex_dump_wmi("connect AI : ", DUMP_PREFIX_OFFSET, 16, 1,
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;
}
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) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
if (!test_bit(wil_status_fwconnecting, wil->status)) {
wil_err(wil, "Not in connecting state\n");
mutex_unlock(&wil->mutex);
return;
}
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) ||
(wdev->iftype == NL80211_IFTYPE_P2P_GO)) {
if (rc)
goto out;
memset(&sinfo, 0, sizeof(sinfo));
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);
} 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);
netif_tx_wake_all_queues(ndev);
/* 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;
wil->pending_connect_cid = evt->cid;
queue_work(wil->wq_service, &wil->connect_worker);
out:
if (rc)
wil->sta[evt->cid].status = wil_sta_unused;
clear_bit(wil_status_fwconnecting, wil->status);
mutex_unlock(&wil->mutex);
}
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;
u16 reason_code = le16_to_cpu(evt->protocol_reason_status);
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
evt->bssid, reason_code, evt->disconnect_reason);
wil_info(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
evt->bssid, reason_code, evt->disconnect_reason);
wil->sinfo_gen++;
@ -727,6 +779,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
void __iomem *src;
ulong flags;
unsigned n;
unsigned int num_immed_reply = 0;
if (!test_bit(wil_status_mbox_ready, wil->status)) {
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++) {
u16 len;
bool q;
bool immed_reply = false;
r->head = wil_r(wil, RGF_MBOX +
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;
u16 id = le16_to_cpu(wmi->id);
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",
id, wmi->mid, tstamp);
@ -799,15 +862,24 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
wil_w(wil, RGF_MBOX +
offsetof(struct wil6210_mbox_ctl, rx.tail), r->tail);
/* 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);
if (immed_reply) {
wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
__func__, wil->reply_id);
kfree(evt);
num_immed_reply++;
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 */
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,
@ -818,13 +890,16 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
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);
if (rc)
goto out;
wil->reply_id = reply_id;
wil->reply_buf = reply;
wil->reply_size = reply_size;
remain = wait_for_completion_timeout(&wil->wmi_call,
msecs_to_jiffies(to_msec));
if (0 == remain) {
@ -837,10 +912,14 @@ int wmi_call(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len,
cmdid, reply_id,
to_msec - jiffies_to_msecs(remain));
}
out:
spin_lock(&wil->wmi_ev_lock);
wil->reply_id = 0;
wil->reply_buf = NULL;
wil->reply_size = 0;
out:
spin_unlock(&wil->wmi_ev_lock);
mutex_unlock(&wil->wmi_mutex);
return rc;
@ -1184,7 +1263,8 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
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;
u16 reason_code;
@ -1208,19 +1288,20 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
return rc;
}
/* call event handler manually after processing wmi_call,
* 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);
if (full_disconnect) {
/* call event handler manually after processing wmi_call,
* 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);
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
reply.evt.bssid, reason_code,
reply.evt.disconnect_reason);
wil->sinfo_gen++;
wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
wil_dbg_wmi(wil, "Disconnect %pM reason [proto %d wmi %d]\n",
reply.evt.bssid, reason_code,
reply.evt.disconnect_reason);
wil->sinfo_gen++;
wil6210_disconnect(wil, reply.evt.bssid, reason_code, true);
}
return 0;
}
@ -1348,14 +1429,11 @@ static void wmi_event_handle(struct wil6210_priv *wil,
id, wil->reply_id);
/* check if someone waits for this event */
if (wil->reply_id && wil->reply_id == id) {
if (wil->reply_buf) {
memcpy(wil->reply_buf, wmi,
min(len, wil->reply_size));
} else {
wmi_evt_call_handler(wil, id, evt_data,
len - sizeof(*wmi));
}
wil_dbg_wmi(wil, "Complete WMI 0x%04x\n", id);
WARN_ON(wil->reply_buf);
wmi_evt_call_handler(wil, id, evt_data,
len - sizeof(*wmi));
wil_dbg_wmi(wil, "%s: Complete WMI 0x%04x\n",
__func__, id);
complete(&wil->wmi_call);
return;
}

View File

@ -2481,9 +2481,7 @@ static int at76_probe(struct usb_interface *interface,
dev_err(&interface->dev,
"error %d downloading internal firmware\n",
ret);
goto exit;
}
usb_put_dev(udev);
goto exit;
}

View File

@ -4375,12 +4375,10 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
/* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
orig_dev = dev;
mutex_unlock(&wl->mutex);
if (b43_bus_host_is_sdio(dev->dev)) {
if (b43_bus_host_is_sdio(dev->dev))
b43_sdio_free_irq(dev);
} else {
synchronize_irq(dev->dev->irq);
else
free_irq(dev->dev->irq, dev);
}
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev)

View File

@ -27,8 +27,6 @@
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/platform_device.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <linux/pm_runtime.h>
#include <linux/suspend.h>
#include <linux/errno.h>
@ -46,7 +44,6 @@
#include "bus.h"
#include "debug.h"
#include "sdio.h"
#include "of.h"
#include "core.h"
#include "common.h"
@ -106,18 +103,18 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
{
struct brcmfmac_sdio_pd *pdata;
int ret = 0;
u8 data;
u32 addr, gpiocontrol;
unsigned long flags;
if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
pdata = &sdiodev->settings->bus.sdio;
if (pdata->oob_irq_supported) {
brcmf_dbg(SDIO, "Enter, register OOB IRQ %d\n",
sdiodev->pdata->oob_irq_nr);
ret = request_irq(sdiodev->pdata->oob_irq_nr,
brcmf_sdiod_oob_irqhandler,
sdiodev->pdata->oob_irq_flags,
"brcmf_oob_intr",
pdata->oob_irq_nr);
ret = request_irq(pdata->oob_irq_nr, brcmf_sdiod_oob_irqhandler,
pdata->oob_irq_flags, "brcmf_oob_intr",
&sdiodev->func[1]->dev);
if (ret != 0) {
brcmf_err("request_irq failed %d\n", ret);
@ -129,7 +126,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
sdiodev->irq_en = true;
spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
ret = enable_irq_wake(sdiodev->pdata->oob_irq_nr);
ret = enable_irq_wake(pdata->oob_irq_nr);
if (ret != 0) {
brcmf_err("enable_irq_wake failed %d\n", ret);
return ret;
@ -158,7 +155,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
/* redirect, configure and enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
if (pdata->oob_irq_flags & IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
@ -176,9 +173,12 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
struct brcmfmac_sdio_pd *pdata;
brcmf_dbg(SDIO, "Entering\n");
if ((sdiodev->pdata) && (sdiodev->pdata->oob_irq_supported)) {
pdata = &sdiodev->settings->bus.sdio;
if (pdata->oob_irq_supported) {
sdio_claim_host(sdiodev->func[1]);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
@ -187,11 +187,10 @@ int brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev)
if (sdiodev->oob_irq_requested) {
sdiodev->oob_irq_requested = false;
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->pdata->oob_irq_nr);
disable_irq_wake(pdata->oob_irq_nr);
sdiodev->irq_wake = false;
}
free_irq(sdiodev->pdata->oob_irq_nr,
&sdiodev->func[1]->dev);
free_irq(pdata->oob_irq_nr, &sdiodev->func[1]->dev);
sdiodev->irq_en = false;
}
} else {
@ -523,7 +522,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
target_list = pktlist;
/* for host with broken sg support, prepare a page aligned list */
__skb_queue_head_init(&local_list);
if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
req_sz = 0;
skb_queue_walk(pktlist, pkt_next)
req_sz += pkt_next->len;
@ -630,7 +629,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
}
}
if (sdiodev->pdata && sdiodev->pdata->broken_sg_support && !write) {
if (!write && sdiodev->settings->bus.sdio.broken_sg_support) {
local_pkt_next = local_list.next;
orig_offset = 0;
skb_queue_walk(pktlist, pkt_next) {
@ -901,7 +900,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
return;
nents = max_t(uint, BRCMF_DEFAULT_RXGLOM_SIZE,
sdiodev->bus_if->drvr->settings->sdiod_txglomsz);
sdiodev->settings->bus.sdio.txglomsz);
nents += (nents >> 4) + 1;
WARN_ON(nents > sdiodev->max_segment_count);
@ -913,7 +912,7 @@ void brcmf_sdiod_sgtable_alloc(struct brcmf_sdio_dev *sdiodev)
sdiodev->sg_support = false;
}
sdiodev->txglomsz = sdiodev->bus_if->drvr->settings->sdiod_txglomsz;
sdiodev->txglomsz = sdiodev->settings->bus.sdio.txglomsz;
}
#ifdef CONFIG_PM_SLEEP
@ -1103,8 +1102,6 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
static struct brcmfmac_sdio_platform_data *brcmfmac_sdio_pdata;
static void brcmf_sdiod_acpi_set_power_manageable(struct device *dev,
int val)
@ -1167,20 +1164,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
dev_set_drvdata(&func->dev, bus_if);
dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
sdiodev->dev = &sdiodev->func[1]->dev;
sdiodev->pdata = brcmfmac_sdio_pdata;
if (!sdiodev->pdata)
brcmf_of_probe(sdiodev);
#ifdef CONFIG_PM_SLEEP
/* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
* is true or when platform data OOB irq is true).
*/
if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
(sdiodev->pdata && sdiodev->pdata->oob_irq_supported)))
bus_if->wowl_supported = true;
#endif
brcmf_sdiod_change_state(sdiodev, BRCMF_SDIOD_DOWN);
@ -1263,8 +1246,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
sdio_flags = MMC_PM_KEEP_POWER;
if (sdiodev->wowl_enabled) {
if (sdiodev->pdata->oob_irq_supported)
enable_irq_wake(sdiodev->pdata->oob_irq_nr);
if (sdiodev->settings->bus.sdio.oob_irq_supported)
enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr);
else
sdio_flags |= MMC_PM_WAKE_SDIO_IRQ;
}
@ -1296,7 +1279,7 @@ static const struct dev_pm_ops brcmf_sdio_pm_ops = {
static struct sdio_driver brcmf_sdmmc_driver = {
.probe = brcmf_ops_sdio_probe,
.remove = brcmf_ops_sdio_remove,
.name = BRCMFMAC_SDIO_PDATA_NAME,
.name = KBUILD_MODNAME,
.id_table = brcmf_sdmmc_ids,
.drv = {
.owner = THIS_MODULE,
@ -1306,37 +1289,6 @@ static struct sdio_driver brcmf_sdmmc_driver = {
},
};
static int __init brcmf_sdio_pd_probe(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
brcmfmac_sdio_pdata = dev_get_platdata(&pdev->dev);
if (brcmfmac_sdio_pdata->power_on)
brcmfmac_sdio_pdata->power_on();
return 0;
}
static int brcmf_sdio_pd_remove(struct platform_device *pdev)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata->power_off)
brcmfmac_sdio_pdata->power_off();
sdio_unregister_driver(&brcmf_sdmmc_driver);
return 0;
}
static struct platform_driver brcmf_sdio_pd = {
.remove = brcmf_sdio_pd_remove,
.driver = {
.name = BRCMFMAC_SDIO_PDATA_NAME,
}
};
void brcmf_sdio_register(void)
{
int ret;
@ -1350,19 +1302,6 @@ void brcmf_sdio_exit(void)
{
brcmf_dbg(SDIO, "Enter\n");
if (brcmfmac_sdio_pdata)
platform_driver_unregister(&brcmf_sdio_pd);
else
sdio_unregister_driver(&brcmf_sdmmc_driver);
sdio_unregister_driver(&brcmf_sdmmc_driver);
}
void __init brcmf_sdio_init(void)
{
int ret;
brcmf_dbg(SDIO, "Enter\n");
ret = platform_driver_probe(&brcmf_sdio_pd, brcmf_sdio_pd_probe);
if (ret == -ENODEV)
brcmf_dbg(SDIO, "No platform data available.\n");
}

View File

@ -43,6 +43,8 @@ enum brcmf_bus_protocol_type {
BRCMF_PROTO_MSGBUF
};
struct brcmf_mp_device;
struct brcmf_bus_dcmd {
char *name;
char *param;
@ -217,7 +219,7 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
/* Indication from bus module regarding presence/insertion of dongle. */
int brcmf_attach(struct device *dev);
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
/* Indication from bus module regarding removal/absence of dongle */
void brcmf_detach(struct device *dev);
/* Indication from bus module that dongle should be reset */

View File

@ -72,8 +72,13 @@
#define RSN_AKM_NONE 0 /* None (IBSS) */
#define RSN_AKM_UNSPECIFIED 1 /* Over 802.1x */
#define RSN_AKM_PSK 2 /* Pre-shared Key */
#define RSN_AKM_SHA256_1X 5 /* SHA256, 802.1X */
#define RSN_AKM_SHA256_PSK 6 /* SHA256, Pre-shared Key */
#define RSN_CAP_LEN 2 /* Length of RSN capabilities */
#define RSN_CAP_PTK_REPLAY_CNTR_MASK 0x000C
#define RSN_CAP_PTK_REPLAY_CNTR_MASK (BIT(2) | BIT(3))
#define RSN_CAP_MFPR_MASK BIT(6)
#define RSN_CAP_MFPC_MASK BIT(7)
#define RSN_PMKID_COUNT_LEN 2
#define VNDR_IE_CMD_LEN 4 /* length of the set command
* string :"add", "del" (+ NUL)
@ -211,12 +216,19 @@ static const struct ieee80211_regdomain brcmf_regdom = {
REG_RULE(5470-10, 5850+10, 80, 6, 20, 0), }
};
static const u32 __wl_cipher_suites[] = {
/* Note: brcmf_cipher_suites is an array of int defining which cipher suites
* are supported. A pointer to this array and the number of entries is passed
* on to upper layers. AES_CMAC defines whether or not the driver supports MFP.
* So the cipher suite AES_CMAC has to be the last one in the array, and when
* device does not support MFP then the number of suites will be decreased by 1
*/
static const u32 brcmf_cipher_suites[] = {
WLAN_CIPHER_SUITE_WEP40,
WLAN_CIPHER_SUITE_WEP104,
WLAN_CIPHER_SUITE_TKIP,
WLAN_CIPHER_SUITE_CCMP,
WLAN_CIPHER_SUITE_AES_CMAC,
/* Keep as last entry: */
WLAN_CIPHER_SUITE_AES_CMAC
};
/* Vendor specific ie. id = 221, oui and type defines exact ie */
@ -456,7 +468,7 @@ send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
}
static s32
brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
brcmf_configure_arp_nd_offload(struct brcmf_if *ifp, bool enable)
{
s32 err;
u32 mode;
@ -484,6 +496,15 @@ brcmf_configure_arp_offload(struct brcmf_if *ifp, bool enable)
enable, mode);
}
err = brcmf_fil_iovar_int_set(ifp, "ndoe", enable);
if (err) {
brcmf_dbg(TRACE, "failed to configure (%d) ND offload err = %d\n",
enable, err);
err = 0;
} else
brcmf_dbg(TRACE, "successfully configured (%d) ND offload to 0x%x\n",
enable, mode);
return err;
}
@ -564,8 +585,8 @@ struct wireless_dev *brcmf_ap_add_vif(struct wiphy *wiphy, const char *name,
}
/* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) {
brcmf_err("timeout occurred\n");
@ -1125,7 +1146,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct brcmf_cfg80211_vif *vif,
/* Arm scan timeout timer */
mod_timer(&cfg->escan_timeout, jiffies +
WL_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
BRCMF_ESCAN_TIMER_INTERVAL_MS * HZ / 1000);
return 0;
@ -1524,7 +1545,7 @@ static s32 brcmf_set_auth_type(struct net_device *ndev,
static s32
brcmf_set_wsec_mode(struct net_device *ndev,
struct cfg80211_connect_params *sme, bool mfp)
struct cfg80211_connect_params *sme)
{
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
struct brcmf_cfg80211_security *sec;
@ -1583,10 +1604,7 @@ brcmf_set_wsec_mode(struct net_device *ndev,
sme->privacy)
pval = AES_ENABLED;
if (mfp)
wsec = pval | gval | MFP_CAPABLE;
else
wsec = pval | gval;
wsec = pval | gval;
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wsec", wsec);
if (err) {
brcmf_err("error (%d)\n", err);
@ -1603,56 +1621,100 @@ brcmf_set_wsec_mode(struct net_device *ndev,
static s32
brcmf_set_key_mgmt(struct net_device *ndev, struct cfg80211_connect_params *sme)
{
struct brcmf_cfg80211_profile *profile = ndev_to_prof(ndev);
struct brcmf_cfg80211_security *sec;
s32 val = 0;
s32 err = 0;
struct brcmf_if *ifp = netdev_priv(ndev);
s32 val;
s32 err;
const struct brcmf_tlv *rsn_ie;
const u8 *ie;
u32 ie_len;
u32 offset;
u16 rsn_cap;
u32 mfp;
u16 count;
if (sme->crypto.n_akm_suites) {
err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev),
"wpa_auth", &val);
if (err) {
brcmf_err("could not get wpa_auth (%d)\n", err);
return err;
}
if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA_AUTH_UNSPECIFIED;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA_AUTH_PSK;
break;
default:
brcmf_err("invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA2_AUTH_UNSPECIFIED;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA2_AUTH_PSK;
break;
default:
brcmf_err("invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
}
if (!sme->crypto.n_akm_suites)
return 0;
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev),
"wpa_auth", val);
if (err) {
brcmf_err("could not set wpa_auth (%d)\n", err);
return err;
err = brcmf_fil_bsscfg_int_get(netdev_priv(ndev), "wpa_auth", &val);
if (err) {
brcmf_err("could not get wpa_auth (%d)\n", err);
return err;
}
if (val & (WPA_AUTH_PSK | WPA_AUTH_UNSPECIFIED)) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA_AUTH_UNSPECIFIED;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA_AUTH_PSK;
break;
default:
brcmf_err("invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
} else if (val & (WPA2_AUTH_PSK | WPA2_AUTH_UNSPECIFIED)) {
switch (sme->crypto.akm_suites[0]) {
case WLAN_AKM_SUITE_8021X:
val = WPA2_AUTH_UNSPECIFIED;
break;
case WLAN_AKM_SUITE_8021X_SHA256:
val = WPA2_AUTH_1X_SHA256;
break;
case WLAN_AKM_SUITE_PSK_SHA256:
val = WPA2_AUTH_PSK_SHA256;
break;
case WLAN_AKM_SUITE_PSK:
val = WPA2_AUTH_PSK;
break;
default:
brcmf_err("invalid cipher group (%d)\n",
sme->crypto.cipher_group);
return -EINVAL;
}
}
sec = &profile->sec;
sec->wpa_auth = sme->crypto.akm_suites[0];
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
goto skip_mfp_config;
/* The MFP mode (1 or 2) needs to be determined, parse IEs. The
* IE will not be verified, just a quick search for MFP config
*/
rsn_ie = brcmf_parse_tlvs((const u8 *)sme->ie, sme->ie_len,
WLAN_EID_RSN);
if (!rsn_ie)
goto skip_mfp_config;
ie = (const u8 *)rsn_ie;
ie_len = rsn_ie->len + TLV_HDR_LEN;
/* Skip unicast suite */
offset = TLV_HDR_LEN + WPA_IE_VERSION_LEN + WPA_IE_MIN_OUI_LEN;
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
goto skip_mfp_config;
/* Skip multicast suite */
count = ie[offset] + (ie[offset + 1] << 8);
offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
if (offset + WPA_IE_SUITE_COUNT_LEN >= ie_len)
goto skip_mfp_config;
/* Skip auth key management suite(s) */
count = ie[offset] + (ie[offset + 1] << 8);
offset += WPA_IE_SUITE_COUNT_LEN + (count * WPA_IE_MIN_OUI_LEN);
if (offset + WPA_IE_SUITE_COUNT_LEN > ie_len)
goto skip_mfp_config;
/* Ready to read capabilities */
mfp = BRCMF_MFP_NONE;
rsn_cap = ie[offset] + (ie[offset + 1] << 8);
if (rsn_cap & RSN_CAP_MFPR_MASK)
mfp = BRCMF_MFP_REQUIRED;
else if (rsn_cap & RSN_CAP_MFPC_MASK)
mfp = BRCMF_MFP_CAPABLE;
brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "mfp", mfp);
skip_mfp_config:
brcmf_dbg(CONN, "setting wpa_auth to %d\n", val);
err = brcmf_fil_bsscfg_int_set(netdev_priv(ndev), "wpa_auth", val);
if (err) {
brcmf_err("could not set wpa_auth (%d)\n", err);
return err;
}
return err;
}
@ -1818,7 +1880,7 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
err = brcmf_set_wsec_mode(ndev, sme, sme->mfp == NL80211_MFP_REQUIRED);
err = brcmf_set_wsec_mode(ndev, sme);
if (err) {
brcmf_err("wl_set_set_cipher failed (%d)\n", err);
goto done;
@ -2064,98 +2126,54 @@ brcmf_cfg80211_config_default_key(struct wiphy *wiphy, struct net_device *ndev,
}
static s32
brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, const u8 *mac_addr, struct key_params *params)
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key key;
s32 err = 0;
u8 keybuf[8];
struct brcmf_wsec_key *key;
s32 err;
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
/* Instead of bcast for ea address for default wep keys,
driver needs it to be Null */
if (!is_multicast_ether_addr(mac_addr))
memcpy((char *)&key.ea, (void *)mac_addr, ETH_ALEN);
key.len = (u32) params->key_len;
/* check for key index change */
if (key.len == 0) {
/* key delete */
err = send_key_to_dongle(ifp, &key);
if (err)
brcmf_err("key delete error (%d)\n", err);
} else {
if (key.len > sizeof(key.data)) {
brcmf_err("Invalid key length (%d)\n", key.len);
return -EINVAL;
}
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CONN, "key index (%d)\n", key_idx);
brcmf_dbg(CONN, "Setting the key index %d\n", key.index);
memcpy(key.data, params->key, key.len);
if (!check_vif_up(ifp->vif))
return -EIO;
if (!brcmf_is_apmode(ifp->vif) &&
(params->cipher == WLAN_CIPHER_SUITE_TKIP)) {
brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
memcpy(keybuf, &key.data[24], sizeof(keybuf));
memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
memcpy(&key.data[16], keybuf, sizeof(keybuf));
}
/* if IW_ENCODE_EXT_RX_SEQ_VALID set */
if (params->seq && params->seq_len == 6) {
/* rx iv */
u8 *ivptr;
ivptr = (u8 *) params->seq;
key.rxiv.hi = (ivptr[5] << 24) | (ivptr[4] << 16) |
(ivptr[3] << 8) | ivptr[2];
key.rxiv.lo = (ivptr[1] << 8) | ivptr[0];
key.iv_initialized = true;
}
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
key.algo = CRYPTO_ALGO_WEP1;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
key.algo = CRYPTO_ALGO_WEP128;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
key.algo = CRYPTO_ALGO_TKIP;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
key.algo = CRYPTO_ALGO_AES_CCM;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
break;
case WLAN_CIPHER_SUITE_CCMP:
key.algo = CRYPTO_ALGO_AES_CCM;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
break;
default:
brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
err = send_key_to_dongle(ifp, &key);
if (err)
brcmf_err("wsec_key error (%d)\n", err);
if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
return -EINVAL;
}
key = &ifp->vif->profile.key[key_idx];
if (key->algo == CRYPTO_ALGO_OFF) {
brcmf_dbg(CONN, "Ignore clearing of (never configured) key\n");
return -EINVAL;
}
memset(key, 0, sizeof(*key));
key->index = (u32)key_idx;
key->flags = BRCMF_PRIMARY_KEY;
/* Clear the key/index */
err = send_key_to_dongle(ifp, key);
brcmf_dbg(TRACE, "Exit\n");
return err;
}
static s32
brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
u8 key_idx, bool pairwise, const u8 *mac_addr,
struct key_params *params)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key *key;
s32 val;
s32 wsec;
s32 err = 0;
s32 err;
u8 keybuf[8];
bool ext_key;
brcmf_dbg(TRACE, "Enter\n");
brcmf_dbg(CONN, "key index (%d)\n", key_idx);
@ -2168,27 +2186,32 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
return -EINVAL;
}
if (mac_addr &&
(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
brcmf_dbg(TRACE, "Exit");
return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
if (params->key_len == 0)
return brcmf_cfg80211_del_key(wiphy, ndev, key_idx, pairwise,
mac_addr);
if (params->key_len > sizeof(key->data)) {
brcmf_err("Too long key length (%u)\n", params->key_len);
return -EINVAL;
}
ext_key = false;
if (mac_addr && (params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
brcmf_dbg(TRACE, "Ext key, mac %pM", mac_addr);
ext_key = true;
}
key = &ifp->vif->profile.key[key_idx];
memset(key, 0, sizeof(*key));
if (params->key_len > sizeof(key->data)) {
brcmf_err("Too long key length (%u)\n", params->key_len);
err = -EINVAL;
goto done;
}
if ((ext_key) && (!is_multicast_ether_addr(mac_addr)))
memcpy((char *)&key->ea, (void *)mac_addr, ETH_ALEN);
key->len = params->key_len;
key->index = key_idx;
memcpy(key->data, params->key, key->len);
if (!ext_key)
key->flags = BRCMF_PRIMARY_KEY;
key->flags = BRCMF_PRIMARY_KEY;
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
key->algo = CRYPTO_ALGO_WEP1;
@ -2228,7 +2251,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
err = send_key_to_dongle(ifp, key);
if (err)
if (ext_key || err)
goto done;
err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
@ -2249,41 +2272,10 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
}
static s32
brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_wsec_key key;
s32 err = 0;
brcmf_dbg(TRACE, "Enter\n");
if (!check_vif_up(ifp->vif))
return -EIO;
if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
return -EINVAL;
}
memset(&key, 0, sizeof(key));
key.index = (u32) key_idx;
key.flags = BRCMF_PRIMARY_KEY;
key.algo = CRYPTO_ALGO_OFF;
brcmf_dbg(CONN, "key index (%d)\n", key_idx);
/* Set the new key/index */
err = send_key_to_dongle(ifp, &key);
brcmf_dbg(TRACE, "Exit\n");
return err;
}
static s32
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_idx, bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback) (void *cookie, struct key_params * params))
brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_idx,
bool pairwise, const u8 *mac_addr, void *cookie,
void (*callback)(void *cookie,
struct key_params *params))
{
struct key_params params;
struct brcmf_if *ifp = netdev_priv(ndev);
@ -2335,8 +2327,15 @@ brcmf_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev,
static s32
brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
struct net_device *ndev, u8 key_idx)
struct net_device *ndev, u8 key_idx)
{
struct brcmf_if *ifp = netdev_priv(ndev);
brcmf_dbg(TRACE, "Enter key_idx %d\n", key_idx);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
return 0;
brcmf_dbg(INFO, "Not supported\n");
return -EOPNOTSUPP;
@ -3020,7 +3019,7 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
list = (struct brcmf_scan_results *)
cfg->escan_info.escan_buf;
if (bi_length > WL_ESCAN_BUF_SIZE - list->buflen) {
if (bi_length > BRCMF_ESCAN_BUF_SIZE - list->buflen) {
brcmf_err("Buffer is too small: ignoring\n");
goto exit;
}
@ -3033,8 +3032,8 @@ brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
bss_info_le))
goto exit;
}
memcpy(&(cfg->escan_info.escan_buf[list->buflen]),
bss_info_le, bi_length);
memcpy(&cfg->escan_info.escan_buf[list->buflen], bss_info_le,
bi_length);
list->version = le32_to_cpu(bss_info_le->version);
list->buflen += bi_length;
list->count++;
@ -3092,6 +3091,11 @@ brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
brcmf_dbg(SCAN, "Enter\n");
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
return 0;
}
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
brcmf_dbg(SCAN, "PFN NET LOST event. Do Nothing\n");
return 0;
@ -3415,6 +3419,11 @@ brcmf_wowl_nd_results(struct brcmf_if *ifp, const struct brcmf_event_msg *e,
brcmf_dbg(SCAN, "Enter\n");
if (e->datalen < (sizeof(*pfn_result) + sizeof(*netinfo))) {
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
return 0;
}
pfn_result = (struct brcmf_pno_scanresults_le *)data;
if (e->event_code == BRCMF_E_PFN_NET_LOST) {
@ -3507,6 +3516,10 @@ static void brcmf_report_wowl_wakeind(struct wiphy *wiphy, struct brcmf_if *ifp)
else
wakeup_data.net_detect = cfg->wowl.nd_info;
}
if (wakeind & BRCMF_WOWL_GTK_FAILURE) {
brcmf_dbg(INFO, "WOWL Wake indicator: BRCMF_WOWL_GTK_FAILURE\n");
wakeup_data.gtk_rekey_failure = true;
}
} else {
wakeup = NULL;
}
@ -3533,7 +3546,8 @@ static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
brcmf_report_wowl_wakeind(wiphy, ifp);
brcmf_fil_iovar_int_set(ifp, "wowl_clear", 0);
brcmf_config_wowl_pattern(ifp, "clr", NULL, 0, NULL, 0);
brcmf_configure_arp_offload(ifp, true);
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
brcmf_configure_arp_nd_offload(ifp, true);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM,
cfg->wowl.pre_pmmode);
cfg->wowl.active = false;
@ -3557,7 +3571,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
brcmf_dbg(TRACE, "Suspend, wowl config.\n");
brcmf_configure_arp_offload(ifp, false);
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ARP_ND))
brcmf_configure_arp_nd_offload(ifp, false);
brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_PM, &cfg->wowl.pre_pmmode);
brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PM, PM_MAX);
@ -3588,6 +3603,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
brcmf_wowl_nd_results);
}
if (wowl->gtk_rekey_failure)
wowl_config |= BRCMF_WOWL_GTK_FAILURE;
if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
wowl_config |= BRCMF_WOWL_UNASSOC;
@ -3818,7 +3835,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
u32 auth = 0; /* d11 open authentication */
u16 count;
s32 err = 0;
s32 len = 0;
s32 len;
u32 i;
u32 wsec;
u32 pval = 0;
@ -3828,6 +3845,7 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
u8 *data;
u16 rsn_cap;
u32 wme_bss_disable;
u32 mfp;
brcmf_dbg(TRACE, "Enter\n");
if (wpa_ie == NULL)
@ -3942,19 +3960,53 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
is_rsn_ie ? (wpa_auth |= WPA2_AUTH_PSK) :
(wpa_auth |= WPA_AUTH_PSK);
break;
case RSN_AKM_SHA256_PSK:
brcmf_dbg(TRACE, "RSN_AKM_MFP_PSK\n");
wpa_auth |= WPA2_AUTH_PSK_SHA256;
break;
case RSN_AKM_SHA256_1X:
brcmf_dbg(TRACE, "RSN_AKM_MFP_1X\n");
wpa_auth |= WPA2_AUTH_1X_SHA256;
break;
default:
brcmf_err("Ivalid key mgmt info\n");
}
offset++;
}
mfp = BRCMF_MFP_NONE;
if (is_rsn_ie) {
wme_bss_disable = 1;
if ((offset + RSN_CAP_LEN) <= len) {
rsn_cap = data[offset] + (data[offset + 1] << 8);
if (rsn_cap & RSN_CAP_PTK_REPLAY_CNTR_MASK)
wme_bss_disable = 0;
if (rsn_cap & RSN_CAP_MFPR_MASK) {
brcmf_dbg(TRACE, "MFP Required\n");
mfp = BRCMF_MFP_REQUIRED;
/* Firmware only supports mfp required in
* combination with WPA2_AUTH_PSK_SHA256 or
* WPA2_AUTH_1X_SHA256.
*/
if (!(wpa_auth & (WPA2_AUTH_PSK_SHA256 |
WPA2_AUTH_1X_SHA256))) {
err = -EINVAL;
goto exit;
}
/* Firmware has requirement that WPA2_AUTH_PSK/
* WPA2_AUTH_UNSPECIFIED be set, if SHA256 OUI
* is to be included in the rsn ie.
*/
if (wpa_auth & WPA2_AUTH_PSK_SHA256)
wpa_auth |= WPA2_AUTH_PSK;
else if (wpa_auth & WPA2_AUTH_1X_SHA256)
wpa_auth |= WPA2_AUTH_UNSPECIFIED;
} else if (rsn_cap & RSN_CAP_MFPC_MASK) {
brcmf_dbg(TRACE, "MFP Capable\n");
mfp = BRCMF_MFP_CAPABLE;
}
}
offset += RSN_CAP_LEN;
/* set wme_bss_disable to sync RSN Capabilities */
err = brcmf_fil_bsscfg_int_set(ifp, "wme_bss_disable",
wme_bss_disable);
@ -3962,6 +4014,21 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
brcmf_err("wme_bss_disable error %d\n", err);
goto exit;
}
/* Skip PMKID cnt as it is know to be 0 for AP. */
offset += RSN_PMKID_COUNT_LEN;
/* See if there is BIP wpa suite left for MFP */
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP) &&
((offset + WPA_IE_MIN_OUI_LEN) <= len)) {
err = brcmf_fil_bsscfg_data_set(ifp, "bip",
&data[offset],
WPA_IE_MIN_OUI_LEN);
if (err < 0) {
brcmf_err("bip error %d\n", err);
goto exit;
}
}
}
/* FOR WPS , set SES_OW_ENABLED */
wsec = (pval | gval | SES_OW_ENABLED);
@ -3978,6 +4045,16 @@ brcmf_configure_wpaie(struct brcmf_if *ifp,
brcmf_err("wsec error %d\n", err);
goto exit;
}
/* Configure MFP, this needs to go after wsec otherwise the wsec command
* will overwrite the values set by MFP
*/
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP)) {
err = brcmf_fil_bsscfg_int_set(ifp, "mfp", mfp);
if (err < 0) {
brcmf_err("mfp error %d\n", err);
goto exit;
}
}
/* set upper-layer auth */
err = brcmf_fil_bsscfg_int_set(ifp, "wpa_auth", wpa_auth);
if (err < 0) {
@ -4326,7 +4403,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
if (!mbss) {
brcmf_set_mpc(ifp, 0);
brcmf_configure_arp_offload(ifp, false);
brcmf_configure_arp_nd_offload(ifp, false);
}
/* find the RSN_IE */
@ -4472,7 +4549,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
exit:
if ((err) && (!mbss)) {
brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_offload(ifp, true);
brcmf_configure_arp_nd_offload(ifp, true);
}
return err;
}
@ -4530,7 +4607,7 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
brcmf_err("bss_enable config failed %d\n", err);
}
brcmf_set_mpc(ifp, 1);
brcmf_configure_arp_offload(ifp, true);
brcmf_configure_arp_nd_offload(ifp, true);
clear_bit(BRCMF_VIF_STATUS_AP_CREATED, &ifp->vif->sme_state);
brcmf_net_setcarrier(ifp, false);
@ -4855,7 +4932,32 @@ static int brcmf_cfg80211_tdls_oper(struct wiphy *wiphy,
return ret;
}
static struct cfg80211_ops wl_cfg80211_ops = {
#ifdef CONFIG_PM
static int
brcmf_cfg80211_set_rekey_data(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_gtk_rekey_data *gtk)
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_gtk_keyinfo_le gtk_le;
int ret;
brcmf_dbg(TRACE, "Enter, bssidx=%d\n", ifp->bsscfgidx);
memcpy(gtk_le.kck, gtk->kck, sizeof(gtk_le.kck));
memcpy(gtk_le.kek, gtk->kek, sizeof(gtk_le.kek));
memcpy(gtk_le.replay_counter, gtk->replay_ctr,
sizeof(gtk_le.replay_counter));
ret = brcmf_fil_iovar_data_set(ifp, "gtk_key_info", &gtk_le,
sizeof(gtk_le));
if (ret < 0)
brcmf_err("gtk_key_info iovar failed: ret=%d\n", ret);
return ret;
}
#endif
static struct cfg80211_ops brcmf_cfg80211_ops = {
.add_virtual_intf = brcmf_cfg80211_add_iface,
.del_virtual_intf = brcmf_cfg80211_del_iface,
.change_virtual_intf = brcmf_cfg80211_change_iface,
@ -5402,14 +5504,14 @@ static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
{
kfree(cfg->conf);
cfg->conf = NULL;
kfree(cfg->escan_ioctl_buf);
cfg->escan_ioctl_buf = NULL;
kfree(cfg->extra_buf);
cfg->extra_buf = NULL;
kfree(cfg->wowl.nd);
cfg->wowl.nd = NULL;
kfree(cfg->wowl.nd_info);
cfg->wowl.nd_info = NULL;
kfree(cfg->escan_info.escan_buf);
cfg->escan_info.escan_buf = NULL;
}
static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
@ -5417,9 +5519,6 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
if (!cfg->conf)
goto init_priv_mem_out;
cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
if (!cfg->escan_ioctl_buf)
goto init_priv_mem_out;
cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
if (!cfg->extra_buf)
goto init_priv_mem_out;
@ -5431,6 +5530,9 @@ static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
GFP_KERNEL);
if (!cfg->wowl.nd_info)
goto init_priv_mem_out;
cfg->escan_info.escan_buf = kzalloc(BRCMF_ESCAN_BUF_SIZE, GFP_KERNEL);
if (!cfg->escan_info.escan_buf)
goto init_priv_mem_out;
return 0;
@ -6120,19 +6222,18 @@ static void brcmf_wiphy_wowl_params(struct wiphy *wiphy, struct brcmf_if *ifp)
{
#ifdef CONFIG_PM
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
s32 err;
u32 wowl_cap;
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_PNO)) {
err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
if (!err) {
if (wowl_cap & BRCMF_WOWL_PFN_FOUND) {
brcmf_wowlan_support.flags |=
WIPHY_WOWLAN_NET_DETECT;
init_waitqueue_head(&cfg->wowl.nd_data_wait);
}
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_ND)) {
brcmf_wowlan_support.flags |= WIPHY_WOWLAN_NET_DETECT;
init_waitqueue_head(&cfg->wowl.nd_data_wait);
}
}
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK)) {
brcmf_wowlan_support.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY;
brcmf_wowlan_support.flags |= WIPHY_WOWLAN_GTK_REKEY_FAILURE;
}
wiphy->wowlan = &brcmf_wowlan_support;
#endif
}
@ -6174,8 +6275,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
wiphy->n_addresses = i;
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = __wl_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(__wl_cipher_suites);
wiphy->cipher_suites = brcmf_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
wiphy->n_cipher_suites--;
wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
WIPHY_FLAG_OFFCHAN_TX |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@ -6277,7 +6380,7 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
if (err)
goto default_conf_out;
brcmf_configure_arp_offload(ifp, true);
brcmf_configure_arp_nd_offload(ifp, true);
cfg->dongle_up = true;
default_conf_out:
@ -6395,8 +6498,9 @@ bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg)
return armed;
}
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout)
int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout)
{
struct brcmf_cfg80211_vif_event *event = &cfg->vif_event;
@ -6404,28 +6508,85 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
vif_event_equals(event, action), timeout);
}
static s32 brcmf_translate_country_code(struct brcmf_pub *drvr, char alpha2[2],
struct brcmf_fil_country_le *ccreq)
{
struct brcmfmac_pd_cc *country_codes;
struct brcmfmac_pd_cc_entry *cc;
s32 found_index;
int i;
country_codes = drvr->settings->country_codes;
if (!country_codes) {
brcmf_dbg(TRACE, "No country codes configured for device\n");
return -EINVAL;
}
if ((alpha2[0] == ccreq->country_abbrev[0]) &&
(alpha2[1] == ccreq->country_abbrev[1])) {
brcmf_dbg(TRACE, "Country code already set\n");
return -EAGAIN;
}
found_index = -1;
for (i = 0; i < country_codes->table_size; i++) {
cc = &country_codes->table[i];
if ((cc->iso3166[0] == '\0') && (found_index == -1))
found_index = i;
if ((cc->iso3166[0] == alpha2[0]) &&
(cc->iso3166[1] == alpha2[1])) {
found_index = i;
break;
}
}
if (found_index == -1) {
brcmf_dbg(TRACE, "No country code match found\n");
return -EINVAL;
}
memset(ccreq, 0, sizeof(*ccreq));
ccreq->rev = cpu_to_le32(country_codes->table[found_index].rev);
memcpy(ccreq->ccode, country_codes->table[found_index].cc,
BRCMF_COUNTRY_BUF_SZ);
ccreq->country_abbrev[0] = alpha2[0];
ccreq->country_abbrev[1] = alpha2[1];
ccreq->country_abbrev[2] = 0;
return 0;
}
static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *req)
{
struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
struct brcmf_fil_country_le ccreq;
s32 err;
int i;
brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
req->alpha2[0], req->alpha2[1]);
/* ignore non-ISO3166 country codes */
for (i = 0; i < sizeof(req->alpha2); i++)
if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
brcmf_err("not a ISO3166 code\n");
brcmf_err("not a ISO3166 code (0x%02x 0x%02x)\n",
req->alpha2[0], req->alpha2[1]);
return;
}
memset(&ccreq, 0, sizeof(ccreq));
ccreq.rev = cpu_to_le32(-1);
memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
if (brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq))) {
brcmf_err("firmware rejected country setting\n");
brcmf_dbg(TRACE, "Enter: initiator=%d, alpha=%c%c\n", req->initiator,
req->alpha2[0], req->alpha2[1]);
err = brcmf_fil_iovar_data_get(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
brcmf_err("Country code iovar returned err = %d\n", err);
return;
}
err = brcmf_translate_country_code(ifp->drvr, req->alpha2, &ccreq);
if (err)
return;
err = brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
if (err) {
brcmf_err("Firmware rejected country setting\n");
return;
}
brcmf_setup_wiphybands(wiphy);
@ -6461,6 +6622,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
struct net_device *ndev = brcmf_get_ifp(drvr, 0)->ndev;
struct brcmf_cfg80211_info *cfg;
struct wiphy *wiphy;
struct cfg80211_ops *ops;
struct brcmf_cfg80211_vif *vif;
struct brcmf_if *ifp;
s32 err = 0;
@ -6472,8 +6634,17 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
return NULL;
}
ops = kzalloc(sizeof(*ops), GFP_KERNEL);
if (!ops)
return NULL;
memcpy(ops, &brcmf_cfg80211_ops, sizeof(*ops));
ifp = netdev_priv(ndev);
wiphy = wiphy_new(&wl_cfg80211_ops, sizeof(struct brcmf_cfg80211_info));
#ifdef CONFIG_PM
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL_GTK))
ops->set_rekey_data = brcmf_cfg80211_set_rekey_data;
#endif
wiphy = wiphy_new(ops, sizeof(struct brcmf_cfg80211_info));
if (!wiphy) {
brcmf_err("Could not allocate wiphy device\n");
return NULL;
@ -6483,6 +6654,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
cfg = wiphy_priv(wiphy);
cfg->wiphy = wiphy;
cfg->ops = ops;
cfg->pub = drvr;
init_vif_event(&cfg->vif_event);
INIT_LIST_HEAD(&cfg->vif_list);
@ -6593,7 +6765,8 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_SCAN_RANDOM_MAC)) {
wiphy->features |= NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR;
#ifdef CONFIG_PM
if (wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
if (wiphy->wowlan &&
wiphy->wowlan->flags & WIPHY_WOWLAN_NET_DETECT)
wiphy->features |= NL80211_FEATURE_ND_RANDOM_MAC_ADDR;
#endif
}
@ -6608,6 +6781,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
ifp->vif = NULL;
wiphy_out:
brcmf_free_wiphy(wiphy);
kfree(ops);
return NULL;
}
@ -6618,6 +6792,7 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
brcmf_btcoex_detach(cfg);
wiphy_unregister(cfg->wiphy);
kfree(cfg->ops);
wl_deinit_priv(cfg);
brcmf_free_wiphy(cfg->wiphy);
}

View File

@ -28,8 +28,11 @@
#define WL_ROAM_TRIGGER_LEVEL -75
#define WL_ROAM_DELTA 20
#define WL_ESCAN_BUF_SIZE (1024 * 64)
#define WL_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
/* Keep BRCMF_ESCAN_BUF_SIZE below 64K (65536). Allocing over 64K can be
* problematic on some systems and should be avoided.
*/
#define BRCMF_ESCAN_BUF_SIZE 65000
#define BRCMF_ESCAN_TIMER_INTERVAL_MS 10000 /* E-Scan timeout */
#define WL_ESCAN_ACTION_START 1
#define WL_ESCAN_ACTION_CONTINUE 2
@ -69,7 +72,7 @@
#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
#define BRCMF_MAX_DEFAULT_KEYS 4
#define BRCMF_MAX_DEFAULT_KEYS 6
/* beacon loss timeout defaults */
#define BRCMF_DEFAULT_BCN_TIMEOUT_ROAM_ON 2
@ -104,7 +107,6 @@ struct brcmf_cfg80211_security {
u32 auth_type;
u32 cipher_pairwise;
u32 cipher_group;
u32 wpa_auth;
};
/**
@ -205,7 +207,7 @@ enum wl_escan_state {
struct escan_info {
u32 escan_state;
u8 escan_buf[WL_ESCAN_BUF_SIZE];
u8 *escan_buf;
struct wiphy *wiphy;
struct brcmf_if *ifp;
s32 (*run)(struct brcmf_cfg80211_info *cfg, struct brcmf_if *ifp,
@ -253,6 +255,7 @@ struct brcmf_cfg80211_wowl {
* struct brcmf_cfg80211_info - dongle private data of cfg80211 interface
*
* @wiphy: wiphy object for cfg80211 interface.
* @ops: pointer to copy of ops as registered with wiphy object.
* @conf: dongle configuration.
* @p2p: peer-to-peer specific information.
* @btcoex: Bluetooth coexistence information.
@ -278,7 +281,6 @@ struct brcmf_cfg80211_wowl {
* @escan_info: escan information.
* @escan_timeout: Timer for catch scan timeout.
* @escan_timeout_work: scan timeout worker.
* @escan_ioctl_buf: dongle command buffer for escan commands.
* @vif_list: linked list of vif instances.
* @vif_cnt: number of vif instances.
* @vif_event: vif event signalling.
@ -286,6 +288,7 @@ struct brcmf_cfg80211_wowl {
*/
struct brcmf_cfg80211_info {
struct wiphy *wiphy;
struct cfg80211_ops *ops;
struct brcmf_cfg80211_conf *conf;
struct brcmf_p2p_info p2p;
struct brcmf_btcoex_info *btcoex;
@ -309,7 +312,6 @@ struct brcmf_cfg80211_info {
struct escan_info escan_info;
struct timer_list escan_timeout;
struct work_struct escan_timeout_work;
u8 *escan_ioctl_buf;
struct list_head vif_list;
struct brcmf_cfg80211_vif_event vif_event;
struct completion vif_disabled;
@ -402,8 +404,8 @@ bool brcmf_get_vif_state_any(struct brcmf_cfg80211_info *cfg,
void brcmf_cfg80211_arm_vif_event(struct brcmf_cfg80211_info *cfg,
struct brcmf_cfg80211_vif *vif);
bool brcmf_cfg80211_vif_event_armed(struct brcmf_cfg80211_info *cfg);
int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout);
int brcmf_cfg80211_wait_vif_event(struct brcmf_cfg80211_info *cfg,
u8 action, ulong timeout);
s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
struct brcmf_if *ifp, bool aborted,
bool fw_abort);

View File

@ -27,6 +27,11 @@
#include "fwil_types.h"
#include "tracepoint.h"
#include "common.h"
#include "of.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
MODULE_LICENSE("Dual BSD/GPL");
const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -75,6 +80,7 @@ module_param_named(ignore_probe_fail, brcmf_ignore_probe_fail, int, 0);
MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
#endif
static struct brcmfmac_platform_data *brcmfmac_pdata;
struct brcmf_mp_global_t brcmf_mp_global;
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
@ -221,33 +227,147 @@ void __brcmf_dbg(u32 level, const char *func, const char *fmt, ...)
}
#endif
void brcmf_mp_attach(void)
static void brcmf_mp_attach(void)
{
/* If module param firmware path is set then this will always be used,
* if not set then if available use the platform data version. To make
* sure it gets initialized at all, always copy the module param version
*/
strlcpy(brcmf_mp_global.firmware_path, brcmf_firmware_path,
BRCMF_FW_ALTPATH_LEN);
if ((brcmfmac_pdata) && (brcmfmac_pdata->fw_alternative_path) &&
(brcmf_mp_global.firmware_path[0] == '\0')) {
strlcpy(brcmf_mp_global.firmware_path,
brcmfmac_pdata->fw_alternative_path,
BRCMF_FW_ALTPATH_LEN);
}
}
int brcmf_mp_device_attach(struct brcmf_pub *drvr)
struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
enum brcmf_bus_type bus_type,
u32 chip, u32 chiprev)
{
drvr->settings = kzalloc(sizeof(*drvr->settings), GFP_ATOMIC);
if (!drvr->settings) {
brcmf_err("Failed to alloca storage space for settings\n");
return -ENOMEM;
}
struct brcmf_mp_device *settings;
struct brcmfmac_pd_device *device_pd;
bool found;
int i;
drvr->settings->sdiod_txglomsz = brcmf_sdiod_txglomsz;
drvr->settings->p2p_enable = !!brcmf_p2p_enable;
drvr->settings->feature_disable = brcmf_feature_disable;
drvr->settings->fcmode = brcmf_fcmode;
drvr->settings->roamoff = !!brcmf_roamoff;
brcmf_dbg(INFO, "Enter, bus=%d, chip=%d, rev=%d\n", bus_type, chip,
chiprev);
settings = kzalloc(sizeof(*settings), GFP_ATOMIC);
if (!settings)
return NULL;
/* start by using the module paramaters */
settings->p2p_enable = !!brcmf_p2p_enable;
settings->feature_disable = brcmf_feature_disable;
settings->fcmode = brcmf_fcmode;
settings->roamoff = !!brcmf_roamoff;
#ifdef DEBUG
drvr->settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
settings->ignore_probe_fail = !!brcmf_ignore_probe_fail;
#endif
if (bus_type == BRCMF_BUSTYPE_SDIO)
settings->bus.sdio.txglomsz = brcmf_sdiod_txglomsz;
/* See if there is any device specific platform data configured */
found = false;
if (brcmfmac_pdata) {
for (i = 0; i < brcmfmac_pdata->device_count; i++) {
device_pd = &brcmfmac_pdata->devices[i];
if ((device_pd->bus_type == bus_type) &&
(device_pd->id == chip) &&
((device_pd->rev == chiprev) ||
(device_pd->rev == -1))) {
brcmf_dbg(INFO, "Platform data for device found\n");
settings->country_codes =
device_pd->country_codes;
if (device_pd->bus_type == BRCMF_BUSTYPE_SDIO)
memcpy(&settings->bus.sdio,
&device_pd->bus.sdio,
sizeof(settings->bus.sdio));
found = true;
break;
}
}
}
if ((bus_type == BRCMF_BUSTYPE_SDIO) && (!found)) {
/* No platform data for this device. In case of SDIO try OF
* (Open Firwmare) Device Tree.
*/
brcmf_of_probe(dev, &settings->bus.sdio);
}
return settings;
}
void brcmf_release_module_param(struct brcmf_mp_device *module_param)
{
kfree(module_param);
}
static int __init brcmf_common_pd_probe(struct platform_device *pdev)
{
brcmf_dbg(INFO, "Enter\n");
brcmfmac_pdata = dev_get_platdata(&pdev->dev);
if (brcmfmac_pdata->power_on)
brcmfmac_pdata->power_on();
return 0;
}
void brcmf_mp_device_detach(struct brcmf_pub *drvr)
static int brcmf_common_pd_remove(struct platform_device *pdev)
{
kfree(drvr->settings);
brcmf_dbg(INFO, "Enter\n");
if (brcmfmac_pdata->power_off)
brcmfmac_pdata->power_off();
return 0;
}
static struct platform_driver brcmf_pd = {
.remove = brcmf_common_pd_remove,
.driver = {
.name = BRCMFMAC_PDATA_NAME,
}
};
static int __init brcmfmac_module_init(void)
{
int err;
/* Initialize debug system first */
brcmf_debugfs_init();
/* Get the platform data (if available) for our devices */
err = platform_driver_probe(&brcmf_pd, brcmf_common_pd_probe);
if (err == -ENODEV)
brcmf_dbg(INFO, "No platform data available.\n");
/* Initialize global module paramaters */
brcmf_mp_attach();
/* Continue the initialization by registering the different busses */
err = brcmf_core_init();
if (err) {
brcmf_debugfs_exit();
if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd);
}
return err;
}
static void __exit brcmfmac_module_exit(void)
{
brcmf_core_exit();
if (brcmfmac_pdata)
platform_driver_unregister(&brcmf_pd);
brcmf_debugfs_exit();
}
module_init(brcmfmac_module_init);
module_exit(brcmfmac_module_exit);

View File

@ -15,6 +15,10 @@
#ifndef BRCMFMAC_COMMON_H
#define BRCMFMAC_COMMON_H
#include <linux/platform_device.h>
#include <linux/platform_data/brcmfmac.h>
#include "fwil_types.h"
extern const u8 ALLFFMAC[ETH_ALEN];
#define BRCMF_FW_ALTPATH_LEN 256
@ -41,37 +45,30 @@ extern struct brcmf_mp_global_t brcmf_mp_global;
/**
* struct brcmf_mp_device - Device module paramaters.
*
* @sdiod_txglomsz: SDIO txglom size.
* @joinboost_5g_rssi: 5g rssi booost for preferred join selection.
* @p2p_enable: Legacy P2P0 enable (old wpa_supplicant).
* @feature_disable: Feature_disable bitmask.
* @fcmode: FWS flow control.
* @roamoff: Firmware roaming off?
* @ignore_probe_fail: Ignore probe failure.
* @country_codes: If available, pointer to struct for translating country codes
* @bus: Bus specific platform data. Only SDIO at the mmoment.
*/
struct brcmf_mp_device {
int sdiod_txglomsz;
int joinboost_5g_rssi;
bool p2p_enable;
int feature_disable;
int fcmode;
bool roamoff;
bool ignore_probe_fail;
bool p2p_enable;
unsigned int feature_disable;
int fcmode;
bool roamoff;
bool ignore_probe_fail;
struct brcmfmac_pd_cc *country_codes;
union {
struct brcmfmac_sdio_pd sdio;
} bus;
};
void brcmf_mp_attach(void);
int brcmf_mp_device_attach(struct brcmf_pub *drvr);
void brcmf_mp_device_detach(struct brcmf_pub *drvr);
#ifdef DEBUG
static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
{
return drvr->settings->ignore_probe_fail;
}
#else
static inline bool brcmf_ignoring_probe_fail(struct brcmf_pub *drvr)
{
return false;
}
#endif
struct brcmf_mp_device *brcmf_get_module_param(struct device *dev,
enum brcmf_bus_type bus_type,
u32 chip, u32 chiprev);
void brcmf_release_module_param(struct brcmf_mp_device *module_param);
/* Sets dongle media info (drv_version, mac address). */
int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);

View File

@ -20,6 +20,8 @@
#include <linux/inetdevice.h>
#include <net/cfg80211.h>
#include <net/rtnetlink.h>
#include <net/addrconf.h>
#include <net/ipv6.h>
#include <brcmu_utils.h>
#include <brcmu_wifi.h>
@ -36,11 +38,7 @@
#include "pcie.h"
#include "common.h"
MODULE_AUTHOR("Broadcom Corporation");
MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
MODULE_LICENSE("Dual BSD/GPL");
#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(50)
#define MAX_WAIT_FOR_8021X_TX msecs_to_jiffies(950)
/* AMPDU rx reordering definitions */
#define BRCMF_RXREORDER_FLOWID_OFFSET 0
@ -172,6 +170,35 @@ _brcmf_set_mac_address(struct work_struct *work)
}
}
#if IS_ENABLED(CONFIG_IPV6)
static void _brcmf_update_ndtable(struct work_struct *work)
{
struct brcmf_if *ifp;
int i, ret;
ifp = container_of(work, struct brcmf_if, ndoffload_work);
/* clear the table in firmware */
ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip_clear", NULL, 0);
if (ret) {
brcmf_dbg(TRACE, "fail to clear nd ip table err:%d\n", ret);
return;
}
for (i = 0; i < ifp->ipv6addr_idx; i++) {
ret = brcmf_fil_iovar_data_set(ifp, "nd_hostip",
&ifp->ipv6_addr_tbl[i],
sizeof(struct in6_addr));
if (ret)
brcmf_err("add nd ip err %d\n", ret);
}
}
#else
static void _brcmf_update_ndtable(struct work_struct *work)
{
}
#endif
static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
{
struct brcmf_if *ifp = netdev_priv(ndev);
@ -685,6 +712,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
INIT_WORK(&ifp->ndoffload_work, _brcmf_update_ndtable);
if (rtnl_locked)
err = register_netdevice(ndev);
@ -884,6 +912,7 @@ static void brcmf_del_if(struct brcmf_pub *drvr, s32 bsscfgidx)
if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
cancel_work_sync(&ifp->setmacaddr_work);
cancel_work_sync(&ifp->multicast_work);
cancel_work_sync(&ifp->ndoffload_work);
}
brcmf_net_detach(ifp->ndev);
} else {
@ -1006,14 +1035,14 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
return NOTIFY_OK;
}
for (i = 0; i < ARPOL_MAX_ENTRIES; i++) {
if (addr_table[i] != 0) {
brcmf_fil_iovar_data_set(ifp,
"arp_hostip", &addr_table[i],
sizeof(addr_table[i]));
if (ret)
brcmf_err("add arp ip err %d\n",
ret);
}
if (addr_table[i] == 0)
continue;
ret = brcmf_fil_iovar_data_set(ifp, "arp_hostip",
&addr_table[i],
sizeof(addr_table[i]));
if (ret)
brcmf_err("add arp ip err %d\n",
ret);
}
}
break;
@ -1025,7 +1054,57 @@ static int brcmf_inetaddr_changed(struct notifier_block *nb,
}
#endif
int brcmf_attach(struct device *dev)
#if IS_ENABLED(CONFIG_IPV6)
static int brcmf_inet6addr_changed(struct notifier_block *nb,
unsigned long action, void *data)
{
struct brcmf_pub *drvr = container_of(nb, struct brcmf_pub,
inet6addr_notifier);
struct inet6_ifaddr *ifa = data;
struct brcmf_if *ifp;
int i;
struct in6_addr *table;
/* Only handle primary interface */
ifp = drvr->iflist[0];
if (!ifp)
return NOTIFY_DONE;
if (ifp->ndev != ifa->idev->dev)
return NOTIFY_DONE;
table = ifp->ipv6_addr_tbl;
for (i = 0; i < NDOL_MAX_ENTRIES; i++)
if (ipv6_addr_equal(&ifa->addr, &table[i]))
break;
switch (action) {
case NETDEV_UP:
if (i == NDOL_MAX_ENTRIES) {
if (ifp->ipv6addr_idx < NDOL_MAX_ENTRIES) {
table[ifp->ipv6addr_idx++] = ifa->addr;
} else {
for (i = 0; i < NDOL_MAX_ENTRIES - 1; i++)
table[i] = table[i + 1];
table[NDOL_MAX_ENTRIES - 1] = ifa->addr;
}
}
break;
case NETDEV_DOWN:
if (i < NDOL_MAX_ENTRIES)
for (; i < ifp->ipv6addr_idx; i++)
table[i] = table[i + 1];
break;
default:
break;
}
schedule_work(&ifp->ndoffload_work);
return NOTIFY_OK;
}
#endif
int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings)
{
struct brcmf_pub *drvr = NULL;
int ret = 0;
@ -1047,10 +1126,7 @@ int brcmf_attach(struct device *dev)
drvr->hdrlen = 0;
drvr->bus_if = dev_get_drvdata(dev);
drvr->bus_if->drvr = drvr;
/* Initialize device specific settings */
if (brcmf_mp_device_attach(drvr))
goto fail;
drvr->settings = settings;
/* attach debug facilities */
brcmf_debug_attach(drvr);
@ -1164,30 +1240,41 @@ int brcmf_bus_start(struct device *dev)
#ifdef CONFIG_INET
drvr->inetaddr_notifier.notifier_call = brcmf_inetaddr_changed;
ret = register_inetaddr_notifier(&drvr->inetaddr_notifier);
if (ret)
goto fail;
#if IS_ENABLED(CONFIG_IPV6)
drvr->inet6addr_notifier.notifier_call = brcmf_inet6addr_changed;
ret = register_inet6addr_notifier(&drvr->inet6addr_notifier);
if (ret) {
unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
goto fail;
}
#endif
#endif /* CONFIG_INET */
return 0;
fail:
if (ret < 0) {
brcmf_err("failed: %d\n", ret);
if (drvr->config) {
brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
}
if (drvr->fws) {
brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr);
}
if (ifp)
brcmf_net_detach(ifp->ndev);
if (p2p_ifp)
brcmf_net_detach(p2p_ifp->ndev);
drvr->iflist[0] = NULL;
drvr->iflist[1] = NULL;
if (brcmf_ignoring_probe_fail(drvr))
ret = 0;
return ret;
brcmf_err("failed: %d\n", ret);
if (drvr->config) {
brcmf_cfg80211_detach(drvr->config);
drvr->config = NULL;
}
return 0;
if (drvr->fws) {
brcmf_fws_del_interface(ifp);
brcmf_fws_deinit(drvr);
}
if (ifp)
brcmf_net_detach(ifp->ndev);
if (p2p_ifp)
brcmf_net_detach(p2p_ifp->ndev);
drvr->iflist[0] = NULL;
drvr->iflist[1] = NULL;
if (drvr->settings->ignore_probe_fail)
ret = 0;
return ret;
}
void brcmf_bus_add_txhdrlen(struct device *dev, uint len)
@ -1237,6 +1324,10 @@ void brcmf_detach(struct device *dev)
unregister_inetaddr_notifier(&drvr->inetaddr_notifier);
#endif
#if IS_ENABLED(CONFIG_IPV6)
unregister_inet6addr_notifier(&drvr->inet6addr_notifier);
#endif
/* stop firmware event handling */
brcmf_fweh_detach(drvr);
if (drvr->config)
@ -1256,8 +1347,6 @@ void brcmf_detach(struct device *dev)
brcmf_proto_detach(drvr);
brcmf_mp_device_detach(drvr);
brcmf_debug_detach(drvr);
bus_if->drvr = NULL;
kfree(drvr);
@ -1324,19 +1413,15 @@ static void brcmf_driver_register(struct work_struct *work)
}
static DECLARE_WORK(brcmf_driver_work, brcmf_driver_register);
static int __init brcmfmac_module_init(void)
int __init brcmf_core_init(void)
{
brcmf_debugfs_init();
#ifdef CONFIG_BRCMFMAC_SDIO
brcmf_sdio_init();
#endif
if (!schedule_work(&brcmf_driver_work))
return -EBUSY;
return 0;
}
static void __exit brcmfmac_module_exit(void)
void __exit brcmf_core_exit(void)
{
cancel_work_sync(&brcmf_driver_work);
@ -1349,8 +1434,5 @@ static void __exit brcmfmac_module_exit(void)
#ifdef CONFIG_BRCMFMAC_PCIE
brcmf_pcie_exit();
#endif
brcmf_debugfs_exit();
}
module_init(brcmfmac_module_init);
module_exit(brcmfmac_module_exit);

View File

@ -48,6 +48,8 @@
*/
#define BRCMF_DRIVER_FIRMWARE_VERSION_LEN 32
#define NDOL_MAX_ENTRIES 8
/**
* struct brcmf_ampdu_rx_reorder - AMPDU receive reorder info
*
@ -143,6 +145,7 @@ struct brcmf_pub {
#endif
struct notifier_block inetaddr_notifier;
struct notifier_block inet6addr_notifier;
struct brcmf_mp_device *settings;
};
@ -175,6 +178,7 @@ enum brcmf_netif_stop_reason {
* @stats: interface specific network statistics.
* @setmacaddr_work: worker object for setting mac address.
* @multicast_work: worker object for multicast provisioning.
* @ndoffload_work: worker object for neighbor discovery offload configuration.
* @fws_desc: interface specific firmware-signalling descriptor.
* @ifidx: interface index in device firmware.
* @bsscfgidx: index of bss associated with this interface.
@ -191,6 +195,7 @@ struct brcmf_if {
struct net_device_stats stats;
struct work_struct setmacaddr_work;
struct work_struct multicast_work;
struct work_struct ndoffload_work;
struct brcmf_fws_mac_descriptor *fws_desc;
int ifidx;
s32 bsscfgidx;
@ -199,6 +204,8 @@ struct brcmf_if {
spinlock_t netif_stop_lock;
atomic_t pend_8021x_cnt;
wait_queue_head_t pend_8021x_wait;
struct in6_addr ipv6_addr_tbl[NDOL_MAX_ENTRIES];
u8 ipv6addr_idx;
};
struct brcmf_skb_reorder_data {
@ -220,5 +227,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
int __init brcmf_core_init(void);
void __exit brcmf_core_exit(void);
#endif /* BRCMFMAC_CORE_H */

View File

@ -136,6 +136,7 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
{
struct brcmf_if *ifp = brcmf_get_ifp(drvr, 0);
struct brcmf_pno_macaddr_le pfn_mac;
u32 wowl_cap;
s32 err;
brcmf_feat_firmware_capabilities(ifp);
@ -143,11 +144,24 @@ void brcmf_feat_attach(struct brcmf_pub *drvr)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_PNO, "pfn");
if (drvr->bus_if->wowl_supported)
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl");
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_WOWL)) {
err = brcmf_fil_iovar_int_get(ifp, "wowl_cap", &wowl_cap);
if (!err) {
ifp->drvr->feat_flags |= BIT(BRCMF_FEAT_WOWL_ARP_ND);
if (wowl_cap & BRCMF_WOWL_PFN_FOUND)
ifp->drvr->feat_flags |=
BIT(BRCMF_FEAT_WOWL_ND);
if (wowl_cap & BRCMF_WOWL_GTK_FAILURE)
ifp->drvr->feat_flags |=
BIT(BRCMF_FEAT_WOWL_GTK);
}
}
/* MBSS does not work for 43362 */
if (drvr->bus_if->chip == BRCM_CC_43362_CHIP_ID)
ifp->drvr->feat_flags &= ~BIT(BRCMF_FEAT_MBSS);
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_RSDB, "rsdb_mode");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_TDLS, "tdls_enable");
brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MFP, "mfp");
pfn_mac.version = BRCMF_PFN_MACADDR_CFG_VER;
err = brcmf_fil_iovar_data_get(ifp, "pfn_macaddr", &pfn_mac,

View File

@ -27,6 +27,10 @@
* RSDB: Real Simultaneous Dual Band
* TDLS: Tunneled Direct Link Setup
* SCAN_RANDOM_MAC: Random MAC during (net detect) scheduled scan.
* WOWL_ND: WOWL net detect (PNO)
* WOWL_GTK: (WOWL) GTK rekeying offload
* WOWL_ARP_ND: ARP and Neighbor Discovery offload support during WOWL.
* MFP: 802.11w Management Frame Protection.
*/
#define BRCMF_FEAT_LIST \
BRCMF_FEAT_DEF(MBSS) \
@ -36,7 +40,11 @@
BRCMF_FEAT_DEF(P2P) \
BRCMF_FEAT_DEF(RSDB) \
BRCMF_FEAT_DEF(TDLS) \
BRCMF_FEAT_DEF(SCAN_RANDOM_MAC)
BRCMF_FEAT_DEF(SCAN_RANDOM_MAC) \
BRCMF_FEAT_DEF(WOWL_ND) \
BRCMF_FEAT_DEF(WOWL_GTK) \
BRCMF_FEAT_DEF(WOWL_ARP_ND) \
BRCMF_FEAT_DEF(MFP)
/*
* Quirks:

View File

@ -32,7 +32,7 @@
#define BRCMF_FLOWRING_LOW (BRCMF_FLOWRING_HIGH - 256)
#define BRCMF_FLOWRING_INVALID_IFIDX 0xff
#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] * 2 + fifo + ifidx * 16)
#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
static const u8 brcmf_flowring_prio2fifo[] = {
@ -68,7 +68,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx)
{
struct brcmf_flowring_hash *hash;
u8 hash_idx;
u16 hash_idx;
u32 i;
bool found;
bool sta;
@ -88,6 +88,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
}
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
found = false;
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
@ -98,6 +99,7 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
break;
}
hash_idx++;
hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
}
if (found)
return hash[hash_idx].flowid;
@ -111,7 +113,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
{
struct brcmf_flowring_ring *ring;
struct brcmf_flowring_hash *hash;
u8 hash_idx;
u16 hash_idx;
u32 i;
bool found;
u8 fifo;
@ -131,6 +133,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
}
hash_idx = sta ? BRCMF_FLOWRING_HASH_STA(fifo, ifidx) :
BRCMF_FLOWRING_HASH_AP(mac, fifo, ifidx);
hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
found = false;
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
@ -140,6 +143,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
break;
}
hash_idx++;
hash_idx &= (BRCMF_FLOWRING_HASHSIZE - 1);
}
if (found) {
for (i = 0; i < flow->nrofrings; i++) {
@ -169,7 +173,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
}
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
@ -179,7 +183,7 @@ u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid)
}
static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
static void brcmf_flowring_block(struct brcmf_flowring *flow, u16 flowid,
bool blocked)
{
struct brcmf_flowring_ring *ring;
@ -228,10 +232,10 @@ static void brcmf_flowring_block(struct brcmf_flowring *flow, u8 flowid,
}
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
u8 hash_idx;
u16 hash_idx;
struct sk_buff *skb;
ring = flow->rings[flowid];
@ -253,7 +257,7 @@ void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid)
}
u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
@ -279,7 +283,7 @@ u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
}
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
struct sk_buff *skb;
@ -300,7 +304,7 @@ struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid)
}
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
struct sk_buff *skb)
{
struct brcmf_flowring_ring *ring;
@ -311,7 +315,7 @@ void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
}
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
@ -326,7 +330,7 @@ u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid)
}
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
@ -340,10 +344,10 @@ void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid)
}
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid)
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid)
{
struct brcmf_flowring_ring *ring;
u8 hash_idx;
u16 hash_idx;
ring = flow->rings[flowid];
hash_idx = ring->hash_id;
@ -384,7 +388,7 @@ void brcmf_flowring_detach(struct brcmf_flowring *flow)
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_flowring_tdls_entry *search;
struct brcmf_flowring_tdls_entry *remove;
u8 flowid;
u16 flowid;
for (flowid = 0; flowid < flow->nrofrings; flowid++) {
if (flow->rings[flowid])
@ -408,7 +412,7 @@ void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,
struct brcmf_bus *bus_if = dev_get_drvdata(flow->dev);
struct brcmf_pub *drvr = bus_if->drvr;
u32 i;
u8 flowid;
u16 flowid;
if (flow->addr_mode[ifidx] != addr_mode) {
for (i = 0; i < ARRAY_SIZE(flow->hash); i++) {
@ -434,7 +438,7 @@ void brcmf_flowring_delete_peer(struct brcmf_flowring *flow, int ifidx,
struct brcmf_flowring_tdls_entry *prev;
struct brcmf_flowring_tdls_entry *search;
u32 i;
u8 flowid;
u16 flowid;
bool sta;
sta = (flow->addr_mode[ifidx] == ADDR_INDIRECT);

View File

@ -16,7 +16,7 @@
#define BRCMFMAC_FLOWRING_H
#define BRCMF_FLOWRING_HASHSIZE 256
#define BRCMF_FLOWRING_HASHSIZE 512 /* has to be 2^x */
#define BRCMF_FLOWRING_INVALID_ID 0xFFFFFFFF
@ -24,7 +24,7 @@ struct brcmf_flowring_hash {
u8 mac[ETH_ALEN];
u8 fifo;
u8 ifidx;
u8 flowid;
u16 flowid;
};
enum ring_status {
@ -61,16 +61,16 @@ u32 brcmf_flowring_lookup(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx);
u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
u8 prio, u8 ifidx);
void brcmf_flowring_delete(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_open(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u8 flowid);
u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u8 flowid,
void brcmf_flowring_delete(struct brcmf_flowring *flow, u16 flowid);
void brcmf_flowring_open(struct brcmf_flowring *flow, u16 flowid);
u8 brcmf_flowring_tid(struct brcmf_flowring *flow, u16 flowid);
u32 brcmf_flowring_enqueue(struct brcmf_flowring *flow, u16 flowid,
struct sk_buff *skb);
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u8 flowid);
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u8 flowid,
struct sk_buff *brcmf_flowring_dequeue(struct brcmf_flowring *flow, u16 flowid);
void brcmf_flowring_reinsert(struct brcmf_flowring *flow, u16 flowid,
struct sk_buff *skb);
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u8 flowid);
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u8 flowid);
u32 brcmf_flowring_qlen(struct brcmf_flowring *flow, u16 flowid);
u8 brcmf_flowring_ifidx_get(struct brcmf_flowring *flow, u16 flowid);
struct brcmf_flowring *brcmf_flowring_attach(struct device *dev, u16 nrofrings);
void brcmf_flowring_detach(struct brcmf_flowring *flow);
void brcmf_flowring_configure_addr_mode(struct brcmf_flowring *flow, int ifidx,

View File

@ -25,50 +25,6 @@
#include "fweh.h"
#include "fwil.h"
/**
* struct brcm_ethhdr - broadcom specific ether header.
*
* @subtype: subtype for this packet.
* @length: TODO: length of appended data.
* @version: version indication.
* @oui: OUI of this packet.
* @usr_subtype: subtype for this OUI.
*/
struct brcm_ethhdr {
__be16 subtype;
__be16 length;
u8 version;
u8 oui[3];
__be16 usr_subtype;
} __packed;
struct brcmf_event_msg_be {
__be16 version;
__be16 flags;
__be32 event_type;
__be32 status;
__be32 reason;
__be32 auth_type;
__be32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
u8 ifidx;
u8 bsscfgidx;
} __packed;
/**
* struct brcmf_event - contents of broadcom event packet.
*
* @eth: standard ether header.
* @hdr: broadcom specific ether header.
* @msg: common part of the actual event message.
*/
struct brcmf_event {
struct ethhdr eth;
struct brcm_ethhdr hdr;
struct brcmf_event_msg_be msg;
} __packed;
/**
* struct brcmf_fweh_queue_item - event item on event queue.
*
@ -85,6 +41,7 @@ struct brcmf_fweh_queue_item {
u8 ifidx;
u8 ifaddr[ETH_ALEN];
struct brcmf_event_msg_be emsg;
u32 datalen;
u8 data[0];
};
@ -294,6 +251,11 @@ static void brcmf_fweh_event_worker(struct work_struct *work)
brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
min_t(u32, emsg.datalen, 64),
"event payload, len=%d\n", emsg.datalen);
if (emsg.datalen > event->datalen) {
brcmf_err("event invalid length header=%d, msg=%d\n",
event->datalen, emsg.datalen);
goto event_free;
}
/* special handling of interface event */
if (event->code == BRCMF_E_IF) {
@ -439,7 +401,8 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
* dispatch the event to a registered handler (using worker).
*/
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet)
struct brcmf_event *event_packet,
u32 packet_len)
{
enum brcmf_fweh_event_code code;
struct brcmf_fweh_info *fweh = &drvr->fweh;
@ -459,6 +422,9 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
if (code != BRCMF_E_IF && !fweh->evt_handler[code])
return;
if (datalen > BRCMF_DCMD_MAXLEN)
return;
if (in_interrupt())
alloc_flag = GFP_ATOMIC;
@ -472,6 +438,7 @@ void brcmf_fweh_process_event(struct brcmf_pub *drvr,
/* use memcpy to get aligned event message */
memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
memcpy(event->data, data, datalen);
event->datalen = datalen;
memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
brcmf_fweh_queue_event(fweh, event);

View File

@ -27,7 +27,6 @@
struct brcmf_pub;
struct brcmf_if;
struct brcmf_cfg80211_info;
struct brcmf_event;
/* list of firmware events */
#define BRCMF_FWEH_EVENT_ENUM_DEFLIST \
@ -180,12 +179,54 @@ enum brcmf_fweh_event_code {
/**
* definitions for event packet validation.
*/
#define BRCMF_EVENT_OUI_OFFSET 19
#define BRCM_OUI "\x00\x10\x18"
#define DOT11_OUI_LEN 3
#define BCMILCP_BCM_SUBTYPE_EVENT 1
#define BRCM_OUI "\x00\x10\x18"
#define BCMILCP_BCM_SUBTYPE_EVENT 1
/**
* struct brcm_ethhdr - broadcom specific ether header.
*
* @subtype: subtype for this packet.
* @length: TODO: length of appended data.
* @version: version indication.
* @oui: OUI of this packet.
* @usr_subtype: subtype for this OUI.
*/
struct brcm_ethhdr {
__be16 subtype;
__be16 length;
u8 version;
u8 oui[3];
__be16 usr_subtype;
} __packed;
struct brcmf_event_msg_be {
__be16 version;
__be16 flags;
__be32 event_type;
__be32 status;
__be32 reason;
__be32 auth_type;
__be32 datalen;
u8 addr[ETH_ALEN];
char ifname[IFNAMSIZ];
u8 ifidx;
u8 bsscfgidx;
} __packed;
/**
* struct brcmf_event - contents of broadcom event packet.
*
* @eth: standard ether header.
* @hdr: broadcom specific ether header.
* @msg: common part of the actual event message.
*/
struct brcmf_event {
struct ethhdr eth;
struct brcm_ethhdr hdr;
struct brcmf_event_msg_be msg;
} __packed;
/**
* struct brcmf_event_msg - firmware event message.
*
@ -256,34 +297,35 @@ void brcmf_fweh_unregister(struct brcmf_pub *drvr,
enum brcmf_fweh_event_code code);
int brcmf_fweh_activate_events(struct brcmf_if *ifp);
void brcmf_fweh_process_event(struct brcmf_pub *drvr,
struct brcmf_event *event_packet);
struct brcmf_event *event_packet,
u32 packet_len);
void brcmf_fweh_p2pdev_setup(struct brcmf_if *ifp, bool ongoing);
static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
struct sk_buff *skb)
{
struct brcmf_event *event_packet;
u8 *data;
u16 usr_stype;
/* only process events when protocol matches */
if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
return;
if ((skb->len + ETH_HLEN) < sizeof(*event_packet))
return;
/* check for BRCM oui match */
event_packet = (struct brcmf_event *)skb_mac_header(skb);
data = (u8 *)event_packet;
data += BRCMF_EVENT_OUI_OFFSET;
if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
if (memcmp(BRCM_OUI, &event_packet->hdr.oui[0],
sizeof(event_packet->hdr.oui)))
return;
/* final match on usr_subtype */
data += DOT11_OUI_LEN;
usr_stype = get_unaligned_be16(data);
usr_stype = get_unaligned_be16(&event_packet->hdr.usr_subtype);
if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
return;
brcmf_fweh_process_event(drvr, event_packet);
brcmf_fweh_process_event(drvr, event_packet, skb->len + ETH_HLEN);
}
#endif /* FWEH_H_ */

View File

@ -111,7 +111,9 @@
/* Wakeup if received matched secured pattern: */
#define BRCMF_WOWL_SECURE (1 << 25)
/* Wakeup on finding preferred network */
#define BRCMF_WOWL_PFN_FOUND (1 << 26)
#define BRCMF_WOWL_PFN_FOUND (1 << 27)
/* Wakeup on receiving pairwise key EAP packets: */
#define WIPHY_WOWL_EAP_PK (1 << 28)
/* Link Down indication in WoWL mode: */
#define BRCMF_WOWL_LINKDOWN (1 << 31)
@ -134,6 +136,16 @@
#define BRCMF_PFN_MAC_OUI_ONLY BIT(0)
#define BRCMF_PFN_SET_MAC_UNASSOC BIT(1)
#define BRCMF_MCSSET_LEN 16
#define BRCMF_RSN_KCK_LENGTH 16
#define BRCMF_RSN_KEK_LENGTH 16
#define BRCMF_RSN_REPLAY_LEN 8
#define BRCMF_MFP_NONE 0
#define BRCMF_MFP_CAPABLE 1
#define BRCMF_MFP_REQUIRED 2
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
BRCMF_JOIN_PREF_RSSI = 1,
@ -279,7 +291,7 @@ struct brcmf_bss_info_le {
__le32 reserved32[1]; /* Reserved for expansion of BSS properties */
u8 flags; /* flags */
u8 reserved[3]; /* Reserved for expansion of BSS properties */
u8 basic_mcs[MCSSET_LEN]; /* 802.11N BSS required MCS set */
u8 basic_mcs[BRCMF_MCSSET_LEN]; /* 802.11N BSS required MCS set */
__le16 ie_offset; /* offset at which IEs start, from beginning */
__le32 ie_length; /* byte length of Information Elements */
@ -787,4 +799,17 @@ struct brcmf_pktcnt_le {
__le32 rx_ocast_good_pkt;
};
/**
* struct brcmf_gtk_keyinfo_le - GTP rekey data
*
* @kck: key confirmation key.
* @kek: key encryption key.
* @replay_counter: replay counter.
*/
struct brcmf_gtk_keyinfo_le {
u8 kck[BRCMF_RSN_KCK_LENGTH];
u8 kek[BRCMF_RSN_KEK_LENGTH];
u8 replay_counter[BRCMF_RSN_REPLAY_LEN];
};
#endif /* FWIL_TYPES_H_ */

View File

@ -677,7 +677,7 @@ static u32 brcmf_msgbuf_flowring_create(struct brcmf_msgbuf *msgbuf, int ifidx,
}
static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u16 flowid)
{
struct brcmf_flowring *flow = msgbuf->flow;
struct brcmf_commonring *commonring;
@ -1310,7 +1310,7 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
}
void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid)
void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid)
{
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
struct msgbuf_tx_flowring_delete_req *delete;
@ -1415,6 +1415,13 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
u32 count;
if_msgbuf = drvr->bus_if->msgbuf;
if (if_msgbuf->nrof_flowrings >= BRCMF_FLOWRING_HASHSIZE) {
brcmf_err("driver not configured for this many flowrings %d\n",
if_msgbuf->nrof_flowrings);
if_msgbuf->nrof_flowrings = BRCMF_FLOWRING_HASHSIZE - 1;
}
msgbuf = kzalloc(sizeof(*msgbuf), GFP_KERNEL);
if (!msgbuf)
goto fail;

View File

@ -33,7 +33,7 @@
int brcmf_proto_msgbuf_rx_trigger(struct device *dev);
void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u8 flowid);
void brcmf_msgbuf_delete_flowring(struct brcmf_pub *drvr, u16 flowid);
int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr);
void brcmf_proto_msgbuf_detach(struct brcmf_pub *drvr);
#else

View File

@ -16,17 +16,15 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/mmc/card.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <linux/mmc/sdio_func.h>
#include <defs.h>
#include "debug.h"
#include "sdio.h"
#include "core.h"
#include "common.h"
#include "of.h"
void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
{
struct device *dev = sdiodev->dev;
struct device_node *np = dev->of_node;
int irq;
u32 irqf;
@ -35,12 +33,8 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
return;
sdiodev->pdata = devm_kzalloc(dev, sizeof(*sdiodev->pdata), GFP_KERNEL);
if (!sdiodev->pdata)
return;
if (of_property_read_u32(np, "brcm,drive-strength", &val) == 0)
sdiodev->pdata->drive_strength = val;
sdio->drive_strength = val;
/* make sure there are interrupts defined in the node */
if (!of_find_property(np, "interrupts", NULL))
@ -53,7 +47,7 @@ void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
}
irqf = irqd_get_trigger_type(irq_get_irq_data(irq));
sdiodev->pdata->oob_irq_supported = true;
sdiodev->pdata->oob_irq_nr = irq;
sdiodev->pdata->oob_irq_flags = irqf;
sdio->oob_irq_supported = true;
sdio->oob_irq_nr = irq;
sdio->oob_irq_flags = irqf;
}

View File

@ -14,9 +14,9 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef CONFIG_OF
void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev);
void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio);
#else
static void brcmf_of_probe(struct brcmf_sdio_dev *sdiodev)
static void brcmf_of_probe(struct device *dev, struct brcmfmac_sdio_pd *sdio)
{
}
#endif /* CONFIG_OF */

View File

@ -1361,6 +1361,11 @@ int brcmf_p2p_notify_action_frame_rx(struct brcmf_if *ifp,
u16 mgmt_type;
u8 action;
if (e->datalen < sizeof(*rxframe)) {
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
return 0;
}
ch.chspec = be16_to_cpu(rxframe->chanspec);
cfg->d11inf.decchspec(&ch);
/* Check if wpa_supplicant has registered for this frame */
@ -1858,6 +1863,11 @@ s32 brcmf_p2p_notify_rx_mgmt_p2p_probereq(struct brcmf_if *ifp,
brcmf_dbg(INFO, "Enter: event %d reason %d\n", e->event_code,
e->reason);
if (e->datalen < sizeof(*rxframe)) {
brcmf_dbg(SCAN, "Event data to small. Ignore\n");
return 0;
}
ch.chspec = be16_to_cpu(rxframe->chanspec);
cfg->d11inf.decchspec(&ch);
@ -1988,8 +1998,8 @@ int brcmf_p2p_ifchange(struct brcmf_cfg80211_info *cfg,
brcmf_cfg80211_arm_vif_event(cfg, NULL);
return err;
}
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_CHANGE,
BRCMF_VIF_EVENT_TIMEOUT);
err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_CHANGE,
BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) {
brcmf_err("No BRCMF_E_IF_CHANGE event received\n");
@ -2090,8 +2100,8 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
}
/* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(p2p->cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
err = brcmf_cfg80211_wait_vif_event(p2p->cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(p2p->cfg, NULL);
brcmf_fweh_p2pdev_setup(pri_ifp, false);
if (!err) {
@ -2180,8 +2190,8 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
}
/* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_ADD,
BRCMF_VIF_EVENT_TIMEOUT);
brcmf_cfg80211_arm_vif_event(cfg, NULL);
if (!err) {
brcmf_err("timeout occurred\n");
@ -2272,8 +2282,8 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
}
if (!err) {
/* wait for firmware event */
err = brcmf_cfg80211_wait_vif_event_timeout(cfg, BRCMF_E_IF_DEL,
BRCMF_VIF_EVENT_TIMEOUT);
err = brcmf_cfg80211_wait_vif_event(cfg, BRCMF_E_IF_DEL,
BRCMF_VIF_EVENT_TIMEOUT);
if (!err)
err = -EIO;
else

View File

@ -37,6 +37,8 @@
#include "pcie.h"
#include "firmware.h"
#include "chip.h"
#include "core.h"
#include "common.h"
enum brcmf_pcie_state {
@ -53,6 +55,7 @@ BRCMF_FW_NVRAM_DEF(4358, "brcmfmac4358-pcie.bin", "brcmfmac4358-pcie.txt");
BRCMF_FW_NVRAM_DEF(4359, "brcmfmac4359-pcie.bin", "brcmfmac4359-pcie.txt");
BRCMF_FW_NVRAM_DEF(4365B, "brcmfmac4365b-pcie.bin", "brcmfmac4365b-pcie.txt");
BRCMF_FW_NVRAM_DEF(4366B, "brcmfmac4366b-pcie.bin", "brcmfmac4366b-pcie.txt");
BRCMF_FW_NVRAM_DEF(4366C, "brcmfmac4366c-pcie.bin", "brcmfmac4366c-pcie.txt");
BRCMF_FW_NVRAM_DEF(4371, "brcmfmac4371-pcie.bin", "brcmfmac4371-pcie.txt");
static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
@ -66,13 +69,13 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4358_CHIP_ID, 0xFFFFFFFF, 4358),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4365_CHIP_ID, 0xFFFFFFFF, 4365B),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFFF, 4366B),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0x0000000F, 4366B),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4366_CHIP_ID, 0xFFFFFFF0, 4366C),
BRCMF_FW_NVRAM_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371),
};
#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */
#define BRCMF_PCIE_TCM_MAP_SIZE (4096 * 1024)
#define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024)
/* backplane addres space accessed by BAR0 */
@ -99,9 +102,6 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_PCIE2REG_CONFIGDATA 0x124
#define BRCMF_PCIE_PCIE2REG_H2D_MAILBOX 0x140
#define BRCMF_PCIE_GENREV1 1
#define BRCMF_PCIE_GENREV2 2
#define BRCMF_PCIE2_INTA 0x01
#define BRCMF_PCIE2_INTB 0x02
@ -207,6 +207,10 @@ static struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = {
#define BRCMF_PCIE_CFGREG_REG_BAR3_CONFIG 0x4F4
#define BRCMF_PCIE_LINK_STATUS_CTRL_ASPM_ENAB 3
/* Magic number at a magic location to find RAM size */
#define BRCMF_RAMSIZE_MAGIC 0x534d4152 /* SMAR */
#define BRCMF_RAMSIZE_OFFSET 0x6c
struct brcmf_pcie_console {
u32 base_addr;
@ -248,14 +252,11 @@ struct brcmf_pciedev_info {
char nvram_name[BRCMF_FW_NAME_LEN];
void __iomem *regs;
void __iomem *tcm;
u32 tcm_size;
u32 ram_base;
u32 ram_size;
struct brcmf_chip *ci;
u32 coreid;
u32 generic_corerev;
struct brcmf_pcie_shared_info shared;
void (*ringbell)(struct brcmf_pciedev_info *devinfo);
wait_queue_head_t mbdata_resp_wait;
bool mbdata_completed;
bool irq_allocated;
@ -267,6 +268,7 @@ struct brcmf_pciedev_info {
u16 (*read_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset);
void (*write_ptr)(struct brcmf_pciedev_info *devinfo, u32 mem_offset,
u16 value);
struct brcmf_mp_device *settings;
};
struct brcmf_pcie_ringbuf {
@ -742,68 +744,22 @@ static void brcmf_pcie_bus_console_read(struct brcmf_pciedev_info *devinfo)
}
static __used void brcmf_pcie_ringbell_v1(struct brcmf_pciedev_info *devinfo)
{
u32 reg_value;
brcmf_dbg(PCIE, "RING !\n");
reg_value = brcmf_pcie_read_reg32(devinfo,
BRCMF_PCIE_PCIE2REG_MAILBOXINT);
reg_value |= BRCMF_PCIE2_INTB;
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
reg_value);
}
static void brcmf_pcie_ringbell_v2(struct brcmf_pciedev_info *devinfo)
{
brcmf_dbg(PCIE, "RING !\n");
/* Any arbitrary value will do, lets use 1 */
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
}
static void brcmf_pcie_intr_disable(struct brcmf_pciedev_info *devinfo)
{
if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
0);
else
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
0);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK, 0);
}
static void brcmf_pcie_intr_enable(struct brcmf_pciedev_info *devinfo)
{
if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1)
pci_write_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTMASK,
BRCMF_PCIE_INT_DEF);
else
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
BRCMF_PCIE_MB_INT_D2H_DB |
BRCMF_PCIE_MB_INT_FN0_0 |
BRCMF_PCIE_MB_INT_FN0_1);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXMASK,
BRCMF_PCIE_MB_INT_D2H_DB |
BRCMF_PCIE_MB_INT_FN0_0 |
BRCMF_PCIE_MB_INT_FN0_1);
}
static irqreturn_t brcmf_pcie_quick_check_isr_v1(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
u32 status;
status = 0;
pci_read_config_dword(devinfo->pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
if (status) {
brcmf_pcie_intr_disable(devinfo);
brcmf_dbg(PCIE, "Enter\n");
return IRQ_WAKE_THREAD;
}
return IRQ_NONE;
}
static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg)
static irqreturn_t brcmf_pcie_quick_check_isr(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
@ -816,29 +772,7 @@ static irqreturn_t brcmf_pcie_quick_check_isr_v2(int irq, void *arg)
}
static irqreturn_t brcmf_pcie_isr_thread_v1(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
const struct pci_dev *pdev = devinfo->pdev;
u32 status;
devinfo->in_irq = true;
status = 0;
pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
brcmf_dbg(PCIE, "Enter %x\n", status);
if (status) {
pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
brcmf_proto_msgbuf_rx_trigger(&devinfo->pdev->dev);
}
if (devinfo->state == BRCMFMAC_PCIE_STATE_UP)
brcmf_pcie_intr_enable(devinfo);
devinfo->in_irq = false;
return IRQ_HANDLED;
}
static irqreturn_t brcmf_pcie_isr_thread_v2(int irq, void *arg)
static irqreturn_t brcmf_pcie_isr_thread(int irq, void *arg)
{
struct brcmf_pciedev_info *devinfo = (struct brcmf_pciedev_info *)arg;
u32 status;
@ -875,28 +809,14 @@ static int brcmf_pcie_request_irq(struct brcmf_pciedev_info *devinfo)
brcmf_pcie_intr_disable(devinfo);
brcmf_dbg(PCIE, "Enter\n");
/* is it a v1 or v2 implementation */
pci_enable_msi(pdev);
if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
if (request_threaded_irq(pdev->irq,
brcmf_pcie_quick_check_isr_v1,
brcmf_pcie_isr_thread_v1,
IRQF_SHARED, "brcmf_pcie_intr",
devinfo)) {
pci_disable_msi(pdev);
brcmf_err("Failed to request IRQ %d\n", pdev->irq);
return -EIO;
}
} else {
if (request_threaded_irq(pdev->irq,
brcmf_pcie_quick_check_isr_v2,
brcmf_pcie_isr_thread_v2,
IRQF_SHARED, "brcmf_pcie_intr",
devinfo)) {
pci_disable_msi(pdev);
brcmf_err("Failed to request IRQ %d\n", pdev->irq);
return -EIO;
}
if (request_threaded_irq(pdev->irq, brcmf_pcie_quick_check_isr,
brcmf_pcie_isr_thread, IRQF_SHARED,
"brcmf_pcie_intr", devinfo)) {
pci_disable_msi(pdev);
brcmf_err("Failed to request IRQ %d\n", pdev->irq);
return -EIO;
}
devinfo->irq_allocated = true;
return 0;
@ -927,16 +847,9 @@ static void brcmf_pcie_release_irq(struct brcmf_pciedev_info *devinfo)
if (devinfo->in_irq)
brcmf_err("Still in IRQ (processing) !!!\n");
if (devinfo->generic_corerev == BRCMF_PCIE_GENREV1) {
status = 0;
pci_read_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, &status);
pci_write_config_dword(pdev, BRCMF_PCIE_REG_INTSTATUS, status);
} else {
status = brcmf_pcie_read_reg32(devinfo,
BRCMF_PCIE_PCIE2REG_MAILBOXINT);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT,
status);
}
status = brcmf_pcie_read_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT);
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_MAILBOXINT, status);
devinfo->irq_allocated = false;
}
@ -985,7 +898,9 @@ static int brcmf_pcie_ring_mb_ring_bell(void *ctx)
if (devinfo->state != BRCMFMAC_PCIE_STATE_UP)
return -EIO;
devinfo->ringbell(devinfo);
brcmf_dbg(PCIE, "RING !\n");
/* Any arbitrary value will do, lets use 1 */
brcmf_pcie_write_reg32(devinfo, BRCMF_PCIE_PCIE2REG_H2D_MAILBOX, 1);
return 0;
}
@ -1412,6 +1327,28 @@ static const struct brcmf_bus_ops brcmf_pcie_bus_ops = {
};
static void
brcmf_pcie_adjust_ramsize(struct brcmf_pciedev_info *devinfo, u8 *data,
u32 data_len)
{
__le32 *field;
u32 newsize;
if (data_len < BRCMF_RAMSIZE_OFFSET + 8)
return;
field = (__le32 *)&data[BRCMF_RAMSIZE_OFFSET];
if (le32_to_cpup(field) != BRCMF_RAMSIZE_MAGIC)
return;
field++;
newsize = le32_to_cpup(field);
brcmf_dbg(PCIE, "Found ramsize info in FW, adjusting to 0x%x\n",
newsize);
devinfo->ci->ramsize = newsize;
}
static int
brcmf_pcie_init_share_ram_info(struct brcmf_pciedev_info *devinfo,
u32 sharedram_addr)
@ -1477,9 +1414,6 @@ static int brcmf_pcie_download_fw_nvram(struct brcmf_pciedev_info *devinfo,
u32 address;
u32 resetintr;
devinfo->ringbell = brcmf_pcie_ringbell_v2;
devinfo->generic_corerev = BRCMF_PCIE_GENREV2;
brcmf_dbg(PCIE, "Halt ARM.\n");
err = brcmf_pcie_enter_download_state(devinfo);
if (err)
@ -1566,8 +1500,7 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo)
}
devinfo->regs = ioremap_nocache(bar0_addr, BRCMF_PCIE_REG_MAP_SIZE);
devinfo->tcm = ioremap_nocache(bar1_addr, BRCMF_PCIE_TCM_MAP_SIZE);
devinfo->tcm_size = BRCMF_PCIE_TCM_MAP_SIZE;
devinfo->tcm = ioremap_nocache(bar1_addr, bar1_size);
if (!devinfo->regs || !devinfo->tcm) {
brcmf_err("ioremap() failed (%p,%p)\n", devinfo->regs,
@ -1576,8 +1509,9 @@ static int brcmf_pcie_get_resource(struct brcmf_pciedev_info *devinfo)
}
brcmf_dbg(PCIE, "Phys addr : reg space = %p base addr %#016llx\n",
devinfo->regs, (unsigned long long)bar0_addr);
brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx\n",
devinfo->tcm, (unsigned long long)bar1_addr);
brcmf_dbg(PCIE, "Phys addr : mem space = %p base addr %#016llx size 0x%x\n",
devinfo->tcm, (unsigned long long)bar1_addr,
(unsigned int)bar1_size);
return 0;
}
@ -1594,16 +1528,16 @@ static void brcmf_pcie_release_resource(struct brcmf_pciedev_info *devinfo)
}
static int brcmf_pcie_attach_bus(struct device *dev)
static int brcmf_pcie_attach_bus(struct brcmf_pciedev_info *devinfo)
{
int ret;
/* Attach to the common driver interface */
ret = brcmf_attach(dev);
ret = brcmf_attach(&devinfo->pdev->dev, devinfo->settings);
if (ret) {
brcmf_err("brcmf_attach failed\n");
} else {
ret = brcmf_bus_start(dev);
ret = brcmf_bus_start(&devinfo->pdev->dev);
if (ret)
brcmf_err("dongle is not responding\n");
}
@ -1694,6 +1628,13 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
brcmf_pcie_attach(devinfo);
/* Some of the firmwares have the size of the memory of the device
* defined inside the firmware. This is because part of the memory in
* the device is shared and the devision is determined by FW. Parse
* the firmware and adjust the chip memory size now.
*/
brcmf_pcie_adjust_ramsize(devinfo, (u8 *)fw->data, fw->size);
ret = brcmf_pcie_download_fw_nvram(devinfo, fw, nvram, nvram_len);
if (ret)
goto fail;
@ -1734,7 +1675,7 @@ static void brcmf_pcie_setup(struct device *dev, const struct firmware *fw,
init_waitqueue_head(&devinfo->mbdata_resp_wait);
brcmf_pcie_intr_enable(devinfo);
if (brcmf_pcie_attach_bus(bus->dev) == 0)
if (brcmf_pcie_attach_bus(devinfo) == 0)
return;
brcmf_pcie_bus_console_read(devinfo);
@ -1778,6 +1719,15 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto fail;
}
devinfo->settings = brcmf_get_module_param(&devinfo->pdev->dev,
BRCMF_BUSTYPE_PCIE,
devinfo->ci->chip,
devinfo->ci->chiprev);
if (!devinfo->settings) {
ret = -ENOMEM;
goto fail;
}
bus = kzalloc(sizeof(*bus), GFP_KERNEL);
if (!bus) {
ret = -ENOMEM;
@ -1822,6 +1772,8 @@ brcmf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
brcmf_pcie_release_resource(devinfo);
if (devinfo->ci)
brcmf_chip_detach(devinfo->ci);
if (devinfo->settings)
brcmf_release_module_param(devinfo->settings);
kfree(pcie_bus_dev);
kfree(devinfo);
return ret;
@ -1861,6 +1813,8 @@ brcmf_pcie_remove(struct pci_dev *pdev)
if (devinfo->ci)
brcmf_chip_detach(devinfo->ci);
if (devinfo->settings)
brcmf_release_module_param(devinfo->settings);
kfree(devinfo);
dev_set_drvdata(&pdev->dev, NULL);

View File

@ -33,8 +33,6 @@
#include <linux/bcma/bcma.h>
#include <linux/debugfs.h>
#include <linux/vmalloc.h>
#include <linux/platform_data/brcmfmac-sdio.h>
#include <linux/moduleparam.h>
#include <asm/unaligned.h>
#include <defs.h>
#include <brcmu_wifi.h>
@ -44,6 +42,8 @@
#include "sdio.h"
#include "chip.h"
#include "firmware.h"
#include "core.h"
#include "common.h"
#define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
#define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
@ -2442,15 +2442,17 @@ static void brcmf_sdio_bus_stop(struct device *dev)
static inline void brcmf_sdio_clrintr(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiodev;
unsigned long flags;
if (bus->sdiodev->oob_irq_requested) {
spin_lock_irqsave(&bus->sdiodev->irq_en_lock, flags);
if (!bus->sdiodev->irq_en && !atomic_read(&bus->ipend)) {
enable_irq(bus->sdiodev->pdata->oob_irq_nr);
bus->sdiodev->irq_en = true;
sdiodev = bus->sdiodev;
if (sdiodev->oob_irq_requested) {
spin_lock_irqsave(&sdiodev->irq_en_lock, flags);
if (!sdiodev->irq_en && !atomic_read(&bus->ipend)) {
enable_irq(sdiodev->settings->bus.sdio.oob_irq_nr);
sdiodev->irq_en = true;
}
spin_unlock_irqrestore(&bus->sdiodev->irq_en_lock, flags);
spin_unlock_irqrestore(&sdiodev->irq_en_lock, flags);
}
}
@ -3394,9 +3396,7 @@ static int brcmf_sdio_bus_preinit(struct device *dev)
sizeof(u32));
} else {
/* otherwise, set txglomalign */
value = 4;
if (sdiodev->pdata)
value = sdiodev->pdata->sd_sgentry_align;
value = sdiodev->settings->bus.sdio.sd_sgentry_align;
/* SDIO ADMA requires at least 32 bit alignment */
value = max_t(u32, value, 4);
err = brcmf_iovar_data_set(dev, "bus:txglomalign", &value,
@ -3775,26 +3775,28 @@ static const struct brcmf_buscore_ops brcmf_sdio_buscore_ops = {
static bool
brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
{
struct brcmf_sdio_dev *sdiodev;
u8 clkctl = 0;
int err = 0;
int reg_addr;
u32 reg_val;
u32 drivestrength;
sdio_claim_host(bus->sdiodev->func[1]);
sdiodev = bus->sdiodev;
sdio_claim_host(sdiodev->func[1]);
pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdiod_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
brcmf_sdiod_regrl(sdiodev, SI_ENUM_BASE, NULL));
/*
* Force PLL off until brcmf_chip_attach()
* programs PLL control regs
*/
brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
brcmf_sdiod_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
BRCMF_INIT_CLKCTL1, &err);
if (!err)
clkctl = brcmf_sdiod_regrb(bus->sdiodev,
clkctl = brcmf_sdiod_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
@ -3803,50 +3805,81 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
goto fail;
}
bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
bus->ci = brcmf_chip_attach(sdiodev, &brcmf_sdio_buscore_ops);
if (IS_ERR(bus->ci)) {
brcmf_err("brcmf_chip_attach failed!\n");
bus->ci = NULL;
goto fail;
}
sdiodev->settings = brcmf_get_module_param(sdiodev->dev,
BRCMF_BUSTYPE_SDIO,
bus->ci->chip,
bus->ci->chiprev);
if (!sdiodev->settings) {
brcmf_err("Failed to get device parameters\n");
goto fail;
}
/* platform specific configuration:
* alignments must be at least 4 bytes for ADMA
*/
bus->head_align = ALIGNMENT;
bus->sgentry_align = ALIGNMENT;
if (sdiodev->settings->bus.sdio.sd_head_align > ALIGNMENT)
bus->head_align = sdiodev->settings->bus.sdio.sd_head_align;
if (sdiodev->settings->bus.sdio.sd_sgentry_align > ALIGNMENT)
bus->sgentry_align =
sdiodev->settings->bus.sdio.sd_sgentry_align;
/* allocate scatter-gather table. sg support
* will be disabled upon allocation failure.
*/
brcmf_sdiod_sgtable_alloc(sdiodev);
#ifdef CONFIG_PM_SLEEP
/* wowl can be supported when KEEP_POWER is true and (WAKE_SDIO_IRQ
* is true or when platform data OOB irq is true).
*/
if ((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_KEEP_POWER) &&
((sdio_get_host_pm_caps(sdiodev->func[1]) & MMC_PM_WAKE_SDIO_IRQ) ||
(sdiodev->settings->bus.sdio.oob_irq_supported)))
sdiodev->bus_if->wowl_supported = true;
#endif
if (brcmf_sdio_kso_init(bus)) {
brcmf_err("error enabling KSO\n");
goto fail;
}
if ((bus->sdiodev->pdata) && (bus->sdiodev->pdata->drive_strength))
drivestrength = bus->sdiodev->pdata->drive_strength;
if (sdiodev->settings->bus.sdio.drive_strength)
drivestrength = sdiodev->settings->bus.sdio.drive_strength;
else
drivestrength = DEFAULT_SDIO_DRIVE_STRENGTH;
brcmf_sdio_drivestrengthinit(bus->sdiodev, bus->ci, drivestrength);
brcmf_sdio_drivestrengthinit(sdiodev, bus->ci, drivestrength);
/* Set card control so an SDIO card reset does a WLAN backplane reset */
reg_val = brcmf_sdiod_regrb(bus->sdiodev,
SDIO_CCCR_BRCM_CARDCTRL, &err);
reg_val = brcmf_sdiod_regrb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, &err);
if (err)
goto fail;
reg_val |= SDIO_CCCR_BRCM_CARDCTRL_WLANRESET;
brcmf_sdiod_regwb(bus->sdiodev,
SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
brcmf_sdiod_regwb(sdiodev, SDIO_CCCR_BRCM_CARDCTRL, reg_val, &err);
if (err)
goto fail;
/* set PMUControl so a backplane reset does PMU state reload */
reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
reg_val = brcmf_sdiod_regrl(sdiodev, reg_addr, &err);
if (err)
goto fail;
reg_val |= (BCMA_CC_PMU_CTL_RES_RELOAD << BCMA_CC_PMU_CTL_RES_SHIFT);
brcmf_sdiod_regwl(bus->sdiodev, reg_addr, reg_val, &err);
brcmf_sdiod_regwl(sdiodev, reg_addr, reg_val, &err);
if (err)
goto fail;
sdio_release_host(bus->sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@ -3867,7 +3900,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
return true;
fail:
sdio_release_host(bus->sdiodev->func[1]);
sdio_release_host(sdiodev->func[1]);
return false;
}
@ -4045,18 +4078,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->txminmax = BRCMF_TXMINMAX;
bus->tx_seq = SDPCM_SEQ_WRAP - 1;
/* platform specific configuration:
* alignments must be at least 4 bytes for ADMA
*/
bus->head_align = ALIGNMENT;
bus->sgentry_align = ALIGNMENT;
if (sdiodev->pdata) {
if (sdiodev->pdata->sd_head_align > ALIGNMENT)
bus->head_align = sdiodev->pdata->sd_head_align;
if (sdiodev->pdata->sd_sgentry_align > ALIGNMENT)
bus->sgentry_align = sdiodev->pdata->sd_sgentry_align;
}
/* single-threaded workqueue */
wq = alloc_ordered_workqueue("brcmf_wq/%s", WQ_MEM_RECLAIM,
dev_name(&sdiodev->func[1]->dev));
@ -4107,7 +4128,7 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->tx_hdrlen = SDPCM_HWHDR_LEN + SDPCM_SWHDR_LEN;
/* Attach to the common layer, reserve hdr space */
ret = brcmf_attach(bus->sdiodev->dev);
ret = brcmf_attach(bus->sdiodev->dev, bus->sdiodev->settings);
if (ret != 0) {
brcmf_err("brcmf_attach failed\n");
goto fail;
@ -4211,6 +4232,8 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
}
brcmf_chip_detach(bus->ci);
}
if (bus->sdiodev->settings)
brcmf_release_module_param(bus->sdiodev->settings);
kfree(bus->rxbuf);
kfree(bus->hdrbuf);

View File

@ -184,7 +184,7 @@ struct brcmf_sdio_dev {
struct brcmf_sdio *bus;
struct device *dev;
struct brcmf_bus *bus_if;
struct brcmfmac_sdio_platform_data *pdata;
struct brcmf_mp_device *settings;
bool oob_irq_requested;
bool irq_en; /* irq enable flags */
spinlock_t irq_en_lock;

View File

@ -27,6 +27,8 @@
#include "debug.h"
#include "firmware.h"
#include "usb.h"
#include "core.h"
#include "common.h"
#define IOCTL_RESP_TIMEOUT msecs_to_jiffies(2000)
@ -171,6 +173,7 @@ struct brcmf_usbdev_info {
struct urb *bulk_urb; /* used for FW download */
bool wowl_enabled;
struct brcmf_mp_device *settings;
};
static void brcmf_usb_rx_refill(struct brcmf_usbdev_info *devinfo,
@ -1027,6 +1030,9 @@ static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
kfree(devinfo->tx_reqs);
kfree(devinfo->rx_reqs);
if (devinfo->settings)
brcmf_release_module_param(devinfo->settings);
}
@ -1136,7 +1142,7 @@ static int brcmf_usb_bus_setup(struct brcmf_usbdev_info *devinfo)
int ret;
/* Attach to the common driver interface */
ret = brcmf_attach(devinfo->dev);
ret = brcmf_attach(devinfo->dev, devinfo->settings);
if (ret) {
brcmf_err("brcmf_attach failed\n");
return ret;
@ -1223,6 +1229,14 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
bus->wowl_supported = true;
#endif
devinfo->settings = brcmf_get_module_param(bus->dev, BRCMF_BUSTYPE_USB,
bus_pub->devid,
bus_pub->chiprev);
if (!devinfo->settings) {
ret = -ENOMEM;
goto fail;
}
if (!brcmf_usb_dlneeded(devinfo)) {
ret = brcmf_usb_bus_setup(devinfo);
if (ret)

View File

@ -236,6 +236,8 @@ static inline bool ac_bitmap_tst(u8 bitmap, int prec)
#define WPA2_AUTH_RESERVED3 0x0200
#define WPA2_AUTH_RESERVED4 0x0400
#define WPA2_AUTH_RESERVED5 0x0800
#define WPA2_AUTH_1X_SHA256 0x1000 /* 1X with SHA256 key derivation */
#define WPA2_AUTH_PSK_SHA256 0x8000 /* PSK with SHA256 key derivation */
#define DOT11_DEFAULT_RTS_LEN 2347
#define DOT11_DEFAULT_FRAG_LEN 2346

View File

@ -73,8 +73,8 @@
/* Highest firmware API version supported */
#define IWL7260_UCODE_API_MAX 17
#define IWL7265_UCODE_API_MAX 17
#define IWL7265D_UCODE_API_MAX 20
#define IWL3168_UCODE_API_MAX 20
#define IWL7265D_UCODE_API_MAX 21
#define IWL3168_UCODE_API_MAX 21
/* Oldest version we won't warn about */
#define IWL7260_UCODE_API_OK 13

View File

@ -70,8 +70,8 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL8000_UCODE_API_MAX 20
#define IWL8265_UCODE_API_MAX 20
#define IWL8000_UCODE_API_MAX 21
#define IWL8265_UCODE_API_MAX 21
/* Oldest version we won't warn about */
#define IWL8000_UCODE_API_OK 13
@ -217,6 +217,7 @@ const struct iwl_cfg iwl8265_2ac_cfg = {
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
.vht_mu_mimo_supported = true,
};
const struct iwl_cfg iwl4165_2ac_cfg = {

View File

@ -55,7 +55,7 @@
#include "iwl-agn-hw.h"
/* Highest firmware API version supported */
#define IWL9000_UCODE_API_MAX 20
#define IWL9000_UCODE_API_MAX 21
/* Oldest version we won't warn about */
#define IWL9000_UCODE_API_OK 13
@ -139,7 +139,8 @@ static const struct iwl_tt_params iwl9000_tt_params = {
.smem_len = IWL9000_SMEM_LEN, \
.thermal_params = &iwl9000_tt_params, \
.apmg_not_supported = true, \
.mq_rx_supported = true
.mq_rx_supported = true, \
.vht_mu_mimo_supported = true
const struct iwl_cfg iwl9260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 9260",

View File

@ -312,6 +312,7 @@ struct iwl_pwr_tx_backoff {
* @smem_offset: offset from which the SMEM begins
* @smem_len: the length of SMEM
* @mq_rx_supported: multi-queue rx support
* @vht_mu_mimo_supported: VHT MU-MIMO support
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@ -364,6 +365,7 @@ struct iwl_cfg {
const struct iwl_tt_params *thermal_params;
bool apmg_not_supported;
bool mq_rx_supported;
bool vht_mu_mimo_supported;
};
/*

View File

@ -7,6 +7,7 @@
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
* Copyright(c) 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@ -549,4 +550,52 @@ enum dtd_diode_reg {
DTS_DIODE_REG_FLAGS_PASS_ONCE = 0x00000080, /* bits [7:7] */
};
/*****************************************************************************
* MSIX related registers *
*****************************************************************************/
#define CSR_MSIX_BASE (0x2000)
#define CSR_MSIX_FH_INT_CAUSES_AD (CSR_MSIX_BASE + 0x800)
#define CSR_MSIX_FH_INT_MASK_AD (CSR_MSIX_BASE + 0x804)
#define CSR_MSIX_HW_INT_CAUSES_AD (CSR_MSIX_BASE + 0x808)
#define CSR_MSIX_HW_INT_MASK_AD (CSR_MSIX_BASE + 0x80C)
#define CSR_MSIX_AUTOMASK_ST_AD (CSR_MSIX_BASE + 0x810)
#define CSR_MSIX_RX_IVAR_AD_REG (CSR_MSIX_BASE + 0x880)
#define CSR_MSIX_IVAR_AD_REG (CSR_MSIX_BASE + 0x890)
#define CSR_MSIX_PENDING_PBA_AD (CSR_MSIX_BASE + 0x1000)
#define CSR_MSIX_RX_IVAR(cause) (CSR_MSIX_RX_IVAR_AD_REG + (cause))
#define CSR_MSIX_IVAR(cause) (CSR_MSIX_IVAR_AD_REG + (cause))
#define MSIX_FH_INT_CAUSES_Q(q) (q)
/*
* Causes for the FH register interrupts
*/
enum msix_fh_int_causes {
MSIX_FH_INT_CAUSES_D2S_CH0_NUM = BIT(16),
MSIX_FH_INT_CAUSES_D2S_CH1_NUM = BIT(17),
MSIX_FH_INT_CAUSES_S2D = BIT(19),
MSIX_FH_INT_CAUSES_FH_ERR = BIT(21),
};
/*
* Causes for the HW register interrupts
*/
enum msix_hw_int_causes {
MSIX_HW_INT_CAUSES_REG_ALIVE = BIT(0),
MSIX_HW_INT_CAUSES_REG_WAKEUP = BIT(1),
MSIX_HW_INT_CAUSES_REG_CT_KILL = BIT(6),
MSIX_HW_INT_CAUSES_REG_RF_KILL = BIT(7),
MSIX_HW_INT_CAUSES_REG_PERIODIC = BIT(8),
MSIX_HW_INT_CAUSES_REG_SW_ERR = BIT(25),
MSIX_HW_INT_CAUSES_REG_SCD = BIT(26),
MSIX_HW_INT_CAUSES_REG_FH_TX = BIT(27),
MSIX_HW_INT_CAUSES_REG_HW_ERR = BIT(29),
MSIX_HW_INT_CAUSES_REG_HAP = BIT(30),
};
#define MSIX_MIN_INTERRUPT_VECTORS 2
#define MSIX_AUTO_CLEAR_CAUSE 0
#define MSIX_NON_AUTO_CLEAR_CAUSE BIT(7)
#endif /* !__iwl_csr_h__ */

View File

@ -73,12 +73,12 @@ TRACE_EVENT(iwlwifi_dev_rx,
TP_ARGS(dev, trans, pkt, len),
TP_STRUCT__entry(
DEV_ENTRY
__field(u8, cmd)
__field(u16, cmd)
__dynamic_array(u8, rxbuf, iwl_rx_trace_len(trans, pkt, len))
),
TP_fast_assign(
DEV_ASSIGN;
__entry->cmd = pkt->hdr.cmd;
__entry->cmd = WIDE_ID(pkt->hdr.group_id, pkt->hdr.cmd);
memcpy(__get_dynamic_array(rxbuf), pkt,
iwl_rx_trace_len(trans, pkt, len));
),

View File

@ -1033,7 +1033,8 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
}
}
if (usniffer_req && !*usniffer_images) {
if (!fw_has_capa(capa, IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED) &&
usniffer_req && !*usniffer_images) {
IWL_ERR(drv,
"user selected to work with usniffer but usniffer image isn't available in ucode package\n");
return -EINVAL;
@ -1718,3 +1719,7 @@ MODULE_PARM_DESC(fw_monitor,
module_param_named(d0i3_timeout, iwlwifi_mod_params.d0i3_entry_delay,
uint, S_IRUGO);
MODULE_PARM_DESC(d0i3_timeout, "Timeout to D0i3 entry when idle (ms)");
module_param_named(disable_11ac, iwlwifi_mod_params.disable_11ac, bool,
S_IRUGO);
MODULE_PARM_DESC(disable_11ac, "Disable VHT capabilities");

View File

@ -6,7 +6,7 @@
* GPL LICENSE SUMMARY
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@ -32,7 +32,7 @@
* BSD LICENSE
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2015 Intel Deutschland GmbH
* Copyright(c) 2015 - 2016 Intel Deutschland GmbH
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -368,20 +368,24 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
#define RFH_RXF_DMA_RBDCB_SIZE_512 (0x9 << RFH_RXF_DMA_RBDCB_SIZE_POS)
#define RFH_RXF_DMA_RBDCB_SIZE_1024 (0xA << RFH_RXF_DMA_RBDCB_SIZE_POS)
#define RFH_RXF_DMA_RBDCB_SIZE_2048 (0xB << RFH_RXF_DMA_RBDCB_SIZE_POS)
#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */
#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */
#define RFH_RXF_DMA_MIN_RB_SIZE_POS 24
#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS)
#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */
#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/
#define RFH_DMA_EN_ENABLE_VAL BIT(31)
#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS)
#define RFH_RXF_DMA_DROP_TOO_LARGE_MASK (0x04000000) /* bit 26 */
#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */
#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/
#define RFH_DMA_EN_ENABLE_VAL BIT(31)
#define RFH_RXF_RXQ_ACTIVE 0xA0980C
#define RFH_GEN_CFG 0xA09800
#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0)
#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1)
#define RFH_GEN_CFG_RB_CHUNK_SIZE BIT(4) /* 0 - 64B, 1- 128B */
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0)
#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1)
#define DEFAULT_RXQ_NUM 8
#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_POS 8
#define DEFAULT_RXQ_NUM 0
/* end of 9000 rx series registers */

View File

@ -318,6 +318,12 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
* @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
* from AP and will send it upon d0i3 exit.
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
* @IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW: firmware responsible for CT-kill
* @IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT: supports temperature
* thresholds reporting
* @IWL_UCODE_TLV_CAPA_CTDP_SUPPORT: supports cTDP command
* @IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED: supports usniffer enabled in
* regular image.
*
* @NUM_IWL_UCODE_TLV_CAPA: number of bits used
*/
@ -351,6 +357,10 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION = (__force iwl_ucode_tlv_capa_t)71,
IWL_UCODE_TLV_CAPA_BEACON_STORING = (__force iwl_ucode_tlv_capa_t)72,
IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2 = (__force iwl_ucode_tlv_capa_t)73,
IWL_UCODE_TLV_CAPA_CT_KILL_BY_FW = (__force iwl_ucode_tlv_capa_t)74,
IWL_UCODE_TLV_CAPA_TEMP_THS_REPORT_SUPPORT = (__force iwl_ucode_tlv_capa_t)75,
IWL_UCODE_TLV_CAPA_CTDP_SUPPORT = (__force iwl_ucode_tlv_capa_t)76,
IWL_UCODE_TLV_CAPA_USNIFFER_UNIFIED = (__force iwl_ucode_tlv_capa_t)77,
NUM_IWL_UCODE_TLV_CAPA
#ifdef __CHECKER__

View File

@ -115,6 +115,7 @@ enum iwl_amsdu_size {
* entering D0i3 (in msecs)
* @lar_disable: disable LAR (regulatory), default = 0
* @fw_monitor: allow to use firmware monitor
* @disable_11ac: disable VHT capabilities, default = false.
*/
struct iwl_mod_params {
int sw_crypto;
@ -135,6 +136,7 @@ struct iwl_mod_params {
unsigned int d0i3_entry_delay;
bool lar_disable;
bool fw_monitor;
bool disable_11ac;
};
#endif /* #__iwl_modparams_h__ */

View File

@ -366,6 +366,9 @@ static void iwl_init_vht_hw_capab(const struct iwl_cfg *cfg,
max_ampdu_exponent <<
IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_SHIFT;
if (cfg->vht_mu_mimo_supported)
vht_cap->cap |= IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE;
if (cfg->ht_params->ldpc)
vht_cap->cap |= IEEE80211_VHT_CAP_RXLDPC;
@ -449,7 +452,7 @@ static void iwl_init_sbands(struct device *dev, const struct iwl_cfg *cfg,
IEEE80211_BAND_5GHZ);
iwl_init_ht_hw_capab(cfg, data, &sband->ht_cap, IEEE80211_BAND_5GHZ,
tx_chains, rx_chains);
if (data->sku_cap_11ac_enable)
if (data->sku_cap_11ac_enable && !iwlwifi_mod_params.disable_11ac)
iwl_init_vht_hw_capab(cfg, data, &sband->vht_cap,
tx_chains, rx_chains);

View File

@ -404,4 +404,6 @@ enum {
LMPM_PAGE_PASS_NOTIF_POS = BIT(20),
};
#define UREG_CHICK (0xA05C00)
#define UREG_CHICK_MSIX_ENABLE BIT(25)
#endif /* __iwl_prph_h__ */

View File

@ -836,6 +836,7 @@ struct iwl_trans {
enum iwl_plat_pm_mode system_pm_mode;
enum iwl_plat_pm_mode runtime_pm_mode;
bool suspending;
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */

View File

@ -816,8 +816,7 @@ static int iwl_mvm_switch_to_d3(struct iwl_mvm *mvm)
{
iwl_mvm_scan_stop(mvm, IWL_MVM_SCAN_REGULAR, true);
iwl_trans_stop_device(mvm->trans);
iwl_mvm_stop_device(mvm);
/*
* Set the HW restart bit -- this is mostly true as we're
* going to load new firmware and reprogram that, though
@ -856,8 +855,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
wowlan_config_cmd->is_11n_connection =
ap_sta->ht_cap.ht_supported;
wowlan_config_cmd->flags = ENABLE_L3_FILTERING |
ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING |
ENABLE_STORE_BEACON;
ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING;
/* Query the last used seqno and set it */
ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);

View File

@ -64,6 +64,7 @@
*
*****************************************************************************/
#include <linux/vmalloc.h>
#include <linux/ieee80211.h>
#include "mvm.h"
#include "fw-dbg.h"
@ -976,7 +977,7 @@ static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
ARRAY_SIZE(cmd.indirection_table) % nbytes);
memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key));
memcpy(cmd.secret_key, mvm->secret_key, sizeof(cmd.secret_key));
mutex_lock(&mvm->mutex);
ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
@ -1080,6 +1081,22 @@ static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
return count;
}
static ssize_t iwl_dbgfs_max_amsdu_len_write(struct iwl_mvm *mvm,
char *buf, size_t count,
loff_t *ppos)
{
unsigned int max_amsdu_len;
int ret;
ret = kstrtouint(buf, 0, &max_amsdu_len);
if (max_amsdu_len > IEEE80211_MAX_MPDU_LEN_VHT_11454)
return -EINVAL;
mvm->max_amsdu_len = max_amsdu_len;
return count;
}
#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@ -1497,7 +1514,9 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, 16);
MVM_DEBUGFS_WRITE_FILE_OPS(max_amsdu_len, 8);
MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl,
(IWL_RSS_INDIRECTION_TABLE_SIZE * 2));
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@ -1540,6 +1559,7 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(max_amsdu_len, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);

Some files were not shown because too many files have changed in this diff Show More