Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
diff --git a/Documentation/ABI/testing/sysfs-bus-bcma b/Documentation/ABI/testing/sysfs-bus-bcma
new file mode 100644
index 0000000..06b62ba
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-bcma
@@ -0,0 +1,31 @@
+What: /sys/bus/bcma/devices/.../manuf
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ Each BCMA core has it's manufacturer id. See
+ include/linux/bcma/bcma.h for possible values.
+
+What: /sys/bus/bcma/devices/.../id
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ There are a few types of BCMA cores, they can be identified by
+ id field.
+
+What: /sys/bus/bcma/devices/.../rev
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ BCMA cores of the same type can still slightly differ depending
+ on their revision. Use it for detailed programming.
+
+What: /sys/bus/bcma/devices/.../class
+Date: May 2011
+KernelVersion: 2.6.40
+Contact: Rafał Miłecki <zajec5@gmail.com>
+Description:
+ Each BCMA core is identified by few fields, including class it
+ belongs to. See include/linux/bcma/bcma.h for possible values.
diff --git a/MAINTAINERS b/MAINTAINERS
index e653a99..e23cbd1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -5812,6 +5812,13 @@
F: drivers/ssb/
F: include/linux/ssb/
+BROADCOM SPECIFIC AMBA DRIVER (BCMA)
+M: Rafał Miłecki <zajec5@gmail.com>
+L: linux-wireless@vger.kernel.org
+S: Maintained
+F: drivers/bcma/
+F: include/linux/bcma/
+
SONY VAIO CONTROL DEVICE DRIVER
M: Mattia Dongili <malattia@linux.it>
L: platform-driver-x86@vger.kernel.org
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 177c7d1..aca7067 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -68,6 +68,8 @@
source "drivers/ssb/Kconfig"
+source "drivers/bcma/Kconfig"
+
source "drivers/mfd/Kconfig"
source "drivers/regulator/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 3f135b6..a29527f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -110,6 +110,7 @@
obj-$(CONFIG_PPC_PS3) += ps3/
obj-$(CONFIG_OF) += of/
obj-$(CONFIG_SSB) += ssb/
+obj-$(CONFIG_BCMA) += bcma/
obj-$(CONFIG_VHOST_NET) += vhost/
obj-$(CONFIG_VLYNQ) += vlynq/
obj-$(CONFIG_STAGING) += staging/
diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig
new file mode 100644
index 0000000..353781b
--- /dev/null
+++ b/drivers/bcma/Kconfig
@@ -0,0 +1,33 @@
+config BCMA_POSSIBLE
+ bool
+ depends on HAS_IOMEM && HAS_DMA
+ default y
+
+menu "Broadcom specific AMBA"
+ depends on BCMA_POSSIBLE
+
+config BCMA
+ tristate "BCMA support"
+ depends on BCMA_POSSIBLE
+ help
+ Bus driver for Broadcom specific Advanced Microcontroller Bus
+ Architecture.
+
+config BCMA_HOST_PCI_POSSIBLE
+ bool
+ depends on BCMA && PCI = y
+ default y
+
+config BCMA_HOST_PCI
+ bool "Support for BCMA on PCI-host bus"
+ depends on BCMA_HOST_PCI_POSSIBLE
+
+config BCMA_DEBUG
+ bool "BCMA debugging"
+ depends on BCMA
+ help
+ This turns on additional debugging messages.
+
+ If unsure, say N
+
+endmenu
diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile
new file mode 100644
index 0000000..0d56245
--- /dev/null
+++ b/drivers/bcma/Makefile
@@ -0,0 +1,7 @@
+bcma-y += main.o scan.o core.o
+bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o
+bcma-y += driver_pci.o
+bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o
+obj-$(CONFIG_BCMA) += bcma.o
+
+ccflags-$(CONFIG_BCMA_DEBUG) := -DDEBUG
diff --git a/drivers/bcma/README b/drivers/bcma/README
new file mode 100644
index 0000000..f7e7ce4
--- /dev/null
+++ b/drivers/bcma/README
@@ -0,0 +1,19 @@
+Broadcom introduced new bus as replacement for older SSB. It is based on AMBA,
+however from programming point of view there is nothing AMBA specific we use.
+
+Standard AMBA drivers are platform specific, have hardcoded addresses and use
+AMBA standard fields like CID and PID.
+
+In case of Broadcom's cards every device consists of:
+1) Broadcom specific AMBA device. It is put on AMBA bus, but can not be treated
+ as standard AMBA device. Reading it's CID or PID can cause machine lockup.
+2) AMBA standard devices called ports or wrappers. They have CIDs (AMBA_CID)
+ and PIDs (0x103BB369), but we do not use that info for anything. One of that
+ devices is used for managing Broadcom specific core.
+
+Addresses of AMBA devices are not hardcoded in driver and have to be read from
+EPROM.
+
+In this situation we decided to introduce separated bus. It can contain up to
+16 devices identified by Broadcom specific fields: manufacturer, id, revision
+and class.
diff --git a/drivers/bcma/TODO b/drivers/bcma/TODO
new file mode 100644
index 0000000..da7aa99
--- /dev/null
+++ b/drivers/bcma/TODO
@@ -0,0 +1,3 @@
+- Interrupts
+- Defines for PCI core driver
+- Create kernel Documentation (use info from README)
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
new file mode 100644
index 0000000..2f72e9c
--- /dev/null
+++ b/drivers/bcma/bcma_private.h
@@ -0,0 +1,28 @@
+#ifndef LINUX_BCMA_PRIVATE_H_
+#define LINUX_BCMA_PRIVATE_H_
+
+#ifndef pr_fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#endif
+
+#include <linux/bcma/bcma.h>
+#include <linux/delay.h>
+
+#define BCMA_CORE_SIZE 0x1000
+
+struct bcma_bus;
+
+/* main.c */
+extern int bcma_bus_register(struct bcma_bus *bus);
+extern void bcma_bus_unregister(struct bcma_bus *bus);
+
+/* scan.c */
+int bcma_bus_scan(struct bcma_bus *bus);
+
+#ifdef CONFIG_BCMA_HOST_PCI
+/* host_pci.c */
+extern int __init bcma_host_pci_init(void);
+extern void __exit bcma_host_pci_exit(void);
+#endif /* CONFIG_BCMA_HOST_PCI */
+
+#endif
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c
new file mode 100644
index 0000000..ced379f
--- /dev/null
+++ b/drivers/bcma/core.c
@@ -0,0 +1,51 @@
+/*
+ * Broadcom specific AMBA
+ * Core ops
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+bool bcma_core_is_enabled(struct bcma_device *core)
+{
+ if ((bcma_aread32(core, BCMA_IOCTL) & (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC))
+ != BCMA_IOCTL_CLK)
+ return false;
+ if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
+ return false;
+ return true;
+}
+EXPORT_SYMBOL_GPL(bcma_core_is_enabled);
+
+static void bcma_core_disable(struct bcma_device *core, u32 flags)
+{
+ if (bcma_aread32(core, BCMA_RESET_CTL) & BCMA_RESET_CTL_RESET)
+ return;
+
+ bcma_awrite32(core, BCMA_IOCTL, flags);
+ bcma_aread32(core, BCMA_IOCTL);
+ udelay(10);
+
+ bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
+ udelay(1);
+}
+
+int bcma_core_enable(struct bcma_device *core, u32 flags)
+{
+ bcma_core_disable(core, flags);
+
+ bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | BCMA_IOCTL_FGC | flags));
+ bcma_aread32(core, BCMA_IOCTL);
+
+ bcma_awrite32(core, BCMA_RESET_CTL, 0);
+ udelay(1);
+
+ bcma_awrite32(core, BCMA_IOCTL, (BCMA_IOCTL_CLK | flags));
+ bcma_aread32(core, BCMA_IOCTL);
+ udelay(1);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcma_core_enable);
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
new file mode 100644
index 0000000..6061022
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon.c
@@ -0,0 +1,89 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon core driver
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
+ u32 mask, u32 value)
+{
+ value &= mask;
+ value |= bcma_cc_read32(cc, offset) & ~mask;
+ bcma_cc_write32(cc, offset, value);
+
+ return value;
+}
+
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
+{
+ if (cc->core->id.rev >= 11)
+ cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
+ cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
+ if (cc->core->id.rev >= 35)
+ cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
+
+ if (cc->core->id.rev >= 20) {
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
+ bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
+ }
+
+ if (cc->capabilities & BCMA_CC_CAP_PMU)
+ bcma_pmu_init(cc);
+ if (cc->capabilities & BCMA_CC_CAP_PCTL)
+ pr_err("Power control not implemented!\n");
+}
+
+/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
+void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
+{
+ /* instant NMI */
+ bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
+}
+
+void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value);
+}
+
+u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask)
+{
+ return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask;
+}
+
+u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
+{
+ return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
+}
+
+u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
+}
+
+u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
+}
+
+u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
+
+u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
+}
+
+u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
+{
+ return bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
+}
diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c
new file mode 100644
index 0000000..f44177a
--- /dev/null
+++ b/drivers/bcma/driver_chipcommon_pmu.c
@@ -0,0 +1,134 @@
+/*
+ * Broadcom specific AMBA
+ * ChipCommon Power Management Unit driver
+ *
+ * Copyright 2009, Michael Buesch <mb@bu3sch.de>
+ * Copyright 2007, Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+ u32 offset, u32 mask, u32 set)
+{
+ u32 value;
+
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+ value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+ value &= mask;
+ value |= set;
+ bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
+ bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+}
+
+static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ case 0x4331:
+ case 43224:
+ case 43225:
+ break;
+ default:
+ pr_err("PLL init unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+}
+
+static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+ u32 min_msk = 0, max_msk = 0;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ min_msk = 0x200D;
+ max_msk = 0xFFFF;
+ break;
+ case 43224:
+ break;
+ default:
+ pr_err("PMU resource config unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+
+ /* Set the resource masks. */
+ if (min_msk)
+ bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+ if (max_msk)
+ bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+}
+
+void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ case 0x4331:
+ case 43224:
+ break;
+ default:
+ pr_err("PMU switch/regulators init unknown for device "
+ "0x%04X\n", bus->chipinfo.id);
+ }
+}
+
+void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
+{
+ struct bcma_bus *bus = cc->core->bus;
+
+ switch (bus->chipinfo.id) {
+ case 0x4313:
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
+ break;
+ case 0x4331:
+ pr_err("Enabling Ext PA lines not implemented\n");
+ break;
+ case 43224:
+ if (bus->chipinfo.rev == 0) {
+ pr_err("Workarounds for 43224 rev 0 not fully "
+ "implemented\n");
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
+ } else {
+ bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
+ }
+ break;
+ default:
+ pr_err("Workarounds unknown for device 0x%04X\n",
+ bus->chipinfo.id);
+ }
+}
+
+void bcma_pmu_init(struct bcma_drv_cc *cc)
+{
+ u32 pmucap;
+
+ pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
+ cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
+
+ pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
+ pmucap);
+
+ if (cc->pmu.rev == 1)
+ bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
+ ~BCMA_CC_PMU_CTL_NOILPONW);
+ else
+ bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
+ BCMA_CC_PMU_CTL_NOILPONW);
+
+ if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
+ pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
+
+ bcma_pmu_pll_init(cc);
+ bcma_pmu_resources_init(cc);
+ bcma_pmu_swreg_init(cc);
+ bcma_pmu_workarounds(cc);
+}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
new file mode 100644
index 0000000..e757e4e
--- /dev/null
+++ b/drivers/bcma/driver_pci.c
@@ -0,0 +1,163 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Core
+ *
+ * Copyright 2005, Broadcom Corporation
+ * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+static u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_read32(pc, 0x130);
+ return pcicore_read32(pc, 0x134);
+}
+
+#if 0
+static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
+{
+ pcicore_write32(pc, 0x130, address);
+ pcicore_read32(pc, 0x130);
+ pcicore_write32(pc, 0x134, data);
+}
+#endif
+
+static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ u32 v;
+ int i;
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ v |= (0x1F << 18);
+ v |= (phy << 4);
+ pcicore_write32(pc, mdio_data, v);
+
+ udelay(10);
+ for (i = 0; i < 200; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+}
+
+static u16 bcma_pcie_mdio_read(struct bcma_drv_pci *pc, u8 device, u8 address)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u16 ret = 0;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
+ }
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 29); /* Read Transaction */
+ v |= (1 << 17); /* Turnaround */
+ if (pc->core->id.rev < 10)
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */) {
+ udelay(10);
+ ret = pcicore_read32(pc, mdio_data);
+ break;
+ }
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+ return ret;
+}
+
+static void bcma_pcie_mdio_write(struct bcma_drv_pci *pc, u8 device,
+ u8 address, u16 data)
+{
+ const u16 mdio_control = 0x128;
+ const u16 mdio_data = 0x12C;
+ int max_retries = 10;
+ u32 v;
+ int i;
+
+ v = 0x80; /* Enable Preamble Sequence */
+ v |= 0x2; /* MDIO Clock Divisor */
+ pcicore_write32(pc, mdio_control, v);
+
+ if (pc->core->id.rev >= 10) {
+ max_retries = 200;
+ bcma_pcie_mdio_set_phy(pc, device);
+ }
+
+ v = (1 << 30); /* Start of Transaction */
+ v |= (1 << 28); /* Write Transaction */
+ v |= (1 << 17); /* Turnaround */
+ if (pc->core->id.rev < 10)
+ v |= (u32)device << 22;
+ v |= (u32)address << 18;
+ v |= data;
+ pcicore_write32(pc, mdio_data, v);
+ /* Wait for the device to complete the transaction */
+ udelay(10);
+ for (i = 0; i < max_retries; i++) {
+ v = pcicore_read32(pc, mdio_control);
+ if (v & 0x100 /* Trans complete */)
+ break;
+ msleep(1);
+ }
+ pcicore_write32(pc, mdio_control, 0);
+}
+
+/**************************************************
+ * Workarounds.
+ **************************************************/
+
+static u8 bcma_pcicore_polarity_workaround(struct bcma_drv_pci *pc)
+{
+ return (bcma_pcie_read(pc, 0x204) & 0x10) ? 0xC0 : 0x80;
+}
+
+static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
+{
+ const u8 serdes_pll_device = 0x1D;
+ const u8 serdes_rx_device = 0x1F;
+ u16 tmp;
+
+ bcma_pcie_mdio_write(pc, serdes_rx_device, 1 /* Control */,
+ bcma_pcicore_polarity_workaround(pc));
+ tmp = bcma_pcie_mdio_read(pc, serdes_pll_device, 1 /* Control */);
+ if (tmp & 0x4000)
+ bcma_pcie_mdio_write(pc, serdes_pll_device, 1, tmp & ~0x4000);
+}
+
+/**************************************************
+ * Init.
+ **************************************************/
+
+void bcma_core_pci_init(struct bcma_drv_pci *pc)
+{
+ bcma_pcicore_serdes_workaround(pc);
+}
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
new file mode 100644
index 0000000..99dd36e
--- /dev/null
+++ b/drivers/bcma/host_pci.c
@@ -0,0 +1,196 @@
+/*
+ * Broadcom specific AMBA
+ * PCI Host
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+#include <linux/pci.h>
+
+static void bcma_host_pci_switch_core(struct bcma_device *core)
+{
+ pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
+ core->addr);
+ pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
+ core->wrap);
+ core->bus->mapped_core = core;
+ pr_debug("Switched to core: 0x%X\n", core->id.id);
+}
+
+static u8 bcma_host_pci_read8(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread8(core->bus->mmio + offset);
+}
+
+static u16 bcma_host_pci_read16(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread16(core->bus->mmio + offset);
+}
+
+static u32 bcma_host_pci_read32(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread32(core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write8(struct bcma_device *core, u16 offset,
+ u8 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite8(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write16(struct bcma_device *core, u16 offset,
+ u16 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite16(value, core->bus->mmio + offset);
+}
+
+static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite32(value, core->bus->mmio + offset);
+}
+
+static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ return ioread32(core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+}
+
+static void bcma_host_pci_awrite32(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ if (core->bus->mapped_core != core)
+ bcma_host_pci_switch_core(core);
+ iowrite32(value, core->bus->mmio + (1 * BCMA_CORE_SIZE) + offset);
+}
+
+const struct bcma_host_ops bcma_host_pci_ops = {
+ .read8 = bcma_host_pci_read8,
+ .read16 = bcma_host_pci_read16,
+ .read32 = bcma_host_pci_read32,
+ .write8 = bcma_host_pci_write8,
+ .write16 = bcma_host_pci_write16,
+ .write32 = bcma_host_pci_write32,
+ .aread32 = bcma_host_pci_aread32,
+ .awrite32 = bcma_host_pci_awrite32,
+};
+
+static int bcma_host_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ struct bcma_bus *bus;
+ int err = -ENOMEM;
+ const char *name;
+ u32 val;
+
+ /* Alloc */
+ bus = kzalloc(sizeof(*bus), GFP_KERNEL);
+ if (!bus)
+ goto out;
+
+ /* Basic PCI configuration */
+ err = pci_enable_device(dev);
+ if (err)
+ goto err_kfree_bus;
+
+ name = dev_name(&dev->dev);
+ if (dev->driver && dev->driver->name)
+ name = dev->driver->name;
+ err = pci_request_regions(dev, name);
+ if (err)
+ goto err_pci_disable;
+ pci_set_master(dev);
+
+ /* Disable the RETRY_TIMEOUT register (0x41) to keep
+ * PCI Tx retries from interfering with C3 CPU state */
+ pci_read_config_dword(dev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(dev, 0x40, val & 0xffff00ff);
+
+ /* SSB needed additional powering up, do we have any AMBA PCI cards? */
+ if (!pci_is_pcie(dev))
+ pr_err("PCI card detected, report problems.\n");
+
+ /* Map MMIO */
+ err = -ENOMEM;
+ bus->mmio = pci_iomap(dev, 0, ~0UL);
+ if (!bus->mmio)
+ goto err_pci_release_regions;
+
+ /* Host specific */
+ bus->host_pci = dev;
+ bus->hosttype = BCMA_HOSTTYPE_PCI;
+ bus->ops = &bcma_host_pci_ops;
+
+ /* Register */
+ err = bcma_bus_register(bus);
+ if (err)
+ goto err_pci_unmap_mmio;
+
+ pci_set_drvdata(dev, bus);
+
+out:
+ return err;
+
+err_pci_unmap_mmio:
+ pci_iounmap(dev, bus->mmio);
+err_pci_release_regions:
+ pci_release_regions(dev);
+err_pci_disable:
+ pci_disable_device(dev);
+err_kfree_bus:
+ kfree(bus);
+ return err;
+}
+
+static void bcma_host_pci_remove(struct pci_dev *dev)
+{
+ struct bcma_bus *bus = pci_get_drvdata(dev);
+
+ bcma_bus_unregister(bus);
+ pci_iounmap(dev, bus->mmio);
+ pci_release_regions(dev);
+ pci_disable_device(dev);
+ kfree(bus);
+ pci_set_drvdata(dev, NULL);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
+ { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4727) },
+ { 0, },
+};
+MODULE_DEVICE_TABLE(pci, bcma_pci_bridge_tbl);
+
+static struct pci_driver bcma_pci_bridge_driver = {
+ .name = "bcma-pci-bridge",
+ .id_table = bcma_pci_bridge_tbl,
+ .probe = bcma_host_pci_probe,
+ .remove = bcma_host_pci_remove,
+};
+
+int __init bcma_host_pci_init(void)
+{
+ return pci_register_driver(&bcma_pci_bridge_driver);
+}
+
+void __exit bcma_host_pci_exit(void)
+{
+ pci_unregister_driver(&bcma_pci_bridge_driver);
+}
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
new file mode 100644
index 0000000..be52344
--- /dev/null
+++ b/drivers/bcma/main.c
@@ -0,0 +1,247 @@
+/*
+ * Broadcom specific AMBA
+ * Bus subsystem
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+#include <linux/bcma/bcma.h>
+
+MODULE_DESCRIPTION("Broadcom's specific AMBA driver");
+MODULE_LICENSE("GPL");
+
+static int bcma_bus_match(struct device *dev, struct device_driver *drv);
+static int bcma_device_probe(struct device *dev);
+static int bcma_device_remove(struct device *dev);
+
+static ssize_t manuf_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%03X\n", core->id.manuf);
+}
+static ssize_t id_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%03X\n", core->id.id);
+}
+static ssize_t rev_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%02X\n", core->id.rev);
+}
+static ssize_t class_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ return sprintf(buf, "0x%X\n", core->id.class);
+}
+static struct device_attribute bcma_device_attrs[] = {
+ __ATTR_RO(manuf),
+ __ATTR_RO(id),
+ __ATTR_RO(rev),
+ __ATTR_RO(class),
+ __ATTR_NULL,
+};
+
+static struct bus_type bcma_bus_type = {
+ .name = "bcma",
+ .match = bcma_bus_match,
+ .probe = bcma_device_probe,
+ .remove = bcma_device_remove,
+ .dev_attrs = bcma_device_attrs,
+};
+
+static struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid)
+{
+ struct bcma_device *core;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ if (core->id.id == coreid)
+ return core;
+ }
+ return NULL;
+}
+
+static void bcma_release_core_dev(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ kfree(core);
+}
+
+static int bcma_register_cores(struct bcma_bus *bus)
+{
+ struct bcma_device *core;
+ int err, dev_id = 0;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ /* We support that cores ourself */
+ switch (core->id.id) {
+ case BCMA_CORE_CHIPCOMMON:
+ case BCMA_CORE_PCI:
+ case BCMA_CORE_PCIE:
+ continue;
+ }
+
+ core->dev.release = bcma_release_core_dev;
+ core->dev.bus = &bcma_bus_type;
+ dev_set_name(&core->dev, "bcma%d:%d", 0/*bus->num*/, dev_id);
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ core->dev.parent = &bus->host_pci->dev;
+ break;
+ case BCMA_HOSTTYPE_NONE:
+ case BCMA_HOSTTYPE_SDIO:
+ break;
+ }
+
+ err = device_register(&core->dev);
+ if (err) {
+ pr_err("Could not register dev for core 0x%03X\n",
+ core->id.id);
+ continue;
+ }
+ core->dev_registered = true;
+ dev_id++;
+ }
+
+ return 0;
+}
+
+static void bcma_unregister_cores(struct bcma_bus *bus)
+{
+ struct bcma_device *core;
+
+ list_for_each_entry(core, &bus->cores, list) {
+ if (core->dev_registered)
+ device_unregister(&core->dev);
+ }
+}
+
+int bcma_bus_register(struct bcma_bus *bus)
+{
+ int err;
+ struct bcma_device *core;
+
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
+ if (err) {
+ pr_err("Failed to scan: %d\n", err);
+ return -1;
+ }
+
+ /* Init CC core */
+ core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON);
+ if (core) {
+ bus->drv_cc.core = core;
+ bcma_core_chipcommon_init(&bus->drv_cc);
+ }
+
+ /* Init PCIE core */
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
+ if (core) {
+ bus->drv_pci.core = core;
+ bcma_core_pci_init(&bus->drv_pci);
+ }
+
+ /* Register found cores */
+ bcma_register_cores(bus);
+
+ pr_info("Bus registered\n");
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(bcma_bus_register);
+
+void bcma_bus_unregister(struct bcma_bus *bus)
+{
+ bcma_unregister_cores(bus);
+}
+EXPORT_SYMBOL_GPL(bcma_bus_unregister);
+
+int __bcma_driver_register(struct bcma_driver *drv, struct module *owner)
+{
+ drv->drv.name = drv->name;
+ drv->drv.bus = &bcma_bus_type;
+ drv->drv.owner = owner;
+
+ return driver_register(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(__bcma_driver_register);
+
+void bcma_driver_unregister(struct bcma_driver *drv)
+{
+ driver_unregister(&drv->drv);
+}
+EXPORT_SYMBOL_GPL(bcma_driver_unregister);
+
+static int bcma_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(drv, struct bcma_driver, drv);
+ const struct bcma_device_id *cid = &core->id;
+ const struct bcma_device_id *did;
+
+ for (did = adrv->id_table; did->manuf || did->id || did->rev; did++) {
+ if ((did->manuf == cid->manuf || did->manuf == BCMA_ANY_MANUF) &&
+ (did->id == cid->id || did->id == BCMA_ANY_ID) &&
+ (did->rev == cid->rev || did->rev == BCMA_ANY_REV) &&
+ (did->class == cid->class || did->class == BCMA_ANY_CLASS))
+ return 1;
+ }
+ return 0;
+}
+
+static int bcma_device_probe(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
+ drv);
+ int err = 0;
+
+ if (adrv->probe)
+ err = adrv->probe(core);
+
+ return err;
+}
+
+static int bcma_device_remove(struct device *dev)
+{
+ struct bcma_device *core = container_of(dev, struct bcma_device, dev);
+ struct bcma_driver *adrv = container_of(dev->driver, struct bcma_driver,
+ drv);
+
+ if (adrv->remove)
+ adrv->remove(core);
+
+ return 0;
+}
+
+static int __init bcma_modinit(void)
+{
+ int err;
+
+ err = bus_register(&bcma_bus_type);
+ if (err)
+ return err;
+
+#ifdef CONFIG_BCMA_HOST_PCI
+ err = bcma_host_pci_init();
+ if (err) {
+ pr_err("PCI host initialization failed\n");
+ err = 0;
+ }
+#endif
+
+ return err;
+}
+fs_initcall(bcma_modinit);
+
+static void __exit bcma_modexit(void)
+{
+#ifdef CONFIG_BCMA_HOST_PCI
+ bcma_host_pci_exit();
+#endif
+ bus_unregister(&bcma_bus_type);
+}
+module_exit(bcma_modexit)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
new file mode 100644
index 0000000..40d7dcc
--- /dev/null
+++ b/drivers/bcma/scan.c
@@ -0,0 +1,360 @@
+/*
+ * Broadcom specific AMBA
+ * Bus scanning
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "scan.h"
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+struct bcma_device_id_name {
+ u16 id;
+ const char *name;
+};
+struct bcma_device_id_name bcma_device_names[] = {
+ { BCMA_CORE_OOB_ROUTER, "OOB Router" },
+ { BCMA_CORE_INVALID, "Invalid" },
+ { BCMA_CORE_CHIPCOMMON, "ChipCommon" },
+ { BCMA_CORE_ILINE20, "ILine 20" },
+ { BCMA_CORE_SRAM, "SRAM" },
+ { BCMA_CORE_SDRAM, "SDRAM" },
+ { BCMA_CORE_PCI, "PCI" },
+ { BCMA_CORE_MIPS, "MIPS" },
+ { BCMA_CORE_ETHERNET, "Fast Ethernet" },
+ { BCMA_CORE_V90, "V90" },
+ { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
+ { BCMA_CORE_ADSL, "ADSL" },
+ { BCMA_CORE_ILINE100, "ILine 100" },
+ { BCMA_CORE_IPSEC, "IPSEC" },
+ { BCMA_CORE_UTOPIA, "UTOPIA" },
+ { BCMA_CORE_PCMCIA, "PCMCIA" },
+ { BCMA_CORE_INTERNAL_MEM, "Internal Memory" },
+ { BCMA_CORE_MEMC_SDRAM, "MEMC SDRAM" },
+ { BCMA_CORE_OFDM, "OFDM" },
+ { BCMA_CORE_EXTIF, "EXTIF" },
+ { BCMA_CORE_80211, "IEEE 802.11" },
+ { BCMA_CORE_PHY_A, "PHY A" },
+ { BCMA_CORE_PHY_B, "PHY B" },
+ { BCMA_CORE_PHY_G, "PHY G" },
+ { BCMA_CORE_MIPS_3302, "MIPS 3302" },
+ { BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
+ { BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
+ { BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
+ { BCMA_CORE_USB20_DEV, "USB 2.0 Device" },
+ { BCMA_CORE_SDIO_HOST, "SDIO Host" },
+ { BCMA_CORE_ROBOSWITCH, "Roboswitch" },
+ { BCMA_CORE_PARA_ATA, "PATA" },
+ { BCMA_CORE_SATA_XORDMA, "SATA XOR-DMA" },
+ { BCMA_CORE_ETHERNET_GBIT, "GBit Ethernet" },
+ { BCMA_CORE_PCIE, "PCIe" },
+ { BCMA_CORE_PHY_N, "PHY N" },
+ { BCMA_CORE_SRAM_CTL, "SRAM Controller" },
+ { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
+ { BCMA_CORE_ARM_1176, "ARM 1176" },
+ { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
+ { BCMA_CORE_PHY_LP, "PHY LP" },
+ { BCMA_CORE_PMU, "PMU" },
+ { BCMA_CORE_PHY_SSN, "PHY SSN" },
+ { BCMA_CORE_SDIO_DEV, "SDIO Device" },
+ { BCMA_CORE_ARM_CM3, "ARM CM3" },
+ { BCMA_CORE_PHY_HT, "PHY HT" },
+ { BCMA_CORE_MIPS_74K, "MIPS 74K" },
+ { BCMA_CORE_MAC_GBIT, "GBit MAC" },
+ { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
+ { BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
+ { BCMA_CORE_OCP_OCP_BRIDGE, "OCP to OCP Bridge" },
+ { BCMA_CORE_SHARED_COMMON, "Common Shared" },
+ { BCMA_CORE_OCP_AHB_BRIDGE, "OCP to AHB Bridge" },
+ { BCMA_CORE_SPI_HOST, "SPI Host" },
+ { BCMA_CORE_I2S, "I2S" },
+ { BCMA_CORE_SDR_DDR1_MEM_CTL, "SDR/DDR1 Memory Controller" },
+ { BCMA_CORE_SHIM, "SHIM" },
+ { BCMA_CORE_DEFAULT, "Default" },
+};
+const char *bcma_device_name(struct bcma_device_id *id)
+{
+ int i;
+
+ if (id->manuf == BCMA_MANUF_BCM) {
+ for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) {
+ if (bcma_device_names[i].id == id->id)
+ return bcma_device_names[i].name;
+ }
+ }
+ return "UNKNOWN";
+}
+
+static u32 bcma_scan_read32(struct bcma_bus *bus, u8 current_coreidx,
+ u16 offset)
+{
+ return readl(bus->mmio + offset);
+}
+
+static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
+{
+ if (bus->hosttype == BCMA_HOSTTYPE_PCI)
+ pci_write_config_dword(bus->host_pci, BCMA_PCI_BAR0_WIN,
+ addr);
+}
+
+static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = readl(*eromptr);
+ (*eromptr)++;
+ return ent;
+}
+
+static void bcma_erom_push_ent(u32 **eromptr)
+{
+ (*eromptr)--;
+}
+
+static s32 bcma_erom_get_ci(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if (!(ent & SCAN_ER_VALID))
+ return -ENOENT;
+ if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_CI)
+ return -ENOENT;
+ return ent;
+}
+
+static bool bcma_erom_is_end(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ bcma_erom_push_ent(eromptr);
+ return (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID));
+}
+
+static bool bcma_erom_is_bridge(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ bcma_erom_push_ent(eromptr);
+ return (((ent & SCAN_ER_VALID)) &&
+ ((ent & SCAN_ER_TAGX) == SCAN_ER_TAG_ADDR) &&
+ ((ent & SCAN_ADDR_TYPE) == SCAN_ADDR_TYPE_BRIDGE));
+}
+
+static void bcma_erom_skip_component(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent;
+ while (1) {
+ ent = bcma_erom_get_ent(bus, eromptr);
+ if ((ent & SCAN_ER_VALID) &&
+ ((ent & SCAN_ER_TAG) == SCAN_ER_TAG_CI))
+ break;
+ if (ent == (SCAN_ER_TAG_END | SCAN_ER_VALID))
+ break;
+ }
+ bcma_erom_push_ent(eromptr);
+}
+
+static s32 bcma_erom_get_mst_port(struct bcma_bus *bus, u32 **eromptr)
+{
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if (!(ent & SCAN_ER_VALID))
+ return -ENOENT;
+ if ((ent & SCAN_ER_TAG) != SCAN_ER_TAG_MP)
+ return -ENOENT;
+ return ent;
+}
+
+static s32 bcma_erom_get_addr_desc(struct bcma_bus *bus, u32 **eromptr,
+ u32 type, u8 port)
+{
+ u32 addrl, addrh, sizel, sizeh = 0;
+ u32 size;
+
+ u32 ent = bcma_erom_get_ent(bus, eromptr);
+ if ((!(ent & SCAN_ER_VALID)) ||
+ ((ent & SCAN_ER_TAGX) != SCAN_ER_TAG_ADDR) ||
+ ((ent & SCAN_ADDR_TYPE) != type) ||
+ (((ent & SCAN_ADDR_PORT) >> SCAN_ADDR_PORT_SHIFT) != port)) {
+ bcma_erom_push_ent(eromptr);
+ return -EINVAL;
+ }
+
+ addrl = ent & SCAN_ADDR_ADDR;
+ if (ent & SCAN_ADDR_AG32)
+ addrh = bcma_erom_get_ent(bus, eromptr);
+ else
+ addrh = 0;
+
+ if ((ent & SCAN_ADDR_SZ) == SCAN_ADDR_SZ_SZD) {
+ size = bcma_erom_get_ent(bus, eromptr);
+ sizel = size & SCAN_SIZE_SZ;
+ if (size & SCAN_SIZE_SG32)
+ sizeh = bcma_erom_get_ent(bus, eromptr);
+ } else
+ sizel = SCAN_ADDR_SZ_BASE <<
+ ((ent & SCAN_ADDR_SZ) >> SCAN_ADDR_SZ_SHIFT);
+
+ return addrl;
+}
+
+int bcma_bus_scan(struct bcma_bus *bus)
+{
+ u32 erombase;
+ u32 __iomem *eromptr, *eromend;
+
+ s32 cia, cib;
+ u8 ports[2], wrappers[2];
+
+ s32 tmp;
+ u8 i, j;
+
+ int err;
+
+ INIT_LIST_HEAD(&bus->cores);
+ bus->nr_cores = 0;
+
+ bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
+
+ tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
+ bus->chipinfo.id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
+ bus->chipinfo.rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
+ bus->chipinfo.pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
+
+ erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
+ eromptr = bus->mmio;
+ eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
+
+ bcma_scan_switch_core(bus, erombase);
+
+ while (eromptr < eromend) {
+ struct bcma_device *core = kzalloc(sizeof(*core), GFP_KERNEL);
+ if (!core)
+ return -ENOMEM;
+ INIT_LIST_HEAD(&core->list);
+ core->bus = bus;
+
+ /* get CIs */
+ cia = bcma_erom_get_ci(bus, &eromptr);
+ if (cia < 0) {
+ bcma_erom_push_ent(&eromptr);
+ if (bcma_erom_is_end(bus, &eromptr))
+ break;
+ err= -EILSEQ;
+ goto out;
+ }
+ cib = bcma_erom_get_ci(bus, &eromptr);
+ if (cib < 0) {
+ err= -EILSEQ;
+ goto out;
+ }
+
+ /* parse CIs */
+ core->id.class = (cia & SCAN_CIA_CLASS) >> SCAN_CIA_CLASS_SHIFT;
+ core->id.id = (cia & SCAN_CIA_ID) >> SCAN_CIA_ID_SHIFT;
+ core->id.manuf = (cia & SCAN_CIA_MANUF) >> SCAN_CIA_MANUF_SHIFT;
+ ports[0] = (cib & SCAN_CIB_NMP) >> SCAN_CIB_NMP_SHIFT;
+ ports[1] = (cib & SCAN_CIB_NSP) >> SCAN_CIB_NSP_SHIFT;
+ wrappers[0] = (cib & SCAN_CIB_NMW) >> SCAN_CIB_NMW_SHIFT;
+ wrappers[1] = (cib & SCAN_CIB_NSW) >> SCAN_CIB_NSW_SHIFT;
+ core->id.rev = (cib & SCAN_CIB_REV) >> SCAN_CIB_REV_SHIFT;
+
+ if (((core->id.manuf == BCMA_MANUF_ARM) &&
+ (core->id.id == 0xFFF)) ||
+ (ports[1] == 0)) {
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ /* check if component is a core at all */
+ if (wrappers[0] + wrappers[1] == 0) {
+ /* we could save addrl of the router
+ if (cid == BCMA_CORE_OOB_ROUTER)
+ */
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ if (bcma_erom_is_bridge(bus, &eromptr)) {
+ bcma_erom_skip_component(bus, &eromptr);
+ continue;
+ }
+
+ /* get & parse master ports */
+ for (i = 0; i < ports[0]; i++) {
+ u32 mst_port_d = bcma_erom_get_mst_port(bus, &eromptr);
+ if (mst_port_d < 0) {
+ err= -EILSEQ;
+ goto out;
+ }
+ }
+
+ /* get & parse slave ports */
+ for (i = 0; i < ports[1]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_SLAVE, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: slave port %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->addr = tmp;
+ }
+ }
+ }
+
+ /* get & parse master wrappers */
+ for (i = 0; i < wrappers[0]; i++) {
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_MWRAP, i);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * "has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (i == 0 && j == 0)
+ core->wrap = tmp;
+ }
+ }
+ }
+
+ /* get & parse slave wrappers */
+ for (i = 0; i < wrappers[1]; i++) {
+ u8 hack = (ports[1] == 1) ? 0 : 1;
+ for (j = 0; ; j++) {
+ tmp = bcma_erom_get_addr_desc(bus, &eromptr,
+ SCAN_ADDR_TYPE_SWRAP, i + hack);
+ if (tmp < 0) {
+ /* no more entries for port _i_ */
+ /* pr_debug("erom: master wrapper %d "
+ * has %d descriptors\n", i, j); */
+ break;
+ } else {
+ if (wrappers[0] == 0 && !i && !j)
+ core->wrap = tmp;
+ }
+ }
+ }
+
+ pr_info("Core %d found: %s "
+ "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
+ bus->nr_cores, bcma_device_name(&core->id),
+ core->id.manuf, core->id.id, core->id.rev,
+ core->id.class);
+
+ core->core_index = bus->nr_cores++;
+ list_add(&core->list, &bus->cores);
+ continue;
+out:
+ return err;
+ }
+
+ return 0;
+}
diff --git a/drivers/bcma/scan.h b/drivers/bcma/scan.h
new file mode 100644
index 0000000..113e6a6
--- /dev/null
+++ b/drivers/bcma/scan.h
@@ -0,0 +1,56 @@
+#ifndef BCMA_SCAN_H_
+#define BCMA_SCAN_H_
+
+#define BCMA_ADDR_BASE 0x18000000
+#define BCMA_WRAP_BASE 0x18100000
+
+#define SCAN_ER_VALID 0x00000001
+#define SCAN_ER_TAGX 0x00000006 /* we have to ignore 0x8 bit when checking tag for SCAN_ER_TAG_ADDR */
+#define SCAN_ER_TAG 0x0000000E
+#define SCAN_ER_TAG_CI 0x00000000
+#define SCAN_ER_TAG_MP 0x00000002
+#define SCAN_ER_TAG_ADDR 0x00000004
+#define SCAN_ER_TAG_END 0x0000000E
+#define SCAN_ER_BAD 0xFFFFFFFF
+
+#define SCAN_CIA_CLASS 0x000000F0
+#define SCAN_CIA_CLASS_SHIFT 4
+#define SCAN_CIA_ID 0x000FFF00
+#define SCAN_CIA_ID_SHIFT 8
+#define SCAN_CIA_MANUF 0xFFF00000
+#define SCAN_CIA_MANUF_SHIFT 20
+
+#define SCAN_CIB_NMP 0x000001F0
+#define SCAN_CIB_NMP_SHIFT 4
+#define SCAN_CIB_NSP 0x00003E00
+#define SCAN_CIB_NSP_SHIFT 9
+#define SCAN_CIB_NMW 0x0007C000
+#define SCAN_CIB_NMW_SHIFT 14
+#define SCAN_CIB_NSW 0x00F80000
+#define SCAN_CIB_NSW_SHIFT 17
+#define SCAN_CIB_REV 0xFF000000
+#define SCAN_CIB_REV_SHIFT 24
+
+#define SCAN_ADDR_AG32 0x00000008
+#define SCAN_ADDR_SZ 0x00000030
+#define SCAN_ADDR_SZ_SHIFT 4
+#define SCAN_ADDR_SZ_4K 0x00000000
+#define SCAN_ADDR_SZ_8K 0x00000010
+#define SCAN_ADDR_SZ_16K 0x00000020
+#define SCAN_ADDR_SZ_SZD 0x00000030
+#define SCAN_ADDR_TYPE 0x000000C0
+#define SCAN_ADDR_TYPE_SLAVE 0x00000000
+#define SCAN_ADDR_TYPE_BRIDGE 0x00000040
+#define SCAN_ADDR_TYPE_SWRAP 0x00000080
+#define SCAN_ADDR_TYPE_MWRAP 0x000000C0
+#define SCAN_ADDR_PORT 0x00000F00
+#define SCAN_ADDR_PORT_SHIFT 8
+#define SCAN_ADDR_ADDR 0xFFFFF000
+
+#define SCAN_ADDR_SZ_BASE 0x00001000 /* 4KB */
+
+#define SCAN_SIZE_SZ_ALIGN 0x00000FFF
+#define SCAN_SIZE_SZ 0xFFFFF000
+#define SCAN_SIZE_SG32 0x00000008
+
+#endif /* BCMA_SCAN_H_ */
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 695d441..6bacef3 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -62,6 +62,7 @@
/* Atheros AR3011 with sflash firmware*/
{ USB_DEVICE(0x0CF3, 0x3002) },
+ { USB_DEVICE(0x13d3, 0x3304) },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03F0, 0x311D) },
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 762a510..c2de895 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -104,6 +104,7 @@
/* Atheros 3011 with sflash firmware */
{ USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+ { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE },
/* Atheros AR9285 Malbec with sflash firmware */
{ USB_DEVICE(0x03f0, 0x311d), .driver_info = BTUSB_IGNORE },
diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c
index 203243b..2204762 100644
--- a/drivers/net/wireless/ath/ath5k/base.c
+++ b/drivers/net/wireless/ath/ath5k/base.c
@@ -2394,7 +2394,7 @@
spin_lock_init(&sc->rxbuflock);
spin_lock_init(&sc->txbuflock);
spin_lock_init(&sc->block);
-
+ spin_lock_init(&sc->irqlock);
/* Setup interrupt handler */
ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_mac.c b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
index c338efb..7a332f1 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_mac.c
@@ -415,15 +415,6 @@
ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr);
}
-static void ar9002_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
-{
- struct ar5416_desc *ads = AR5416DESC(ds);
-
- ads->ds_ctl2 &= ~AR_BurstDur;
- ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur);
-}
-
void ath9k_hw_setuprxdesc(struct ath_hw *ah, struct ath_desc *ds,
u32 size, u32 flags)
{
@@ -456,6 +447,5 @@
ops->set11n_aggr_middle = ar9002_hw_set11n_aggr_middle;
ops->set11n_aggr_last = ar9002_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9002_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9002_hw_set11n_burstduration;
ops->set_clrdmask = ar9002_hw_set_clrdmask;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9002_phy.c b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
index 7d68d61..a57e963 100644
--- a/drivers/net/wireless/ath/ath9k/ar9002_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9002_phy.c
@@ -517,23 +517,7 @@
}
}
-void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
-{
- struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
-
- priv_ops->set_rf_regs = NULL;
- priv_ops->rf_alloc_ext_banks = NULL;
- priv_ops->rf_free_ext_banks = NULL;
- priv_ops->rf_set_freq = ar9002_hw_set_channel;
- priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
- priv_ops->olc_init = ar9002_olc_init;
- priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
- priv_ops->do_getnf = ar9002_hw_do_getnf;
-
- ar9002_hw_set_nf_limits(ah);
-}
-
-void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+static void ar9002_hw_antdiv_comb_conf_get(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
@@ -545,10 +529,11 @@
AR_PHY_9285_ANT_DIV_ALT_LNACONF_S;
antconf->fast_div_bias = (regval & AR_PHY_9285_FAST_DIV_BIAS) >>
AR_PHY_9285_FAST_DIV_BIAS_S;
+ antconf->lna1_lna2_delta = -3;
+ antconf->div_group = 0;
}
-EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_get);
-void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+static void ar9002_hw_antdiv_comb_conf_set(struct ath_hw *ah,
struct ath_hw_antcomb_conf *antconf)
{
u32 regval;
@@ -566,4 +551,23 @@
REG_WRITE(ah, AR_PHY_MULTICHAIN_GAIN_CTL, regval);
}
-EXPORT_SYMBOL(ath9k_hw_antdiv_comb_conf_set);
+
+void ar9002_hw_attach_phy_ops(struct ath_hw *ah)
+{
+ struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
+
+ priv_ops->set_rf_regs = NULL;
+ priv_ops->rf_alloc_ext_banks = NULL;
+ priv_ops->rf_free_ext_banks = NULL;
+ priv_ops->rf_set_freq = ar9002_hw_set_channel;
+ priv_ops->spur_mitigate_freq = ar9002_hw_spur_mitigate;
+ priv_ops->olc_init = ar9002_olc_init;
+ priv_ops->compute_pll_control = ar9002_hw_compute_pll_control;
+ priv_ops->do_getnf = ar9002_hw_do_getnf;
+
+ ops->antdiv_comb_conf_get = ar9002_hw_antdiv_comb_conf_get;
+ ops->antdiv_comb_conf_set = ar9002_hw_antdiv_comb_conf_set;
+
+ ar9002_hw_set_nf_limits(ah);
+}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index fb892e5..1e22035 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -652,7 +652,7 @@
.regDmn = { LE16(0), LE16(0x1f) },
.txrxMask = 0x77, /* 4 bits tx and 4 bits rx */
.opCapFlags = {
- .opFlags = AR5416_OPFLAGS_11G | AR5416_OPFLAGS_11A,
+ .opFlags = AR5416_OPFLAGS_11A,
.eepMisc = 0,
},
.rfSilent = 0,
@@ -922,7 +922,7 @@
.db_stage2 = {3, 3, 3}, /* 3 chain */
.db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
.db_stage4 = {3, 3, 3}, /* don't exist for 2G */
- .xpaBiasLvl = 0,
+ .xpaBiasLvl = 0xf,
.txFrameToDataStart = 0x0e,
.txFrameToPaOn = 0x0e,
.txClip = 3, /* 4 bits tx_clip, 4 bits dac_scale_cck */
@@ -3442,17 +3442,15 @@
{
int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz);
- if (AR_SREV_9485(ah))
+ if (AR_SREV_9485(ah) || AR_SREV_9340(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
else {
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
- if (!AR_SREV_9340(ah)) {
- REG_RMW_FIELD(ah, AR_CH0_THERM,
- AR_CH0_THERM_XPABIASLVL_MSB,
- bias >> 2);
- REG_RMW_FIELD(ah, AR_CH0_THERM,
- AR_CH0_THERM_XPASHORT2GND, 1);
- }
+ REG_RMW_FIELD(ah, AR_CH0_THERM,
+ AR_CH0_THERM_XPABIASLVL_MSB,
+ bias >> 2);
+ REG_RMW_FIELD(ah, AR_CH0_THERM,
+ AR_CH0_THERM_XPASHORT2GND, 1);
}
}
@@ -3500,6 +3498,8 @@
static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
{
int chain;
+ u32 regval;
+ u32 ant_div_ctl1;
static const u32 switch_chain_reg[AR9300_MAX_CHAINS] = {
AR_PHY_SWITCH_CHAIN_0,
AR_PHY_SWITCH_CHAIN_1,
@@ -3525,13 +3525,49 @@
if (AR_SREV_9485(ah)) {
value = ath9k_hw_ar9300_get_eeprom(ah, EEP_ANT_DIV_CTL1);
- REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_CTRL_ALL,
- value);
- REG_RMW_FIELD(ah, AR_PHY_MC_GAIN_CTRL, AR_ANT_DIV_ENABLE,
- value >> 6);
- REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, AR_FAST_DIV_ENABLE,
- value >> 7);
+ /*
+ * main_lnaconf, alt_lnaconf, main_tb, alt_tb
+ * are the fields present
+ */
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ regval &= (~AR_ANT_DIV_CTRL_ALL);
+ regval |= (value & 0x3f) << AR_ANT_DIV_CTRL_ALL_S;
+ /* enable_lnadiv */
+ regval &= (~AR_PHY_9485_ANT_DIV_LNADIV);
+ regval |= ((value >> 6) & 0x1) <<
+ AR_PHY_9485_ANT_DIV_LNADIV_S;
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+
+ /*enable fast_div */
+ regval = REG_READ(ah, AR_PHY_CCK_DETECT);
+ regval &= (~AR_FAST_DIV_ENABLE);
+ regval |= ((value >> 7) & 0x1) <<
+ AR_FAST_DIV_ENABLE_S;
+ REG_WRITE(ah, AR_PHY_CCK_DETECT, regval);
+ ant_div_ctl1 =
+ ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ /* check whether antenna diversity is enabled */
+ if ((ant_div_ctl1 >> 0x6) == 0x3) {
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ /*
+ * clear bits 25-30 main_lnaconf, alt_lnaconf,
+ * main_tb, alt_tb
+ */
+ regval &= (~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_GAINTB |
+ AR_PHY_9485_ANT_DIV_MAIN_GAINTB));
+ /* by default use LNA1 for the main antenna */
+ regval |= (AR_PHY_9485_ANT_DIV_LNA1 <<
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S);
+ regval |= (AR_PHY_9485_ANT_DIV_LNA2 <<
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF_S);
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+ }
+
+
}
+
}
static void ar9003_hw_drive_strength_apply(struct ath_hw *ah)
@@ -4005,6 +4041,16 @@
POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
);
+ /* Write the power for duplicated frames - HT40 */
+
+ /* dup40_cck (LSB), dup40_ofdm, ext20_cck, ext20_ofdm (MSB) */
+ REG_WRITE(ah, 0xa3e0,
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 24) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 16) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_6_24], 8) |
+ POW_SM(pPwrArray[ALL_TARGET_LEGACY_1L_5L], 0)
+ );
+
/* Write the HT20 power per rate set */
/* 0/8/16 (LSB), 1-3/9-11/17-19, 4, 5 (MSB) */
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
index c1264d6..be6adec 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c
@@ -484,16 +484,6 @@
ads->ctl12 &= (~AR_IsAggr & ~AR_MoreAggr);
}
-static void ar9003_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
-{
- struct ar9003_txc *ads = (struct ar9003_txc *) ds;
-
- ads->ctl13 &= ~AR_BurstDur;
- ads->ctl13 |= SM(burstDuration, AR_BurstDur);
-
-}
-
void ar9003_hw_set_paprd_txdesc(struct ath_hw *ah, void *ds, u8 chains)
{
struct ar9003_txc *ads = ds;
@@ -518,7 +508,6 @@
ops->set11n_aggr_middle = ar9003_hw_set11n_aggr_middle;
ops->set11n_aggr_last = ar9003_hw_set11n_aggr_last;
ops->clr11n_aggr = ar9003_hw_clr11n_aggr;
- ops->set11n_burstduration = ar9003_hw_set11n_burstduration;
ops->set_clrdmask = ar9003_hw_set_clrdmask;
}
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index c83be2d..25f3c2f 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -1184,9 +1184,52 @@
conf->radar_inband = 8;
}
+static void ar9003_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ antconf->main_lna_conf = (regval & AR_PHY_9485_ANT_DIV_MAIN_LNACONF) >>
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S;
+ antconf->alt_lna_conf = (regval & AR_PHY_9485_ANT_DIV_ALT_LNACONF) >>
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF_S;
+ antconf->fast_div_bias = (regval & AR_PHY_9485_ANT_FAST_DIV_BIAS) >>
+ AR_PHY_9485_ANT_FAST_DIV_BIAS_S;
+ antconf->lna1_lna2_delta = -9;
+ antconf->div_group = 2;
+}
+
+static void ar9003_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ u32 regval;
+
+ regval = REG_READ(ah, AR_PHY_MC_GAIN_CTRL);
+ regval &= ~(AR_PHY_9485_ANT_DIV_MAIN_LNACONF |
+ AR_PHY_9485_ANT_DIV_ALT_LNACONF |
+ AR_PHY_9485_ANT_FAST_DIV_BIAS |
+ AR_PHY_9485_ANT_DIV_MAIN_GAINTB |
+ AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+ regval |= ((antconf->main_lna_conf <<
+ AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S)
+ & AR_PHY_9485_ANT_DIV_MAIN_LNACONF);
+ regval |= ((antconf->alt_lna_conf << AR_PHY_9485_ANT_DIV_ALT_LNACONF_S)
+ & AR_PHY_9485_ANT_DIV_ALT_LNACONF);
+ regval |= ((antconf->fast_div_bias << AR_PHY_9485_ANT_FAST_DIV_BIAS_S)
+ & AR_PHY_9485_ANT_FAST_DIV_BIAS);
+ regval |= ((antconf->main_gaintb << AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S)
+ & AR_PHY_9485_ANT_DIV_MAIN_GAINTB);
+ regval |= ((antconf->alt_gaintb << AR_PHY_9485_ANT_DIV_ALT_GAINTB_S)
+ & AR_PHY_9485_ANT_DIV_ALT_GAINTB);
+
+ REG_WRITE(ah, AR_PHY_MC_GAIN_CTRL, regval);
+}
+
void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
+ struct ath_hw_ops *ops = ath9k_hw_ops(ah);
static const u32 ar9300_cca_regs[6] = {
AR_PHY_CCA_0,
AR_PHY_CCA_1,
@@ -1213,6 +1256,9 @@
priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
priv_ops->set_radar_params = ar9003_hw_set_radar_params;
+ ops->antdiv_comb_conf_get = ar9003_hw_antdiv_comb_conf_get;
+ ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set;
+
ar9003_hw_set_nf_limits(ah);
ar9003_hw_set_radar_conf(ah);
memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index 2a0d5cb..c7505b4 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -261,12 +261,34 @@
#define AR_PHY_EXT_CCA0 (AR_AGC_BASE + 0x20)
#define AR_PHY_RESTART (AR_AGC_BASE + 0x24)
+/*
+ * Antenna Diversity settings
+ */
#define AR_PHY_MC_GAIN_CTRL (AR_AGC_BASE + 0x28)
#define AR_ANT_DIV_CTRL_ALL 0x7e000000
#define AR_ANT_DIV_CTRL_ALL_S 25
#define AR_ANT_DIV_ENABLE 0x1000000
#define AR_ANT_DIV_ENABLE_S 24
+
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS 0x00007e00
+#define AR_PHY_9485_ANT_FAST_DIV_BIAS_S 9
+#define AR_PHY_9485_ANT_DIV_LNADIV 0x01000000
+#define AR_PHY_9485_ANT_DIV_LNADIV_S 24
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF 0x06000000
+#define AR_PHY_9485_ANT_DIV_ALT_LNACONF_S 25
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF 0x18000000
+#define AR_PHY_9485_ANT_DIV_MAIN_LNACONF_S 27
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB 0x20000000
+#define AR_PHY_9485_ANT_DIV_ALT_GAINTB_S 29
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB 0x40000000
+#define AR_PHY_9485_ANT_DIV_MAIN_GAINTB_S 30
+
+#define AR_PHY_9485_ANT_DIV_LNA1_MINUS_LNA2 0x0
+#define AR_PHY_9485_ANT_DIV_LNA2 0x1
+#define AR_PHY_9485_ANT_DIV_LNA1 0x2
+#define AR_PHY_9485_ANT_DIV_LNA1_PLUS_LNA2 0x3
+
#define AR_PHY_EXTCHN_PWRTHR1 (AR_AGC_BASE + 0x2c)
#define AR_PHY_EXT_CHN_WIN (AR_AGC_BASE + 0x30)
#define AR_PHY_20_40_DET_THR (AR_AGC_BASE + 0x34)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 0312aa0..03b37d7 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -62,7 +62,6 @@
#define ATH_TXQ_SETUP(sc, i) ((sc)->tx.txqsetup & (1<<i))
struct ath_config {
- u32 ath_aggr_prot;
u16 txpowlimit;
u8 cabqReadytime;
};
@@ -484,7 +483,6 @@
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO 30
#define ATH_ANT_DIV_COMB_ALT_ANT_RATIO2 20
-#define ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA -3
#define ATH_ANT_DIV_COMB_LNA1_LNA2_SWITCH_DELTA -1
#define ATH_ANT_DIV_COMB_LNA1_DELTA_HI -4
#define ATH_ANT_DIV_COMB_LNA1_DELTA_MID -2
@@ -565,6 +563,7 @@
#define PS_WAIT_FOR_PSPOLL_DATA BIT(2)
#define PS_WAIT_FOR_TX_ACK BIT(3)
#define PS_BEACON_SYNC BIT(4)
+#define PS_TSFOOR_SYNC BIT(5)
struct ath_rate_table;
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 22cd241..637dbc5 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -620,7 +620,13 @@
ath9k_hw_disable_interrupts(ah);
ath9k_hw_set_sta_beacon_timers(ah, &bs);
ah->imask |= ATH9K_INT_BMISS;
- ath9k_hw_set_interrupts(ah, ah->imask);
+
+ /*
+ * If the beacon config is called beacause of TSFOOR,
+ * Interrupts will be enabled back at the end of ath9k_tasklet
+ */
+ if (!(sc->ps_flags & PS_TSFOOR_SYNC))
+ ath9k_hw_set_interrupts(ah, ah->imask);
}
static void ath_beacon_config_adhoc(struct ath_softc *sc,
@@ -661,7 +667,12 @@
ath9k_hw_disable_interrupts(ah);
ath9k_beacon_init(sc, nexttbtt, intval);
sc->beacon.bmisscnt = 0;
- ath9k_hw_set_interrupts(ah, ah->imask);
+ /*
+ * If the beacon config is called beacause of TSFOOR,
+ * Interrupts will be enabled back at the end of ath9k_tasklet
+ */
+ if (!(sc->ps_flags & PS_TSFOOR_SYNC))
+ ath9k_hw_set_interrupts(ah, ah->imask);
}
static bool ath9k_allow_beacon_config(struct ath_softc *sc,
diff --git a/drivers/net/wireless/ath/ath9k/calib.c b/drivers/net/wireless/ath/ath9k/calib.c
index 8649581..558b228 100644
--- a/drivers/net/wireless/ath/ath9k/calib.c
+++ b/drivers/net/wireless/ath/ath9k/calib.c
@@ -69,15 +69,21 @@
int16_t *nfarray)
{
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
struct ath_nf_limits *limit;
struct ath9k_nfcal_hist *h;
bool high_nf_mid = false;
+ u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
int i;
h = cal->nfCalHist;
limit = ath9k_hw_get_nf_limits(ah, ah->curchan);
for (i = 0; i < NUM_NF_READINGS; i++) {
+ if (!(chainmask & (1 << i)) ||
+ ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf)))
+ continue;
+
h[i].nfCalBuffer[h[i].currIndex] = nfarray[i];
if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX)
@@ -225,6 +231,7 @@
int32_t val;
u8 chainmask = (ah->rxchainmask << 3) | ah->rxchainmask;
struct ath_common *common = ath9k_hw_common(ah);
+ struct ieee80211_conf *conf = &common->hw->conf;
s16 default_nf = ath9k_hw_get_default_nf(ah, chan);
if (ah->caldata)
@@ -234,6 +241,9 @@
if (chainmask & (1 << i)) {
s16 nfval;
+ if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+ continue;
+
if (h)
nfval = h[i].privNF;
else
@@ -293,6 +303,9 @@
ENABLE_REGWRITE_BUFFER(ah);
for (i = 0; i < NUM_NF_READINGS; i++) {
if (chainmask & (1 << i)) {
+ if ((i >= AR5416_MAX_CHAINS) && !conf_is_ht40(conf))
+ continue;
+
val = REG_READ(ah, ah->nf_regs[i]);
val &= 0xFFFFFE00;
val |= (((u32) (-50) << 1) & 0x1ff);
@@ -396,14 +409,6 @@
}
}
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
-{
- if (!ah->curchan || !ah->curchan->noisefloor)
- return ath9k_hw_get_default_nf(ah, chan);
-
- return ah->curchan->noisefloor;
-}
-EXPORT_SYMBOL(ath9k_hw_getchan_noise);
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h
index b8973eb..4420780 100644
--- a/drivers/net/wireless/ath/ath9k/calib.h
+++ b/drivers/net/wireless/ath/ath9k/calib.h
@@ -106,7 +106,6 @@
void ath9k_init_nfcal_hist_buffer(struct ath_hw *ah,
struct ath9k_channel *chan);
void ath9k_hw_bstuck_nfcal(struct ath_hw *ah);
-s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan);
void ath9k_hw_reset_calibration(struct ath_hw *ah,
struct ath9k_cal_list *currCal);
diff --git a/drivers/net/wireless/ath/ath9k/hw-ops.h b/drivers/net/wireless/ath/ath9k/hw-ops.h
index 9dd90a8..8b8f044 100644
--- a/drivers/net/wireless/ath/ath9k/hw-ops.h
+++ b/drivers/net/wireless/ath/ath9k/hw-ops.h
@@ -116,17 +116,23 @@
ath9k_hw_ops(ah)->clr11n_aggr(ah, ds);
}
-static inline void ath9k_hw_set11n_burstduration(struct ath_hw *ah, void *ds,
- u32 burstDuration)
-{
- ath9k_hw_ops(ah)->set11n_burstduration(ah, ds, burstDuration);
-}
-
static inline void ath9k_hw_set_clrdmask(struct ath_hw *ah, void *ds, bool val)
{
ath9k_hw_ops(ah)->set_clrdmask(ah, ds, val);
}
+static inline void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ ath9k_hw_ops(ah)->antdiv_comb_conf_get(ah, antconf);
+}
+
+static inline void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf)
+{
+ ath9k_hw_ops(ah)->antdiv_comb_conf_set(ah, antconf);
+}
+
/* Private hardware call ops */
/* PHY ops */
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 58f3d42..b75b5dc 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -2022,6 +2022,22 @@
}
+ if (AR_SREV_9485(ah)) {
+ ant_div_ctl1 = ah->eep_ops->get_eeprom(ah, EEP_ANT_DIV_CTL1);
+ /*
+ * enable the diversity-combining algorithm only when
+ * both enable_lna_div and enable_fast_div are set
+ * Table for Diversity
+ * ant_div_alt_lnaconf bit 0-1
+ * ant_div_main_lnaconf bit 2-3
+ * ant_div_alt_gaintb bit 4
+ * ant_div_main_gaintb bit 5
+ * enable_ant_div_lnadiv bit 6
+ * enable_ant_fast_div bit 7
+ */
+ if ((ant_div_ctl1 >> 0x6) == 0x3)
+ pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
+ }
if (AR_SREV_9485_10(ah)) {
pCap->pcie_lcr_extsync_en = true;
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 34ed1bd..7af2773 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -479,6 +479,10 @@
u8 main_lna_conf;
u8 alt_lna_conf;
u8 fast_div_bias;
+ u8 main_gaintb;
+ u8 alt_gaintb;
+ int lna1_lna2_delta;
+ u8 div_group;
};
/**
@@ -628,9 +632,12 @@
u32 numDelims);
void (*set11n_aggr_last)(struct ath_hw *ah, void *ds);
void (*clr11n_aggr)(struct ath_hw *ah, void *ds);
- void (*set11n_burstduration)(struct ath_hw *ah, void *ds,
- u32 burstDuration);
void (*set_clrdmask)(struct ath_hw *ah, void *ds, bool val);
+ void (*antdiv_comb_conf_get)(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
+ void (*antdiv_comb_conf_set)(struct ath_hw *ah,
+ struct ath_hw_antcomb_conf *antconf);
+
};
struct ath_nf_limits {
@@ -906,10 +913,6 @@
void ath9k_hw_set_gpio(struct ath_hw *ah, u32 gpio, u32 val);
u32 ath9k_hw_getdefantenna(struct ath_hw *ah);
void ath9k_hw_setantenna(struct ath_hw *ah, u32 antenna);
-void ath9k_hw_antdiv_comb_conf_get(struct ath_hw *ah,
- struct ath_hw_antcomb_conf *antconf);
-void ath9k_hw_antdiv_comb_conf_set(struct ath_hw *ah,
- struct ath_hw_antcomb_conf *antconf);
/* General Operation */
bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 9cf7a7d..bd6d2b9 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -430,8 +430,13 @@
SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH));
REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ);
- REG_WRITE(ah, AR_DMISC(q),
- AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
+
+ if (AR_SREV_9340(ah))
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x1);
+ else
+ REG_WRITE(ah, AR_DMISC(q),
+ AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2);
if (qi->tqi_cbrPeriod) {
REG_WRITE(ah, AR_QCBRCFG(q),
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index c3dbf26..45303bdb 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -689,6 +689,17 @@
!ath9k_hw_check_alive(ah))
ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+ if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
+ /*
+ * TSF sync does not look correct; remain awake to sync with
+ * the next Beacon.
+ */
+ ath_dbg(common, ATH_DBG_PS,
+ "TSFOOR - Sync with next Beacon\n");
+ sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC |
+ PS_TSFOOR_SYNC;
+ }
+
if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
rxmask = (ATH9K_INT_RXHP | ATH9K_INT_RXLP | ATH9K_INT_RXEOL |
ATH9K_INT_RXORN);
@@ -711,16 +722,6 @@
ath_tx_tasklet(sc);
}
- if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
- /*
- * TSF sync does not look correct; remain awake to sync with
- * the next Beacon.
- */
- ath_dbg(common, ATH_DBG_PS,
- "TSFOOR - Sync with next Beacon\n");
- sc->ps_flags |= PS_WAIT_FOR_BEACON | PS_BEACON_SYNC;
- }
-
if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
if (status & ATH9K_INT_GENTIMER)
ath_gen_timer_isr(sc->sc_ah);
@@ -1384,7 +1385,9 @@
ath9k_hw_set_tsfadjust(ah, 0);
sc->sc_flags &= ~SC_OP_TSF_RESET;
- if (iter_data.nwds + iter_data.nmeshes)
+ if (iter_data.nmeshes)
+ ah->opmode = NL80211_IFTYPE_MESH_POINT;
+ else if (iter_data.nwds)
ah->opmode = NL80211_IFTYPE_AP;
else if (iter_data.nadhocs)
ah->opmode = NL80211_IFTYPE_ADHOC;
@@ -1408,6 +1411,7 @@
/* Set up ANI */
if ((iter_data.naps + iter_data.nadhocs) > 0) {
+ sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
sc->sc_flags |= SC_OP_ANI_RUN;
ath_start_ani(common);
} else {
@@ -1778,6 +1782,11 @@
struct ieee80211_key_conf ps_key = { };
ath_node_attach(sc, sta);
+
+ if (vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_AP_VLAN)
+ return 0;
+
an->ps_key = ath_key_config(common, vif, sta, &ps_key);
return 0;
@@ -2039,9 +2048,6 @@
if (changed & BSS_CHANGED_BSSID) {
ath9k_config_bss(sc, vif);
- /* Set aggregation protection mode parameters */
- sc->config.ath_aggr_prot = 0;
-
ath_dbg(common, ATH_DBG_CONFIG, "BSSID: %pM aid: 0x%x\n",
common->curbssid, common->curaid);
}
@@ -2261,6 +2267,7 @@
struct ath_softc *sc = hw->priv;
int timeout = 200; /* ms */
int i, j;
+ bool drain_txq;
mutex_lock(&sc->mutex);
cancel_delayed_work_sync(&sc->tx_complete_work);
@@ -2269,7 +2276,7 @@
timeout = 1;
for (j = 0; j < timeout; j++) {
- int npend = 0;
+ bool npend = false;
if (j)
usleep_range(1000, 2000);
@@ -2278,7 +2285,10 @@
if (!ATH_TXQ_SETUP(sc, i))
continue;
- npend += ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+ npend = ath9k_has_pending_frames(sc, &sc->tx.txq[i]);
+
+ if (npend)
+ break;
}
if (!npend)
@@ -2286,7 +2296,10 @@
}
ath9k_ps_wakeup(sc);
- if (!ath_drain_all_txq(sc, false))
+ spin_lock_bh(&sc->sc_pcu_lock);
+ drain_txq = ath_drain_all_txq(sc, false);
+ spin_unlock_bh(&sc->sc_pcu_lock);
+ if (!drain_txq)
ath_reset(sc, false);
ath9k_ps_restore(sc);
ieee80211_wake_queues(hw);
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index c5b7cbe..4f52e04 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -28,6 +28,33 @@
(alt_rssi_avg > main_rssi_avg + mindelta)) && (pkt_count > 50);
}
+static inline bool ath_ant_div_comb_alt_check(u8 div_group, int alt_ratio,
+ int curr_main_set, int curr_alt_set,
+ int alt_rssi_avg, int main_rssi_avg)
+{
+ bool result = false;
+ switch (div_group) {
+ case 0:
+ if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO)
+ result = true;
+ break;
+ case 1:
+ if ((((curr_main_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (alt_rssi_avg >= (main_rssi_avg - 5))) ||
+ ((curr_main_set == ATH_ANT_DIV_COMB_LNA1) &&
+ (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) &&
+ (alt_rssi_avg >= (main_rssi_avg - 2)))) &&
+ (alt_rssi_avg >= 4))
+ result = true;
+ else
+ result = false;
+ break;
+ }
+
+ return result;
+}
+
static inline bool ath9k_check_auto_sleep(struct ath_softc *sc)
{
return sc->ps_enabled &&
@@ -572,6 +599,7 @@
ath_dbg(common, ATH_DBG_PS,
"Reconfigure Beacon timers based on timestamp from the AP\n");
ath_set_beacon(sc);
+ sc->ps_flags &= ~PS_TSFOOR_SYNC;
}
if (ath_beacon_dtim_pending_cab(skb)) {
@@ -916,7 +944,8 @@
int last_rssi;
__le16 fc;
- if (ah->opmode != NL80211_IFTYPE_STATION)
+ if ((ah->opmode != NL80211_IFTYPE_STATION) &&
+ (ah->opmode != NL80211_IFTYPE_ADHOC))
return;
fc = hdr->frame_control;
@@ -1288,49 +1317,138 @@
}
}
-static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf)
+static void ath_ant_div_conf_fast_divbias(struct ath_hw_antcomb_conf *ant_conf,
+ struct ath_ant_comb *antcomb, int alt_ratio)
{
- /* Adjust the fast_div_bias based on main and alt lna conf */
- switch ((ant_conf->main_lna_conf << 4) | ant_conf->alt_lna_conf) {
- case (0x01): /* A-B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x02): /* A-B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- case (0x03): /* A-B A+B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x10): /* LNA2 A-B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x12): /* LNA2 LNA1 */
- ant_conf->fast_div_bias = 0x2;
- break;
- case (0x13): /* LNA2 A+B */
- ant_conf->fast_div_bias = 0x7;
- break;
- case (0x20): /* LNA1 A-B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x21): /* LNA1 LNA2 */
- ant_conf->fast_div_bias = 0x0;
- break;
- case (0x23): /* LNA1 A+B */
- ant_conf->fast_div_bias = 0x6;
- break;
- case (0x30): /* A+B A-B */
- ant_conf->fast_div_bias = 0x1;
- break;
- case (0x31): /* A+B LNA2 */
- ant_conf->fast_div_bias = 0x3b;
- break;
- case (0x32): /* A+B LNA1 */
- ant_conf->fast_div_bias = 0x3d;
- break;
- default:
- break;
+ if (ant_conf->div_group == 0) {
+ /* Adjust the fast_div_bias based on main and alt lna conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case (0x01): /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x02): /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ case (0x03): /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x10): /* LNA2 A-B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x2;
+ break;
+ case (0x13): /* LNA2 A+B */
+ ant_conf->fast_div_bias = 0x7;
+ break;
+ case (0x20): /* LNA1 A-B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x0;
+ break;
+ case (0x23): /* LNA1 A+B */
+ ant_conf->fast_div_bias = 0x6;
+ break;
+ case (0x30): /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ break;
+ case (0x31): /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x3b;
+ break;
+ case (0x32): /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x3d;
+ break;
+ default:
+ break;
+ }
+ } else if (ant_conf->div_group == 2) {
+ /* Adjust the fast_div_bias based on main and alt_lna_conf */
+ switch ((ant_conf->main_lna_conf << 4) |
+ ant_conf->alt_lna_conf) {
+ case (0x01): /* A-B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x02): /* A-B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x03): /* A-B A+B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x10): /* LNA2 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x12): /* LNA2 LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x13): /* LNA2 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x20): /* LNA1 A-B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x21): /* LNA1 LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x23): /* LNA1 A+B */
+ if (!(antcomb->scan) &&
+ (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO))
+ ant_conf->fast_div_bias = 0x1;
+ else
+ ant_conf->fast_div_bias = 0x2;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x30): /* A+B A-B */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x31): /* A+B LNA2 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ case (0x32): /* A+B LNA1 */
+ ant_conf->fast_div_bias = 0x1;
+ ant_conf->main_gaintb = 0;
+ ant_conf->alt_gaintb = 0;
+ break;
+ default:
+ break;
+ }
+
}
+
}
/* Antenna diversity and combining */
@@ -1350,8 +1468,8 @@
main_ant_conf = (rs->rs_rssi_ctl2 >> ATH_ANT_RX_MAIN_SHIFT) &
ATH_ANT_RX_MASK;
- /* Record packet only when alt_rssi is positive */
- if (alt_rssi > 0) {
+ /* Record packet only when both main_rssi and alt_rssi is positive */
+ if (main_rssi > 0 && alt_rssi > 0) {
antcomb->total_pkt_count++;
antcomb->main_total_rssi += main_rssi;
antcomb->alt_total_rssi += alt_rssi;
@@ -1411,7 +1529,9 @@
}
if (!antcomb->scan) {
- if (alt_ratio > ATH_ANT_DIV_COMB_ALT_ANT_RATIO) {
+ if (ath_ant_div_comb_alt_check(div_ant_conf.div_group,
+ alt_ratio, curr_main_set, curr_alt_set,
+ alt_rssi_avg, main_rssi_avg)) {
if (curr_alt_set == ATH_ANT_DIV_COMB_LNA2) {
/* Switch main and alt LNA */
div_ant_conf.main_lna_conf =
@@ -1440,7 +1560,7 @@
}
if ((alt_rssi_avg < (main_rssi_avg +
- ATH_ANT_DIV_COMB_LNA1_LNA2_DELTA)))
+ div_ant_conf.lna1_lna2_delta)))
goto div_comb_done;
}
@@ -1554,8 +1674,7 @@
antcomb->quick_scan_cnt++;
div_comb_done:
- ath_ant_div_conf_fast_divbias(&div_ant_conf);
-
+ ath_ant_div_conf_fast_divbias(&div_ant_conf, antcomb, alt_ratio);
ath9k_hw_antdiv_comb_conf_set(sc->sc_ah, &div_ant_conf);
antcomb->scan_start_time = jiffies;
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 7b91b2a..97dd1fa 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1663,8 +1663,7 @@
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
- (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
+ if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) {
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
flags |= ATH9K_TXDESC_RTSENA;
} else if (rates[i].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
@@ -1733,8 +1732,6 @@
!is_pspoll, ctsrate,
0, series, 4, flags);
- if (sc->config.ath_aggr_prot && flags)
- ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
}
static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
@@ -1848,6 +1845,7 @@
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = info->control.sta;
+ struct ieee80211_vif *vif = info->control.vif;
struct ath_softc *sc = hw->priv;
struct ath_txq *txq = txctl->txq;
struct ath_buf *bf;
@@ -1885,6 +1883,11 @@
memmove(skb->data, skb->data + padsize, padpos);
}
+ if ((vif && vif->type != NL80211_IFTYPE_AP &&
+ vif->type != NL80211_IFTYPE_AP_VLAN) ||
+ !ieee80211_is_data(hdr->frame_control))
+ info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
setup_frame_info(hw, skb, frmlen);
/*
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index 1638468..7d5c65e 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -883,7 +883,7 @@
* then checking the error flags, later.
*/
- if (changed_flags & FIF_ALLMULTI && *new_flags & FIF_ALLMULTI)
+ if (*new_flags & FIF_ALLMULTI)
multicast = ~0ULL;
if (multicast != ar->cur_mc_hash)
diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c
index bf2eff9..e94084f 100644
--- a/drivers/net/wireless/ath/carl9170/tx.c
+++ b/drivers/net/wireless/ath/carl9170/tx.c
@@ -156,10 +156,8 @@
static void carl9170_tx_accounting_free(struct ar9170 *ar, struct sk_buff *skb)
{
- struct ieee80211_tx_info *txinfo;
int queue;
- txinfo = IEEE80211_SKB_CB(skb);
queue = skb_get_queue_mapping(skb);
spin_lock_bh(&ar->tx_stats_lock);
@@ -380,7 +378,6 @@
{
struct _carl9170_tx_superframe *super = (void *) skb->data;
struct ieee80211_hdr *hdr = (void *) super->frame_data;
- struct carl9170_tx_info *ar_info;
struct ieee80211_sta *sta;
struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *tid_info;
@@ -391,8 +388,6 @@
(!(super->f.mac_control & cpu_to_le16(AR9170_TX_MAC_AGGR))))
return;
- ar_info = (void *) txinfo->rate_driver_data;
-
rcu_read_lock();
sta = __carl9170_get_tx_sta(ar, skb);
if (unlikely(!sta))
@@ -623,7 +618,6 @@
{
struct sk_buff *skb;
struct ieee80211_tx_info *txinfo;
- struct carl9170_tx_info *arinfo;
unsigned int r, t, q;
bool success = true;
@@ -639,7 +633,6 @@
}
txinfo = IEEE80211_SKB_CB(skb);
- arinfo = (void *) txinfo->rate_driver_data;
if (!(info & CARL9170_TX_STATUS_SUCCESS))
success = false;
@@ -1321,7 +1314,6 @@
struct carl9170_sta_info *sta_info;
struct carl9170_sta_tid *agg;
struct sk_buff *iter;
- unsigned int max;
u16 tid, seq, qseq, off;
bool run = false;
@@ -1331,7 +1323,6 @@
rcu_read_lock();
agg = rcu_dereference(sta_info->agg[tid]);
- max = sta_info->ampdu_max_len;
if (!agg)
goto err_unlock_rcu;
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 5af40d9..5a43984 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -2686,6 +2686,17 @@
dev->mac_suspended++;
}
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
+void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on)
+{
+ u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
+ if (on)
+ tmslow |= B43_TMSLOW_MACPHYCLKEN;
+ else
+ tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
+ ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
+}
+
static void b43_adjust_opmode(struct b43_wldev *dev)
{
struct b43_wl *wl = dev->wl;
@@ -2842,7 +2853,7 @@
{
struct b43_phy *phy = &dev->phy;
int err;
- u32 value32, macctl;
+ u32 macctl;
u16 value16;
/* Initialize the MAC control */
@@ -2920,9 +2931,7 @@
b43_write32(dev, B43_MMIO_DMA4_IRQ_MASK, 0x0000DC00);
b43_write32(dev, B43_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
- value32 = ssb_read32(dev->dev, SSB_TMSLOW);
- value32 |= 0x00100000;
- ssb_write32(dev->dev, SSB_TMSLOW, value32);
+ b43_mac_phy_clock_set(dev, true);
b43_write16(dev, B43_MMIO_POWERUP_DELAY,
dev->dev->bus->chipco.fast_pwrup_delay);
@@ -4213,33 +4222,18 @@
static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
{
-#ifdef CONFIG_SSB_DRIVER_PCICORE
struct ssb_bus *bus = dev->dev->bus;
u32 tmp;
- if (bus->pcicore.dev &&
- bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
- bus->pcicore.dev->id.revision <= 5) {
- /* IMCFGLO timeouts workaround. */
+ if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
+ (bus->chip_id == 0x4312)) {
tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- switch (bus->bustype) {
- case SSB_BUSTYPE_PCI:
- case SSB_BUSTYPE_PCMCIA:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x32;
- break;
- case SSB_BUSTYPE_SSB:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x53;
- break;
- default:
- break;
- }
+ tmp &= ~SSB_IMCFGLO_REQTO;
+ tmp &= ~SSB_IMCFGLO_SERTO;
+ tmp |= 0x3;
ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
+ ssb_commit_settings(bus);
}
-#endif /* CONFIG_SSB_DRIVER_PCICORE */
}
static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle)
@@ -4863,25 +4857,8 @@
static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
{
struct b43_wldev *wldev;
- struct pci_dev *pdev;
int err = -ENOMEM;
- if (!list_empty(&wl->devlist)) {
- /* We are not the first core on this chip. */
- pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
- /* Only special chips support more than one wireless
- * core, although some of the other chips have more than
- * one wireless core as well. Check for this and
- * bail out early.
- */
- if (!pdev ||
- ((pdev->device != 0x4321) &&
- (pdev->device != 0x4313) && (pdev->device != 0x431A))) {
- b43dbg(wl, "Ignoring unconnected 802.11 core\n");
- return -ENODEV;
- }
- }
-
wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
if (!wldev)
goto out;
@@ -5002,7 +4979,7 @@
return err;
}
-static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
{
struct b43_wl *wl;
int err;
@@ -5040,7 +5017,7 @@
return err;
}
-static void b43_remove(struct ssb_device *dev)
+static void b43_ssb_remove(struct ssb_device *dev)
{
struct b43_wl *wl = ssb_get_devtypedata(dev);
struct b43_wldev *wldev = ssb_get_drvdata(dev);
@@ -5083,8 +5060,8 @@
static struct ssb_driver b43_ssb_driver = {
.name = KBUILD_MODNAME,
.id_table = b43_ssb_tbl,
- .probe = b43_probe,
- .remove = b43_remove,
+ .probe = b43_ssb_probe,
+ .remove = b43_ssb_remove,
};
static void b43_print_driverinfo(void)
diff --git a/drivers/net/wireless/b43/main.h b/drivers/net/wireless/b43/main.h
index 40db036..a0d327f 100644
--- a/drivers/net/wireless/b43/main.h
+++ b/drivers/net/wireless/b43/main.h
@@ -133,6 +133,7 @@
void b43_mac_suspend(struct b43_wldev *dev);
void b43_mac_enable(struct b43_wldev *dev);
+void b43_mac_phy_clock_set(struct b43_wldev *dev, bool on);
struct b43_request_fw_context;
diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c
index 6755063..b075a3f 100644
--- a/drivers/net/wireless/b43/phy_n.c
+++ b/drivers/net/wireless/b43/phy_n.c
@@ -3540,17 +3540,6 @@
return b43_nphy_rev2_cal_rx_iq(dev, target, type, debug);
}
-/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MacPhyClkSet */
-static void b43_nphy_mac_phy_clock_set(struct b43_wldev *dev, bool on)
-{
- u32 tmslow = ssb_read32(dev->dev, SSB_TMSLOW);
- if (on)
- tmslow |= B43_TMSLOW_MACPHYCLKEN;
- else
- tmslow &= ~B43_TMSLOW_MACPHYCLKEN;
- ssb_write32(dev->dev, SSB_TMSLOW, tmslow);
-}
-
/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCoreSetState */
static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
{
@@ -3691,7 +3680,7 @@
b43_phy_write(dev, B43_NPHY_BBCFG, tmp & ~B43_NPHY_BBCFG_RSTCCA);
b43_nphy_bmac_clock_fgc(dev, 0);
- b43_nphy_mac_phy_clock_set(dev, true);
+ b43_mac_phy_clock_set(dev, true);
b43_nphy_pa_override(dev, false);
b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index c7fd73e..1ab8861 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -2234,7 +2234,7 @@
b43legacy_write32(dev, B43legacy_MMIO_DMA5_IRQ_MASK, 0x0000DC00);
value32 = ssb_read32(dev->dev, SSB_TMSLOW);
- value32 |= 0x00100000;
+ value32 |= B43legacy_TMSLOW_MACPHYCLKEN;
ssb_write32(dev->dev, SSB_TMSLOW, value32);
b43legacy_write16(dev, B43legacy_MMIO_POWERUP_DELAY,
@@ -3104,37 +3104,6 @@
memset(&dev->noisecalc, 0, sizeof(dev->noisecalc));
}
-static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev)
-{
-#ifdef CONFIG_SSB_DRIVER_PCICORE
- struct ssb_bus *bus = dev->dev->bus;
- u32 tmp;
-
- if (bus->pcicore.dev &&
- bus->pcicore.dev->id.coreid == SSB_DEV_PCI &&
- bus->pcicore.dev->id.revision <= 5) {
- /* IMCFGLO timeouts workaround. */
- tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
- switch (bus->bustype) {
- case SSB_BUSTYPE_PCI:
- case SSB_BUSTYPE_PCMCIA:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x32;
- break;
- case SSB_BUSTYPE_SSB:
- tmp &= ~SSB_IMCFGLO_REQTO;
- tmp &= ~SSB_IMCFGLO_SERTO;
- tmp |= 0x53;
- break;
- default:
- break;
- }
- ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
- }
-#endif /* CONFIG_SSB_DRIVER_PCICORE */
-}
-
static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev,
bool idle) {
u16 pu_delay = 1050;
@@ -3278,7 +3247,6 @@
/* Enable IRQ routing to this device. */
ssb_pcicore_dev_irqvecs_enable(&bus->pcicore, dev->dev);
- b43legacy_imcfglo_timeouts_workaround(dev);
prepare_phy_data_for_init(dev);
b43legacy_phy_calibrate(dev);
err = b43legacy_chip_init(dev);
@@ -3728,26 +3696,8 @@
struct b43legacy_wl *wl)
{
struct b43legacy_wldev *wldev;
- struct pci_dev *pdev;
int err = -ENOMEM;
- if (!list_empty(&wl->devlist)) {
- /* We are not the first core on this chip. */
- pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
- /* Only special chips support more than one wireless
- * core, although some of the other chips have more than
- * one wireless core as well. Check for this and
- * bail out early.
- */
- if (!pdev ||
- ((pdev->device != 0x4321) &&
- (pdev->device != 0x4313) &&
- (pdev->device != 0x431A))) {
- b43legacydbg(wl, "Ignoring unconnected 802.11 core\n");
- return -ENODEV;
- }
- }
-
wldev = kzalloc(sizeof(*wldev), GFP_KERNEL);
if (!wldev)
goto out;
diff --git a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
index 8950939..24d1499 100644
--- a/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
+++ b/drivers/net/wireless/iwlegacy/iwl-4965-rs.c
@@ -2604,7 +2604,7 @@
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64];
- int buf_size;
+ size_t buf_size;
u32 parsed_rate;
struct iwl_station_priv *sta_priv =
container_of(lq_sta, struct iwl_station_priv, lq_sta);
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 17d555f..ad3bdba 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -102,6 +102,16 @@
occur.
endmenu
+config IWLWIFI_DEVICE_SVTOOL
+ bool "iwlwifi device svtool support"
+ depends on IWLAGN
+ select NL80211_TESTMODE
+ help
+ This option enables the svtool support for iwlwifi device through
+ NL80211_TESTMODE. svtool is a software validation tool that runs in
+ the user space and interacts with the device in the kernel space
+ through the generic netlink message via NL80211_TESTMODE channel.
+
config IWL_P2P
bool "iwlwifi experimental P2P support"
depends on IWLAGN
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 89a41d3..8226604 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -16,6 +16,7 @@
iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
+iwlagn-$(CONFIG_IWLWIFI_DEVICE_SVTOOL) += iwl-sv-open.o
CFLAGS_iwl-devtrace.o := -I$(src)
diff --git a/drivers/net/wireless/iwlwifi/iwl-1000.c b/drivers/net/wireless/iwlwifi/iwl-1000.c
index 3da8cf2..b4c8193 100644
--- a/drivers/net/wireless/iwlwifi/iwl-1000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-1000.c
@@ -171,8 +171,6 @@
static struct iwl_lib_ops iwl1000_lib = {
.set_hw_params = iwl1000_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-2000.c b/drivers/net/wireless/iwlwifi/iwl-2000.c
index bca462c..89b8da7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-2000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-2000.c
@@ -252,8 +252,6 @@
static struct iwl_lib_ops iwl2000_lib = {
.set_hw_params = iwl2000_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c
index 561f2cd..98f81df 100644
--- a/drivers/net/wireless/iwlwifi/iwl-5000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-5000.c
@@ -339,8 +339,6 @@
static struct iwl_lib_ops iwl5000_lib = {
.set_hw_params = iwl5000_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
@@ -376,8 +374,6 @@
static struct iwl_lib_ops iwl5150_lib = {
.set_hw_params = iwl5150_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-6000.c b/drivers/net/wireless/iwlwifi/iwl-6000.c
index 6045457..a7921f9a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-6000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-6000.c
@@ -278,8 +278,6 @@
static struct iwl_lib_ops iwl6000_lib = {
.set_hw_params = iwl6000_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
@@ -316,8 +314,6 @@
static struct iwl_lib_ops iwl6030_lib = {
.set_hw_params = iwl6000_hw_set_hw_params,
- .txq_update_byte_cnt_tbl = iwlagn_txq_update_byte_cnt_tbl,
- .txq_inval_byte_cnt_tbl = iwlagn_txq_inval_byte_cnt_tbl,
.txq_set_sched = iwlagn_txq_set_sched,
.txq_attach_buf_to_tfd = iwl_hw_txq_attach_buf_to_tfd,
.txq_free_tfd = iwl_hw_txq_free_tfd,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
index 49dd03f..b12c72d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
@@ -54,12 +54,6 @@
}
}
-/* Currently this is the superset of everything */
-static u16 iwlagn_get_hcmd_size(u8 cmd_id, u16 len)
-{
- return len;
-}
-
static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
{
u16 size = (u16)sizeof(struct iwl_addsta_cmd);
@@ -332,7 +326,6 @@
};
struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
- .get_hcmd_size = iwlagn_get_hcmd_size,
.build_addsta_hcmd = iwlagn_build_addsta_hcmd,
.gain_computation = iwlagn_gain_computation,
.chain_noise_reset = iwlagn_chain_noise_reset,
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
index dbe6295..91f2655 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c
@@ -3086,7 +3086,7 @@
struct iwl_lq_sta *lq_sta = file->private_data;
struct iwl_priv *priv;
char buf[64];
- int buf_size;
+ size_t buf_size;
u32 parsed_rate;
struct iwl_station_priv *sta_priv =
container_of(lq_sta, struct iwl_station_priv, lq_sta);
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 4afae14..342de78 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -98,9 +98,9 @@
/**
* iwlagn_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
*/
-void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt)
+static void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq,
+ u16 byte_cnt)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int write_ptr = txq->q.write_ptr;
@@ -112,21 +112,19 @@
WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
- if (txq_id != priv->cmd_queue) {
- sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
- sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+ sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
+ sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
- switch (sec_ctl & TX_CMD_SEC_MSK) {
- case TX_CMD_SEC_CCM:
- len += CCMP_MIC_LEN;
- break;
- case TX_CMD_SEC_TKIP:
- len += TKIP_ICV_LEN;
- break;
- case TX_CMD_SEC_WEP:
- len += WEP_IV_LEN + WEP_ICV_LEN;
- break;
- }
+ switch (sec_ctl & TX_CMD_SEC_MSK) {
+ case TX_CMD_SEC_CCM:
+ len += CCMP_MIC_LEN;
+ break;
+ case TX_CMD_SEC_TKIP:
+ len += TKIP_ICV_LEN;
+ break;
+ case TX_CMD_SEC_WEP:
+ len += WEP_IV_LEN + WEP_ICV_LEN;
+ break;
}
bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12));
@@ -138,8 +136,8 @@
tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
}
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq)
+static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
+ struct iwl_tx_queue *txq)
{
struct iwlagn_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr;
int txq_id = txq->q.id;
@@ -539,7 +537,7 @@
struct iwl_tx_cmd *tx_cmd;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int txq_id;
- dma_addr_t phys_addr;
+ dma_addr_t phys_addr = 0;
dma_addr_t txcmd_phys;
dma_addr_t scratch_phys;
u16 len, firstlen, secondlen;
@@ -566,7 +564,7 @@
spin_lock_irqsave(&priv->lock, flags);
if (iwl_is_rfkill(priv)) {
IWL_DEBUG_DROP(priv, "Dropping - RF KILL\n");
- goto drop_unlock;
+ goto drop_unlock_priv;
}
fc = hdr->frame_control;
@@ -591,7 +589,7 @@
if (sta_id == IWL_INVALID_STATION) {
IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
hdr->addr1);
- goto drop_unlock;
+ goto drop_unlock_priv;
}
}
@@ -635,10 +633,10 @@
if (ieee80211_is_data_qos(fc)) {
qc = ieee80211_get_qos_ctl(hdr);
tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
- if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
- spin_unlock(&priv->sta_lock);
- goto drop_unlock;
- }
+
+ if (WARN_ON_ONCE(tid >= MAX_TID_COUNT))
+ goto drop_unlock_sta;
+
seq_number = priv->stations[sta_id].tid[tid].seq_number;
seq_number &= IEEE80211_SCTL_SEQ;
hdr->seq_ctrl = hdr->seq_ctrl &
@@ -656,18 +654,8 @@
txq = &priv->txq[txq_id];
q = &txq->q;
- if (unlikely(iwl_queue_space(q) < q->high_mark)) {
- spin_unlock(&priv->sta_lock);
- goto drop_unlock;
- }
-
- if (ieee80211_is_data_qos(fc)) {
- priv->stations[sta_id].tid[tid].tfds_in_queue++;
- if (!ieee80211_has_morefrags(fc))
- priv->stations[sta_id].tid[tid].seq_number = seq_number;
- }
-
- spin_unlock(&priv->sta_lock);
+ if (unlikely(iwl_queue_space(q) < q->high_mark))
+ goto drop_unlock_sta;
/* Set up driver data for this TFD */
memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -731,12 +719,10 @@
txcmd_phys = pci_map_single(priv->pci_dev,
&out_cmd->hdr, firstlen,
PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, txcmd_phys)))
+ goto drop_unlock_sta;
dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
dma_unmap_len_set(out_meta, len, firstlen);
- /* Add buffer containing Tx command and MAC(!) header to TFD's
- * first entry */
- priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
- txcmd_phys, firstlen, 1, 0);
if (!ieee80211_has_morefrags(hdr->frame_control)) {
txq->need_update = 1;
@@ -751,10 +737,30 @@
if (secondlen > 0) {
phys_addr = pci_map_single(priv->pci_dev, skb->data + hdr_len,
secondlen, PCI_DMA_TODEVICE);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
+ pci_unmap_single(priv->pci_dev,
+ dma_unmap_addr(out_meta, mapping),
+ dma_unmap_len(out_meta, len),
+ PCI_DMA_BIDIRECTIONAL);
+ goto drop_unlock_sta;
+ }
+ }
+
+ if (ieee80211_is_data_qos(fc)) {
+ priv->stations[sta_id].tid[tid].tfds_in_queue++;
+ if (!ieee80211_has_morefrags(fc))
+ priv->stations[sta_id].tid[tid].seq_number = seq_number;
+ }
+
+ spin_unlock(&priv->sta_lock);
+
+ /* Attach buffers to TFD */
+ priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
+ txcmd_phys, firstlen, 1, 0);
+ if (secondlen > 0)
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
phys_addr, secondlen,
0, 0);
- }
scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
offsetof(struct iwl_tx_cmd, scratch);
@@ -773,8 +779,8 @@
/* Set up entry for this TFD in Tx byte-count array */
if (info->flags & IEEE80211_TX_CTL_AMPDU)
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq,
- le16_to_cpu(tx_cmd->len));
+ iwlagn_txq_update_byte_cnt_tbl(priv, txq,
+ le16_to_cpu(tx_cmd->len));
pci_dma_sync_single_for_device(priv->pci_dev, txcmd_phys,
firstlen, PCI_DMA_BIDIRECTIONAL);
@@ -820,7 +826,9 @@
return 0;
-drop_unlock:
+drop_unlock_sta:
+ spin_unlock(&priv->sta_lock);
+drop_unlock_priv:
spin_unlock_irqrestore(&priv->lock, flags);
return -1;
}
@@ -1253,8 +1261,7 @@
txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
tx_info->skb = NULL;
- if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl)
- priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq);
+ iwlagn_txq_inval_byte_cnt_tbl(priv, txq);
priv->cfg->ops->lib->txq_free_tfd(priv, txq);
}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
index c3ae2e4..8bda0e8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
@@ -269,7 +269,7 @@
iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
}
-static int iwlagn_init_alive_start(struct iwl_priv *priv)
+int iwlagn_init_alive_start(struct iwl_priv *priv)
{
int ret;
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 003d524..3ecc319 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -102,70 +102,6 @@
}
}
-static void iwl_clear_free_frames(struct iwl_priv *priv)
-{
- struct list_head *element;
-
- IWL_DEBUG_INFO(priv, "%d frames on pre-allocated heap on clear.\n",
- priv->frames_count);
-
- while (!list_empty(&priv->free_frames)) {
- element = priv->free_frames.next;
- list_del(element);
- kfree(list_entry(element, struct iwl_frame, list));
- priv->frames_count--;
- }
-
- if (priv->frames_count) {
- IWL_WARN(priv, "%d frames still in use. Did we lose one?\n",
- priv->frames_count);
- priv->frames_count = 0;
- }
-}
-
-static struct iwl_frame *iwl_get_free_frame(struct iwl_priv *priv)
-{
- struct iwl_frame *frame;
- struct list_head *element;
- if (list_empty(&priv->free_frames)) {
- frame = kzalloc(sizeof(*frame), GFP_KERNEL);
- if (!frame) {
- IWL_ERR(priv, "Could not allocate frame!\n");
- return NULL;
- }
-
- priv->frames_count++;
- return frame;
- }
-
- element = priv->free_frames.next;
- list_del(element);
- return list_entry(element, struct iwl_frame, list);
-}
-
-static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame)
-{
- memset(frame, 0, sizeof(*frame));
- list_add(&frame->list, &priv->free_frames);
-}
-
-static u32 iwl_fill_beacon_frame(struct iwl_priv *priv,
- struct ieee80211_hdr *hdr,
- int left)
-{
- lockdep_assert_held(&priv->mutex);
-
- if (!priv->beacon_skb)
- return 0;
-
- if (priv->beacon_skb->len > left)
- return 0;
-
- memcpy(hdr, priv->beacon_skb->data, priv->beacon_skb->len);
-
- return priv->beacon_skb->len;
-}
-
/* Parse the beacon frame to find the TIM element and set tim_idx & tim_size */
static void iwl_set_beacon_tim(struct iwl_priv *priv,
struct iwl_tx_beacon_cmd *tx_beacon_cmd,
@@ -193,13 +129,18 @@
IWL_WARN(priv, "Unable to find TIM Element in beacon\n");
}
-static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv,
- struct iwl_frame *frame)
+int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
{
struct iwl_tx_beacon_cmd *tx_beacon_cmd;
+ struct iwl_host_cmd cmd = {
+ .id = REPLY_TX_BEACON,
+ .flags = CMD_SIZE_HUGE,
+ };
u32 frame_size;
u32 rate_flags;
u32 rate;
+ int err;
+
/*
* We have to set up the TX command, the TX Beacon command, and the
* beacon contents.
@@ -212,17 +153,19 @@
return 0;
}
- /* Initialize memory */
- tx_beacon_cmd = &frame->u.beacon;
- memset(tx_beacon_cmd, 0, sizeof(*tx_beacon_cmd));
+ if (WARN_ON(!priv->beacon_skb))
+ return -EINVAL;
+
+ /* Allocate beacon memory */
+ tx_beacon_cmd = kzalloc(sizeof(*tx_beacon_cmd) + priv->beacon_skb->len,
+ GFP_KERNEL);
+ if (!tx_beacon_cmd)
+ return -ENOMEM;
+
+ frame_size = priv->beacon_skb->len;
/* Set up TX beacon contents */
- frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame,
- sizeof(frame->u) - sizeof(*tx_beacon_cmd));
- if (WARN_ON_ONCE(frame_size > MAX_MPDU_SIZE))
- return 0;
- if (!frame_size)
- return 0;
+ memcpy(tx_beacon_cmd->frame, priv->beacon_skb->data, frame_size);
/* Set up TX command fields */
tx_beacon_cmd->tx.len = cpu_to_le16((u16)frame_size);
@@ -245,41 +188,16 @@
tx_beacon_cmd->tx.rate_n_flags = iwl_hw_set_rate_n_flags(rate,
rate_flags);
- return sizeof(*tx_beacon_cmd) + frame_size;
-}
+ /* Submit command */
+ cmd.len = sizeof(*tx_beacon_cmd) + frame_size;
+ cmd.data = tx_beacon_cmd;
-int iwlagn_send_beacon_cmd(struct iwl_priv *priv)
-{
- struct iwl_frame *frame;
- unsigned int frame_size;
- int rc;
- struct iwl_host_cmd cmd = {
- .id = REPLY_TX_BEACON,
- .flags = CMD_SIZE_HUGE,
- };
+ err = iwl_send_cmd_sync(priv, &cmd);
- frame = iwl_get_free_frame(priv);
- if (!frame) {
- IWL_ERR(priv, "Could not obtain free frame buffer for beacon "
- "command.\n");
- return -ENOMEM;
- }
+ /* Free temporary storage */
+ kfree(tx_beacon_cmd);
- frame_size = iwl_hw_get_beacon_cmd(priv, frame);
- if (!frame_size) {
- IWL_ERR(priv, "Error configuring the beacon command\n");
- iwl_free_frame(priv, frame);
- return -EINVAL;
- }
-
- cmd.len = frame_size;
- cmd.data = &frame->u.cmd[0];
-
- rc = iwl_send_cmd_sync(priv, &cmd);
-
- iwl_free_frame(priv, frame);
-
- return rc;
+ return err;
}
static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
@@ -776,6 +694,8 @@
wake_up_all(&priv->_agn.notif_waitq);
}
+ if (priv->pre_rx_handler)
+ priv->pre_rx_handler(priv, rxb);
/* Based on type of command response or notification,
* handle those that need handling via function in
@@ -2211,7 +2131,7 @@
* from protocol/runtime uCode (initialization uCode's
* Alive gets handled by iwl_init_alive_start()).
*/
-static int iwl_alive_start(struct iwl_priv *priv)
+int iwl_alive_start(struct iwl_priv *priv)
{
int ret = 0;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
@@ -2354,9 +2274,6 @@
dev_kfree_skb(priv->beacon_skb);
priv->beacon_skb = NULL;
-
- /* clear out any free frames */
- iwl_clear_free_frames(priv);
}
static void iwl_down(struct iwl_priv *priv)
@@ -3414,8 +3331,6 @@
spin_lock_init(&priv->sta_lock);
spin_lock_init(&priv->hcmd_lock);
- INIT_LIST_HEAD(&priv->free_frames);
-
mutex_init(&priv->mutex);
priv->ieee_channels = NULL;
@@ -3507,6 +3422,7 @@
.cancel_remain_on_channel = iwl_mac_cancel_remain_on_channel,
.offchannel_tx = iwl_mac_offchannel_tx,
.offchannel_tx_cancel_wait = iwl_mac_offchannel_tx_cancel_wait,
+ CFG80211_TESTMODE_CMD(iwl_testmode_cmd)
};
static u32 iwl_hw_detect(struct iwl_priv *priv)
@@ -3816,6 +3732,7 @@
iwl_setup_deferred_work(priv);
iwl_setup_rx_handlers(priv);
+ iwl_testmode_init(priv);
/*********************************************
* 8. Enable interrupts and read RFKILL state
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index b477336..fe33fe8 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -139,11 +139,6 @@
void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
int tx_fifo_id, int scd_retry);
-void iwlagn_txq_update_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
-void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
void iwlagn_txq_set_sched(struct iwl_priv *priv, u32 mask);
void iwl_free_tfds_in_queue(struct iwl_priv *priv,
int sta_id, int tid, int freed);
@@ -344,5 +339,22 @@
void __releases(wait_entry)
iwlagn_remove_notification(struct iwl_priv *priv,
struct iwl_notification_wait *wait_entry);
+extern int iwlagn_init_alive_start(struct iwl_priv *priv);
+extern int iwl_alive_start(struct iwl_priv *priv);
+/* svtool */
+#ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
+extern int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len);
+extern void iwl_testmode_init(struct iwl_priv *priv);
+#else
+static inline
+int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+ return -ENOSYS;
+}
+static inline
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+}
+#endif
#endif /* __iwl_agn_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index dec98207..5b5b0cce 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -99,7 +99,6 @@
};
struct iwl_hcmd_utils_ops {
- u16 (*get_hcmd_size)(u8 cmd_id, u16 len);
u16 (*build_addsta_hcmd)(const struct iwl_addsta_cmd *cmd, u8 *data);
void (*gain_computation)(struct iwl_priv *priv,
u32 *average_noise,
@@ -129,11 +128,6 @@
/* set hw dependent parameters */
int (*set_hw_params)(struct iwl_priv *priv);
/* Handling TX */
- void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq,
- u16 byte_cnt);
- void (*txq_inval_byte_cnt_tbl)(struct iwl_priv *priv,
- struct iwl_tx_queue *txq);
void (*txq_set_sched)(struct iwl_priv *priv, u32 mask);
int (*txq_attach_buf_to_tfd)(struct iwl_priv *priv,
struct iwl_tx_queue *txq,
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index f098eff..214e465 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -238,15 +238,6 @@
#define IEEE80211_HLEN (IEEE80211_4ADDR_LEN)
#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
-struct iwl_frame {
- union {
- struct ieee80211_hdr frame;
- struct iwl_tx_beacon_cmd beacon;
- u8 raw[IEEE80211_FRAME_LEN];
- u8 cmd[360];
- } u;
- struct list_head list;
-};
#define SEQ_TO_SN(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4)
#define SN_TO_SEQ(ssn) (((ssn) << 4) & IEEE80211_SCTL_SEQ)
@@ -1188,12 +1179,10 @@
struct ieee80211_rate *ieee_rates;
struct iwl_cfg *cfg;
- /* temporary frame storage list */
- struct list_head free_frames;
- int frames_count;
-
enum ieee80211_band band;
+ void (*pre_rx_handler)(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb);
void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
struct iwl_rx_mem_buffer *rxb);
@@ -1569,21 +1558,24 @@
ctx < &priv->contexts[NUM_IWL_RXON_CTX]; ctx++) \
if (priv->valid_contexts & BIT(ctx->ctxid))
+static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
+{
+ return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+}
+
static inline int iwl_is_associated(struct iwl_priv *priv,
enum iwl_rxon_context_id ctxid)
{
- return (priv->contexts[ctxid].active.filter_flags &
- RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+ return iwl_is_associated_ctx(&priv->contexts[ctxid]);
}
static inline int iwl_is_any_associated(struct iwl_priv *priv)
{
- return iwl_is_associated(priv, IWL_RXON_CTX_BSS);
-}
-
-static inline int iwl_is_associated_ctx(struct iwl_rxon_context *ctx)
-{
- return (ctx->active.filter_flags & RXON_FILTER_ASSOC_MSK) ? 1 : 0;
+ struct iwl_rxon_context *ctx;
+ for_each_context(priv, ctx)
+ if (iwl_is_associated_ctx(ctx))
+ return true;
+ return false;
}
static inline int is_channel_valid(const struct iwl_channel_info *ch_info)
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
index d798c2a..439187f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-led.c
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -48,8 +48,21 @@
MODULE_PARM_DESC(led_mode, "0=system default, "
"1=On(RF On)/Off(RF Off), 2=blinking");
+/* Throughput OFF time(ms) ON time (ms)
+ * >300 25 25
+ * >200 to 300 40 40
+ * >100 to 200 55 55
+ * >70 to 100 65 65
+ * >50 to 70 75 75
+ * >20 to 50 85 85
+ * >10 to 20 95 95
+ * >5 to 10 110 110
+ * >1 to 5 130 130
+ * >0 to 1 167 167
+ * <=0 SOLID ON
+ */
static const struct ieee80211_tpt_blink iwl_blink[] = {
- { .throughput = 0 * 1024 - 1, .blink_time = 334 },
+ { .throughput = 0, .blink_time = 334 },
{ .throughput = 1 * 1024 - 1, .blink_time = 260 },
{ .throughput = 5 * 1024 - 1, .blink_time = 220 },
{ .throughput = 10 * 1024 - 1, .blink_time = 190 },
@@ -125,6 +138,11 @@
if (priv->blink_on == on && priv->blink_off == off)
return 0;
+ if (off == 0) {
+ /* led is SOLID_ON */
+ on = IWL_LED_SOLID;
+ }
+
IWL_DEBUG_LED(priv, "Led blink time compensation=%u\n",
priv->cfg->base_params->led_compensation);
led_cmd.on = iwl_blink_compensation(priv, on,
diff --git a/drivers/net/wireless/iwlwifi/iwl-sv-open.c b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
new file mode 100644
index 0000000..89b6696
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-sv-open.c
@@ -0,0 +1,469 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <net/net_namespace.h>
+#include <linux/netdevice.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include <net/netlink.h>
+
+
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-debug.h"
+#include "iwl-fh.h"
+#include "iwl-io.h"
+#include "iwl-agn.h"
+#include "iwl-testmode.h"
+
+
+/* The TLVs used in the gnl message policy between the kernel module and
+ * user space application. iwl_testmode_gnl_msg_policy is to be carried
+ * through the NL80211_CMD_TESTMODE channel regulated by nl80211.
+ * See iwl-testmode.h
+ */
+static
+struct nla_policy iwl_testmode_gnl_msg_policy[IWL_TM_ATTR_MAX] = {
+ [IWL_TM_ATTR_COMMAND] = { .type = NLA_U32, },
+
+ [IWL_TM_ATTR_UCODE_CMD_ID] = { .type = NLA_U8, },
+ [IWL_TM_ATTR_UCODE_CMD_DATA] = { .type = NLA_UNSPEC, },
+
+ [IWL_TM_ATTR_REG_OFFSET] = { .type = NLA_U32, },
+ [IWL_TM_ATTR_REG_VALUE8] = { .type = NLA_U8, },
+ [IWL_TM_ATTR_REG_VALUE32] = { .type = NLA_U32, },
+
+ [IWL_TM_ATTR_SYNC_RSP] = { .type = NLA_UNSPEC, },
+ [IWL_TM_ATTR_UCODE_RX_PKT] = { .type = NLA_UNSPEC, },
+};
+
+/*
+ * See the struct iwl_rx_packet in iwl-commands.h for the format of the
+ * received events from the device
+ */
+static inline int get_event_length(struct iwl_rx_mem_buffer *rxb)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ if (pkt)
+ return le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+ else
+ return 0;
+}
+
+
+/*
+ * This function multicasts the spontaneous messages from the device to the
+ * user space. It is invoked whenever there is a received messages
+ * from the device. This function is called within the ISR of the rx handlers
+ * in iwlagn driver.
+ *
+ * The parsing of the message content is left to the user space application,
+ * The message content is treated as unattacked raw data and is encapsulated
+ * with IWL_TM_ATTR_UCODE_RX_PKT multicasting to the user space.
+ *
+ * @priv: the instance of iwlwifi device
+ * @rxb: pointer to rx data content received by the ISR
+ *
+ * See the message policies and TLVs in iwl_testmode_gnl_msg_policy[].
+ * For the messages multicasting to the user application, the mandatory
+ * TLV fields are :
+ * IWL_TM_ATTR_COMMAND must be IWL_TM_CMD_DEV2APP_UCODE_RX_PKT
+ * IWL_TM_ATTR_UCODE_RX_PKT for carrying the message content
+ */
+
+static void iwl_testmode_ucode_rx_pkt(struct iwl_priv *priv,
+ struct iwl_rx_mem_buffer *rxb)
+{
+ struct ieee80211_hw *hw = priv->hw;
+ struct sk_buff *skb;
+ void *data;
+ int length;
+
+ data = (void *)rxb_addr(rxb);
+ length = get_event_length(rxb);
+
+ if (!data || length == 0)
+ return;
+
+ skb = cfg80211_testmode_alloc_event_skb(hw->wiphy, 20 + length,
+ GFP_ATOMIC);
+ if (skb == NULL) {
+ IWL_DEBUG_INFO(priv,
+ "Run out of memory for messages to user space ?\n");
+ return;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND, IWL_TM_CMD_DEV2APP_UCODE_RX_PKT);
+ NLA_PUT(skb, IWL_TM_ATTR_UCODE_RX_PKT, length, data);
+ cfg80211_testmode_event(skb, GFP_ATOMIC);
+ return;
+
+nla_put_failure:
+ kfree_skb(skb);
+ IWL_DEBUG_INFO(priv, "Ouch, overran buffer, check allocation!\n");
+}
+
+void iwl_testmode_init(struct iwl_priv *priv)
+{
+ priv->pre_rx_handler = iwl_testmode_ucode_rx_pkt;
+}
+
+/*
+ * This function handles the user application commands to the ucode.
+ *
+ * It retrieves the mandatory fields IWL_TM_ATTR_UCODE_CMD_ID and
+ * IWL_TM_ATTR_UCODE_CMD_DATA and calls to the handler to send the
+ * host command to the ucode.
+ *
+ * If any mandatory field is missing, -ENOMSG is replied to the user space
+ * application; otherwise, the actual execution result of the host command to
+ * ucode is replied.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_ucode(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct iwl_host_cmd cmd;
+
+ memset(&cmd, 0, sizeof(struct iwl_host_cmd));
+
+ if (!tb[IWL_TM_ATTR_UCODE_CMD_ID] ||
+ !tb[IWL_TM_ATTR_UCODE_CMD_DATA]) {
+ IWL_DEBUG_INFO(priv,
+ "Error finding ucode command mandatory fields\n");
+ return -ENOMSG;
+ }
+
+ cmd.id = nla_get_u8(tb[IWL_TM_ATTR_UCODE_CMD_ID]);
+ cmd.data = nla_data(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+ cmd.len = nla_len(tb[IWL_TM_ATTR_UCODE_CMD_DATA]);
+ IWL_INFO(priv, "testmode ucode command ID 0x%x, flags 0x%x,"
+ " len %d\n", cmd.id, cmd.flags, cmd.len);
+ /* ok, let's submit the command to ucode */
+ return iwl_send_cmd(priv, &cmd);
+}
+
+
+/*
+ * This function handles the user application commands for register access.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is returned; or -ENOMSG if the
+ * mandatory fields(IWL_TM_ATTR_REG_OFFSET,IWL_TM_ATTR_REG_VALUE32,
+ * IWL_TM_ATTR_REG_VALUE8) are missing; Otherwise 0 is replied indicating
+ * the success of the command execution.
+ *
+ * If IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_READ32, the register read
+ * value is returned with IWL_TM_ATTR_REG_VALUE32.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_reg(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ u32 ofs, val32;
+ u8 val8;
+ struct sk_buff *skb;
+ int status = 0;
+
+ if (!tb[IWL_TM_ATTR_REG_OFFSET]) {
+ IWL_DEBUG_INFO(priv, "Error finding register offset\n");
+ return -ENOMSG;
+ }
+ ofs = nla_get_u32(tb[IWL_TM_ATTR_REG_OFFSET]);
+ IWL_INFO(priv, "testmode register access command offset 0x%x\n", ofs);
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_REG_READ32:
+ val32 = iwl_read32(priv, ofs);
+ IWL_INFO(priv, "32bit value to read 0x%x\n", val32);
+
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy, 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv, "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_REG_VALUE32, val32);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0)
+ IWL_DEBUG_INFO(priv,
+ "Error sending msg : %d\n", status);
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_WRITE32:
+ if (!tb[IWL_TM_ATTR_REG_VALUE32]) {
+ IWL_DEBUG_INFO(priv,
+ "Error finding value to write\n");
+ return -ENOMSG;
+ } else {
+ val32 = nla_get_u32(tb[IWL_TM_ATTR_REG_VALUE32]);
+ IWL_INFO(priv, "32bit value to write 0x%x\n", val32);
+ iwl_write32(priv, ofs, val32);
+ }
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_WRITE8:
+ if (!tb[IWL_TM_ATTR_REG_VALUE8]) {
+ IWL_DEBUG_INFO(priv, "Error finding value to write\n");
+ return -ENOMSG;
+ } else {
+ val8 = nla_get_u8(tb[IWL_TM_ATTR_REG_VALUE8]);
+ IWL_INFO(priv, "8bit value to write 0x%x\n", val8);
+ iwl_write8(priv, ofs, val8);
+ }
+ break;
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode register command ID\n");
+ return -ENOSYS;
+ }
+
+ return status;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+
+static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
+{
+ struct iwl_notification_wait calib_wait;
+ int ret;
+
+ iwlagn_init_notification_wait(priv, &calib_wait,
+ CALIBRATION_COMPLETE_NOTIFICATION,
+ NULL, NULL);
+ ret = iwlagn_init_alive_start(priv);
+ if (ret) {
+ IWL_DEBUG_INFO(priv,
+ "Error configuring init calibration: %d\n", ret);
+ goto cfg_init_calib_error;
+ }
+
+ ret = iwlagn_wait_notification(priv, &calib_wait, 2 * HZ);
+ if (ret)
+ IWL_DEBUG_INFO(priv, "Error detecting"
+ " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
+ return ret;
+
+cfg_init_calib_error:
+ iwlagn_remove_notification(priv, &calib_wait);
+ return ret;
+}
+
+/*
+ * This function handles the user application commands for driver.
+ *
+ * It retrieves command ID carried with IWL_TM_ATTR_COMMAND and calls to the
+ * handlers respectively.
+ *
+ * If it's an unknown commdn ID, -ENOSYS is replied; otherwise, the returned
+ * value of the actual command execution is replied to the user application.
+ *
+ * If there's any message responding to the user space, IWL_TM_ATTR_SYNC_RSP
+ * is used for carry the message while IWL_TM_ATTR_COMMAND must set to
+ * IWL_TM_CMD_DEV2APP_SYNC_RSP.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @tb: gnl message fields from the user space
+ */
+static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
+{
+ struct iwl_priv *priv = hw->priv;
+ struct sk_buff *skb;
+ unsigned char *rsp_data_ptr = NULL;
+ int status = 0, rsp_data_len = 0;
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+ rsp_data_ptr = (unsigned char *)priv->cfg->name;
+ rsp_data_len = strlen(priv->cfg->name);
+ skb = cfg80211_testmode_alloc_reply_skb(hw->wiphy,
+ rsp_data_len + 20);
+ if (!skb) {
+ IWL_DEBUG_INFO(priv,
+ "Error allocating memory\n");
+ return -ENOMEM;
+ }
+ NLA_PUT_U32(skb, IWL_TM_ATTR_COMMAND,
+ IWL_TM_CMD_DEV2APP_SYNC_RSP);
+ NLA_PUT(skb, IWL_TM_ATTR_SYNC_RSP,
+ rsp_data_len, rsp_data_ptr);
+ status = cfg80211_testmode_reply(skb);
+ if (status < 0)
+ IWL_DEBUG_INFO(priv, "Error sending msg : %d\n",
+ status);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+ status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
+ UCODE_SUBTYPE_INIT, -1);
+ if (status)
+ IWL_DEBUG_INFO(priv,
+ "Error loading init ucode: %d\n", status);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+ iwl_testmode_cfg_init_calib(priv);
+ iwlagn_stop_device(priv);
+ break;
+
+ case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+ status = iwlagn_load_ucode_wait_alive(priv,
+ &priv->ucode_rt,
+ UCODE_SUBTYPE_REGULAR,
+ UCODE_SUBTYPE_REGULAR_NEW);
+ if (status) {
+ IWL_DEBUG_INFO(priv,
+ "Error loading runtime ucode: %d\n", status);
+ break;
+ }
+ status = iwl_alive_start(priv);
+ if (status)
+ IWL_DEBUG_INFO(priv,
+ "Error starting the device: %d\n", status);
+ break;
+
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode driver command ID\n");
+ return -ENOSYS;
+ }
+ return status;
+
+nla_put_failure:
+ kfree_skb(skb);
+ return -EMSGSIZE;
+}
+
+/* The testmode gnl message handler that takes the gnl message from the
+ * user space and parses it per the policy iwl_testmode_gnl_msg_policy, then
+ * invoke the corresponding handlers.
+ *
+ * This function is invoked when there is user space application sending
+ * gnl message through the testmode tunnel NL80211_CMD_TESTMODE regulated
+ * by nl80211.
+ *
+ * It retrieves the mandatory field, IWL_TM_ATTR_COMMAND, before
+ * dispatching it to the corresponding handler.
+ *
+ * If IWL_TM_ATTR_COMMAND is missing, -ENOMSG is replied to user application;
+ * -ENOSYS is replied to the user application if the command is unknown;
+ * Otherwise, the command is dispatched to the respective handler.
+ *
+ * @hw: ieee80211_hw object that represents the device
+ * @data: pointer to user space message
+ * @len: length in byte of @data
+ */
+int iwl_testmode_cmd(struct ieee80211_hw *hw, void *data, int len)
+{
+ struct nlattr *tb[IWL_TM_ATTR_MAX - 1];
+ struct iwl_priv *priv = hw->priv;
+ int result;
+
+ result = nla_parse(tb, IWL_TM_ATTR_MAX - 1, data, len,
+ iwl_testmode_gnl_msg_policy);
+ if (result != 0) {
+ IWL_DEBUG_INFO(priv,
+ "Error parsing the gnl message : %d\n", result);
+ return result;
+ }
+
+ /* IWL_TM_ATTR_COMMAND is absolutely mandatory */
+ if (!tb[IWL_TM_ATTR_COMMAND]) {
+ IWL_DEBUG_INFO(priv, "Error finding testmode command type\n");
+ return -ENOMSG;
+ }
+ /* in case multiple accesses to the device happens */
+ mutex_lock(&priv->mutex);
+
+ switch (nla_get_u32(tb[IWL_TM_ATTR_COMMAND])) {
+ case IWL_TM_CMD_APP2DEV_UCODE:
+ IWL_DEBUG_INFO(priv, "testmode cmd to uCode\n");
+ result = iwl_testmode_ucode(hw, tb);
+ break;
+ case IWL_TM_CMD_APP2DEV_REG_READ32:
+ case IWL_TM_CMD_APP2DEV_REG_WRITE32:
+ case IWL_TM_CMD_APP2DEV_REG_WRITE8:
+ IWL_DEBUG_INFO(priv, "testmode cmd to register\n");
+ result = iwl_testmode_reg(hw, tb);
+ break;
+ case IWL_TM_CMD_APP2DEV_GET_DEVICENAME:
+ case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
+ case IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB:
+ case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
+ IWL_DEBUG_INFO(priv, "testmode cmd to driver\n");
+ result = iwl_testmode_driver(hw, tb);
+ break;
+ default:
+ IWL_DEBUG_INFO(priv, "Unknown testmode command\n");
+ result = -ENOSYS;
+ break;
+ }
+
+ mutex_unlock(&priv->mutex);
+ return result;
+}
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.h b/drivers/net/wireless/iwlwifi/iwl-testmode.h
new file mode 100644
index 0000000..31f8949
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.h
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2010 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+#ifndef __IWL_TESTMODE_H__
+#define __IWL_TESTMODE_H__
+
+#include <linux/types.h>
+
+
+/* Commands from user space to kernel space(IWL_TM_CMD_ID_APP2DEV_XX) and
+ * from and kernel space to user space(IWL_TM_CMD_ID_DEV2APP_XX).
+ * The command ID is carried with IWL_TM_ATTR_COMMAND. There are three types of
+ * of command from user space and two types of command from kernel space.
+ * See below.
+ */
+enum iwl_tm_cmd_t {
+ /* commands from user application to the uCode,
+ * the actual uCode host command ID is carried with
+ * IWL_TM_ATTR_UCODE_CMD_ID */
+ IWL_TM_CMD_APP2DEV_UCODE = 1,
+
+ /* commands from user applicaiton to access register */
+ IWL_TM_CMD_APP2DEV_REG_READ32,
+ IWL_TM_CMD_APP2DEV_REG_WRITE32,
+ IWL_TM_CMD_APP2DEV_REG_WRITE8,
+
+ /* commands fom user space for pure driver level operations */
+ IWL_TM_CMD_APP2DEV_GET_DEVICENAME,
+ IWL_TM_CMD_APP2DEV_LOAD_INIT_FW,
+ IWL_TM_CMD_APP2DEV_CFG_INIT_CALIB,
+ IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW,
+ /* if there is other new command for the driver layer operation,
+ * append them here */
+
+
+ /* commands from kernel space to carry the synchronous response
+ * to user application */
+ IWL_TM_CMD_DEV2APP_SYNC_RSP,
+
+ /* commands from kernel space to multicast the spontaneous messages
+ * to user application */
+ IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+ IWL_TM_CMD_MAX,
+};
+
+enum iwl_tm_attr_t {
+ IWL_TM_ATTR_NOT_APPLICABLE = 0,
+
+ /* From user space to kernel space:
+ * the command either destines to ucode, driver, or register;
+ * See enum iwl_tm_cmd_t.
+ *
+ * From kernel space to user space:
+ * the command either carries synchronous response,
+ * or the spontaneous message multicast from the device;
+ * See enum iwl_tm_cmd_t. */
+ IWL_TM_ATTR_COMMAND,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_UCODE,
+ * The mandatory fields are :
+ * IWL_TM_ATTR_UCODE_CMD_ID for recognizable command ID;
+ * IWL_TM_ATTR_COMMAND_FLAG for the flags of the commands;
+ * The optional fields are:
+ * IWL_TM_ATTR_UCODE_CMD_DATA for the actual command payload
+ * to the ucode */
+ IWL_TM_ATTR_UCODE_CMD_ID,
+ IWL_TM_ATTR_UCODE_CMD_DATA,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_APP2DEV_REG_XXX,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_REG_OFFSET for the offset of the target register;
+ * IWL_TM_ATTR_REG_VALUE8 or IWL_TM_ATTR_REG_VALUE32 for value */
+ IWL_TM_ATTR_REG_OFFSET,
+ IWL_TM_ATTR_REG_VALUE8,
+ IWL_TM_ATTR_REG_VALUE32,
+
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_SYNC_RSP,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_SYNC_RSP for the data content responding to the user
+ * application command */
+ IWL_TM_ATTR_SYNC_RSP,
+ /* When IWL_TM_ATTR_COMMAND is IWL_TM_CMD_DEV2APP_UCODE_RX_PKT,
+ * The mandatory fields are:
+ * IWL_TM_ATTR_UCODE_RX_PKT for the data content multicast to the user
+ * application */
+ IWL_TM_ATTR_UCODE_RX_PKT,
+
+ IWL_TM_ATTR_MAX,
+};
+
+
+#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 52b1b66..e69597e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -442,12 +442,10 @@
struct iwl_cmd_meta *out_meta;
dma_addr_t phys_addr;
unsigned long flags;
- int len;
u32 idx;
u16 fix_size;
bool is_ct_kill = false;
- cmd->len = priv->cfg->ops->utils->get_hcmd_size(cmd->id, cmd->len);
fix_size = (u16)(cmd->len + sizeof(out_cmd->hdr));
/*
@@ -502,7 +500,6 @@
}
memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
- out_meta->flags = cmd->flags | CMD_MAPPED;
if (cmd->flags & CMD_WANT_SKB)
out_meta->source = cmd;
if (cmd->flags & CMD_ASYNC)
@@ -519,9 +516,6 @@
INDEX_TO_SEQ(q->write_ptr));
if (cmd->flags & CMD_SIZE_HUGE)
out_cmd->hdr.sequence |= SEQ_HUGE_FRAME;
- len = sizeof(struct iwl_device_cmd);
- if (idx == TFD_CMD_SLOTS)
- len = IWL_MAX_CMD_SIZE;
#ifdef CONFIG_IWLWIFI_DEBUG
switch (out_cmd->hdr.cmd) {
@@ -543,17 +537,20 @@
q->write_ptr, idx, priv->cmd_queue);
}
#endif
- txq->need_update = 1;
-
- if (priv->cfg->ops->lib->txq_update_byte_cnt_tbl)
- /* Set up entry in queue's byte count circular buffer */
- priv->cfg->ops->lib->txq_update_byte_cnt_tbl(priv, txq, 0);
-
phys_addr = pci_map_single(priv->pci_dev, &out_cmd->hdr,
fix_size, PCI_DMA_BIDIRECTIONAL);
+ if (unlikely(pci_dma_mapping_error(priv->pci_dev, phys_addr))) {
+ idx = -ENOMEM;
+ goto out;
+ }
+
dma_unmap_addr_set(out_meta, mapping, phys_addr);
dma_unmap_len_set(out_meta, len, fix_size);
+ out_meta->flags = cmd->flags | CMD_MAPPED;
+
+ txq->need_update = 1;
+
trace_iwlwifi_dev_hcmd(priv, &out_cmd->hdr, fix_size, cmd->flags);
priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq,
@@ -564,6 +561,7 @@
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
iwl_txq_update_write_ptr(priv, txq);
+ out:
spin_unlock_irqrestore(&priv->hcmd_lock, flags);
return idx;
}
diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c
index 9a57cf6..5665a1a 100644
--- a/drivers/net/wireless/iwmc3200wifi/rx.c
+++ b/drivers/net/wireless/iwmc3200wifi/rx.c
@@ -1576,7 +1576,8 @@
IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len);
__skb_queue_head_init(&list);
- ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0);
+ ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0,
+ true);
while ((frame = __skb_dequeue(&list))) {
ndev->stats.rx_packets++;
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 486544e..5d637af 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -6,6 +6,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/sched.h>
#include <linux/wait.h>
#include <linux/slab.h>
@@ -1322,8 +1324,8 @@
sme->ssid, sme->ssid_len,
WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS);
if (!bss) {
- lbs_pr_err("assoc: bss %pM not in scan results\n",
- sme->bssid);
+ wiphy_err(wiphy, "assoc: bss %pM not in scan results\n",
+ sme->bssid);
ret = -ENOENT;
goto done;
}
@@ -1380,8 +1382,8 @@
lbs_enable_rsn(priv, sme->crypto.cipher_group != 0);
break;
default:
- lbs_pr_err("unsupported cipher group 0x%x\n",
- sme->crypto.cipher_group);
+ wiphy_err(wiphy, "unsupported cipher group 0x%x\n",
+ sme->crypto.cipher_group);
ret = -ENOTSUPP;
goto done;
}
@@ -1499,7 +1501,7 @@
params->key, params->key_len);
break;
default:
- lbs_pr_err("unhandled cipher 0x%x\n", params->cipher);
+ wiphy_err(wiphy, "unhandled cipher 0x%x\n", params->cipher);
ret = -ENOTSUPP;
break;
}
@@ -2127,13 +2129,13 @@
ret = wiphy_register(wdev->wiphy);
if (ret < 0)
- lbs_pr_err("cannot register wiphy device\n");
+ pr_err("cannot register wiphy device\n");
priv->wiphy_registered = true;
ret = register_netdev(priv->dev);
if (ret)
- lbs_pr_err("cannot register network device\n");
+ pr_err("cannot register network device\n");
INIT_DELAYED_WORK(&priv->scan_work, lbs_scan_worker);
diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c
index 6a96fc9..6d59b4c 100644
--- a/drivers/net/wireless/libertas/cmd.c
+++ b/drivers/net/wireless/libertas/cmd.c
@@ -110,7 +110,7 @@
* CF card firmware 5.0.16p0: cap 0x00000303
* USB dongle firmware 5.110.17p2: cap 0x00000303
*/
- lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n",
+ netdev_info(priv->dev, "%pM, fw %u.%u.%up%u, cap 0x%08x\n",
cmd.permanentaddr,
priv->fwrelease >> 24 & 0xff,
priv->fwrelease >> 16 & 0xff,
@@ -141,7 +141,8 @@
/* if it's unidentified region code, use the default (USA) */
if (i >= MRVDRV_MAX_REGION_CODE) {
priv->regioncode = 0x10;
- lbs_pr_info("unidentified region code; using the default (USA)\n");
+ netdev_info(priv->dev,
+ "unidentified region code; using the default (USA)\n");
}
if (priv->current_addr[0] == 0xff)
@@ -211,7 +212,7 @@
(uint8_t *)&cmd_config.wol_conf,
sizeof(struct wol_config));
} else {
- lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret);
+ netdev_info(priv->dev, "HOST_SLEEP_CFG failed %d\n", ret);
}
return ret;
@@ -314,7 +315,7 @@
if (priv->is_deep_sleep) {
if (!wait_event_interruptible_timeout(priv->ds_awake_q,
!priv->is_deep_sleep, (10 * HZ))) {
- lbs_pr_err("ds_awake_q: timer expired\n");
+ netdev_err(priv->dev, "ds_awake_q: timer expired\n");
ret = -1;
}
}
@@ -339,7 +340,7 @@
netif_carrier_off(priv->dev);
}
} else {
- lbs_pr_err("deep sleep: already enabled\n");
+ netdev_err(priv->dev, "deep sleep: already enabled\n");
}
} else {
if (priv->is_deep_sleep) {
@@ -349,8 +350,8 @@
if (!ret) {
ret = lbs_wait_for_ds_awake(priv);
if (ret)
- lbs_pr_err("deep sleep: wakeup"
- "failed\n");
+ netdev_err(priv->dev,
+ "deep sleep: wakeup failed\n");
}
}
}
@@ -384,8 +385,9 @@
ret = lbs_host_sleep_cfg(priv, priv->wol_criteria,
(struct wol_config *)NULL);
if (ret) {
- lbs_pr_info("Host sleep configuration failed: "
- "%d\n", ret);
+ netdev_info(priv->dev,
+ "Host sleep configuration failed: %d\n",
+ ret);
return ret;
}
if (priv->psstate == PS_STATE_FULL_POWER) {
@@ -395,19 +397,21 @@
sizeof(cmd),
lbs_ret_host_sleep_activate, 0);
if (ret)
- lbs_pr_info("HOST_SLEEP_ACTIVATE "
- "failed: %d\n", ret);
+ netdev_info(priv->dev,
+ "HOST_SLEEP_ACTIVATE failed: %d\n",
+ ret);
}
if (!wait_event_interruptible_timeout(
priv->host_sleep_q,
priv->is_host_sleep_activated,
(10 * HZ))) {
- lbs_pr_err("host_sleep_q: timer expired\n");
+ netdev_err(priv->dev,
+ "host_sleep_q: timer expired\n");
ret = -1;
}
} else {
- lbs_pr_err("host sleep: already enabled\n");
+ netdev_err(priv->dev, "host sleep: already enabled\n");
}
} else {
if (priv->is_host_sleep_activated)
@@ -1007,7 +1011,8 @@
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) cmd, cmdsize);
if (ret) {
- lbs_pr_info("DNLD_CMD: hw_host_to_card failed: %d\n", ret);
+ netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n",
+ ret);
/* Let the timer kick in and retry, and potentially reset
the whole thing if the condition persists */
timeo = HZ/4;
@@ -1276,7 +1281,8 @@
spin_lock_irqsave(&priv->driver_lock, flags);
if (priv->cur_cmd) {
- lbs_pr_alert( "EXEC_NEXT_CMD: already processing command!\n");
+ netdev_alert(priv->dev,
+ "EXEC_NEXT_CMD: already processing command!\n");
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -1438,7 +1444,7 @@
ret = priv->hw_host_to_card(priv, MVMS_CMD, (u8 *) &confirm_sleep,
sizeof(confirm_sleep));
if (ret) {
- lbs_pr_alert("confirm_sleep failed\n");
+ netdev_alert(priv->dev, "confirm_sleep failed\n");
goto out;
}
@@ -1664,7 +1670,7 @@
spin_lock_irqsave(&priv->driver_lock, flags);
ret = cmdnode->result;
if (ret)
- lbs_pr_info("PREP_CMD: command 0x%04x failed: %d\n",
+ netdev_info(priv->dev, "PREP_CMD: command 0x%04x failed: %d\n",
command, ret);
__lbs_cleanup_and_insert_cmd(priv, cmdnode);
diff --git a/drivers/net/wireless/libertas/cmdresp.c b/drivers/net/wireless/libertas/cmdresp.c
index 03e5289..207fc36 100644
--- a/drivers/net/wireless/libertas/cmdresp.c
+++ b/drivers/net/wireless/libertas/cmdresp.c
@@ -2,6 +2,7 @@
* This file contains the handling of command
* responses as well as events generated by firmware.
*/
+
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/sched.h>
@@ -85,15 +86,18 @@
lbs_deb_hex(LBS_DEB_CMD, "CMD_RESP", (void *) resp, len);
if (resp->seqnum != priv->cur_cmd->cmdbuf->seqnum) {
- lbs_pr_info("Received CMD_RESP with invalid sequence %d (expected %d)\n",
- le16_to_cpu(resp->seqnum), le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
+ netdev_info(priv->dev,
+ "Received CMD_RESP with invalid sequence %d (expected %d)\n",
+ le16_to_cpu(resp->seqnum),
+ le16_to_cpu(priv->cur_cmd->cmdbuf->seqnum));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
}
if (respcmd != CMD_RET(curcmd) &&
respcmd != CMD_RET_802_11_ASSOCIATE && curcmd != CMD_802_11_ASSOCIATE) {
- lbs_pr_info("Invalid CMD_RESP %x to command %x!\n", respcmd, curcmd);
+ netdev_info(priv->dev, "Invalid CMD_RESP %x to command %x!\n",
+ respcmd, curcmd);
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
goto done;
@@ -102,7 +106,8 @@
if (resp->result == cpu_to_le16(0x0004)) {
/* 0x0004 means -EAGAIN. Drop the response, let it time out
and be resubmitted */
- lbs_pr_info("Firmware returns DEFER to command %x. Will let it time out...\n",
+ netdev_info(priv->dev,
+ "Firmware returns DEFER to command %x. Will let it time out...\n",
le16_to_cpu(resp->command));
spin_unlock_irqrestore(&priv->driver_lock, flags);
ret = -1;
@@ -314,28 +319,28 @@
lbs_deb_cmd("EVENT: ADHOC beacon lost\n");
break;
case MACREG_INT_CODE_RSSI_LOW:
- lbs_pr_alert("EVENT: rssi low\n");
+ netdev_alert(priv->dev, "EVENT: rssi low\n");
break;
case MACREG_INT_CODE_SNR_LOW:
- lbs_pr_alert("EVENT: snr low\n");
+ netdev_alert(priv->dev, "EVENT: snr low\n");
break;
case MACREG_INT_CODE_MAX_FAIL:
- lbs_pr_alert("EVENT: max fail\n");
+ netdev_alert(priv->dev, "EVENT: max fail\n");
break;
case MACREG_INT_CODE_RSSI_HIGH:
- lbs_pr_alert("EVENT: rssi high\n");
+ netdev_alert(priv->dev, "EVENT: rssi high\n");
break;
case MACREG_INT_CODE_SNR_HIGH:
- lbs_pr_alert("EVENT: snr high\n");
+ netdev_alert(priv->dev, "EVENT: snr high\n");
break;
case MACREG_INT_CODE_MESH_AUTO_STARTED:
/* Ignore spurious autostart events */
- lbs_pr_info("EVENT: MESH_AUTO_STARTED (ignoring)\n");
+ netdev_info(priv->dev, "EVENT: MESH_AUTO_STARTED (ignoring)\n");
break;
default:
- lbs_pr_alert("EVENT: unknown event id %d\n", event);
+ netdev_alert(priv->dev, "EVENT: unknown event id %d\n", event);
break;
}
diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c
index 851fe7b..23250f6 100644
--- a/drivers/net/wireless/libertas/debugfs.c
+++ b/drivers/net/wireless/libertas/debugfs.c
@@ -151,13 +151,14 @@
ret = lbs_set_host_sleep(priv, 0);
else if (host_sleep == 1) {
if (priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("wake parameters not configured");
+ netdev_info(priv->dev,
+ "wake parameters not configured\n");
ret = -EINVAL;
goto out_unlock;
}
ret = lbs_set_host_sleep(priv, 1);
} else {
- lbs_pr_err("invalid option\n");
+ netdev_err(priv->dev, "invalid option\n");
ret = -EINVAL;
}
diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h
index 92b5b1f..ab966f0 100644
--- a/drivers/net/wireless/libertas/defs.h
+++ b/drivers/net/wireless/libertas/defs.h
@@ -89,13 +89,6 @@
#define lbs_deb_spi(fmt, args...) LBS_DEB_LL(LBS_DEB_SPI, " spi", fmt, ##args)
#define lbs_deb_cfg80211(fmt, args...) LBS_DEB_LL(LBS_DEB_CFG80211, " cfg80211", fmt, ##args)
-#define lbs_pr_info(format, args...) \
- printk(KERN_INFO DRV_NAME": " format, ## args)
-#define lbs_pr_err(format, args...) \
- printk(KERN_ERR DRV_NAME": " format, ## args)
-#define lbs_pr_alert(format, args...) \
- printk(KERN_ALERT DRV_NAME": " format, ## args)
-
#ifdef DEBUG
static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, int len)
{
diff --git a/drivers/net/wireless/libertas/if_cs.c b/drivers/net/wireless/libertas/if_cs.c
index 4dfd48f..63ed579 100644
--- a/drivers/net/wireless/libertas/if_cs.c
+++ b/drivers/net/wireless/libertas/if_cs.c
@@ -21,6 +21,8 @@
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
@@ -362,7 +364,7 @@
if (status & IF_CS_BIT_COMMAND)
break;
if (++loops > 100) {
- lbs_pr_err("card not ready for commands\n");
+ netdev_err(priv->dev, "card not ready for commands\n");
goto done;
}
mdelay(1);
@@ -432,14 +434,16 @@
/* is hardware ready? */
status = if_cs_read16(priv->card, IF_CS_CARD_STATUS);
if ((status & IF_CS_BIT_RESP) == 0) {
- lbs_pr_err("no cmd response in card\n");
+ netdev_err(priv->dev, "no cmd response in card\n");
*len = 0;
goto out;
}
*len = if_cs_read16(priv->card, IF_CS_RESP_LEN);
if ((*len == 0) || (*len > LBS_CMD_BUFFER_SIZE)) {
- lbs_pr_err("card cmd buffer has invalid # of bytes (%d)\n", *len);
+ netdev_err(priv->dev,
+ "card cmd buffer has invalid # of bytes (%d)\n",
+ *len);
goto out;
}
@@ -473,7 +477,9 @@
len = if_cs_read16(priv->card, IF_CS_READ_LEN);
if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
+ netdev_err(priv->dev,
+ "card data buffer has invalid # of bytes (%d)\n",
+ len);
priv->dev->stats.rx_dropped++;
goto dat_err;
}
@@ -653,8 +659,8 @@
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download helper at 0x%x, ret %d\n",
- sent, ret);
+ pr_err("can't download helper at 0x%x, ret %d\n",
+ sent, ret);
goto done;
}
@@ -684,7 +690,7 @@
ret = if_cs_poll_while_fw_download(card, IF_CS_SQ_READ_LOW,
IF_CS_SQ_HELPER_OK);
if (ret < 0) {
- lbs_pr_err("helper firmware doesn't answer\n");
+ pr_err("helper firmware doesn't answer\n");
goto done;
}
@@ -692,13 +698,13 @@
len = if_cs_read16(card, IF_CS_SQ_READ_LOW);
if (len & 1) {
retry++;
- lbs_pr_info("odd, need to retry this firmware block\n");
+ pr_info("odd, need to retry this firmware block\n");
} else {
retry = 0;
}
if (retry > 20) {
- lbs_pr_err("could not download firmware\n");
+ pr_err("could not download firmware\n");
ret = -ENODEV;
goto done;
}
@@ -718,14 +724,14 @@
ret = if_cs_poll_while_fw_download(card, IF_CS_CARD_STATUS,
IF_CS_BIT_COMMAND);
if (ret < 0) {
- lbs_pr_err("can't download firmware at 0x%x\n", sent);
+ pr_err("can't download firmware at 0x%x\n", sent);
goto done;
}
}
ret = if_cs_poll_while_fw_download(card, IF_CS_SCRATCH, 0x5a);
if (ret < 0)
- lbs_pr_err("firmware download failed\n");
+ pr_err("firmware download failed\n");
done:
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -759,7 +765,8 @@
ret = if_cs_send_cmd(priv, buf, nb);
break;
default:
- lbs_pr_err("%s: unsupported type %d\n", __func__, type);
+ netdev_err(priv->dev, "%s: unsupported type %d\n",
+ __func__, type);
}
lbs_deb_leave_args(LBS_DEB_CS, "ret %d", ret);
@@ -788,7 +795,7 @@
p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_AUTO;
if (p_dev->resource[1]->end) {
- lbs_pr_err("wrong CIS (check number of IO windows)\n");
+ pr_err("wrong CIS (check number of IO windows)\n");
return -ENODEV;
}
@@ -809,7 +816,7 @@
card = kzalloc(sizeof(struct if_cs_card), GFP_KERNEL);
if (!card) {
- lbs_pr_err("error in kzalloc\n");
+ pr_err("error in kzalloc\n");
goto out;
}
card->p_dev = p_dev;
@@ -818,7 +825,7 @@
p_dev->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_SET_IO;
if (pcmcia_loop_config(p_dev, if_cs_ioprobe, NULL)) {
- lbs_pr_err("error in pcmcia_loop_config\n");
+ pr_err("error in pcmcia_loop_config\n");
goto out1;
}
@@ -834,14 +841,14 @@
card->iobase = ioport_map(p_dev->resource[0]->start,
resource_size(p_dev->resource[0]));
if (!card->iobase) {
- lbs_pr_err("error in ioport_map\n");
+ pr_err("error in ioport_map\n");
ret = -EIO;
goto out1;
}
ret = pcmcia_enable_device(p_dev);
if (ret) {
- lbs_pr_err("error in pcmcia_enable_device\n");
+ pr_err("error in pcmcia_enable_device\n");
goto out2;
}
@@ -856,8 +863,8 @@
card->model = get_model(p_dev->manf_id, p_dev->card_id);
if (card->model == MODEL_UNKNOWN) {
- lbs_pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
- p_dev->manf_id, p_dev->card_id);
+ pr_err("unsupported manf_id 0x%04x / card_id 0x%04x\n",
+ p_dev->manf_id, p_dev->card_id);
goto out2;
}
@@ -866,20 +873,20 @@
if (card->model == MODEL_8305) {
card->align_regs = 1;
if (prod_id < IF_CS_CF8305_B1_REV) {
- lbs_pr_err("8305 rev B0 and older are not supported\n");
+ pr_err("8305 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
}
if ((card->model == MODEL_8381) && prod_id < IF_CS_CF8381_B3_REV) {
- lbs_pr_err("8381 rev B2 and older are not supported\n");
+ pr_err("8381 rev B2 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
if ((card->model == MODEL_8385) && prod_id < IF_CS_CF8385_B1_REV) {
- lbs_pr_err("8385 rev B0 and older are not supported\n");
+ pr_err("8385 rev B0 and older are not supported\n");
ret = -ENODEV;
goto out2;
}
@@ -887,7 +894,7 @@
ret = lbs_get_firmware(&p_dev->dev, NULL, NULL, card->model,
&fw_table[0], &helper, &mainfw);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto out2;
}
@@ -918,7 +925,7 @@
ret = request_irq(p_dev->irq, if_cs_interrupt,
IRQF_SHARED, DRV_NAME, card);
if (ret) {
- lbs_pr_err("error in request_irq\n");
+ pr_err("error in request_irq\n");
goto out3;
}
@@ -931,7 +938,7 @@
/* And finally bring the card up */
if (lbs_start_card(priv) != 0) {
- lbs_pr_err("could not activate card\n");
+ pr_err("could not activate card\n");
goto out3;
}
diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c
index b4de0ca..a7b5cb0 100644
--- a/drivers/net/wireless/libertas/if_sdio.c
+++ b/drivers/net/wireless/libertas/if_sdio.c
@@ -26,6 +26,8 @@
* if_sdio_card_to_host() to pad the data.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
@@ -409,7 +411,7 @@
out:
if (ret)
- lbs_pr_err("problem fetching packet from firmware\n");
+ pr_err("problem fetching packet from firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -446,7 +448,7 @@
}
if (ret)
- lbs_pr_err("error %d sending packet to firmware\n", ret);
+ pr_err("error %d sending packet to firmware\n", ret);
sdio_release_host(card->func);
@@ -555,7 +557,7 @@
out:
if (ret)
- lbs_pr_err("failed to load helper firmware\n");
+ pr_err("failed to load helper firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
@@ -669,7 +671,7 @@
out:
if (ret)
- lbs_pr_err("failed to load firmware\n");
+ pr_err("failed to load firmware\n");
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
return ret;
@@ -723,7 +725,7 @@
ret = lbs_get_firmware(&card->func->dev, lbs_helper_name, lbs_fw_name,
card->model, &fw_table[0], &helper, &mainfw);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto out;
}
@@ -849,7 +851,7 @@
ret = __lbs_cmd(priv, CMD_802_11_DEEP_SLEEP, &cmd, sizeof(cmd),
lbs_cmd_copyback, (unsigned long) &cmd);
if (ret)
- lbs_pr_err("DEEP_SLEEP cmd failed\n");
+ netdev_err(priv->dev, "DEEP_SLEEP cmd failed\n");
mdelay(200);
return ret;
@@ -865,7 +867,7 @@
sdio_writeb(card->func, HOST_POWER_UP, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -882,7 +884,7 @@
sdio_writeb(card->func, 0, CONFIGURATION_REG, &ret);
if (ret)
- lbs_pr_err("sdio_writeb failed!\n");
+ netdev_err(priv->dev, "sdio_writeb failed!\n");
sdio_release_host(card->func);
lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
@@ -961,7 +963,7 @@
}
if (i == func->card->num_info) {
- lbs_pr_err("unable to identify card model\n");
+ pr_err("unable to identify card model\n");
return -ENODEV;
}
@@ -995,7 +997,7 @@
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("unknown card model 0x%x\n", card->model);
+ pr_err("unknown card model 0x%x\n", card->model);
ret = -ENODEV;
goto free;
}
@@ -1101,7 +1103,7 @@
lbs_deb_sdio("send function INIT command\n");
if (__lbs_cmd(priv, CMD_FUNC_INIT, &cmd, sizeof(cmd),
lbs_cmd_copyback, (unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_INIT cmd failed\n");
+ netdev_alert(priv->dev, "CMD_FUNC_INIT cmd failed\n");
}
ret = lbs_start_card(priv);
@@ -1163,7 +1165,7 @@
if (__lbs_cmd(card->priv, CMD_FUNC_SHUTDOWN,
&cmd, sizeof(cmd), lbs_cmd_copyback,
(unsigned long) &cmd))
- lbs_pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
+ pr_alert("CMD_FUNC_SHUTDOWN cmd failed\n");
}
@@ -1202,20 +1204,19 @@
mmc_pm_flag_t flags = sdio_get_host_pm_caps(func);
- lbs_pr_info("%s: suspend: PM flags = 0x%x\n",
- sdio_func_id(func), flags);
+ dev_info(dev, "%s: suspend: PM flags = 0x%x\n",
+ sdio_func_id(func), flags);
/* If we aren't being asked to wake on anything, we should bail out
* and let the SD stack power down the card.
*/
if (card->priv->wol_criteria == EHS_REMOVE_WAKEUP) {
- lbs_pr_info("Suspend without wake params -- "
- "powering down card.");
+ dev_info(dev, "Suspend without wake params -- powering down card\n");
return -ENOSYS;
}
if (!(flags & MMC_PM_KEEP_POWER)) {
- lbs_pr_err("%s: cannot remain alive while host is suspended\n",
+ dev_err(dev, "%s: cannot remain alive while host is suspended\n",
sdio_func_id(func));
return -ENOSYS;
}
@@ -1237,7 +1238,7 @@
struct if_sdio_card *card = sdio_get_drvdata(func);
int ret;
- lbs_pr_info("%s: resume: we're back\n", sdio_func_id(func));
+ dev_info(dev, "%s: resume: we're back\n", sdio_func_id(func));
ret = lbs_resume(card->priv);
diff --git a/drivers/net/wireless/libertas/if_spi.c b/drivers/net/wireless/libertas/if_spi.c
index 67de5b3..463352c 100644
--- a/drivers/net/wireless/libertas/if_spi.c
+++ b/drivers/net/wireless/libertas/if_spi.c
@@ -17,6 +17,8 @@
* (at your option) any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/moduleparam.h>
#include <linux/firmware.h>
#include <linux/jiffies.h>
@@ -305,8 +307,7 @@
}
udelay(100);
if (time_after(jiffies, timeout)) {
- lbs_pr_err("%s: timeout with val=%02x, "
- "target_mask=%02x, target=%02x\n",
+ pr_err("%s: timeout with val=%02x, target_mask=%02x, target=%02x\n",
__func__, val, target_mask, target);
return -ETIMEDOUT;
}
@@ -405,7 +406,7 @@
if (err)
return err;
if ((rval & 0xF) != mode) {
- lbs_pr_err("Can't read bus mode register.\n");
+ pr_err("Can't read bus mode register\n");
return -EIO;
}
return 0;
@@ -534,7 +535,7 @@
out:
if (err)
- lbs_pr_err("failed to load helper firmware (err=%d)\n", err);
+ pr_err("failed to load helper firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
@@ -557,7 +558,7 @@
IF_SPI_HIST_CMD_DOWNLOAD_RDY,
IF_SPI_HIST_CMD_DOWNLOAD_RDY);
if (err) {
- lbs_pr_err("timed out waiting for host_int_status\n");
+ pr_err("timed out waiting for host_int_status\n");
return err;
}
@@ -567,9 +568,8 @@
return err;
if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("firmware load device requested a larger "
- "tranfer than we are prepared to "
- "handle. (len = %d)\n", len);
+ pr_err("firmware load device requested a larger transfer than we are prepared to handle (len = %d)\n",
+ len);
return -EIO;
}
if (len & 0x1) {
@@ -585,6 +585,7 @@
static int if_spi_prog_main_firmware(struct if_spi_card *card,
const struct firmware *firmware)
{
+ struct lbs_private *priv = card->priv;
int len, prev_len;
int bytes, crc_err = 0, err = 0;
const u8 *fw;
@@ -598,8 +599,9 @@
err = spu_wait_for_u16(card, IF_SPI_SCRATCH_1_REG, 0, 0);
if (err) {
- lbs_pr_err("%s: timed out waiting for initial "
- "scratch reg = 0\n", __func__);
+ netdev_err(priv->dev,
+ "%s: timed out waiting for initial scratch reg = 0\n",
+ __func__);
goto out;
}
@@ -617,15 +619,14 @@
* If there are no more bytes left, we would normally
* expect to have terminated with len = 0
*/
- lbs_pr_err("Firmware load wants more bytes "
- "than we have to offer.\n");
+ netdev_err(priv->dev,
+ "Firmware load wants more bytes than we have to offer.\n");
break;
}
if (crc_err) {
/* Previous transfer failed. */
if (++num_crc_errs > MAX_MAIN_FW_LOAD_CRC_ERR) {
- lbs_pr_err("Too many CRC errors encountered "
- "in firmware load.\n");
+ pr_err("Too many CRC errors encountered in firmware load.\n");
err = -EIO;
goto out;
}
@@ -654,21 +655,20 @@
prev_len = len;
}
if (bytes > prev_len) {
- lbs_pr_err("firmware load wants fewer bytes than "
- "we have to offer.\n");
+ pr_err("firmware load wants fewer bytes than we have to offer\n");
}
/* Confirm firmware download */
err = spu_wait_for_u32(card, IF_SPI_SCRATCH_4_REG,
SUCCESSFUL_FW_DOWNLOAD_MAGIC);
if (err) {
- lbs_pr_err("failed to confirm the firmware download\n");
+ pr_err("failed to confirm the firmware download\n");
goto out;
}
out:
if (err)
- lbs_pr_err("failed to load firmware (err=%d)\n", err);
+ pr_err("failed to load firmware (err=%d)\n", err);
lbs_deb_leave_args(LBS_DEB_SPI, "err %d", err);
return err;
}
@@ -709,13 +709,13 @@
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > IF_SPI_CMD_BUF_SIZE) {
- lbs_pr_err("%s: error: response packet too large: "
- "%d bytes, but maximum is %d\n",
+ netdev_err(priv->dev,
+ "%s: error: response packet too large: %d bytes, but maximum is %d\n",
__func__, len, IF_SPI_CMD_BUF_SIZE);
err = -EINVAL;
goto out;
@@ -737,7 +737,7 @@
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
@@ -745,6 +745,7 @@
/* Move data from the card to the host */
static int if_spi_c2h_data(struct if_spi_card *card)
{
+ struct lbs_private *priv = card->priv;
struct sk_buff *skb;
char *data;
u16 len;
@@ -757,13 +758,13 @@
if (err)
goto out;
if (!len) {
- lbs_pr_err("%s: error: card has no data for host\n",
+ netdev_err(priv->dev, "%s: error: card has no data for host\n",
__func__);
err = -EINVAL;
goto out;
} else if (len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
- lbs_pr_err("%s: error: card has %d bytes of data, but "
- "our maximum skb size is %zu\n",
+ netdev_err(priv->dev,
+ "%s: error: card has %d bytes of data, but our maximum skb size is %zu\n",
__func__, len, MRVDRV_ETH_RX_PACKET_BUFFER_SIZE);
err = -EINVAL;
goto out;
@@ -795,7 +796,7 @@
dev_kfree_skb(skb);
out:
if (err)
- lbs_pr_err("%s: err=%d\n", __func__, err);
+ netdev_err(priv->dev, "%s: err=%d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
return err;
}
@@ -804,6 +805,7 @@
static void if_spi_h2c(struct if_spi_card *card,
struct if_spi_packet *packet, int type)
{
+ struct lbs_private *priv = card->priv;
int err = 0;
u16 int_type, port_reg;
@@ -817,7 +819,8 @@
port_reg = IF_SPI_CMD_RDWRPORT_REG;
break;
default:
- lbs_pr_err("can't transfer buffer of type %d\n", type);
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
err = -EINVAL;
goto out;
}
@@ -831,7 +834,7 @@
kfree(packet);
if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
/* Inform the host about a card event */
@@ -855,7 +858,7 @@
lbs_queue_event(priv, cause & 0xff);
out:
if (err)
- lbs_pr_err("%s: error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: error %d\n", __func__, err);
}
static void if_spi_host_to_card_worker(struct work_struct *work)
@@ -865,8 +868,10 @@
u16 hiStatus;
unsigned long flags;
struct if_spi_packet *packet;
+ struct lbs_private *priv;
card = container_of(work, struct if_spi_card, packet_work);
+ priv = card->priv;
lbs_deb_enter(LBS_DEB_SPI);
@@ -877,7 +882,7 @@
err = spu_read_u16(card, IF_SPI_HOST_INT_STATUS_REG,
&hiStatus);
if (err) {
- lbs_pr_err("I/O error\n");
+ netdev_err(priv->dev, "I/O error\n");
goto err;
}
@@ -940,7 +945,7 @@
err:
if (err)
- lbs_pr_err("%s: got error %d\n", __func__, err);
+ netdev_err(priv->dev, "%s: got error %d\n", __func__, err);
lbs_deb_leave(LBS_DEB_SPI);
}
@@ -963,7 +968,8 @@
lbs_deb_enter_args(LBS_DEB_SPI, "type %d, bytes %d", type, nb);
if (nb == 0) {
- lbs_pr_err("%s: invalid size requested: %d\n", __func__, nb);
+ netdev_err(priv->dev, "%s: invalid size requested: %d\n",
+ __func__, nb);
err = -EINVAL;
goto out;
}
@@ -991,7 +997,8 @@
spin_unlock_irqrestore(&card->buffer_lock, flags);
break;
default:
- lbs_pr_err("can't transfer buffer of type %d", type);
+ netdev_err(priv->dev, "can't transfer buffer of type %d\n",
+ type);
err = -EINVAL;
break;
}
@@ -1024,6 +1031,7 @@
static int if_spi_init_card(struct if_spi_card *card)
{
+ struct lbs_private *priv = card->priv;
struct spi_device *spi = card->spi;
int err, i;
u32 scratch;
@@ -1052,8 +1060,8 @@
break;
}
if (i == ARRAY_SIZE(fw_table)) {
- lbs_pr_err("Unsupported chip_id: 0x%02x\n",
- card->card_id);
+ netdev_err(priv->dev, "Unsupported chip_id: 0x%02x\n",
+ card->card_id);
err = -ENODEV;
goto out;
}
@@ -1062,7 +1070,8 @@
card->card_id, &fw_table[0], &helper,
&mainfw);
if (err) {
- lbs_pr_err("failed to find firmware (%d)\n", err);
+ netdev_err(priv->dev, "failed to find firmware (%d)\n",
+ err);
goto out;
}
@@ -1187,7 +1196,7 @@
err = request_irq(spi->irq, if_spi_host_interrupt,
IRQF_TRIGGER_FALLING, "libertas_spi", card);
if (err) {
- lbs_pr_err("can't get host irq line-- request_irq failed\n");
+ pr_err("can't get host irq line-- request_irq failed\n");
goto terminate_workqueue;
}
diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c
index e1e2128f..b5acc39 100644
--- a/drivers/net/wireless/libertas/if_usb.c
+++ b/drivers/net/wireless/libertas/if_usb.c
@@ -1,6 +1,9 @@
/*
* This file contains functions used in USB interface module.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/moduleparam.h>
#include <linux/firmware.h>
@@ -153,7 +156,7 @@
lbs_host_to_card_done(priv);
} else {
/* print the failure status number for debug */
- lbs_pr_info("URB in failure status: %d\n", urb->status);
+ pr_info("URB in failure status: %d\n", urb->status);
}
}
@@ -203,7 +206,7 @@
wake_method.hdr.size = cpu_to_le16(sizeof(wake_method));
wake_method.action = cpu_to_le16(CMD_ACT_GET);
if (lbs_cmd_with_response(priv, CMD_802_11_FW_WAKE_METHOD, &wake_method)) {
- lbs_pr_info("Firmware does not seem to support PS mode\n");
+ netdev_info(priv->dev, "Firmware does not seem to support PS mode\n");
priv->fwcapinfo &= ~FW_CAPINFO_PS;
} else {
if (le16_to_cpu(wake_method.method) == CMD_WAKE_METHOD_COMMAND_INT) {
@@ -212,7 +215,8 @@
/* The versions which boot up this way don't seem to
work even if we set it to the command interrupt */
priv->fwcapinfo &= ~FW_CAPINFO_PS;
- lbs_pr_info("Firmware doesn't wake via command interrupt; disabling PS mode\n");
+ netdev_info(priv->dev,
+ "Firmware doesn't wake via command interrupt; disabling PS mode\n");
}
}
}
@@ -224,7 +228,7 @@
if (cardp->fwdnldover) {
lbs_deb_usb("Download complete, no event. Assuming success\n");
} else {
- lbs_pr_err("Download timed out\n");
+ pr_err("Download timed out\n");
cardp->surprise_removed = 1;
}
wake_up(&cardp->fw_wq);
@@ -258,7 +262,7 @@
cardp = kzalloc(sizeof(struct if_usb_card), GFP_KERNEL);
if (!cardp) {
- lbs_pr_err("Out of memory allocating private data.\n");
+ pr_err("Out of memory allocating private data\n");
goto error;
}
@@ -348,10 +352,12 @@
usb_set_intfdata(intf, cardp);
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_fw))
- lbs_pr_err("cannot register lbs_flash_fw attribute\n");
+ netdev_err(priv->dev,
+ "cannot register lbs_flash_fw attribute\n");
if (device_create_file(&priv->dev->dev, &dev_attr_lbs_flash_boot2))
- lbs_pr_err("cannot register lbs_flash_boot2 attribute\n");
+ netdev_err(priv->dev,
+ "cannot register lbs_flash_boot2 attribute\n");
/*
* EHS_REMOVE_WAKEUP is not supported on all versions of the firmware.
@@ -536,7 +542,7 @@
int ret = -1;
if (!(skb = dev_alloc_skb(MRVDRV_ETH_RX_PACKET_BUFFER_SIZE))) {
- lbs_pr_err("No free skb\n");
+ pr_err("No free skb\n");
goto rx_ret;
}
@@ -595,7 +601,7 @@
if (tmp[0] == cpu_to_le32(CMD_TYPE_INDICATION) &&
tmp[1] == cpu_to_le32(MACREG_INT_CODE_FIRMWARE_READY)) {
- lbs_pr_info("Firmware ready event received\n");
+ pr_info("Firmware ready event received\n");
wake_up(&cardp->fw_wq);
} else {
lbs_deb_usb("Waiting for confirmation; got %x %x\n",
@@ -622,20 +628,20 @@
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_DATA) ||
bootcmdresp.magic == cpu_to_le32(CMD_TYPE_INDICATION)) {
if (!cardp->bootcmdresp)
- lbs_pr_info("Firmware already seems alive; resetting\n");
+ pr_info("Firmware already seems alive; resetting\n");
cardp->bootcmdresp = -1;
} else {
- lbs_pr_info("boot cmd response wrong magic number (0x%x)\n",
+ pr_info("boot cmd response wrong magic number (0x%x)\n",
le32_to_cpu(bootcmdresp.magic));
}
} else if ((bootcmdresp.cmd != BOOT_CMD_FW_BY_USB) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_FW) &&
(bootcmdresp.cmd != BOOT_CMD_UPDATE_BOOT2)) {
- lbs_pr_info("boot cmd response cmd_tag error (%d)\n",
- bootcmdresp.cmd);
+ pr_info("boot cmd response cmd_tag error (%d)\n",
+ bootcmdresp.cmd);
} else if (bootcmdresp.result != BOOT_CMD_RESP_OK) {
- lbs_pr_info("boot cmd response result error (%d)\n",
- bootcmdresp.result);
+ pr_info("boot cmd response result error (%d)\n",
+ bootcmdresp.result);
} else {
cardp->bootcmdresp = 1;
lbs_deb_usbd(&cardp->udev->dev,
@@ -901,7 +907,7 @@
} while (!exit);
if (ret)
- lbs_pr_err("firmware file format check FAIL\n");
+ pr_err("firmware file format check FAIL\n");
else
lbs_deb_fw("firmware file format check PASS\n");
@@ -998,7 +1004,7 @@
ret = get_fw(cardp, fwname);
if (ret) {
- lbs_pr_err("failed to find firmware (%d)\n", ret);
+ pr_err("failed to find firmware (%d)\n", ret);
goto done;
}
@@ -1073,13 +1079,13 @@
usb_kill_urb(cardp->rx_urb);
if (!cardp->fwdnldover) {
- lbs_pr_info("failed to load fw, resetting device!\n");
+ pr_info("failed to load fw, resetting device!\n");
if (--reset_count >= 0) {
if_usb_reset_device(cardp);
goto restart;
}
- lbs_pr_info("FW download failure, time = %d ms\n", i * 100);
+ pr_info("FW download failure, time = %d ms\n", i * 100);
ret = -EIO;
goto release_fw;
}
diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c
index ed57cf8..8c40949 100644
--- a/drivers/net/wireless/libertas/main.c
+++ b/drivers/net/wireless/libertas/main.c
@@ -4,6 +4,8 @@
* thread etc..
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/etherdevice.h>
@@ -34,6 +36,10 @@
EXPORT_SYMBOL_GPL(lbs_debug);
module_param_named(libertas_debug, lbs_debug, int, 0644);
+unsigned int lbs_disablemesh;
+EXPORT_SYMBOL_GPL(lbs_disablemesh);
+module_param_named(libertas_disablemesh, lbs_disablemesh, int, 0644);
+
/*
* This global structure is used to send the confirm_sleep command as
@@ -149,28 +155,6 @@
return 0;
}
-static void lbs_tx_timeout(struct net_device *dev)
-{
- struct lbs_private *priv = dev->ml_priv;
-
- lbs_deb_enter(LBS_DEB_TX);
-
- lbs_pr_err("tx watch dog timeout\n");
-
- dev->trans_start = jiffies; /* prevent tx timeout */
-
- if (priv->currenttxskb)
- lbs_send_tx_feedback(priv, 0);
-
- /* XX: Shouldn't we also call into the hw-specific driver
- to kick it somehow? */
- lbs_host_to_card_done(priv);
-
- /* FIXME: reset the card */
-
- lbs_deb_leave(LBS_DEB_TX);
-}
-
void lbs_host_to_card_done(struct lbs_private *priv)
{
unsigned long flags;
@@ -464,8 +448,8 @@
if (priv->cmd_timed_out && priv->cur_cmd) {
struct cmd_ctrl_node *cmdnode = priv->cur_cmd;
- lbs_pr_info("Timeout submitting command 0x%04x\n",
- le16_to_cpu(cmdnode->cmdbuf->command));
+ netdev_info(dev, "Timeout submitting command 0x%04x\n",
+ le16_to_cpu(cmdnode->cmdbuf->command));
lbs_complete_command(priv, cmdnode, -ETIMEDOUT);
if (priv->reset_card)
priv->reset_card(priv);
@@ -492,8 +476,8 @@
* after firmware fixes it
*/
priv->psstate = PS_STATE_AWAKE;
- lbs_pr_alert("ignore PS_SleepConfirm in "
- "non-connected state\n");
+ netdev_alert(dev,
+ "ignore PS_SleepConfirm in non-connected state\n");
}
}
@@ -587,7 +571,8 @@
if (priv->is_deep_sleep) {
ret = lbs_set_deep_sleep(priv, 0);
if (ret) {
- lbs_pr_err("deep sleep cancellation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep cancellation failed: %d\n", ret);
return ret;
}
priv->deep_sleep_required = 1;
@@ -620,7 +605,8 @@
priv->deep_sleep_required = 0;
ret = lbs_set_deep_sleep(priv, 1);
if (ret)
- lbs_pr_err("deep sleep activation failed: %d\n", ret);
+ netdev_err(priv->dev,
+ "deep sleep activation failed: %d\n", ret);
}
if (priv->setup_fw_on_resume)
@@ -648,8 +634,8 @@
if (!priv->cur_cmd)
goto out;
- lbs_pr_info("command 0x%04x timed out\n",
- le16_to_cpu(priv->cur_cmd->cmdbuf->command));
+ netdev_info(priv->dev, "command 0x%04x timed out\n",
+ le16_to_cpu(priv->cur_cmd->cmdbuf->command));
priv->cmd_timed_out = 1;
wake_up_interruptible(&priv->waitq);
@@ -754,7 +740,7 @@
/* Allocate the command buffers */
if (lbs_allocate_cmd_buffer(priv)) {
- lbs_pr_err("Out of memory allocating command buffers\n");
+ pr_err("Out of memory allocating command buffers\n");
ret = -ENOMEM;
goto out;
}
@@ -764,7 +750,7 @@
/* Create the event FIFO */
ret = kfifo_alloc(&priv->event_fifo, sizeof(u32) * 16, GFP_KERNEL);
if (ret) {
- lbs_pr_err("Out of memory allocating event FIFO buffer\n");
+ pr_err("Out of memory allocating event FIFO buffer\n");
goto out;
}
@@ -791,7 +777,6 @@
.ndo_stop = lbs_eth_stop,
.ndo_start_xmit = lbs_hard_start_xmit,
.ndo_set_mac_address = lbs_set_mac_address,
- .ndo_tx_timeout = lbs_tx_timeout,
.ndo_set_multicast_list = lbs_set_multicast_list,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
@@ -816,7 +801,7 @@
/* Allocate an Ethernet device and register it */
wdev = lbs_cfg_alloc(dmdev);
if (IS_ERR(wdev)) {
- lbs_pr_err("cfg80211 init failed\n");
+ pr_err("cfg80211 init failed\n");
goto done;
}
@@ -825,7 +810,7 @@
priv->wdev = wdev;
if (lbs_init_adapter(priv)) {
- lbs_pr_err("failed to initialize adapter structure.\n");
+ pr_err("failed to initialize adapter structure\n");
goto err_wdev;
}
@@ -957,17 +942,20 @@
goto done;
if (lbs_cfg_register(priv)) {
- lbs_pr_err("cannot register device\n");
+ pr_err("cannot register device\n");
goto done;
}
lbs_update_channel(priv);
- lbs_init_mesh(priv);
+ if (!lbs_disablemesh)
+ lbs_init_mesh(priv);
+ else
+ pr_info("%s: mesh disabled\n", dev->name);
lbs_debugfs_init_one(priv, dev);
- lbs_pr_info("%s: Marvell WLAN 802.11 adapter\n", dev->name);
+ netdev_info(dev, "Marvell WLAN 802.11 adapter\n");
ret = 0;
@@ -1094,16 +1082,16 @@
if (user_helper) {
ret = request_firmware(helper, user_helper, dev);
if (ret) {
- lbs_pr_err("couldn't find helper firmware %s",
- user_helper);
+ dev_err(dev, "couldn't find helper firmware %s\n",
+ user_helper);
goto fail;
}
}
if (user_mainfw) {
ret = request_firmware(mainfw, user_mainfw, dev);
if (ret) {
- lbs_pr_err("couldn't find main firmware %s",
- user_mainfw);
+ dev_err(dev, "couldn't find main firmware %s\n",
+ user_mainfw);
goto fail;
}
}
diff --git a/drivers/net/wireless/libertas/mesh.c b/drivers/net/wireless/libertas/mesh.c
index a0804d1..24cf066 100644
--- a/drivers/net/wireless/libertas/mesh.c
+++ b/drivers/net/wireless/libertas/mesh.c
@@ -1,3 +1,5 @@
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/delay.h>
#include <linux/etherdevice.h>
#include <linux/netdevice.h>
@@ -267,7 +269,7 @@
lbs_add_mesh(priv);
if (device_create_file(&dev->dev, &dev_attr_lbs_mesh))
- lbs_pr_err("cannot register lbs_mesh attribute\n");
+ netdev_err(dev, "cannot register lbs_mesh attribute\n");
ret = 1;
}
@@ -395,7 +397,7 @@
/* Register virtual mesh interface */
ret = register_netdev(mesh_dev);
if (ret) {
- lbs_pr_err("cannot register mshX virtual interface\n");
+ pr_err("cannot register mshX virtual interface\n");
goto err_free;
}
@@ -973,7 +975,7 @@
return ret;
if (defs.meshie.val.mesh_id_len > IEEE80211_MAX_SSID_LEN) {
- lbs_pr_err("inconsistent mesh ID length");
+ dev_err(dev, "inconsistent mesh ID length\n");
defs.meshie.val.mesh_id_len = IEEE80211_MAX_SSID_LEN;
}
diff --git a/drivers/net/wireless/libertas/rx.c b/drivers/net/wireless/libertas/rx.c
index a3f4b55..fdb0448 100644
--- a/drivers/net/wireless/libertas/rx.c
+++ b/drivers/net/wireless/libertas/rx.c
@@ -1,6 +1,9 @@
/*
* This file contains the handling of RX in wlan driver.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/etherdevice.h>
#include <linux/slab.h>
#include <linux/types.h>
@@ -191,7 +194,7 @@
case 12: /* 54 Mbps */
return 108;
}
- lbs_pr_alert("Invalid Marvell WLAN rate %i\n", rate);
+ pr_alert("Invalid Marvell WLAN rate %i\n", rate);
return 0;
}
@@ -248,7 +251,7 @@
/* add space for the new radio header */
if ((skb_headroom(skb) < sizeof(struct rx_radiotap_hdr)) &&
pskb_expand_head(skb, sizeof(struct rx_radiotap_hdr), 0, GFP_ATOMIC)) {
- lbs_pr_alert("%s: couldn't pskb_expand_head\n", __func__);
+ netdev_alert(dev, "%s: couldn't pskb_expand_head\n", __func__);
ret = -ENOMEM;
kfree_skb(skb);
goto done;
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 1d294cf..916183d 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -187,7 +187,7 @@
*/
int mwifiex_ret_11n_cfg(struct host_cmd_ds_command *resp, void *data_buf)
{
- struct mwifiex_ds_11n_tx_cfg *tx_cfg = NULL;
+ struct mwifiex_ds_11n_tx_cfg *tx_cfg;
struct host_cmd_ds_11n_cfg *htcfg = &resp->params.htcfg;
if (data_buf) {
@@ -274,7 +274,7 @@
int mwifiex_ret_amsdu_aggr_ctrl(struct host_cmd_ds_command *resp,
void *data_buf)
{
- struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl = NULL;
+ struct mwifiex_ds_11n_amsdu_aggr_ctrl *amsdu_aggr_ctrl;
struct host_cmd_ds_amsdu_aggr_ctrl *amsdu_ctrl =
&resp->params.amsdu_aggr_ctrl;
@@ -461,8 +461,7 @@
struct mwifiex_bssdescriptor *bss_desc)
{
u16 max_amsdu = MWIFIEX_TX_DATA_BUF_SIZE_2K;
- u16 tx_buf = 0;
- u16 curr_tx_buf_size = 0;
+ u16 tx_buf, curr_tx_buf_size = 0;
if (bss_desc->bcn_ht_cap) {
if (le16_to_cpu(bss_desc->bcn_ht_cap->cap_info) &
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index c9fb062..d3d5e08 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -60,7 +60,7 @@
* later with ethertype
*/
};
- struct tx_packet_hdr *tx_header = NULL;
+ struct tx_packet_hdr *tx_header;
skb_put(skb_aggr, sizeof(*tx_header));
@@ -136,131 +136,6 @@
}
/*
- * Counts the number of subframes in an aggregate packet.
- *
- * This function parses an aggregate packet buffer, looking for
- * subframes and counting the number of such subframe found. The
- * function automatically skips the DA/SA fields at the beginning
- * of each subframe and padding at the end.
- */
-static int
-mwifiex_11n_get_num_aggr_pkts(u8 *data, int total_pkt_len)
-{
- int pkt_count = 0, pkt_len, pad;
-
- while (total_pkt_len > 0) {
- /* Length will be in network format, change it to host */
- pkt_len = ntohs((*(__be16 *)(data + 2 * ETH_ALEN)));
- pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
- (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
- data += pkt_len + pad + sizeof(struct ethhdr);
- total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
- ++pkt_count;
- }
-
- return pkt_count;
-}
-
-/*
- * De-aggregate received packets.
- *
- * This function parses the received aggregate buffer, extracts each subframe,
- * strips off the SNAP header from them and sends the data portion for further
- * processing.
- *
- * Each subframe body is copied onto a separate buffer, which are freed by
- * upper layer after processing. The function also performs sanity tests on
- * the received buffer.
- */
-int mwifiex_11n_deaggregate_pkt(struct mwifiex_private *priv,
- struct sk_buff *skb)
-{
- u16 pkt_len;
- int total_pkt_len;
- u8 *data;
- int pad;
- struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
- struct rxpd *local_rx_pd = (struct rxpd *) skb->data;
- struct sk_buff *skb_daggr;
- struct mwifiex_rxinfo *rx_info_daggr = NULL;
- int ret = -1;
- struct rx_packet_hdr *rx_pkt_hdr;
- struct mwifiex_adapter *adapter = priv->adapter;
- u8 rfc1042_eth_hdr[ETH_ALEN] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
- data = (u8 *) (local_rx_pd + local_rx_pd->rx_pkt_offset);
- total_pkt_len = local_rx_pd->rx_pkt_length;
-
- /* Sanity test */
- if (total_pkt_len > MWIFIEX_RX_DATA_BUF_SIZE) {
- dev_err(adapter->dev, "total pkt len greater than buffer"
- " size %d\n", total_pkt_len);
- return -1;
- }
-
- rx_info->use_count = mwifiex_11n_get_num_aggr_pkts(data, total_pkt_len);
-
- while (total_pkt_len > 0) {
- rx_pkt_hdr = (struct rx_packet_hdr *) data;
- /* Length will be in network format, change it to host */
- pkt_len = ntohs((*(__be16 *) (data + 2 * ETH_ALEN)));
- if (pkt_len > total_pkt_len) {
- dev_err(adapter->dev, "pkt_len %d > total_pkt_len %d\n",
- total_pkt_len, pkt_len);
- break;
- }
-
- pad = (((pkt_len + sizeof(struct ethhdr)) & 3)) ?
- (4 - ((pkt_len + sizeof(struct ethhdr)) & 3)) : 0;
-
- total_pkt_len -= pkt_len + pad + sizeof(struct ethhdr);
-
- if (memcmp(&rx_pkt_hdr->rfc1042_hdr,
- rfc1042_eth_hdr, sizeof(rfc1042_eth_hdr)) == 0) {
- memmove(data + LLC_SNAP_LEN, data, 2 * ETH_ALEN);
- data += LLC_SNAP_LEN;
- pkt_len += sizeof(struct ethhdr) - LLC_SNAP_LEN;
- } else {
- *(u16 *) (data + 2 * ETH_ALEN) = (u16) 0;
- pkt_len += sizeof(struct ethhdr);
- }
-
- skb_daggr = dev_alloc_skb(pkt_len);
- if (!skb_daggr) {
- dev_err(adapter->dev, "%s: failed to alloc skb_daggr\n",
- __func__);
- return -1;
- }
- rx_info_daggr = MWIFIEX_SKB_RXCB(skb_daggr);
-
- rx_info_daggr->bss_index = rx_info->bss_index;
- skb_daggr->tstamp = skb->tstamp;
- rx_info_daggr->parent = skb;
- skb_daggr->priority = skb->priority;
- skb_put(skb_daggr, pkt_len);
- memcpy(skb_daggr->data, data, pkt_len);
-
- ret = mwifiex_recv_packet(adapter, skb_daggr);
-
- switch (ret) {
- case -EINPROGRESS:
- break;
- case -1:
- dev_err(adapter->dev, "deaggr: host_to_card failed\n");
- case 0:
- mwifiex_recv_packet_complete(adapter, skb_daggr, ret);
- break;
- default:
- break;
- }
-
- data += pkt_len + pad;
- }
-
- return ret;
-}
-
-/*
* Create aggregated packet.
*
* This function creates an aggregated MSDU packet, by combining buffers
@@ -285,8 +160,7 @@
struct mwifiex_adapter *adapter = priv->adapter;
struct sk_buff *skb_aggr, *skb_src;
struct mwifiex_txinfo *tx_info_aggr, *tx_info_src;
- int pad = 0;
- int ret = 0;
+ int pad = 0, ret;
struct mwifiex_tx_param tx_param;
struct txpd *ptx_pd = NULL;
@@ -319,7 +193,8 @@
else
skb_src = NULL;
- pra_list->total_pkts_size -= skb_src->len;
+ if (skb_src)
+ pra_list->total_pkts_size -= skb_src->len;
spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
ra_list_flags);
@@ -374,7 +249,8 @@
(adapter->pps_uapsd_mode) &&
(adapter->tx_lock_flag)) {
priv->adapter->tx_lock_flag = false;
- ptx_pd->flags = 0;
+ if (ptx_pd)
+ ptx_pd->flags = 0;
}
skb_queue_tail(&pra_list->skb_head, skb_aggr);
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index a93c03f..e5dfdc3 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -39,7 +39,7 @@
*rx_reor_tbl_ptr, int start_win)
{
int no_pkt_to_send, i;
- void *rx_tmp_ptr = NULL;
+ void *rx_tmp_ptr;
unsigned long flags;
no_pkt_to_send = (start_win > rx_reor_tbl_ptr->start_win) ?
@@ -88,7 +88,7 @@
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
{
int i, j, xchg;
- void *rx_tmp_ptr = NULL;
+ void *rx_tmp_ptr;
unsigned long flags;
for (i = 0; i < rx_reor_tbl_ptr->win_size; ++i) {
@@ -335,8 +335,8 @@
&cmd->params.add_ba_rsp;
struct host_cmd_ds_11n_addba_req *cmd_addba_req =
(struct host_cmd_ds_11n_addba_req *) data_buf;
- u8 tid = 0;
- int win_size = 0;
+ u8 tid;
+ int win_size;
uint16_t block_ack_param_set;
cmd->command = cpu_to_le16(HostCmd_CMD_11N_ADDBA_RSP);
@@ -406,9 +406,8 @@
u8 *ta, u8 pkt_type, void *payload)
{
struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
- int start_win, end_win, win_size;
- int ret = 0;
- u16 pkt_index = 0;
+ int start_win, end_win, win_size, ret;
+ u16 pkt_index;
rx_reor_tbl_ptr =
mwifiex_11n_get_rx_reorder_tbl((struct mwifiex_private *) priv,
@@ -540,7 +539,7 @@
(struct host_cmd_ds_11n_addba_rsp *)
&resp->params.add_ba_rsp;
int tid, win_size;
- struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr = NULL;
+ struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
uint16_t block_ack_param_set;
block_ack_param_set = le16_to_cpu(add_ba_rsp->block_ack_param_set);
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 98009e2..660831c 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -77,18 +77,15 @@
static int
mwifiex_is_alg_wep(u32 cipher)
{
- int alg = 0;
-
switch (cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
- alg = 1;
- break;
+ return 1;
default:
- alg = 0;
break;
}
- return alg;
+
+ return 0;
}
/*
@@ -408,7 +405,7 @@
static int
mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
{
- int ret = 0;
+ int ret;
if (frag_thr < MWIFIEX_FRAG_MIN_VALUE
|| frag_thr > MWIFIEX_FRAG_MAX_VALUE)
@@ -449,7 +446,6 @@
mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
-
int ret = 0;
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
@@ -473,7 +469,7 @@
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- int ret = 0;
+ int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_mode == type) {
@@ -717,7 +713,7 @@
{
struct ieee80211_channel *chan;
struct mwifiex_bss_info bss_info;
- int ie_len = 0;
+ int ie_len;
u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
if (mwifiex_get_bss_info(priv, &bss_info))
@@ -765,7 +761,6 @@
static int mwifiex_inform_bss_from_scan_result(struct mwifiex_private *priv,
struct mwifiex_802_11_ssid *ssid)
{
- struct mwifiex_scan_resp scan_resp;
struct mwifiex_bssdescriptor *scan_table;
int i, j;
struct ieee80211_channel *chan;
@@ -775,10 +770,6 @@
int beacon_size;
u8 element_id, element_len;
- memset(&scan_resp, 0, sizeof(scan_resp));
- scan_resp.scan_table = (u8 *) priv->adapter->scan_table;
- scan_resp.num_in_scan_table = priv->adapter->num_in_scan_table;
-
#define MAX_IE_BUF 2048
ie_buf = kzalloc(MAX_IE_BUF, GFP_KERNEL);
if (!ie_buf) {
@@ -787,8 +778,8 @@
return -ENOMEM;
}
- scan_table = (struct mwifiex_bssdescriptor *) scan_resp.scan_table;
- for (i = 0; i < scan_resp.num_in_scan_table; i++) {
+ scan_table = priv->adapter->scan_table;
+ for (i = 0; i < priv->adapter->num_in_scan_table; i++) {
if (ssid) {
/* Inform specific BSS only */
if (memcmp(ssid->ssid, scan_table[i].ssid.ssid,
@@ -903,8 +894,7 @@
{
struct mwifiex_802_11_ssid req_ssid;
struct mwifiex_ssid_bssid ssid_bssid;
- int ret = 0;
- int auth_type = 0;
+ int ret, auth_type = 0;
memset(&req_ssid, 0, sizeof(struct mwifiex_802_11_ssid));
memset(&ssid_bssid, 0, sizeof(struct mwifiex_ssid_bssid));
@@ -1044,7 +1034,7 @@
goto done;
}
- priv->assoc_request = 1;
+ priv->assoc_request = -EINPROGRESS;
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@@ -1052,6 +1042,7 @@
ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
priv->bss_mode, sme->channel, sme, 0);
+ priv->assoc_request = 1;
done:
priv->assoc_result = ret;
queue_work(priv->workqueue, &priv->cfg_workqueue);
@@ -1080,7 +1071,7 @@
goto done;
}
- priv->ibss_join_request = 1;
+ priv->ibss_join_request = -EINPROGRESS;
wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n",
(char *) params->ssid, params->bssid);
@@ -1088,6 +1079,8 @@
ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
params->bssid, priv->bss_mode,
params->channel, NULL, params->privacy);
+
+ priv->ibss_join_request = 1;
done:
priv->ibss_join_result = ret;
queue_work(priv->workqueue, &priv->cfg_workqueue);
@@ -1244,8 +1237,8 @@
int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
struct mwifiex_private *priv)
{
- int ret = 0;
- void *wdev_priv = NULL;
+ int ret;
+ void *wdev_priv;
struct wireless_dev *wdev;
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
@@ -1257,8 +1250,10 @@
wdev->wiphy =
wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_private *));
- if (!wdev->wiphy)
+ if (!wdev->wiphy) {
+ kfree(wdev);
return -ENOMEM;
+ }
wdev->iftype = NL80211_IFTYPE_STATION;
wdev->wiphy->max_scan_ssids = 10;
wdev->wiphy->interface_modes =
@@ -1298,6 +1293,7 @@
dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
__func__);
wiphy_free(wdev->wiphy);
+ kfree(wdev);
return ret;
} else {
dev_dbg(priv->adapter->dev,
@@ -1380,7 +1376,7 @@
kfree(scan_req);
}
- if (priv->assoc_request) {
+ if (priv->assoc_request == 1) {
if (!priv->assoc_result) {
cfg80211_connect_result(priv->netdev, priv->cfg_bssid,
NULL, 0, NULL, 0,
@@ -1399,7 +1395,7 @@
priv->assoc_result = 0;
}
- if (priv->ibss_join_request) {
+ if (priv->ibss_join_request == 1) {
if (!priv->ibss_join_result) {
cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid,
GFP_KERNEL);
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 776146a..cd89fed 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -91,7 +91,7 @@
cmd_node->wait_q_enabled = false;
if (cmd_node->resp_skb) {
- mwifiex_recv_complete(adapter, cmd_node->resp_skb, 0);
+ dev_kfree_skb_any(cmd_node->resp_skb);
cmd_node->resp_skb = NULL;
}
}
@@ -128,7 +128,7 @@
{
struct mwifiex_adapter *adapter = priv->adapter;
- int ret = 0;
+ int ret;
struct host_cmd_ds_command *host_cmd;
uint16_t cmd_code;
uint16_t cmd_size;
@@ -222,25 +222,24 @@
*/
static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
{
- int ret = 0;
- u16 cmd_len = 0;
+ int ret;
struct mwifiex_private *priv;
- struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf =
- (struct mwifiex_opt_sleep_confirm_buffer *)
+ struct mwifiex_opt_sleep_confirm *sleep_cfm_buf =
+ (struct mwifiex_opt_sleep_confirm *)
adapter->sleep_cfm->data;
- cmd_len = sizeof(struct mwifiex_opt_sleep_confirm);
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- sleep_cfm_buf->ps_cfm_sleep.seq_num =
+ sleep_cfm_buf->seq_num =
cpu_to_le16((HostCmd_SET_SEQ_NO_BSS_INFO
(adapter->seq_num, priv->bss_num,
priv->bss_type)));
adapter->seq_num++;
+ skb_push(adapter->sleep_cfm, INTF_HEADER_LEN);
ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_CMD,
adapter->sleep_cfm->data,
- adapter->sleep_cfm->len +
- INTF_HEADER_LEN, NULL);
+ adapter->sleep_cfm->len, NULL);
+ skb_pull(adapter->sleep_cfm, INTF_HEADER_LEN);
if (ret == -1) {
dev_err(adapter->dev, "SLEEP_CFM: failed\n");
@@ -249,14 +248,14 @@
}
if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
== MWIFIEX_BSS_ROLE_STA) {
- if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl)
+ if (!sleep_cfm_buf->resp_ctrl)
/* Response is not needed for sleep
confirm command */
adapter->ps_state = PS_STATE_SLEEP;
else
adapter->ps_state = PS_STATE_SLEEP_CFM;
- if (!sleep_cfm_buf->ps_cfm_sleep.resp_ctrl
+ if (!sleep_cfm_buf->resp_ctrl
&& (adapter->is_hs_configured
&& !adapter->sleep_period.period)) {
adapter->pm_wakeup_card_req = true;
@@ -292,7 +291,7 @@
if (!cmd_array) {
dev_err(adapter->dev, "%s: failed to alloc cmd_array\n",
__func__);
- return -1;
+ return -ENOMEM;
}
adapter->cmd_pool = cmd_array;
@@ -340,7 +339,7 @@
}
if (!cmd_array[i].resp_skb)
continue;
- mwifiex_recv_complete(adapter, cmd_array[i].resp_skb, 0);
+ dev_kfree_skb_any(cmd_array[i].resp_skb);
}
/* Release struct cmd_ctrl_node */
if (adapter->cmd_pool) {
@@ -364,13 +363,13 @@
*/
int mwifiex_process_event(struct mwifiex_adapter *adapter)
{
- int ret = 0;
+ int ret;
struct mwifiex_private *priv =
mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
struct sk_buff *skb = adapter->event_skb;
u32 eventcause = adapter->event_cause;
struct timeval tstamp;
- struct mwifiex_rxinfo *rx_info = NULL;
+ struct mwifiex_rxinfo *rx_info;
/* Save the last event to debug log */
adapter->dbg.last_event_index =
@@ -403,7 +402,7 @@
adapter->event_cause = 0;
adapter->event_skb = NULL;
- mwifiex_recv_complete(adapter, skb, 0);
+ dev_kfree_skb_any(skb);
return ret;
}
@@ -446,10 +445,10 @@
int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid, void *data_buf)
{
- int ret = 0;
+ int ret;
struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node = NULL;
- struct host_cmd_ds_command *cmd_ptr = NULL;
+ struct cmd_ctrl_node *cmd_node;
+ struct host_cmd_ds_command *cmd_ptr;
if (!adapter) {
pr_err("PREP_CMD: adapter is NULL\n");
@@ -605,8 +604,8 @@
*/
int mwifiex_exec_next_cmd(struct mwifiex_adapter *adapter)
{
- struct mwifiex_private *priv = NULL;
- struct cmd_ctrl_node *cmd_node = NULL;
+ struct mwifiex_private *priv;
+ struct cmd_ctrl_node *cmd_node;
int ret = 0;
struct host_cmd_ds_command *host_cmd;
unsigned long cmd_flags;
@@ -673,7 +672,7 @@
*/
int mwifiex_process_cmdresp(struct mwifiex_adapter *adapter)
{
- struct host_cmd_ds_command *resp = NULL;
+ struct host_cmd_ds_command *resp;
struct mwifiex_private *priv =
mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
int ret = 0;
@@ -805,7 +804,7 @@
{
struct mwifiex_adapter *adapter =
(struct mwifiex_adapter *) function_context;
- struct cmd_ctrl_node *cmd_node = NULL;
+ struct cmd_ctrl_node *cmd_node;
struct timeval tstamp;
adapter->num_cmd_timeout++;
@@ -877,7 +876,7 @@
void
mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
{
- struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
unsigned long flags;
/* Cancel current cmd */
@@ -1160,7 +1159,7 @@
{
struct host_cmd_ds_802_11_ps_mode_enh *psmode_enh =
&cmd->params.psmode_enh;
- u8 *tlv = NULL;
+ u8 *tlv;
u16 cmd_size = 0;
cmd->command = cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 7ddcb06..46d65e0 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -193,7 +193,7 @@
unsigned long page = get_zeroed_page(GFP_KERNEL);
char *p = (char *) page, fmt[64];
struct mwifiex_bss_info info;
- ssize_t ret = 0;
+ ssize_t ret;
int i = 0;
if (!p)
@@ -288,7 +288,7 @@
(struct mwifiex_private *) file->private_data;
unsigned long page = get_zeroed_page(GFP_KERNEL);
char *p = (char *) page;
- ssize_t ret = 0;
+ ssize_t ret;
struct mwifiex_ds_get_stats stats;
if (!p)
@@ -400,7 +400,7 @@
struct mwifiex_debug_data *d = &items[0];
unsigned long page = get_zeroed_page(GFP_KERNEL);
char *p = (char *) page;
- ssize_t ret = 0;
+ ssize_t ret;
size_t size, addr;
long val;
int i, j;
@@ -507,7 +507,7 @@
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *) addr;
size_t buf_size = min(count, (size_t) (PAGE_SIZE - 1));
- int ret = 0;
+ int ret;
u32 reg_type = 0, reg_offset = 0, reg_value = UINT_MAX;
if (!buf)
@@ -650,7 +650,7 @@
(struct mwifiex_private *) file->private_data;
unsigned long addr = get_zeroed_page(GFP_KERNEL);
char *buf = (char *) addr;
- int pos = 0, ret = 0, i = 0;
+ int pos = 0, ret = 0, i;
u8 value[MAX_EEPROM_DATA];
if (!buf)
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index 6d1c454..afdd145 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -816,14 +816,7 @@
struct mwifiex_scan_cmd_config {
/*
- * BSS Type to be sent in the firmware command
- *
- * Field can be used to restrict the types of networks returned in the
- * scan. Valid settings are:
- *
- * - MWIFIEX_SCAN_MODE_BSS (infrastructure)
- * - MWIFIEX_SCAN_MODE_IBSS (adhoc)
- * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
+ * BSS mode to be sent in the firmware command
*/
u8 bss_mode;
@@ -866,13 +859,6 @@
u8 keep_previous_scan;
/*
* BSS mode to be sent in the firmware command
- *
- * Field can be used to restrict the types of networks returned in the
- * scan. Valid settings are:
- *
- * - MWIFIEX_SCAN_MODE_BSS (infrastructure)
- * - MWIFIEX_SCAN_MODE_IBSS (adhoc)
- * - MWIFIEX_SCAN_MODE_ANY (unrestricted, adhoc and infrastructure)
*/
u8 bss_mode;
/* Configure the number of probe requests for active chan scans */
@@ -1198,9 +1184,4 @@
__le16 action;
__le16 resp_ctrl;
} __packed;
-
-struct mwifiex_opt_sleep_confirm_buffer {
- u8 hdr[4];
- struct mwifiex_opt_sleep_confirm ps_cfm_sleep;
-} __packed;
#endif /* !_MWIFIEX_FW_H_ */
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index fc2c0c5..3f1559e 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -41,7 +41,7 @@
if (!bss_prio) {
dev_err(adapter->dev, "%s: failed to alloc bss_prio\n",
__func__);
- return -1;
+ return -ENOMEM;
}
bss_prio->priv = priv;
@@ -151,7 +151,7 @@
*/
static int mwifiex_allocate_adapter(struct mwifiex_adapter *adapter)
{
- int ret = 0;
+ int ret;
u32 buf_size;
struct mwifiex_bssdescriptor *temp_scan_table;
@@ -161,7 +161,7 @@
if (!temp_scan_table) {
dev_err(adapter->dev, "%s: failed to alloc temp_scan_table\n",
__func__);
- return -1;
+ return -ENOMEM;
}
adapter->scan_table = temp_scan_table;
@@ -175,7 +175,7 @@
}
adapter->sleep_cfm =
- dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm_buffer)
+ dev_alloc_skb(sizeof(struct mwifiex_opt_sleep_confirm)
+ INTF_HEADER_LEN);
if (!adapter->sleep_cfm) {
@@ -197,10 +197,10 @@
*/
static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
{
- struct mwifiex_opt_sleep_confirm_buffer *sleep_cfm_buf = NULL;
+ struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
- skb_put(adapter->sleep_cfm, sizeof(sleep_cfm_buf->ps_cfm_sleep));
- sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm_buffer *)
+ skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
+ sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
(adapter->sleep_cfm->data);
adapter->cmd_sent = false;
@@ -268,16 +268,14 @@
mwifiex_wmm_init(adapter);
if (adapter->sleep_cfm) {
- memset(&sleep_cfm_buf->ps_cfm_sleep, 0,
- adapter->sleep_cfm->len);
- sleep_cfm_buf->ps_cfm_sleep.command =
- cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
- sleep_cfm_buf->ps_cfm_sleep.size =
- cpu_to_le16(adapter->sleep_cfm->len);
- sleep_cfm_buf->ps_cfm_sleep.result = 0;
- sleep_cfm_buf->ps_cfm_sleep.action = cpu_to_le16(SLEEP_CONFIRM);
- sleep_cfm_buf->ps_cfm_sleep.resp_ctrl =
- cpu_to_le16(RESP_NEEDED);
+ memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
+ sleep_cfm_buf->command =
+ cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
+ sleep_cfm_buf->size =
+ cpu_to_le16(adapter->sleep_cfm->len);
+ sleep_cfm_buf->result = 0;
+ sleep_cfm_buf->action = cpu_to_le16(SLEEP_CONFIRM);
+ sleep_cfm_buf->resp_ctrl = cpu_to_le16(RESP_NEEDED);
}
memset(&adapter->sleep_params, 0, sizeof(adapter->sleep_params));
memset(&adapter->sleep_period, 0, sizeof(adapter->sleep_period));
@@ -342,9 +340,8 @@
*/
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter)
{
- struct mwifiex_private *priv = NULL;
- s32 i = 0;
- u32 j = 0;
+ struct mwifiex_private *priv;
+ s32 i, j;
spin_lock_init(&adapter->mwifiex_lock);
spin_lock_init(&adapter->int_lock);
@@ -400,9 +397,8 @@
*/
void mwifiex_free_lock_list(struct mwifiex_adapter *adapter)
{
- struct mwifiex_private *priv = NULL;
- s32 i = 0;
- s32 j = 0;
+ struct mwifiex_private *priv;
+ s32 i, j;
/* Free lists */
list_del(&adapter->cmd_free_q);
@@ -436,10 +432,9 @@
*/
int mwifiex_init_fw(struct mwifiex_adapter *adapter)
{
- int ret = 0;
- struct mwifiex_private *priv = NULL;
- u8 i = 0;
- u8 first_sta = true;
+ int ret;
+ struct mwifiex_private *priv;
+ u8 i, first_sta = true;
int is_cmd_pend_q_empty;
unsigned long flags;
@@ -497,8 +492,7 @@
{
int i;
struct mwifiex_adapter *adapter = priv->adapter;
- struct mwifiex_bss_prio_node *bssprio_node = NULL, *tmp_node = NULL,
- **cur = NULL;
+ struct mwifiex_bss_prio_node *bssprio_node, *tmp_node, **cur;
struct list_head *head;
spinlock_t *lock;
unsigned long flags;
@@ -552,8 +546,8 @@
mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
{
int ret = -EINPROGRESS;
- struct mwifiex_private *priv = NULL;
- s32 i = 0;
+ struct mwifiex_private *priv;
+ s32 i;
unsigned long flags;
/* mwifiex already shutdown */
@@ -608,9 +602,8 @@
int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *pmfw)
{
- int ret = 0;
+ int ret, winner;
u32 poll_num = 1;
- int winner;
/* Check if firmware is already running */
ret = adapter->if_ops.check_fw_status(adapter, poll_num, &winner);
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 5488e11..7c1c5ee 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -23,49 +23,16 @@
#include <net/mac80211.h>
enum {
- MWIFIEX_SCAN_MODE_UNCHANGED = 0,
- MWIFIEX_SCAN_MODE_BSS,
- MWIFIEX_SCAN_MODE_IBSS,
- MWIFIEX_SCAN_MODE_ANY
-};
-
-enum {
MWIFIEX_SCAN_TYPE_UNCHANGED = 0,
MWIFIEX_SCAN_TYPE_ACTIVE,
MWIFIEX_SCAN_TYPE_PASSIVE
};
-struct mwifiex_get_scan_table_fixed {
- u8 bssid[ETH_ALEN];
- u8 channel;
- u8 rssi;
- long long network_tsf;
-};
-
-struct mwifiex_scan_time_params {
- u32 specific_scan_time;
- u32 active_scan_time;
- u32 passive_scan_time;
-};
-
struct mwifiex_user_scan {
u32 scan_cfg_len;
u8 scan_cfg_buf[1];
};
-struct mwifiex_scan_req {
- u32 scan_mode;
- u32 scan_type;
- struct mwifiex_802_11_ssid scan_ssid;
- struct mwifiex_scan_time_params scan_time;
- struct mwifiex_user_scan user_scan;
-};
-
-struct mwifiex_scan_resp {
- u32 num_in_scan_table;
- u8 *scan_table;
-};
-
#define MWIFIEX_PROMISC_MODE 1
#define MWIFIEX_MULTICAST_MODE 2
#define MWIFIEX_ALL_MULTI_MODE 4
@@ -77,18 +44,11 @@
u8 mac_list[MWIFIEX_MAX_MULTICAST_LIST_SIZE][ETH_ALEN];
};
-#define MWIFIEX_MAX_CHANNEL_NUM 128
-
struct mwifiex_chan_freq {
u32 channel;
u32 freq;
};
-struct mwifiex_chan_list {
- u32 num_of_chan;
- struct mwifiex_chan_freq cf[MWIFIEX_MAX_CHANNEL_NUM];
-};
-
struct mwifiex_ssid_bssid {
struct mwifiex_802_11_ssid ssid;
u8 bssid[ETH_ALEN];
@@ -136,18 +96,8 @@
u32 wep_icv_error[4];
};
-#define BCN_RSSI_LAST_MASK 0x00000001
#define BCN_RSSI_AVG_MASK 0x00000002
-#define DATA_RSSI_LAST_MASK 0x00000004
-#define DATA_RSSI_AVG_MASK 0x00000008
-#define BCN_SNR_LAST_MASK 0x00000010
-#define BCN_SNR_AVG_MASK 0x00000020
-#define DATA_SNR_LAST_MASK 0x00000040
-#define DATA_SNR_AVG_MASK 0x00000080
-#define BCN_NF_LAST_MASK 0x00000100
#define BCN_NF_AVG_MASK 0x00000200
-#define DATA_NF_LAST_MASK 0x00000400
-#define DATA_NF_AVG_MASK 0x00000800
#define ALL_RSSI_INFO_MASK 0x00000fff
struct mwifiex_ds_get_signal {
@@ -174,11 +124,6 @@
s16 data_nf_avg;
};
-struct mwifiex_fw_info {
- u32 fw_ver;
- u8 mac_addr[ETH_ALEN];
-};
-
#define MWIFIEX_MAX_VER_STR_LEN 128
struct mwifiex_ver_ext {
@@ -286,11 +231,6 @@
u32 rate;
};
-struct mwifiex_data_rate {
- u32 tx_data_rate;
- u32 rx_data_rate;
-};
-
struct mwifiex_power_cfg {
u32 is_power_auto;
u32 power_level;
@@ -309,21 +249,14 @@
};
#define DEEP_SLEEP_ON 1
-#define DEEP_SLEEP_OFF 0
-
#define DEEP_SLEEP_IDLE_TIME 100
+#define PS_MODE_AUTO 1
struct mwifiex_ds_auto_ds {
u16 auto_ds;
u16 idle_time;
};
-#define PS_MODE_UNCHANGED 0
-#define PS_MODE_AUTO 1
-#define PS_MODE_POLL 2
-#define PS_MODE_NULL 3
-
-
struct mwifiex_ds_pm_cfg {
union {
u32 ps_mode;
@@ -333,18 +266,6 @@
} param;
};
-struct mwifiex_ioctl_wmm_queue_status_ac {
- u8 wmm_acm;
- u8 flow_required;
- u8 flow_created;
- u8 disabled;
-};
-
-struct mwifiex_ds_wmm_queue_status {
- struct mwifiex_ioctl_wmm_queue_status_ac
- ac_status[IEEE80211_MAX_QUEUES];
-};
-
struct mwifiex_ds_11n_tx_cfg {
u16 tx_htcap;
u16 tx_htinfo;
diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c
index 85fca5e..5eab3dc 100644
--- a/drivers/net/wireless/mwifiex/join.c
+++ b/drivers/net/wireless/mwifiex/join.c
@@ -143,9 +143,8 @@
static int mwifiex_get_common_rates(struct mwifiex_private *priv, u8 *rate1,
u32 rate1_size, u8 *rate2, u32 rate2_size)
{
- int ret = 0;
- u8 *ptr = rate1;
- u8 *tmp = NULL;
+ int ret;
+ u8 *ptr = rate1, *tmp;
u32 i, j;
tmp = kmalloc(rate1_size, GFP_KERNEL);
@@ -203,7 +202,7 @@
u8 *out_rates, u32 *out_rates_size)
{
u8 card_rates[MWIFIEX_SUPPORTED_RATES];
- u32 card_rates_size = 0;
+ u32 card_rates_size;
/* Copy AP supported rates */
memcpy(out_rates, bss_desc->supported_rates, MWIFIEX_SUPPORTED_RATES);
@@ -1359,7 +1358,7 @@
static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
{
u8 mac_address[ETH_ALEN];
- int ret = 0;
+ int ret;
u8 zero_mac[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
if (mac) {
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index d16cea7..f058225 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -69,7 +69,7 @@
adapter = kzalloc(sizeof(struct mwifiex_adapter), GFP_KERNEL);
if (!adapter)
- return -1;
+ return -ENOMEM;
g_adapter = adapter;
adapter->card = card;
@@ -150,7 +150,7 @@
*/
static int mwifiex_unregister(struct mwifiex_adapter *adapter)
{
- s32 i = 0;
+ s32 i;
del_timer(&adapter->cmd_timer);
@@ -379,8 +379,7 @@
*/
static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
{
- int ret = 0;
- int err;
+ int ret, err;
struct mwifiex_fw_image fw;
memset(&fw, 0, sizeof(struct mwifiex_fw_image));
@@ -449,7 +448,7 @@
static void
mwifiex_fill_buffer(struct sk_buff *skb)
{
- struct ethhdr *eth = NULL;
+ struct ethhdr *eth;
struct iphdr *iph;
struct timeval tv;
u8 tid = 0;
@@ -510,20 +509,20 @@
mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- struct sk_buff *new_skb = NULL;
+ struct sk_buff *new_skb;
struct mwifiex_txinfo *tx_info;
dev_dbg(priv->adapter->dev, "data: %lu BSS(%d): Data <= kernel\n",
jiffies, priv->bss_index);
if (priv->adapter->surprise_removed) {
- kfree(skb);
+ kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
if (!skb->len || (skb->len > ETH_FRAME_LEN)) {
dev_err(priv->adapter->dev, "Tx: bad skb len %d\n", skb->len);
- kfree(skb);
+ kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
@@ -536,7 +535,7 @@
skb_realloc_headroom(skb, MWIFIEX_MIN_DATA_HEADER_LEN);
if (unlikely(!new_skb)) {
dev_err(priv->adapter->dev, "Tx: cannot alloca new_skb\n");
- kfree(skb);
+ kfree_skb(skb);
priv->stats.tx_dropped++;
return 0;
}
@@ -571,7 +570,7 @@
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
struct sockaddr *hw_addr = (struct sockaddr *) addr;
- int ret = 0;
+ int ret;
memcpy(priv->curr_addr, hw_addr->sa_data, ETH_ALEN);
@@ -696,9 +695,9 @@
struct mwifiex_adapter *adapter,
u8 bss_index, u8 bss_type)
{
- struct net_device *dev = NULL;
- struct mwifiex_private *priv = NULL;
- void *mdev_priv = NULL;
+ struct net_device *dev;
+ struct mwifiex_private *priv;
+ void *mdev_priv;
dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), "mlan%d",
ether_setup, 1);
@@ -759,7 +758,7 @@
static void
mwifiex_remove_interface(struct mwifiex_adapter *adapter, u8 bss_index)
{
- struct net_device *dev = NULL;
+ struct net_device *dev;
struct mwifiex_private *priv = adapter->priv[bss_index];
if (!priv)
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index 5043fcd..672701d 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -479,9 +479,9 @@
u8 report_scan_result;
struct cfg80211_scan_request *scan_request;
int scan_result_status;
- bool assoc_request;
+ int assoc_request;
u16 assoc_result;
- bool ibss_join_request;
+ int ibss_join_request;
u16 ibss_join_result;
bool disconnect;
u8 cfg_bssid[6];
@@ -692,10 +692,6 @@
int mwifiex_dnld_fw(struct mwifiex_adapter *, struct mwifiex_fw_image *);
-int mwifiex_recv_complete(struct mwifiex_adapter *,
- struct sk_buff *skb,
- int status);
-
int mwifiex_recv_packet(struct mwifiex_adapter *, struct sk_buff *skb);
int mwifiex_process_event(struct mwifiex_adapter *adapter);
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 31a5295..5c22860 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -117,8 +117,8 @@
static u8
mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
{
- u8 *oui = NULL;
- struct ie_body *iebody = NULL;
+ u8 *oui;
+ struct ie_body *iebody;
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
@@ -144,8 +144,8 @@
static u8
mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
{
- u8 *oui = NULL;
- struct ie_body *iebody = NULL;
+ u8 *oui;
+ struct ie_body *iebody;
u8 ret = MWIFIEX_OUI_NOT_PRESENT;
if (((bss_desc->bcn_wpa_ie) && ((*(bss_desc->bcn_wpa_ie)).
@@ -181,7 +181,7 @@
struct mwifiex_ssid_bssid *ssid_bssid)
{
struct mwifiex_ssid_bssid tmp_ssid_bssid;
- u8 *mac = NULL;
+ u8 *mac;
if (!ssid_bssid)
return -1;
@@ -213,7 +213,7 @@
int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv,
struct mwifiex_user_scan_cfg *scan_req)
{
- int status = 0;
+ int status;
priv->adapter->cmd_wait_q.condition = false;
@@ -2253,8 +2253,8 @@
{
int ret = 0;
struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node = NULL;
- union mwifiex_scan_cmd_config_tlv *scan_cfg_out = NULL;
+ struct cmd_ctrl_node *cmd_node;
+ union mwifiex_scan_cmd_config_tlv *scan_cfg_out;
struct mwifiex_ie_types_chan_list_param_set *chan_list_out;
u32 buf_size;
struct mwifiex_chan_scan_param_set *scan_chan_list;
@@ -2283,7 +2283,7 @@
GFP_KERNEL);
if (!scan_cfg_out) {
dev_err(adapter->dev, "failed to alloc scan_cfg_out\n");
- return -1;
+ return -ENOMEM;
}
buf_size = sizeof(struct mwifiex_chan_scan_param_set) *
@@ -2292,7 +2292,7 @@
if (!scan_chan_list) {
dev_err(adapter->dev, "failed to alloc scan_chan_list\n");
kfree(scan_cfg_out);
- return -1;
+ return -ENOMEM;
}
keep_previous_scan = false;
@@ -2404,8 +2404,8 @@
{
int ret = 0;
struct mwifiex_adapter *adapter = priv->adapter;
- struct cmd_ctrl_node *cmd_node = NULL;
- struct host_cmd_ds_802_11_scan_rsp *scan_rsp = NULL;
+ struct cmd_ctrl_node *cmd_node;
+ struct host_cmd_ds_802_11_scan_rsp *scan_rsp;
struct mwifiex_bssdescriptor *bss_new_entry = NULL;
struct mwifiex_ie_types_data *tlv_data;
struct mwifiex_ie_types_tsf_timestamp *tsf_tlv;
@@ -2491,7 +2491,7 @@
GFP_KERNEL);
if (!bss_new_entry) {
dev_err(adapter->dev, " failed to alloc bss_new_entry\n");
- return -1;
+ return -ENOMEM;
}
for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
@@ -2881,7 +2881,7 @@
scan_cfg = kzalloc(sizeof(struct mwifiex_user_scan_cfg), GFP_KERNEL);
if (!scan_cfg) {
dev_err(adapter->dev, "failed to alloc scan_cfg\n");
- return -1;
+ return -ENOMEM;
}
memcpy(scan_cfg->ssid_list[0].ssid, req_ssid->ssid,
@@ -2906,7 +2906,7 @@
int mwifiex_request_scan(struct mwifiex_private *priv,
struct mwifiex_802_11_ssid *req_ssid)
{
- int ret = 0;
+ int ret;
if (down_interruptible(&priv->async_sem)) {
dev_err(priv->adapter->dev, "%s: acquire semaphore\n",
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 5148d0e..d425dbd 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -46,7 +46,7 @@
static int
mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
{
- int ret = 0;
+ int ret;
struct sdio_mmc_card *card = NULL;
pr_debug("info: vendor=0x%4.04X device=0x%4.04X class=%d function=%d\n",
@@ -68,6 +68,7 @@
if (ret) {
pr_err("%s: failed to enable function\n", __func__);
+ kfree(card);
return -EIO;
}
@@ -119,7 +120,7 @@
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct sdio_mmc_card *card;
- struct mwifiex_adapter *adapter = NULL;
+ struct mwifiex_adapter *adapter;
mmc_pm_flag_t pm_flag = 0;
int hs_actived = 0;
int i;
@@ -177,7 +178,7 @@
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct sdio_mmc_card *card;
- struct mwifiex_adapter *adapter = NULL;
+ struct mwifiex_adapter *adapter;
mmc_pm_flag_t pm_flag = 0;
int i;
@@ -420,7 +421,7 @@
u8 *payload, u32 pkt_len, u32 port)
{
u32 i = 0;
- int ret = 0;
+ int ret;
do {
ret = mwifiex_write_data_sync(adapter, payload, pkt_len, port);
@@ -531,7 +532,7 @@
mwifiex_sdio_poll_card_status(struct mwifiex_adapter *adapter, u8 bits)
{
u32 tries;
- u32 cs = 0;
+ u32 cs;
for (tries = 0; tries < MAX_POLL_TRIES; tries++) {
if (mwifiex_read_reg(adapter, CARD_STATUS_REG, &cs))
@@ -553,7 +554,7 @@
static int
mwifiex_sdio_read_fw_status(struct mwifiex_adapter *adapter, u16 *dat)
{
- u32 fws0 = 0, fws1 = 0;
+ u32 fws0, fws1;
if (mwifiex_read_reg(adapter, CARD_FW_STATUS0_REG, &fws0))
return -1;
@@ -574,7 +575,7 @@
*/
static int mwifiex_sdio_disable_host_int(struct mwifiex_adapter *adapter)
{
- u32 host_int_mask = 0;
+ u32 host_int_mask;
/* Read back the host_int_mask register */
if (mwifiex_read_reg(adapter, HOST_INT_MASK_REG, &host_int_mask))
@@ -614,7 +615,7 @@
u32 *type, u8 *buffer,
u32 npayload, u32 ioport)
{
- int ret = 0;
+ int ret;
u32 nb;
if (!buffer) {
@@ -652,14 +653,14 @@
static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
struct mwifiex_fw_image *fw)
{
- int ret = 0;
+ int ret;
u8 *firmware = fw->fw_buf;
u32 firmware_len = fw->fw_len;
u32 offset = 0;
u32 base0, base1;
u8 *fwbuf;
u16 len = 0;
- u32 txlen = 0, tx_blocks = 0, tries = 0;
+ u32 txlen, tx_blocks = 0, tries;
u32 i = 0;
if (!firmware_len) {
@@ -676,7 +677,7 @@
if (!fwbuf) {
dev_err(adapter->dev, "unable to alloc buffer for firmware."
" Terminating download\n");
- return -1;
+ return -ENOMEM;
}
/* Perform firmware data transfer */
@@ -830,7 +831,7 @@
static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
{
struct sdio_mmc_card *card = adapter->card;
- u32 sdio_ireg = 0;
+ u32 sdio_ireg;
unsigned long flags;
if (mwifiex_read_data_sync(adapter, card->mp_regs, MAX_MP_REGS,
@@ -964,7 +965,7 @@
s32 f_do_rx_cur = 0;
s32 f_aggr_cur = 0;
struct sk_buff *skb_deaggr;
- u32 pind = 0;
+ u32 pind;
u32 pkt_len, pkt_type = 0;
u8 *curr_ptr;
u32 rx_len = skb->len;
@@ -1114,7 +1115,7 @@
struct sdio_mmc_card *card = adapter->card;
int ret = 0;
u8 sdio_ireg;
- struct sk_buff *skb = NULL;
+ struct sk_buff *skb;
u8 port = CTRL_PORT;
u32 len_reg_l, len_reg_u;
u32 rx_blocks;
@@ -1377,7 +1378,7 @@
struct mwifiex_tx_param *tx_param)
{
struct sdio_mmc_card *card = adapter->card;
- int ret = 0;
+ int ret;
u32 buf_block_len;
u32 blk_size;
u8 port = CTRL_PORT;
@@ -1560,7 +1561,7 @@
{
struct sdio_mmc_card *card = adapter->card;
int ret;
- u32 sdio_ireg = 0;
+ u32 sdio_ireg;
/*
* Read the HOST_INT_STATUS_REG for ACK the first interrupt got
@@ -1605,7 +1606,7 @@
card->mp_regs = kzalloc(MAX_MP_REGS, GFP_KERNEL);
if (!card->mp_regs) {
dev_err(adapter->dev, "failed to alloc mp_regs\n");
- return -1;
+ return -ENOMEM;
}
ret = mwifiex_alloc_sdio_mpa_buffers(adapter,
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 33c8ba1..8af3a78 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -274,8 +274,8 @@
static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd,
u16 cmd_action, void *data_buf)
{
- struct mwifiex_types_power_group *pg_tlv = NULL;
- struct host_cmd_ds_txpwr_cfg *txp = NULL;
+ struct mwifiex_types_power_group *pg_tlv;
+ struct host_cmd_ds_txpwr_cfg *txp;
struct host_cmd_ds_txpwr_cfg *cmd_txp_cfg = &cmd->params.txp_cfg;
cmd->command = cpu_to_le16(HostCmd_CMD_TXPWR_CFG);
@@ -478,7 +478,7 @@
struct mwifiex_ie_type_key_param_set *key_param_set,
u16 *key_param_len)
{
- int cur_key_param_len = 0;
+ int cur_key_param_len;
u8 i;
/* Multi-key_param_set TLV is supported */
@@ -1121,7 +1121,7 @@
*/
int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
{
- int ret = 0;
+ int ret;
u16 enable = true;
struct mwifiex_ds_11n_amsdu_aggr_ctrl amsdu_aggr_ctrl;
struct mwifiex_ds_auto_ds auto_ds;
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index 7f4f10b..d08f764 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -43,7 +43,7 @@
mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
struct host_cmd_ds_command *resp)
{
- struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+ struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
struct mwifiex_adapter *adapter = priv->adapter;
struct host_cmd_ds_802_11_ps_mode_enh *pm;
unsigned long flags;
@@ -124,7 +124,7 @@
{
struct host_cmd_ds_802_11_rssi_info_rsp *rssi_info_rsp =
&resp->params.rssi_info_rsp;
- struct mwifiex_ds_get_signal *signal = NULL;
+ struct mwifiex_ds_get_signal *signal;
priv->data_rssi_last = le16_to_cpu(rssi_info_rsp->data_rssi_last);
priv->data_nf_last = le16_to_cpu(rssi_info_rsp->data_nf_last);
@@ -232,7 +232,7 @@
{
struct host_cmd_ds_802_11_get_log *get_log =
(struct host_cmd_ds_802_11_get_log *) &resp->params.get_log;
- struct mwifiex_ds_get_stats *stats = NULL;
+ struct mwifiex_ds_get_stats *stats;
if (data_buf) {
stats = (struct mwifiex_ds_get_stats *) data_buf;
@@ -280,10 +280,10 @@
struct host_cmd_ds_command *resp,
void *data_buf)
{
- struct mwifiex_rate_cfg *ds_rate = NULL;
+ struct mwifiex_rate_cfg *ds_rate;
struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg;
struct mwifiex_rate_scope *rate_scope;
- struct mwifiex_ie_types_header *head = NULL;
+ struct mwifiex_ie_types_header *head;
u16 tlv, tlv_buf_len;
u8 *tlv_buf;
u32 i;
@@ -368,9 +368,9 @@
*/
static int mwifiex_get_power_level(struct mwifiex_private *priv, void *data_buf)
{
- int length = -1, max_power = -1, min_power = -1;
- struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
- struct mwifiex_power_group *pg = NULL;
+ int length, max_power = -1, min_power = -1;
+ struct mwifiex_types_power_group *pg_tlv_hdr;
+ struct mwifiex_power_group *pg;
if (data_buf) {
pg_tlv_hdr =
@@ -418,8 +418,8 @@
{
struct mwifiex_adapter *adapter = priv->adapter;
struct host_cmd_ds_txpwr_cfg *txp_cfg = &resp->params.txp_cfg;
- struct mwifiex_types_power_group *pg_tlv_hdr = NULL;
- struct mwifiex_power_group *pg = NULL;
+ struct mwifiex_types_power_group *pg_tlv_hdr;
+ struct mwifiex_power_group *pg;
u16 action = le16_to_cpu(txp_cfg->action);
switch (action) {
@@ -593,7 +593,7 @@
&resp->params.domain_info_resp;
struct mwifiex_ietypes_domain_param_set *domain = &domain_info->domain;
u16 action = le16_to_cpu(domain_info->action);
- u8 no_of_triplet = 0;
+ u8 no_of_triplet;
no_of_triplet = (u8) ((le16_to_cpu(domain->header.len) -
IEEE80211_COUNTRY_STRING_LEN) /
@@ -661,7 +661,7 @@
void *data_buf)
{
struct host_cmd_ds_version_ext *ver_ext = &resp->params.verext;
- struct host_cmd_ds_version_ext *version_ext = NULL;
+ struct host_cmd_ds_version_ext *version_ext;
if (data_buf) {
version_ext = (struct host_cmd_ds_version_ext *)data_buf;
@@ -682,8 +682,8 @@
static int mwifiex_ret_reg_access(u16 type, struct host_cmd_ds_command *resp,
void *data_buf)
{
- struct mwifiex_ds_reg_rw *reg_rw = NULL;
- struct mwifiex_ds_read_eeprom *eeprom = NULL;
+ struct mwifiex_ds_reg_rw *reg_rw;
+ struct mwifiex_ds_read_eeprom *eeprom;
if (data_buf) {
reg_rw = (struct mwifiex_ds_reg_rw *) data_buf;
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index e7adaab..d05907d 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -149,7 +149,7 @@
int mwifiex_bss_start(struct mwifiex_private *priv,
struct mwifiex_ssid_bssid *ssid_bssid)
{
- int ret = 0;
+ int ret;
struct mwifiex_adapter *adapter = priv->adapter;
s32 i = -1;
@@ -376,7 +376,7 @@
{
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_bssdescriptor *bss_desc;
- s32 tbl_idx = 0;
+ s32 tbl_idx;
if (!info)
return -1;
@@ -436,9 +436,8 @@
struct mwifiex_ds_band_cfg *radio_cfg)
{
struct mwifiex_adapter *adapter = priv->adapter;
- u8 infra_band = 0;
- u8 adhoc_band = 0;
- u32 adhoc_channel = 0;
+ u8 infra_band, adhoc_band;
+ u32 adhoc_channel;
infra_band = (u8) radio_cfg->config_bands;
adhoc_band = (u8) radio_cfg->adhoc_start_band;
@@ -636,7 +635,7 @@
int
mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
{
- int ret = 0;
+ int ret;
struct mwifiex_bss_info bss_info;
struct mwifiex_ssid_bssid ssid_bssid;
u16 curr_chan = 0;
@@ -755,11 +754,10 @@
struct mwifiex_rate_cfg *rate_cfg)
{
u8 rates[MWIFIEX_SUPPORTED_RATES];
- u8 *rate = NULL;
- int rate_index = 0;
+ u8 *rate;
+ int rate_index, ret;
u16 bitmap_rates[MAX_BITMAP_RATES_SIZE];
- u32 i = 0;
- int ret = 0;
+ u32 i;
struct mwifiex_adapter *adapter = priv->adapter;
if (rate_cfg->is_rate_auto) {
@@ -819,7 +817,7 @@
static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate_cfg)
{
- int status = 0;
+ int status;
if (!rate_cfg)
return -1;
@@ -841,7 +839,7 @@
int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
struct mwifiex_rate_cfg *rate)
{
- int ret = 0;
+ int ret;
memset(rate, 0, sizeof(struct mwifiex_rate_cfg));
rate->action = HostCmd_ACT_GEN_GET;
@@ -875,11 +873,11 @@
int mwifiex_set_tx_power(struct mwifiex_private *priv,
struct mwifiex_power_cfg *power_cfg)
{
- int ret = 0;
- struct host_cmd_ds_txpwr_cfg *txp_cfg = NULL;
- struct mwifiex_types_power_group *pg_tlv = NULL;
- struct mwifiex_power_group *pg = NULL;
- u8 *buf = NULL;
+ int ret;
+ struct host_cmd_ds_txpwr_cfg *txp_cfg;
+ struct mwifiex_types_power_group *pg_tlv;
+ struct mwifiex_power_group *pg;
+ u8 *buf;
u16 dbm = 0;
if (!power_cfg->is_power_auto) {
@@ -897,7 +895,7 @@
if (!buf) {
dev_err(priv->adapter->dev, "%s: failed to alloc cmd buffer\n",
__func__);
- return -1;
+ return -ENOMEM;
}
txp_cfg = (struct host_cmd_ds_txpwr_cfg *) buf;
@@ -960,7 +958,7 @@
*/
int mwifiex_drv_set_power(struct mwifiex_private *priv, u32 *ps_mode)
{
- int ret = 0;
+ int ret;
struct mwifiex_adapter *adapter = priv->adapter;
u16 sub_cmd;
@@ -1078,8 +1076,8 @@
static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
struct mwifiex_ds_encrypt_key *encrypt_key)
{
- int ret = 0;
- struct mwifiex_wep_key *wep_key = NULL;
+ int ret;
+ struct mwifiex_wep_key *wep_key;
int index;
if (priv->wep_key_curr_index >= NUM_WEP_KEYS)
@@ -1142,7 +1140,7 @@
static int mwifiex_sec_ioctl_set_wpa_key(struct mwifiex_private *priv,
struct mwifiex_ds_encrypt_key *encrypt_key)
{
- int ret = 0;
+ int ret;
u8 remove_key = false;
struct host_cmd_ds_802_11_key_material *ibss_key;
@@ -1209,7 +1207,7 @@
mwifiex_sec_ioctl_encrypt_key(struct mwifiex_private *priv,
struct mwifiex_ds_encrypt_key *encrypt_key)
{
- int status = 0;
+ int status;
if (encrypt_key->is_wapi_key)
status = mwifiex_sec_ioctl_set_wapi_key(priv, encrypt_key);
@@ -1252,11 +1250,9 @@
int mwifiex_get_signal_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_signal *signal)
{
- struct mwifiex_ds_get_signal info;
- int status = 0;
+ int status;
- memset(&info, 0, sizeof(struct mwifiex_ds_get_signal));
- info.selector = ALL_RSSI_INFO_MASK;
+ signal->selector = ALL_RSSI_INFO_MASK;
/* Signal info can be obtained only if connected */
if (!priv->media_connected) {
@@ -1269,13 +1265,10 @@
HostCmd_ACT_GEN_GET, 0, signal);
if (!status) {
- if (signal)
- memcpy(signal, &info,
- sizeof(struct mwifiex_ds_get_signal));
- if (info.selector & BCN_RSSI_AVG_MASK)
- priv->w_stats.qual.level = info.bcn_rssi_avg;
- if (info.selector & BCN_NF_AVG_MASK)
- priv->w_stats.qual.noise = info.bcn_nf_avg;
+ if (signal->selector & BCN_RSSI_AVG_MASK)
+ priv->w_stats.qual.level = signal->bcn_rssi_avg;
+ if (signal->selector & BCN_NF_AVG_MASK)
+ priv->w_stats.qual.noise = signal->bcn_nf_avg;
}
return status;
@@ -1334,20 +1327,15 @@
mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log)
{
- int ret = 0;
- struct mwifiex_ds_get_stats get_log;
+ int ret;
- memset(&get_log, 0, sizeof(struct mwifiex_ds_get_stats));
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_GET_LOG,
- HostCmd_ACT_GEN_GET, 0, &get_log);
+ HostCmd_ACT_GEN_GET, 0, log);
if (!ret) {
- if (log)
- memcpy(log, &get_log, sizeof(struct
- mwifiex_ds_get_stats));
- priv->w_stats.discard.fragment = get_log.fcs_error;
- priv->w_stats.discard.retries = get_log.retry;
- priv->w_stats.discard.misc = get_log.ack_failure;
+ priv->w_stats.discard.fragment = log->fcs_error;
+ priv->w_stats.discard.retries = log->retry;
+ priv->w_stats.discard.misc = log->ack_failure;
}
return ret;
@@ -1425,7 +1413,7 @@
mwifiex_reg_read(struct mwifiex_private *priv, u32 reg_type,
u32 reg_offset, u32 *value)
{
- int ret = 0;
+ int ret;
struct mwifiex_ds_reg_rw reg_rw;
reg_rw.type = cpu_to_le32(reg_type);
@@ -1451,7 +1439,7 @@
mwifiex_eeprom_read(struct mwifiex_private *priv, u16 offset, u16 bytes,
u8 *value)
{
- int ret = 0;
+ int ret;
struct mwifiex_ds_read_eeprom rd_eeprom;
rd_eeprom.offset = cpu_to_le16((u16) offset);
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index 8282679..1fdddec 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -41,7 +41,7 @@
int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
struct sk_buff *skb)
{
- int ret = 0;
+ int ret;
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
struct rx_packet_hdr *rx_pkt_hdr;
@@ -123,7 +123,7 @@
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
struct rx_packet_hdr *rx_pkt_hdr;
u8 ta[ETH_ALEN];
- u16 rx_pkt_type = 0;
+ u16 rx_pkt_type;
struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
local_rx_pd = (struct rxpd *) (skb->data);
@@ -141,10 +141,28 @@
dev_kfree_skb_any(skb);
return ret;
}
+
if (local_rx_pd->rx_pkt_type == PKT_TYPE_AMSDU) {
- mwifiex_11n_deaggregate_pkt(priv, skb);
- return ret;
+ struct sk_buff_head list;
+ struct sk_buff *rx_skb;
+
+ __skb_queue_head_init(&list);
+
+ skb_pull(skb, local_rx_pd->rx_pkt_offset);
+ skb_trim(skb, local_rx_pd->rx_pkt_length);
+
+ ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
+ priv->wdev->iftype, 0, false);
+
+ while (!skb_queue_empty(&list)) {
+ rx_skb = __skb_dequeue(&list);
+ ret = mwifiex_recv_packet(adapter, rx_skb);
+ if (ret == -1)
+ dev_err(adapter->dev, "Rx of A-MSDU failed");
+ }
+ return 0;
}
+
/*
* If the packet is not an unicast packet then send the packet
* directly to os. Don't pass thru rx reordering
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index 5d37ef1..fa6221b 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -113,8 +113,8 @@
/* sizeof(struct txpd) + Interface specific header */
#define NULL_PACKET_HDR 64
u32 data_len = NULL_PACKET_HDR;
- struct sk_buff *skb = NULL;
- int ret = 0;
+ struct sk_buff *skb;
+ int ret;
struct mwifiex_txinfo *tx_info = NULL;
if (adapter->surprise_removed)
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index ce772e0..2101208 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -68,7 +68,7 @@
{
int ret = -1;
struct mwifiex_adapter *adapter = priv->adapter;
- u8 *head_ptr = NULL;
+ u8 *head_ptr;
struct txpd *local_tx_pd = NULL;
head_ptr = (u8 *) mwifiex_process_sta_txpd(priv, skb);
@@ -121,8 +121,8 @@
int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
struct sk_buff *skb, int status)
{
- struct mwifiex_private *priv = NULL, *tpriv = NULL;
- struct mwifiex_txinfo *tx_info = NULL;
+ struct mwifiex_private *priv, *tpriv;
+ struct mwifiex_txinfo *tx_info;
int i;
if (!skb)
@@ -169,9 +169,9 @@
struct sk_buff *skb, int status)
{
struct mwifiex_rxinfo *rx_info = MWIFIEX_SKB_RXCB(skb);
- struct mwifiex_rxinfo *rx_info_parent = NULL;
+ struct mwifiex_rxinfo *rx_info_parent;
struct mwifiex_private *priv;
- struct sk_buff *skb_parent = NULL;
+ struct sk_buff *skb_parent;
unsigned long flags;
priv = adapter->priv[rx_info->bss_index];
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index 7ab4fb2..d412915 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -152,8 +152,8 @@
*/
int mwifiex_recv_packet(struct mwifiex_adapter *adapter, struct sk_buff *skb)
{
- struct mwifiex_rxinfo *rx_info = NULL;
- struct mwifiex_private *priv = NULL;
+ struct mwifiex_rxinfo *rx_info;
+ struct mwifiex_private *priv;
if (!skb)
return -1;
@@ -177,31 +177,6 @@
}
/*
- * Receive packet completion callback handler.
- *
- * This function updates the statistics and frees the buffer SKB.
- */
-int mwifiex_recv_complete(struct mwifiex_adapter *adapter,
- struct sk_buff *skb, int status)
-{
- struct mwifiex_private *priv = NULL;
- struct mwifiex_rxinfo *rx_info = NULL;
-
- if (!skb)
- return 0;
-
- rx_info = MWIFIEX_SKB_RXCB(skb);
- priv = mwifiex_bss_index_to_priv(adapter, rx_info->bss_index);
-
- if (priv && (status == -1))
- priv->stats.rx_dropped++;
-
- dev_kfree_skb_any(skb);
-
- return 0;
-}
-
-/*
* IOCTL completion callback handler.
*
* This function is called when a pending IOCTL is completed.
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index c009370..faa09e3 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -799,7 +799,7 @@
mwifiex_wmm_compute_drv_pkt_delay(struct mwifiex_private *priv,
const struct sk_buff *skb)
{
- u8 ret_val = 0;
+ u8 ret_val;
struct timeval out_tstamp, in_tstamp;
u32 queue_delay;
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index 9f5ecef..3226118 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -784,7 +784,8 @@
#define REDUCED_TX_HEADROOM 8
static void
-mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb, int tail_pad)
+mwl8k_add_dma_header(struct mwl8k_priv *priv, struct sk_buff *skb,
+ int head_pad, int tail_pad)
{
struct ieee80211_hdr *wh;
int hdrlen;
@@ -816,7 +817,7 @@
skb->truesize += REDUCED_TX_HEADROOM;
}
- reqd_hdrlen = sizeof(*tr);
+ reqd_hdrlen = sizeof(*tr) + head_pad;
if (hdrlen != reqd_hdrlen)
skb_push(skb, reqd_hdrlen - hdrlen);
@@ -845,6 +846,7 @@
struct ieee80211_tx_info *tx_info;
struct ieee80211_key_conf *key_conf;
int data_pad;
+ int head_pad = 0;
wh = (struct ieee80211_hdr *)skb->data;
@@ -856,9 +858,7 @@
/*
* Make sure the packet header is in the DMA header format (4-address
- * without QoS), the necessary crypto padding between the header and the
- * payload has already been provided by mac80211, but it doesn't add
- * tail padding when HW crypto is enabled.
+ * without QoS), and add head & tail padding when HW crypto is enabled.
*
* We have the following trailer padding requirements:
* - WEP: 4 trailer bytes (ICV)
@@ -867,6 +867,7 @@
*/
data_pad = 0;
if (key_conf != NULL) {
+ head_pad = key_conf->iv_len;
switch (key_conf->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
@@ -880,7 +881,7 @@
break;
}
}
- mwl8k_add_dma_header(priv, skb, data_pad);
+ mwl8k_add_dma_header(priv, skb, head_pad, data_pad);
}
/*
@@ -1837,7 +1838,7 @@
if (priv->ap_fw)
mwl8k_encapsulate_tx_frame(priv, skb);
else
- mwl8k_add_dma_header(priv, skb, 0);
+ mwl8k_add_dma_header(priv, skb, 0, 0);
wh = &((struct mwl8k_dma_data *)skb->data)->wh;
@@ -3997,7 +3998,7 @@
mwl8k_vif->wep_key_conf[idx].enabled = 1;
}
- keymlen = 0;
+ keymlen = key->keylen;
action = MWL8K_ENCR_SET_KEY;
break;
case WLAN_CIPHER_SUITE_TKIP:
@@ -4071,7 +4072,6 @@
addr = sta->addr;
if (cmd_param == SET_KEY) {
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
rc = mwl8k_cmd_encryption_set_key(hw, vif, addr, key);
if (rc)
goto out;
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index 0494d7b..1b75317 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -331,10 +331,9 @@
struct p54p_ring_control *ring_control = priv->ring_control;
struct p54p_desc *desc;
dma_addr_t mapping;
- u32 device_idx, idx, i;
+ u32 idx, i;
spin_lock_irqsave(&priv->lock, flags);
- device_idx = le32_to_cpu(ring_control->device_idx[1]);
idx = le32_to_cpu(ring_control->host_idx[1]);
i = idx % ARRAY_SIZE(ring_control->tx_data);
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index c457731..9def1e5 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -93,7 +93,7 @@
intended for testers and developers.
config RT2800PCI_RT53XX
- bool "rt2800-pci - Include support for rt53xx devices (EXPERIMENTAL)"
+ bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
default y
---help---
@@ -163,6 +163,15 @@
Support for these devices is non-functional at the moment and is
intended for testers and developers.
+config RT2800USB_RT53XX
+ bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ default y
+ ---help---
+ This adds support for rt53xx wireless chipset family to the
+ rt2800pci driver.
+ Supported chips: RT5370
+
config RT2800USB_UNKNOWN
bool "rt2800usb - Include support for unknown (USB) devices"
default n
diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h
index ce20109..f67bc9b 100644
--- a/drivers/net/wireless/rt2x00/rt2800.h
+++ b/drivers/net/wireless/rt2x00/rt2800.h
@@ -51,6 +51,7 @@
* RF3320 2.4G 1T1R(RT3350/RT3370/RT3390)
* RF3322 2.4G 2T2R(RT3352/RT3371/RT3372/RT3391/RT3392)
* RF3853 2.4G/5G 3T3R(RT3883/RT3563/RT3573/RT3593/RT3662)
+ * RF5370 2.4G 1T1R
* RF5390 2.4G 1T1R
*/
#define RF2820 0x0001
@@ -66,6 +67,7 @@
#define RF3320 0x000b
#define RF3322 0x000c
#define RF3853 0x000d
+#define RF5370 0x5370
#define RF5390 0x5390
/*
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 790afd3..2a6aa85 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -1751,7 +1751,8 @@
rt2x00_rf(rt2x00dev, RF3052) ||
rt2x00_rf(rt2x00dev, RF3320))
rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
- else if (rt2x00_rf(rt2x00dev, RF5390))
+ else if (rt2x00_rf(rt2x00dev, RF5370) ||
+ rt2x00_rf(rt2x00dev, RF5390))
rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
else
rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info);
@@ -3686,6 +3687,7 @@
!rt2x00_rf(rt2x00dev, RF3022) &&
!rt2x00_rf(rt2x00dev, RF3052) &&
!rt2x00_rf(rt2x00dev, RF3320) &&
+ !rt2x00_rf(rt2x00dev, RF5370) &&
!rt2x00_rf(rt2x00dev, RF5390)) {
ERROR(rt2x00dev, "Invalid RF chipset detected.\n");
return -ENODEV;
@@ -3988,6 +3990,7 @@
rt2x00_rf(rt2x00dev, RF3021) ||
rt2x00_rf(rt2x00dev, RF3022) ||
rt2x00_rf(rt2x00dev, RF3320) ||
+ rt2x00_rf(rt2x00dev, RF5370) ||
rt2x00_rf(rt2x00dev, RF5390)) {
spec->num_channels = 14;
spec->channels = rf_vals_3x;
diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c
index 0eb44cf..ba82c97 100644
--- a/drivers/net/wireless/rt2x00/rt2800usb.c
+++ b/drivers/net/wireless/rt2x00/rt2800usb.c
@@ -1000,6 +1000,14 @@
/* Zinwell */
{ USB_DEVICE(0x5a57, 0x0284) },
#endif
+#ifdef CONFIG_RT2800USB_RT53XX
+ /* Azurewave */
+ { USB_DEVICE(0x13d3, 0x3329) },
+ { USB_DEVICE(0x13d3, 0x3365) },
+ /* Ralink */
+ { USB_DEVICE(0x148f, 0x5370) },
+ { USB_DEVICE(0x148f, 0x5372) },
+#endif
#ifdef CONFIG_RT2800USB_UNKNOWN
/*
* Unclear what kind of devices these are (they aren't supported by the
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 2eb5196..c018d67a 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -1159,9 +1159,9 @@
/*
* Stop all work.
*/
- del_timer_sync(&rt2x00dev->txstatus_timer);
cancel_work_sync(&rt2x00dev->intf_work);
if (rt2x00_is_usb(rt2x00dev)) {
+ del_timer_sync(&rt2x00dev->txstatus_timer);
cancel_work_sync(&rt2x00dev->rxdone_work);
cancel_work_sync(&rt2x00dev->txdone_work);
}
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 39e1052..8f90f62 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -298,7 +298,7 @@
if (!test_and_clear_bit(ENTRY_DATA_PENDING, &entry->flags) ||
test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return true;
+ return false;
/*
* USB devices cannot blindly pass the skb->len as the
@@ -392,7 +392,7 @@
if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags) ||
test_bit(ENTRY_DATA_STATUS_PENDING, &entry->flags))
- return true;
+ return false;
rt2x00lib_dmastart(entry);
@@ -447,7 +447,7 @@
struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data;
if (!test_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags))
- return true;
+ return false;
usb_kill_urb(entry_priv->urb);
diff --git a/drivers/net/wireless/rtlwifi/Kconfig b/drivers/net/wireless/rtlwifi/Kconfig
index ce49e0c..5aee8b2 100644
--- a/drivers/net/wireless/rtlwifi/Kconfig
+++ b/drivers/net/wireless/rtlwifi/Kconfig
@@ -10,6 +10,17 @@
If you choose to build it as a module, it will be called rtl8192ce
+config RTL8192SE
+ tristate "Realtek RTL8192SE/RTL8191SE PCIe Wireless Network Adapter"
+ depends on MAC80211 && EXPERIMENTAL
+ select FW_LOADER
+ select RTLWIFI
+ ---help---
+ This is the driver for Realtek RTL8192SE/RTL8191SE 802.11n PCIe
+ wireless network adapters.
+
+ If you choose to build it as a module, it will be called rtl8192se
+
config RTL8192CU
tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
depends on MAC80211 && USB && EXPERIMENTAL
@@ -24,10 +35,10 @@
config RTLWIFI
tristate
- depends on RTL8192CE || RTL8192CU
+ depends on RTL8192CE || RTL8192CU || RTL8192SE
default m
config RTL8192C_COMMON
tristate
- depends on RTL8192CE || RTL8192CU
+ depends on RTL8192CE || RTL8192CU || RTL8192SE
default m
diff --git a/drivers/net/wireless/rtlwifi/Makefile b/drivers/net/wireless/rtlwifi/Makefile
index ec9393f..7acce83 100644
--- a/drivers/net/wireless/rtlwifi/Makefile
+++ b/drivers/net/wireless/rtlwifi/Makefile
@@ -22,5 +22,6 @@
obj-$(CONFIG_RTL8192C_COMMON) += rtl8192c/
obj-$(CONFIG_RTL8192CE) += rtl8192ce/
obj-$(CONFIG_RTL8192CU) += rtl8192cu/
+obj-$(CONFIG_RTL8192SE) += rtl8192se/
ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/efuse.c b/drivers/net/wireless/rtlwifi/efuse.c
index 510d42e..50de6f5 100644
--- a/drivers/net/wireless/rtlwifi/efuse.c
+++ b/drivers/net/wireless/rtlwifi/efuse.c
@@ -235,7 +235,7 @@
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
- u8 efuse_tbl[HWSET_MAX_SIZE];
+ u8 *efuse_tbl;
u8 rtemp8[1];
u16 efuse_addr = 0;
u8 offset, wren;
@@ -245,7 +245,7 @@
rtlpriv->cfg->maps[EFUSE_MAX_SECTION_MAP];
const u32 efuse_len =
rtlpriv->cfg->maps[EFUSE_REAL_CONTENT_SIZE];
- u16 efuse_word[EFUSE_MAX_SECTION][EFUSE_MAX_WORD_UNIT];
+ u16 **efuse_word;
u16 efuse_utilized = 0;
u8 efuse_usage;
@@ -256,9 +256,24 @@
return;
}
+ /* allocate memory for efuse_tbl and efuse_word */
+ efuse_tbl = kmalloc(rtlpriv->cfg->maps[EFUSE_HWSET_MAX_SIZE] *
+ sizeof(u8), GFP_ATOMIC);
+ if (!efuse_tbl)
+ return;
+ efuse_word = kmalloc(EFUSE_MAX_WORD_UNIT * sizeof(u16 *), GFP_ATOMIC);
+ if (!efuse_word)
+ goto done;
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+ efuse_word[i] = kmalloc(efuse_max_section * sizeof(u16),
+ GFP_ATOMIC);
+ if (!efuse_word[i])
+ goto done;
+ }
+
for (i = 0; i < efuse_max_section; i++)
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++)
- efuse_word[i][j] = 0xFFFF;
+ efuse_word[j][i] = 0xFFFF;
read_efuse_byte(hw, efuse_addr, rtemp8);
if (*rtemp8 != 0xFF) {
@@ -285,7 +300,8 @@
read_efuse_byte(hw, efuse_addr, rtemp8);
efuse_addr++;
efuse_utilized++;
- efuse_word[offset][i] = (*rtemp8 & 0xff);
+ efuse_word[i][offset] =
+ (*rtemp8 & 0xff);
if (efuse_addr >= efuse_len)
break;
@@ -297,7 +313,7 @@
read_efuse_byte(hw, efuse_addr, rtemp8);
efuse_addr++;
efuse_utilized++;
- efuse_word[offset][i] |=
+ efuse_word[i][offset] |=
(((u16)*rtemp8 << 8) & 0xff00);
if (efuse_addr >= efuse_len)
@@ -320,9 +336,9 @@
for (i = 0; i < efuse_max_section; i++) {
for (j = 0; j < EFUSE_MAX_WORD_UNIT; j++) {
efuse_tbl[(i * 8) + (j * 2)] =
- (efuse_word[i][j] & 0xff);
+ (efuse_word[j][i] & 0xff);
efuse_tbl[(i * 8) + ((j * 2) + 1)] =
- ((efuse_word[i][j] >> 8) & 0xff);
+ ((efuse_word[j][i] >> 8) & 0xff);
}
}
@@ -336,6 +352,11 @@
(u8 *)&efuse_utilized);
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_EFUSE_USAGE,
(u8 *)&efuse_usage);
+done:
+ for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++)
+ kfree(efuse_word[i]);
+ kfree(efuse_word);
+ kfree(efuse_tbl);
}
bool efuse_shadow_update_chk(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 3550c9f..a409528 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -1611,6 +1611,7 @@
u16 irqline;
u8 tmp;
+ pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
venderid = pdev->vendor;
deviceid = pdev->device;
pci_read_config_byte(pdev, 0x8, &revisionid);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index 79c98f6..3a92ba3 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -372,7 +372,7 @@
__le16 fc;
struct ieee80211_hdr *hdr;
- memset(rx_status, 0, sizeof(rx_status));
+ memset(rx_status, 0, sizeof(*rx_status));
rxdesc = skb->data;
skb_len = skb->len;
drvinfo_len = (GET_RX_DESC_DRVINFO_SIZE(rxdesc) * RTL_RX_DRV_INFO_UNIT);
@@ -434,7 +434,7 @@
"0x%02X\n", fc, (u32)hdr->addr1[0], (u32)hdr->addr1[1],
(u32)hdr->addr1[2], (u32)hdr->addr1[3], (u32)hdr->addr1[4],
(u32)hdr->addr1[5]));
- memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+ memcpy(IEEE80211_SKB_RXCB(skb), rx_status, sizeof(*rx_status));
ieee80211_rx_irqsafe(hw, skb);
}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/Makefile b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile
new file mode 100644
index 0000000..b7eb138
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/Makefile
@@ -0,0 +1,15 @@
+rtl8192se-objs := \
+ dm.o \
+ fw.o \
+ hw.o \
+ led.o \
+ phy.o \
+ rf.o \
+ sw.o \
+ table.o \
+ trx.o
+
+obj-$(CONFIG_RTL8192SE) += rtl8192se.o
+
+ccflags-y += -D__CHECK_ENDIAN__
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
new file mode 100644
index 0000000..69828f2
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -0,0 +1,598 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_92S_DEF_H__
+#define __REALTEK_92S_DEF_H__
+
+#define RX_MPDU_QUEUE 0
+#define RX_CMD_QUEUE 1
+#define RX_MAX_QUEUE 2
+
+#define DESC92S_RATE1M 0x00
+#define DESC92S_RATE2M 0x01
+#define DESC92S_RATE5_5M 0x02
+#define DESC92S_RATE11M 0x03
+#define DESC92S_RATE6M 0x04
+#define DESC92S_RATE9M 0x05
+#define DESC92S_RATE12M 0x06
+#define DESC92S_RATE18M 0x07
+#define DESC92S_RATE24M 0x08
+#define DESC92S_RATE36M 0x09
+#define DESC92S_RATE48M 0x0a
+#define DESC92S_RATE54M 0x0b
+#define DESC92S_RATEMCS0 0x0c
+#define DESC92S_RATEMCS1 0x0d
+#define DESC92S_RATEMCS2 0x0e
+#define DESC92S_RATEMCS3 0x0f
+#define DESC92S_RATEMCS4 0x10
+#define DESC92S_RATEMCS5 0x11
+#define DESC92S_RATEMCS6 0x12
+#define DESC92S_RATEMCS7 0x13
+#define DESC92S_RATEMCS8 0x14
+#define DESC92S_RATEMCS9 0x15
+#define DESC92S_RATEMCS10 0x16
+#define DESC92S_RATEMCS11 0x17
+#define DESC92S_RATEMCS12 0x18
+#define DESC92S_RATEMCS13 0x19
+#define DESC92S_RATEMCS14 0x1a
+#define DESC92S_RATEMCS15 0x1b
+#define DESC92S_RATEMCS15_SG 0x1c
+#define DESC92S_RATEMCS32 0x20
+
+#define SHORT_SLOT_TIME 9
+#define NON_SHORT_SLOT_TIME 20
+
+/* Rx smooth factor */
+#define RX_SMOOTH_FACTOR 20
+
+/* Queue Select Value in TxDesc */
+#define QSLT_BK 0x2
+#define QSLT_BE 0x0
+#define QSLT_VI 0x5
+#define QSLT_VO 0x6
+#define QSLT_BEACON 0x10
+#define QSLT_HIGH 0x11
+#define QSLT_MGNT 0x12
+#define QSLT_CMD 0x13
+
+#define PHY_RSSI_SLID_WIN_MAX 100
+#define PHY_LINKQUALITY_SLID_WIN_MAX 20
+#define PHY_BEACON_RSSI_SLID_WIN_MAX 10
+
+/* Tx Desc */
+#define TX_DESC_SIZE_RTL8192S (16 * 4)
+#define TX_CMDDESC_SIZE_RTL8192S (16 * 4)
+
+/* Define a macro that takes a le32 word, converts it to host ordering,
+ * right shifts by a specified count, creates a mask of the specified
+ * bit count, and extracts that number of bits.
+ */
+
+#define SHIFT_AND_MASK_LE(__pdesc, __shift, __mask) \
+ ((le32_to_cpu(*(((__le32 *)(__pdesc)))) >> (__shift)) & \
+ BIT_LEN_MASK_32(__mask))
+
+/* Define a macro that clears a bit field in an le32 word and
+ * sets the specified value into that bit field. The resulting
+ * value remains in le32 ordering; however, it is properly converted
+ * to host ordering for the clear and set operations before conversion
+ * back to le32.
+ */
+
+#define SET_BITS_OFFSET_LE(__pdesc, __shift, __len, __val) \
+ (*(__le32 *)(__pdesc) = \
+ (cpu_to_le32((le32_to_cpu(*((__le32 *)(__pdesc))) & \
+ (~(BIT_OFFSET_LEN_MASK_32((__shift), __len)))) | \
+ (((u32)(__val) & BIT_LEN_MASK_32(__len)) << (__shift)))));
+
+/* macros to read/write various fields in RX or TX descriptors */
+
+/* Dword 0 */
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_AMSDU(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GREEN_FIELD(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_OWN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 31, 1)
+
+/* Dword 1 */
+#define SET_TX_DESC_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val)
+#define SET_TX_DESC_MORE_DATA(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 1, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 6, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 7, 1, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 8, 5, __val)
+#define SET_TX_DESC_ACK_POLICY(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 13, 2, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val)
+#define SET_TX_DESC_NON_QOS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 1, __val)
+#define SET_TX_DESC_KEY_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 17, 2, __val)
+#define SET_TX_DESC_OUI(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 19, 1, __val)
+#define SET_TX_DESC_PKT_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 22, 2, __val)
+#define SET_TX_DESC_WDS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 5, __val)
+#define SET_TX_DESC_HWPC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val)
+
+/* Dword 2 */
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 6, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 6, 1, __val)
+#define SET_TX_DESC_TSFL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 7, 5, __val)
+#define SET_TX_DESC_RTS_RETRY_COUNT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 6, __val)
+#define SET_TX_DESC_DATA_RETRY_COUNT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 18, 6, __val)
+#define SET_TX_DESC_RSVD_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(((__pdesc) + 8), 24, 5, __val)
+#define SET_TX_DESC_AGG_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 29, 1, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val)
+#define SET_TX_DESC_OWN_MAC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 31, 1, __val)
+
+/* Dword 3 */
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 12, __val)
+#define SET_TX_DESC_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 28, 4, __val)
+
+/* Dword 4 */
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 6, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 6, 1, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 7, 4, __val)
+#define SET_TX_DESC_CTS_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 12, 1, __val)
+#define SET_TX_DESC_RA_BRSR_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 13, 3, __val)
+#define SET_TX_DESC_TXHT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 16, 1, __val)
+#define SET_TX_DESC_TX_SHORT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 17, 1, __val)
+#define SET_TX_DESC_TX_BANDWIDTH(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 18, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 19, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 21, 2, __val)
+#define SET_TX_DESC_TX_REVERSE_DIRECTION(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 23, 1, __val)
+#define SET_TX_DESC_RTS_HT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 24, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 25, 1, __val)
+#define SET_TX_DESC_RTS_BANDWIDTH(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 26, 1, __val)
+#define SET_TX_DESC_RTS_SUB_CARRIER(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 27, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 29, 2, __val)
+#define SET_TX_DESC_USER_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 31, 1, __val)
+
+/* Dword 5 */
+#define SET_TX_DESC_PACKET_ID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 9, __val)
+#define SET_TX_DESC_TX_RATE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 9, 6, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 15, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 16, 5, __val)
+#define SET_TX_DESC_TX_AGC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 21, 11, __val)
+
+/* Dword 6 */
+#define SET_TX_DESC_IP_CHECK_SUM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 16, __val)
+#define SET_TX_DESC_TCP_CHECK_SUM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 16, 16, __val)
+
+/* Dword 7 */
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 0, 16, __val)
+#define SET_TX_DESC_IP_HEADER_OFFSET(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 16, 8, __val)
+#define SET_TX_DESC_TCP_ENABLE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 28, 31, 1, __val)
+
+/* Dword 8 */
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 32, 0, 32, __val)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 32, 0, 32)
+
+/* Dword 9 */
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 36, 0, 32, __val)
+
+/* Because the PCI Tx descriptors are chaied at the
+ * initialization and all the NextDescAddresses in
+ * these descriptors cannot not be cleared (,or
+ * driver/HW cannot find the next descriptor), the
+ * offset 36 (NextDescAddresses) is reserved when
+ * the desc is cleared. */
+#define TX_DESC_NEXT_DESC_OFFSET 36
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size) \
+do { \
+ if (_size > TX_DESC_NEXT_DESC_OFFSET) \
+ memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET); \
+ else \
+ memset(__pdesc, 0, _size); \
+} while (0);
+
+/* Rx Desc */
+#define RX_STATUS_DESC_SIZE 24
+#define RX_DRV_INFO_SIZE_UNIT 8
+
+/* DWORD 0 */
+#define SET_RX_STATUS_DESC_PKT_LEN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 0, 14, __val)
+#define SET_RX_STATUS_DESC_CRC32(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 14, 1, __val)
+#define SET_RX_STATUS_DESC_ICV(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 15, 1, __val)
+#define SET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 16, 4, __val)
+#define SET_RX_STATUS_DESC_SECURITY(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 20, 3, __val)
+#define SET_RX_STATUS_DESC_QOS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 23, 1, __val)
+#define SET_RX_STATUS_DESC_SHIFT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 24, 2, __val)
+#define SET_RX_STATUS_DESC_PHY_STATUS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 26, 1, __val)
+#define SET_RX_STATUS_DESC_SWDEC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 27, 1, __val)
+#define SET_RX_STATUS_DESC_LAST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 28, 1, __val)
+#define SET_RX_STATUS_DESC_FIRST_SEG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 29, 1, __val)
+#define SET_RX_STATUS_DESC_EOR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 30, 1, __val)
+#define SET_RX_STATUS_DESC_OWN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc, 31, 1, __val)
+
+#define GET_RX_STATUS_DESC_PKT_LEN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 0, 14)
+#define GET_RX_STATUS_DESC_CRC32(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 14, 1)
+#define GET_RX_STATUS_DESC_ICV(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 15, 1)
+#define GET_RX_STATUS_DESC_DRVINFO_SIZE(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 16, 4)
+#define GET_RX_STATUS_DESC_SECURITY(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 20, 3)
+#define GET_RX_STATUS_DESC_QOS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 23, 1)
+#define GET_RX_STATUS_DESC_SHIFT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 24, 2)
+#define GET_RX_STATUS_DESC_PHY_STATUS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 26, 1)
+#define GET_RX_STATUS_DESC_SWDEC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 27, 1)
+#define GET_RX_STATUS_DESC_LAST_SEG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 28, 1)
+#define GET_RX_STATUS_DESC_FIRST_SEG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 29, 1)
+#define GET_RX_STATUS_DESC_EOR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 30, 1)
+#define GET_RX_STATUS_DESC_OWN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc, 31, 1)
+
+/* DWORD 1 */
+#define SET_RX_STATUS_DESC_MACID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 0, 5, __val)
+#define SET_RX_STATUS_DESC_TID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 5, 4, __val)
+#define SET_RX_STATUS_DESC_PAGGR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 14, 1, __val)
+#define SET_RX_STATUS_DESC_FAGGR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 15, 1, __val)
+#define SET_RX_STATUS_DESC_A1_FIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 16, 4, __val)
+#define SET_RX_STATUS_DESC_A2_FIT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 20, 4, __val)
+#define SET_RX_STATUS_DESC_PAM(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 24, 1, __val)
+#define SET_RX_STATUS_DESC_PWR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 25, 1, __val)
+#define SET_RX_STATUS_DESC_MOREDATA(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 26, 1, __val)
+#define SET_RX_STATUS_DESC_MOREFRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 27, 1, __val)
+#define SET_RX_STATUS_DESC_TYPE(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 28, 2, __val)
+#define SET_RX_STATUS_DESC_MC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 30, 1, __val)
+#define SET_RX_STATUS_DESC_BC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 4, 31, 1, __val)
+
+#define GET_RX_STATUS_DEC_MACID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 0, 5)
+#define GET_RX_STATUS_DESC_TID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 5, 4)
+#define GET_RX_STATUS_DESC_PAGGR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 14, 1)
+#define GET_RX_STATUS_DESC_FAGGR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 15, 1)
+#define GET_RX_STATUS_DESC_A1_FIT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 16, 4)
+#define GET_RX_STATUS_DESC_A2_FIT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 20, 4)
+#define GET_RX_STATUS_DESC_PAM(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 24, 1)
+#define GET_RX_STATUS_DESC_PWR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 25, 1)
+#define GET_RX_STATUS_DESC_MORE_DATA(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 26, 1)
+#define GET_RX_STATUS_DESC_MORE_FRAG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 27, 1)
+#define GET_RX_STATUS_DESC_TYPE(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 28, 2)
+#define GET_RX_STATUS_DESC_MC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 30, 1)
+#define GET_RX_STATUS_DESC_BC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 4, 31, 1)
+
+/* DWORD 2 */
+#define SET_RX_STATUS_DESC_SEQ(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 0, 12, __val)
+#define SET_RX_STATUS_DESC_FRAG(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 12, 4, __val)
+#define SET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 16, 8, __val)
+#define SET_RX_STATUS_DESC_NEXT_IND(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 8, 30, 1, __val)
+
+#define GET_RX_STATUS_DESC_SEQ(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 0, 12)
+#define GET_RX_STATUS_DESC_FRAG(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 12, 4)
+#define GET_RX_STATUS_DESC_NEXT_PKTLEN(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 16, 8)
+#define GET_RX_STATUS_DESC_NEXT_IND(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 8, 30, 1)
+
+/* DWORD 3 */
+#define SET_RX_STATUS_DESC_RX_MCS(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 0, 6, __val)
+#define SET_RX_STATUS_DESC_RX_HT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 6, 1, __val)
+#define SET_RX_STATUS_DESC_AMSDU(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 7, 1, __val)
+#define SET_RX_STATUS_DESC_SPLCP(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 8, 1, __val)
+#define SET_RX_STATUS_DESC_BW(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 9, 1, __val)
+#define SET_RX_STATUS_DESC_HTC(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 10, 1, __val)
+#define SET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 11, 1, __val)
+#define SET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 12, 1, __val)
+#define SET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 13, 1, __val)
+#define SET_RX_STATUS_DESC_HWPC_ERR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 14, 1, __val)
+#define SET_RX_STATUS_DESC_HWPC_IND(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 15, 1, __val)
+#define SET_RX_STATUS_DESC_IV0(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 12, 16, 16, __val)
+
+#define GET_RX_STATUS_DESC_RX_MCS(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 0, 6)
+#define GET_RX_STATUS_DESC_RX_HT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 6, 1)
+#define GET_RX_STATUS_DESC_AMSDU(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 7, 1)
+#define GET_RX_STATUS_DESC_SPLCP(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 8, 1)
+#define GET_RX_STATUS_DESC_BW(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 9, 1)
+#define GET_RX_STATUS_DESC_HTC(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 10, 1)
+#define GET_RX_STATUS_DESC_TCP_CHK_RPT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 11, 1)
+#define GET_RX_STATUS_DESC_IP_CHK_RPT(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 12, 1)
+#define GET_RX_STATUS_DESC_TCP_CHK_VALID(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 13, 1)
+#define GET_RX_STATUS_DESC_HWPC_ERR(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 14, 1)
+#define GET_RX_STATUS_DESC_HWPC_IND(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 15, 1)
+#define GET_RX_STATUS_DESC_IV0(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 12, 16, 16)
+
+/* DWORD 4 */
+#define SET_RX_STATUS_DESC_IV1(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 16, 0, 32, __val)
+#define GET_RX_STATUS_DESC_IV1(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 16, 0, 32)
+
+/* DWORD 5 */
+#define SET_RX_STATUS_DESC_TSFL(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 20, 0, 32, __val)
+#define GET_RX_STATUS_DESC_TSFL(__pdesc) \
+ SHIFT_AND_MASK_LE(__pdesc + 20, 0, 32)
+
+/* DWORD 6 */
+#define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val) \
+ SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
+
+#define RX_HAL_IS_CCK_RATE(_pdesc)\
+ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE1M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE2M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE5_5M ||\
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92S_RATE11M)
+
+enum rf_optype {
+ RF_OP_BY_SW_3WIRE = 0,
+ RF_OP_BY_FW,
+ RF_OP_MAX
+};
+
+enum ic_inferiority {
+ IC_INFERIORITY_A = 0,
+ IC_INFERIORITY_B = 1,
+};
+
+enum fwcmd_iotype {
+ /* For DIG DM */
+ FW_CMD_DIG_ENABLE = 0,
+ FW_CMD_DIG_DISABLE = 1,
+ FW_CMD_DIG_HALT = 2,
+ FW_CMD_DIG_RESUME = 3,
+ /* For High Power DM */
+ FW_CMD_HIGH_PWR_ENABLE = 4,
+ FW_CMD_HIGH_PWR_DISABLE = 5,
+ /* For Rate adaptive DM */
+ FW_CMD_RA_RESET = 6,
+ FW_CMD_RA_ACTIVE = 7,
+ FW_CMD_RA_REFRESH_N = 8,
+ FW_CMD_RA_REFRESH_BG = 9,
+ FW_CMD_RA_INIT = 10,
+ /* For FW supported IQK */
+ FW_CMD_IQK_INIT = 11,
+ /* Tx power tracking switch,
+ * MP driver only */
+ FW_CMD_TXPWR_TRACK_ENABLE = 12,
+ /* Tx power tracking switch,
+ * MP driver only */
+ FW_CMD_TXPWR_TRACK_DISABLE = 13,
+ /* Tx power tracking with thermal
+ * indication, for Normal driver */
+ FW_CMD_TXPWR_TRACK_THERMAL = 14,
+ FW_CMD_PAUSE_DM_BY_SCAN = 15,
+ FW_CMD_RESUME_DM_BY_SCAN = 16,
+ FW_CMD_RA_REFRESH_N_COMB = 17,
+ FW_CMD_RA_REFRESH_BG_COMB = 18,
+ FW_CMD_ANTENNA_SW_ENABLE = 19,
+ FW_CMD_ANTENNA_SW_DISABLE = 20,
+ /* Tx Status report for CCX from FW */
+ FW_CMD_TX_FEEDBACK_CCX_ENABLE = 21,
+ /* Indifate firmware that driver
+ * enters LPS, For PS-Poll issue */
+ FW_CMD_LPS_ENTER = 22,
+ /* Indicate firmware that driver
+ * leave LPS*/
+ FW_CMD_LPS_LEAVE = 23,
+ /* Set DIG mode to signal strength */
+ FW_CMD_DIG_MODE_SS = 24,
+ /* Set DIG mode to false alarm. */
+ FW_CMD_DIG_MODE_FA = 25,
+ FW_CMD_ADD_A2_ENTRY = 26,
+ FW_CMD_CTRL_DM_BY_DRIVER = 27,
+ FW_CMD_CTRL_DM_BY_DRIVER_NEW = 28,
+ FW_CMD_PAPE_CONTROL = 29,
+ FW_CMD_IQK_ENABLE = 30,
+};
+
+/*
+ * Driver info contain PHY status
+ * and other variabel size info
+ * PHY Status content as below
+ */
+struct rx_fwinfo {
+ /* DWORD 0 */
+ u8 gain_trsw[4];
+ /* DWORD 1 */
+ u8 pwdb_all;
+ u8 cfosho[4];
+ /* DWORD 2 */
+ u8 cfotail[4];
+ /* DWORD 3 */
+ s8 rxevm[2];
+ s8 rxsnr[4];
+ /* DWORD 4 */
+ u8 pdsnr[2];
+ /* DWORD 5 */
+ u8 csi_current[2];
+ u8 csi_target[2];
+ /* DWORD 6 */
+ u8 sigevm;
+ u8 max_ex_pwr;
+ u8 ex_intf_flag:1;
+ u8 sgi_en:1;
+ u8 rxsc:2;
+ u8 reserve:4;
+};
+
+struct phy_sts_cck_8192s_t {
+ u8 adc_pwdb_x[4];
+ u8 sq_rpt;
+ u8 cck_agc_rpt;
+};
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
new file mode 100644
index 0000000..da86db8
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -0,0 +1,733 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+
+struct dig_t digtable;
+static const u32 edca_setting_dl[PEER_MAX] = {
+ 0xa44f, /* 0 UNKNOWN */
+ 0x5ea44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0xa630, /* 3 BROAD */
+ 0xa44f, /* 4 RAL */
+ 0xa630, /* 5 ATH */
+ 0xa630, /* 6 CISCO */
+ 0xa42b, /* 7 MARV */
+};
+
+static const u32 edca_setting_dl_gmode[PEER_MAX] = {
+ 0x4322, /* 0 UNKNOWN */
+ 0xa44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0xa42b, /* 3 BROAD */
+ 0x5e4322, /* 4 RAL */
+ 0x4322, /* 5 ATH */
+ 0xa430, /* 6 CISCO */
+ 0x5ea44f, /* 7 MARV */
+};
+
+static const u32 edca_setting_ul[PEER_MAX] = {
+ 0x5e4322, /* 0 UNKNOWN */
+ 0xa44f, /* 1 REALTEK_90 */
+ 0x5ea44f, /* 2 REALTEK_92SE */
+ 0x5ea322, /* 3 BROAD */
+ 0x5ea422, /* 4 RAL */
+ 0x5ea322, /* 5 ATH */
+ 0x3ea44f, /* 6 CISCO */
+ 0x5ea44f, /* 7 MARV */
+};
+
+static void _rtl92s_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+ static u64 last_txok_cnt;
+ static u64 last_rxok_cnt;
+ u64 cur_txok_cnt = 0;
+ u64 cur_rxok_cnt = 0;
+
+ u32 edca_be_ul = edca_setting_ul[mac->vendor];
+ u32 edca_be_dl = edca_setting_dl[mac->vendor];
+ u32 edca_gmode = edca_setting_dl_gmode[mac->vendor];
+
+ if (mac->link_state != MAC80211_LINKED) {
+ rtlpriv->dm.current_turbo_edca = false;
+ goto dm_checkedcaturbo_exit;
+ }
+
+ if ((!rtlpriv->dm.is_any_nonbepkts) &&
+ (!rtlpriv->dm.disable_framebursting)) {
+ cur_txok_cnt = rtlpriv->stats.txbytesunicast - last_txok_cnt;
+ cur_rxok_cnt = rtlpriv->stats.rxbytesunicast - last_rxok_cnt;
+
+ if (rtlpriv->phy.rf_type == RF_1T2R) {
+ if (cur_txok_cnt > 4 * cur_rxok_cnt) {
+ /* Uplink TP is present. */
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv, EDCAPARA_BE,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ } else {/* Balance TP is present. */
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ if (mac->mode == WIRELESS_MODE_G ||
+ mac->mode == WIRELESS_MODE_B)
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_gmode);
+ else
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ } else {
+ if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+ if (!rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ if (mac->mode == WIRELESS_MODE_G ||
+ mac->mode == WIRELESS_MODE_B)
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_gmode);
+ else
+ rtl_write_dword(rtlpriv,
+ EDCAPARA_BE,
+ edca_be_dl);
+ rtlpriv->dm.is_cur_rdlstate = true;
+ }
+ } else {
+ if (rtlpriv->dm.is_cur_rdlstate ||
+ !rtlpriv->dm.current_turbo_edca) {
+ rtl_write_dword(rtlpriv, EDCAPARA_BE,
+ edca_be_ul);
+ rtlpriv->dm.is_cur_rdlstate = false;
+ }
+ }
+ rtlpriv->dm.current_turbo_edca = true;
+ }
+ } else {
+ if (rtlpriv->dm.current_turbo_edca) {
+ u8 tmp = AC0_BE;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AC_PARAM,
+ (u8 *)(&tmp));
+ rtlpriv->dm.current_turbo_edca = false;
+ }
+ }
+
+dm_checkedcaturbo_exit:
+ rtlpriv->dm.is_any_nonbepkts = false;
+ last_txok_cnt = rtlpriv->stats.txbytesunicast;
+ last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void _rtl92s_dm_txpowertracking_callback_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 thermalvalue = 0;
+
+ rtlpriv->dm.txpower_trackinginit = true;
+
+ thermalvalue = (u8)rtl_get_rfreg(hw, RF90_PATH_A, RF_T_METER, 0x1f);
+
+ RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+ ("Readback Thermal Meter = 0x%x pre thermal meter 0x%x "
+ "eeprom_thermalmeter 0x%x\n", thermalvalue,
+ rtlpriv->dm.thermalvalue, rtlefuse->eeprom_thermalmeter));
+
+ if (thermalvalue) {
+ rtlpriv->dm.thermalvalue = thermalvalue;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_TXPWR_TRACK_THERMAL);
+ }
+
+ rtlpriv->dm.txpowercount = 0;
+}
+
+static void _rtl92s_dm_check_txpowertracking_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ static u8 tm_trigger;
+ u8 tx_power_checkcnt = 5;
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.txpower_tracking)
+ return;
+
+ if (rtlpriv->dm.txpowercount <= tx_power_checkcnt) {
+ rtlpriv->dm.txpowercount++;
+ return;
+ }
+
+ if (!tm_trigger) {
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_T_METER,
+ RFREG_OFFSET_MASK, 0x60);
+ tm_trigger = 1;
+ } else {
+ _rtl92s_dm_txpowertracking_callback_thermalmeter(hw);
+ tm_trigger = 0;
+ }
+}
+
+static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+
+ u32 low_rssi_thresh = 0;
+ u32 middle_rssi_thresh = 0;
+ u32 high_rssi_thresh = 0;
+ u8 rssi_level;
+ struct ieee80211_sta *sta = NULL;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if (!rtlpriv->dm.useramask)
+ return;
+
+ if (!rtlpriv->dm.inform_fw_driverctrldm) {
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_CTRL_DM_BY_DRIVER);
+ rtlpriv->dm.inform_fw_driverctrldm = true;
+ }
+
+ rcu_read_lock();
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ sta = get_sta(hw, mac->vif, mac->bssid);
+ if ((mac->link_state == MAC80211_LINKED) &&
+ (mac->opmode == NL80211_IFTYPE_STATION)) {
+ switch (ra->pre_ratr_state) {
+ case DM_RATR_STA_HIGH:
+ high_rssi_thresh = 40;
+ middle_rssi_thresh = 30;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_MIDDLE:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 30;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_LOW:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 20;
+ break;
+ case DM_RATR_STA_ULTRALOW:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 24;
+ break;
+ default:
+ high_rssi_thresh = 44;
+ middle_rssi_thresh = 34;
+ low_rssi_thresh = 24;
+ break;
+ }
+
+ if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)high_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_HIGH;
+ rssi_level = 1;
+ } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)middle_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_LOW;
+ rssi_level = 3;
+ } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
+ (long)low_rssi_thresh) {
+ ra->ratr_state = DM_RATR_STA_LOW;
+ rssi_level = 5;
+ } else {
+ ra->ratr_state = DM_RATR_STA_ULTRALOW;
+ rssi_level = 6;
+ }
+
+ if (ra->pre_ratr_state != ra->ratr_state) {
+ RT_TRACE(rtlpriv, COMP_RATE, DBG_LOUD, ("RSSI = %ld "
+ "RSSI_LEVEL = %d PreState = %d, CurState = %d\n",
+ rtlpriv->dm.undecorated_smoothed_pwdb,
+ ra->ratr_state,
+ ra->pre_ratr_state, ra->ratr_state));
+
+ rtlpriv->cfg->ops->update_rate_tbl(hw, sta,
+ ra->ratr_state);
+ ra->pre_ratr_state = ra->ratr_state;
+ }
+ }
+ rcu_read_unlock();
+}
+
+static void _rtl92s_dm_switch_baseband_mrc(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ bool current_mrc;
+ bool enable_mrc = true;
+ long tmpentry_maxpwdb = 0;
+ u8 rssi_a = 0;
+ u8 rssi_b = 0;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ if ((rtlphy->rf_type == RF_1T1R) || (rtlphy->rf_type == RF_2T2R))
+ return;
+
+ rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_MRC, (u8 *)(¤t_mrc));
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (rtlpriv->dm.undecorated_smoothed_pwdb > tmpentry_maxpwdb) {
+ rssi_a = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_A];
+ rssi_b = rtlpriv->stats.rx_rssi_percentage[RF90_PATH_B];
+ }
+ }
+
+ /* MRC settings would NOT affect TP on Wireless B mode. */
+ if (mac->mode != WIRELESS_MODE_B) {
+ if ((rssi_a == 0) && (rssi_b == 0)) {
+ enable_mrc = true;
+ } else if (rssi_b > 30) {
+ /* Turn on B-Path */
+ enable_mrc = true;
+ } else if (rssi_b < 5) {
+ /* Turn off B-path */
+ enable_mrc = false;
+ /* Take care of RSSI differentiation. */
+ } else if (rssi_a > 15 && (rssi_a >= rssi_b)) {
+ if ((rssi_a - rssi_b) > 15)
+ /* Turn off B-path */
+ enable_mrc = false;
+ else if ((rssi_a - rssi_b) < 10)
+ /* Turn on B-Path */
+ enable_mrc = true;
+ else
+ enable_mrc = current_mrc;
+ } else {
+ /* Turn on B-Path */
+ enable_mrc = true;
+ }
+ }
+
+ /* Update MRC settings if needed. */
+ if (enable_mrc != current_mrc)
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC,
+ (u8 *)&enable_mrc);
+
+}
+
+void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.current_turbo_edca = false;
+ rtlpriv->dm.is_any_nonbepkts = false;
+ rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+static void _rtl92s_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rate_adaptive *ra = &(rtlpriv->ra);
+
+ ra->ratr_state = DM_RATR_STA_MAX;
+ ra->pre_ratr_state = DM_RATR_STA_MAX;
+
+ if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+ rtlpriv->dm.useramask = true;
+ else
+ rtlpriv->dm.useramask = false;
+
+ rtlpriv->dm.useramask = false;
+ rtlpriv->dm.inform_fw_driverctrldm = false;
+}
+
+static void _rtl92s_dm_init_txpowertracking_thermalmeter(
+ struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.txpower_tracking = true;
+ rtlpriv->dm.txpowercount = 0;
+ rtlpriv->dm.txpower_trackinginit = false;
+}
+
+static void _rtl92s_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+ u32 ret_value;
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+ falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+ falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+ falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+ ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+ falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+
+ falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+ falsealm_cnt->cnt_rate_illegal + falsealm_cnt->cnt_crc8_fail +
+ falsealm_cnt->cnt_mcs_fail;
+
+ /* read CCK false alarm */
+ ret_value = rtl_get_bbreg(hw, 0xc64, MASKDWORD);
+ falsealm_cnt->cnt_cck_fail = (ret_value & 0xffff);
+ falsealm_cnt->cnt_all = falsealm_cnt->cnt_ofdm_fail +
+ falsealm_cnt->cnt_cck_fail;
+}
+
+static void rtl92s_backoff_enable_flag(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+ if (falsealm_cnt->cnt_all > digtable.fa_highthresh) {
+ if ((digtable.backoff_val - 6) <
+ digtable.backoffval_range_min)
+ digtable.backoff_val = digtable.backoffval_range_min;
+ else
+ digtable.backoff_val -= 6;
+ } else if (falsealm_cnt->cnt_all < digtable.fa_lowthresh) {
+ if ((digtable.backoff_val + 6) >
+ digtable.backoffval_range_max)
+ digtable.backoff_val =
+ digtable.backoffval_range_max;
+ else
+ digtable.backoff_val += 6;
+ }
+}
+
+static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+ static u8 initialized, force_write;
+ u8 initial_gain = 0;
+
+ if ((digtable.pre_sta_connectstate == digtable.cur_sta_connectstate) ||
+ (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT)) {
+ if (digtable.cur_sta_connectstate == DIG_STA_BEFORE_CONNECT) {
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (digtable.backoff_enable_flag == true)
+ rtl92s_backoff_enable_flag(hw);
+ else
+ digtable.backoff_val = DM_DIG_BACKOFF;
+
+ if ((digtable.rssi_val + 10 - digtable.backoff_val) >
+ digtable.rx_gain_range_max)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_max;
+ else if ((digtable.rssi_val + 10 - digtable.backoff_val)
+ < digtable.rx_gain_range_min)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_min;
+ else
+ digtable.cur_igvalue = digtable.rssi_val + 10 -
+ digtable.backoff_val;
+
+ if (falsealm_cnt->cnt_all > 10000)
+ digtable.cur_igvalue =
+ (digtable.cur_igvalue > 0x33) ?
+ digtable.cur_igvalue : 0x33;
+
+ if (falsealm_cnt->cnt_all > 16000)
+ digtable.cur_igvalue =
+ digtable.rx_gain_range_max;
+ /* connected -> connected or disconnected -> disconnected */
+ } else {
+ /* Firmware control DIG, do nothing in driver dm */
+ return;
+ }
+ /* disconnected -> connected or connected ->
+ * disconnected or beforeconnect->(dis)connected */
+ } else {
+ /* Enable FW DIG */
+ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE);
+
+ digtable.backoff_val = DM_DIG_BACKOFF;
+ digtable.cur_igvalue = rtlpriv->phy.default_initialgain[0];
+ digtable.pre_igvalue = 0;
+ return;
+ }
+
+ /* Forced writing to prevent from fw-dig overwriting. */
+ if (digtable.pre_igvalue != rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1,
+ MASKBYTE0))
+ force_write = 1;
+
+ if ((digtable.pre_igvalue != digtable.cur_igvalue) ||
+ !initialized || force_write) {
+ /* Disable FW DIG */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_DISABLE);
+
+ initial_gain = (u8)digtable.cur_igvalue;
+
+ /* Set initial gain. */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, initial_gain);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, initial_gain);
+ digtable.pre_igvalue = digtable.cur_igvalue;
+ initialized = 1;
+ force_write = 0;
+ }
+}
+
+static void _rtl92s_dm_ctrl_initgain_bytwoport(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->mac80211.act_scanning)
+ return;
+
+ /* Decide the current status and if modify initial gain or not */
+ if (rtlpriv->mac80211.link_state >= MAC80211_LINKED ||
+ rtlpriv->mac80211.opmode == NL80211_IFTYPE_ADHOC)
+ digtable.cur_sta_connectstate = DIG_STA_CONNECT;
+ else
+ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT;
+
+ digtable.rssi_val = rtlpriv->dm.undecorated_smoothed_pwdb;
+
+ /* Change dig mode to rssi */
+ if (digtable.cur_sta_connectstate != DIG_STA_DISCONNECT) {
+ if (digtable.dig_twoport_algorithm ==
+ DIG_TWO_PORT_ALGO_FALSE_ALARM) {
+ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_MODE_SS);
+ }
+ }
+
+ _rtl92s_dm_false_alarm_counter_statistics(hw);
+ _rtl92s_dm_initial_gain_sta_beforeconnect(hw);
+
+ digtable.pre_sta_connectstate = digtable.cur_sta_connectstate;
+}
+
+static void _rtl92s_dm_ctrl_initgain_byrssi(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.dm_initialgain_enable)
+ return;
+
+ if (digtable.dig_enable_flag == false)
+ return;
+
+ _rtl92s_dm_ctrl_initgain_bytwoport(hw);
+}
+
+static void _rtl92s_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undecorated_smoothed_pwdb;
+ long txpwr_threshold_lv1, txpwr_threshold_lv2;
+
+ /* 2T2R TP issue */
+ if (rtlphy->rf_type == RF_2T2R)
+ return;
+
+ if (!rtlpriv->dm.dynamic_txpower_enable ||
+ rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ return;
+ }
+
+ if ((mac->link_state < MAC80211_LINKED) &&
+ (rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb == 0)) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+ ("Not connected to any\n"));
+
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+
+ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ return;
+ }
+
+ if (mac->link_state >= MAC80211_LINKED) {
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Client PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("STA Default Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+ } else {
+ undecorated_smoothed_pwdb =
+ rtlpriv->dm.entry_min_undecoratedsmoothed_pwdb;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("AP Ext Port PWDB = 0x%lx\n",
+ undecorated_smoothed_pwdb));
+ }
+
+ txpwr_threshold_lv2 = TX_POWER_NEAR_FIELD_THRESH_LVL2;
+ txpwr_threshold_lv1 = TX_POWER_NEAR_FIELD_THRESH_LVL1;
+
+ if (rtl_get_bbreg(hw, 0xc90, MASKBYTE0) == 1)
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ else if (undecorated_smoothed_pwdb >= txpwr_threshold_lv2)
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL2;
+ else if ((undecorated_smoothed_pwdb < (txpwr_threshold_lv2 - 3)) &&
+ (undecorated_smoothed_pwdb >= txpwr_threshold_lv1))
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL1;
+ else if (undecorated_smoothed_pwdb < (txpwr_threshold_lv1 - 3))
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+
+ if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl))
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+
+ rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ /* Disable DIG scheme now.*/
+ digtable.dig_enable_flag = true;
+ digtable.backoff_enable_flag = true;
+
+ if ((rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER) &&
+ (hal_get_firmwareversion(rtlpriv) >= 0x3c))
+ digtable.dig_algorithm = DIG_ALGO_BY_TOW_PORT;
+ else
+ digtable.dig_algorithm =
+ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM;
+
+ digtable.dig_twoport_algorithm = DIG_TWO_PORT_ALGO_RSSI;
+ digtable.dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ /* off=by real rssi value, on=by digtable.rssi_val for new dig */
+ digtable.dig_dbgmode = DM_DBG_OFF;
+ digtable.dig_slgorithm_switch = 0;
+
+ /* 2007/10/04 MH Define init gain threshol. */
+ digtable.dig_state = DM_STA_DIG_MAX;
+ digtable.dig_highpwrstate = DM_STA_DIG_MAX;
+
+ digtable.cur_sta_connectstate = DIG_STA_DISCONNECT;
+ digtable.pre_sta_connectstate = DIG_STA_DISCONNECT;
+ digtable.cur_ap_connectstate = DIG_AP_DISCONNECT;
+ digtable.pre_ap_connectstate = DIG_AP_DISCONNECT;
+
+ digtable.rssi_lowthresh = DM_DIG_THRESH_LOW;
+ digtable.rssi_highthresh = DM_DIG_THRESH_HIGH;
+
+ digtable.fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ digtable.fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+
+ digtable.rssi_highpower_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
+ digtable.rssi_highpower_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
+
+ /* for dig debug rssi value */
+ digtable.rssi_val = 50;
+ digtable.backoff_val = DM_DIG_BACKOFF;
+ digtable.rx_gain_range_max = DM_DIG_MAX;
+
+ digtable.rx_gain_range_min = DM_DIG_MIN;
+
+ digtable.backoffval_range_max = DM_DIG_BACKOFF_MAX;
+ digtable.backoffval_range_min = DM_DIG_BACKOFF_MIN;
+}
+
+static void _rtl92s_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if ((hal_get_firmwareversion(rtlpriv) >= 60) &&
+ (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER))
+ rtlpriv->dm.dynamic_txpower_enable = true;
+ else
+ rtlpriv->dm.dynamic_txpower_enable = false;
+
+ rtlpriv->dm.last_dtp_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+ rtlpriv->dm.dynamic_txhighpower_lvl = TX_HIGHPWR_LEVEL_NORMAL;
+}
+
+void rtl92s_dm_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+ rtlpriv->dm.undecorated_smoothed_pwdb = -1;
+
+ _rtl92s_dm_init_dynamic_txpower(hw);
+ rtl92s_dm_init_edca_turbo(hw);
+ _rtl92s_dm_init_rate_adaptive_mask(hw);
+ _rtl92s_dm_init_txpowertracking_thermalmeter(hw);
+ _rtl92s_dm_init_dig(hw);
+
+ rtl_write_dword(rtlpriv, WFM5, FW_CCA_CHK_ENABLE);
+}
+
+void rtl92s_dm_watchdog(struct ieee80211_hw *hw)
+{
+ _rtl92s_dm_check_edca_turbo(hw);
+ _rtl92s_dm_check_txpowertracking_thermalmeter(hw);
+ _rtl92s_dm_ctrl_initgain_byrssi(hw);
+ _rtl92s_dm_dynamic_txpower(hw);
+ _rtl92s_dm_refresh_rateadaptive_mask(hw);
+ _rtl92s_dm_switch_baseband_mrc(hw);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
new file mode 100644
index 0000000..9051a55
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
@@ -0,0 +1,164 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __RTL_92S_DM_H__
+#define __RTL_92S_DM_H__
+
+struct dig_t {
+ u8 dig_enable_flag;
+ u8 dig_algorithm;
+ u8 dig_twoport_algorithm;
+ u8 dig_ext_port_stage;
+ u8 dig_dbgmode;
+ u8 dig_slgorithm_switch;
+
+ long rssi_lowthresh;
+ long rssi_highthresh;
+
+ u32 fa_lowthresh;
+ u32 fa_highthresh;
+
+ long rssi_highpower_lowthresh;
+ long rssi_highpower_highthresh;
+
+ u8 dig_state;
+ u8 dig_highpwrstate;
+ u8 cur_sta_connectstate;
+ u8 pre_sta_connectstate;
+ u8 cur_ap_connectstate;
+ u8 pre_ap_connectstate;
+
+ u8 cur_pd_thstate;
+ u8 pre_pd_thstate;
+ u8 cur_cs_ratiostate;
+ u8 pre_cs_ratiostate;
+
+ u32 pre_igvalue;
+ u32 cur_igvalue;
+
+ u8 backoff_enable_flag;
+ char backoff_val;
+ char backoffval_range_max;
+ char backoffval_range_min;
+ u8 rx_gain_range_max;
+ u8 rx_gain_range_min;
+
+ long rssi_val;
+};
+
+enum dm_dig_alg {
+ DIG_ALGO_BY_FALSE_ALARM = 0,
+ DIG_ALGO_BY_RSSI = 1,
+ DIG_ALGO_BEFORE_CONNECT_BY_RSSI_AND_ALARM = 2,
+ DIG_ALGO_BY_TOW_PORT = 3,
+ DIG_ALGO_MAX
+};
+
+enum dm_dig_two_port_alg {
+ DIG_TWO_PORT_ALGO_RSSI = 0,
+ DIG_TWO_PORT_ALGO_FALSE_ALARM = 1,
+};
+
+enum dm_dig_dbg {
+ DM_DBG_OFF = 0,
+ DM_DBG_ON = 1,
+ DM_DBG_MAX
+};
+
+enum dm_dig_sta {
+ DM_STA_DIG_OFF = 0,
+ DM_STA_DIG_ON,
+ DM_STA_DIG_MAX
+};
+
+enum dm_dig_connect {
+ DIG_STA_DISCONNECT = 0,
+ DIG_STA_CONNECT = 1,
+ DIG_STA_BEFORE_CONNECT = 2,
+ DIG_AP_DISCONNECT = 3,
+ DIG_AP_CONNECT = 4,
+ DIG_AP_ADD_STATION = 5,
+ DIG_CONNECT_MAX
+};
+
+enum dm_dig_ext_port_alg {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_ratr_sta {
+ DM_RATR_STA_HIGH = 0,
+ DM_RATR_STA_MIDDLEHIGH = 1,
+ DM_RATR_STA_MIDDLE = 2,
+ DM_RATR_STA_MIDDLELOW = 3,
+ DM_RATR_STA_LOW = 4,
+ DM_RATR_STA_ULTRALOW = 5,
+ DM_RATR_STA_MAX
+};
+
+#define DM_TYPE_BYFW 0
+#define DM_TYPE_BYDRIVER 1
+
+#define TX_HIGH_PWR_LEVEL_NORMAL 0
+#define TX_HIGH_PWR_LEVEL_LEVEL1 1
+#define TX_HIGH_PWR_LEVEL_LEVEL2 2
+
+#define HAL_DM_DIG_DISABLE BIT(0) /* Disable Dig */
+#define HAL_DM_HIPWR_DISABLE BIT(1) /* Disable High Power */
+
+#define TX_HIGHPWR_LEVEL_NORMAL 0
+#define TX_HIGHPWR_LEVEL_NORMAL1 1
+#define TX_HIGHPWR_LEVEL_NORMAL2 2
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+#define DM_FALSEALARM_THRESH_LOW 40
+#define DM_FALSEALARM_THRESH_HIGH 1000
+#define DM_DIG_HIGH_PWR_THRESH_HIGH 75
+#define DM_DIG_HIGH_PWR_THRESH_LOW 70
+#define DM_DIG_BACKOFF 12
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1c
+#define DM_DIG_MIN_Netcore 0x12
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+
+extern struct dig_t digtable;
+
+void rtl92s_dm_watchdog(struct ieee80211_hw *hw);
+void rtl92s_dm_init(struct ieee80211_hw *hw);
+void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.c b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
new file mode 100644
index 0000000..3b5af01
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.c
@@ -0,0 +1,654 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+
+static void _rtl92s_fw_set_rqpn(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ rtl_write_dword(rtlpriv, RQPN, 0xffffffff);
+ rtl_write_dword(rtlpriv, RQPN + 4, 0xffffffff);
+ rtl_write_byte(rtlpriv, RQPN + 8, 0xff);
+ rtl_write_byte(rtlpriv, RQPN + 0xB, 0x80);
+}
+
+static bool _rtl92s_firmware_enable_cpu(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 ichecktime = 200;
+ u16 tmpu2b;
+ u8 tmpu1b, cpustatus = 0;
+
+ _rtl92s_fw_set_rqpn(hw);
+
+ /* Enable CPU. */
+ tmpu1b = rtl_read_byte(rtlpriv, SYS_CLKR);
+ /* AFE source */
+ rtl_write_byte(rtlpriv, SYS_CLKR, (tmpu1b | SYS_CPU_CLKSEL));
+
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | FEN_CPUEN));
+
+ /* Polling IMEM Ready after CPU has refilled. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & IMEM_RDY) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("IMEM Ready after CPU has refilled.\n"));
+ break;
+ }
+
+ udelay(100);
+ } while (ichecktime--);
+
+ if (!(cpustatus & IMEM_RDY))
+ return false;
+
+ return true;
+}
+
+static enum fw_status _rtl92s_firmware_get_nextstatus(
+ enum fw_status fw_currentstatus)
+{
+ enum fw_status next_fwstatus = 0;
+
+ switch (fw_currentstatus) {
+ case FW_STATUS_INIT:
+ next_fwstatus = FW_STATUS_LOAD_IMEM;
+ break;
+ case FW_STATUS_LOAD_IMEM:
+ next_fwstatus = FW_STATUS_LOAD_EMEM;
+ break;
+ case FW_STATUS_LOAD_EMEM:
+ next_fwstatus = FW_STATUS_LOAD_DMEM;
+ break;
+ case FW_STATUS_LOAD_DMEM:
+ next_fwstatus = FW_STATUS_READY;
+ break;
+ default:
+ break;
+ }
+
+ return next_fwstatus;
+}
+
+static u8 _rtl92s_firmware_header_map_rftype(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (rtlphy->rf_type) {
+ case RF_1T1R:
+ return 0x11;
+ break;
+ case RF_1T2R:
+ return 0x12;
+ break;
+ case RF_2T2R:
+ return 0x22;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Unknown RF type(%x)\n",
+ rtlphy->rf_type));
+ break;
+ }
+ return 0x22;
+}
+
+static void _rtl92s_firmwareheader_priveupdate(struct ieee80211_hw *hw,
+ struct fw_priv *pfw_priv)
+{
+ /* Update RF types for RATR settings. */
+ pfw_priv->rf_config = _rtl92s_firmware_header_map_rftype(hw);
+}
+
+
+
+static bool _rtl92s_cmd_send_packet(struct ieee80211_hw *hw,
+ struct sk_buff *skb, u8 last)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl8192_tx_ring *ring;
+ struct rtl_tx_desc *pdesc;
+ unsigned long flags;
+ u8 idx = 0;
+
+ ring = &rtlpci->tx_ring[TXCMD_QUEUE];
+
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+ idx = (ring->idx + skb_queue_len(&ring->queue)) % ring->entries;
+ pdesc = &ring->desc[idx];
+ rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *)pdesc, 1, 1, skb);
+ __skb_queue_tail(&ring->queue, skb);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+ return true;
+}
+
+static bool _rtl92s_firmware_downloadcode(struct ieee80211_hw *hw,
+ u8 *code_virtual_address, u32 buffer_len)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct sk_buff *skb;
+ struct rtl_tcb_desc *tcb_desc;
+ unsigned char *seg_ptr;
+ u16 frag_threshold = MAX_FIRMWARE_CODE_SIZE;
+ u16 frag_length, frag_offset = 0;
+ u16 extra_descoffset = 0;
+ u8 last_inipkt = 0;
+
+ _rtl92s_fw_set_rqpn(hw);
+
+ if (buffer_len >= MAX_FIRMWARE_CODE_SIZE) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Size over FIRMWARE_CODE_SIZE!\n"));
+
+ return false;
+ }
+
+ extra_descoffset = 0;
+
+ do {
+ if ((buffer_len - frag_offset) > frag_threshold) {
+ frag_length = frag_threshold + extra_descoffset;
+ } else {
+ frag_length = (u16)(buffer_len - frag_offset +
+ extra_descoffset);
+ last_inipkt = 1;
+ }
+
+ /* Allocate skb buffer to contain firmware */
+ /* info and tx descriptor info. */
+ skb = dev_alloc_skb(frag_length);
+ skb_reserve(skb, extra_descoffset);
+ seg_ptr = (u8 *)skb_put(skb, (u32)(frag_length -
+ extra_descoffset));
+ memcpy(seg_ptr, code_virtual_address + frag_offset,
+ (u32)(frag_length - extra_descoffset));
+
+ tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
+ tcb_desc->queue_index = TXCMD_QUEUE;
+ tcb_desc->cmd_or_init = DESC_PACKET_TYPE_INIT;
+ tcb_desc->last_inipkt = last_inipkt;
+
+ _rtl92s_cmd_send_packet(hw, skb, last_inipkt);
+
+ frag_offset += (frag_length - extra_descoffset);
+
+ } while (frag_offset < buffer_len);
+
+ rtl_write_byte(rtlpriv, TP_POLL, TPPOLL_CQ);
+
+ return true ;
+}
+
+static bool _rtl92s_firmware_checkready(struct ieee80211_hw *hw,
+ u8 loadfw_status)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rt_firmware *firmware = (struct rt_firmware *)rtlhal->pfirmware;
+ u32 tmpu4b;
+ u8 cpustatus = 0;
+ short pollingcnt = 1000;
+ bool rtstatus = true;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("LoadStaus(%d)\n",
+ loadfw_status));
+
+ firmware->fwstatus = (enum fw_status)loadfw_status;
+
+ switch (loadfw_status) {
+ case FW_STATUS_LOAD_IMEM:
+ /* Polling IMEM code done. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & IMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & IMEM_CHK_RPT) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("FW_STATUS_LOAD_IMEM"
+ " FAIL CPU, Status=%x\r\n", cpustatus));
+ goto status_check_fail;
+ }
+ break;
+
+ case FW_STATUS_LOAD_EMEM:
+ /* Check Put Code OK and Turn On CPU */
+ /* Polling EMEM code done. */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & EMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & EMEM_CHK_RPT) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("FW_STATUS_LOAD_EMEM"
+ " FAIL CPU, Status=%x\r\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ /* Turn On CPU */
+ rtstatus = _rtl92s_firmware_enable_cpu(hw);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Enable CPU fail!\n"));
+ goto status_check_fail;
+ }
+ break;
+
+ case FW_STATUS_LOAD_DMEM:
+ /* Polling DMEM code done */
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & DMEM_CODE_DONE)
+ break;
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (!(cpustatus & DMEM_CODE_DONE) || (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling DMEM code done"
+ " fail ! cpustatus(%#x)\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("DMEM code download success,"
+ " cpustatus(%#x)\n", cpustatus));
+
+ /* Prevent Delay too much and being scheduled out */
+ /* Polling Load Firmware ready */
+ pollingcnt = 2000;
+ do {
+ cpustatus = rtl_read_byte(rtlpriv, TCR);
+ if (cpustatus & FWRDY)
+ break;
+ udelay(40);
+ } while (pollingcnt--);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Polling Load Firmware ready,"
+ " cpustatus(%x)\n", cpustatus));
+
+ if (((cpustatus & LOAD_FW_READY) != LOAD_FW_READY) ||
+ (pollingcnt <= 0)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling Load Firmware"
+ " ready fail ! cpustatus(%x)\n", cpustatus));
+ goto status_check_fail;
+ }
+
+ /* If right here, we can set TCR/RCR to desired value */
+ /* and config MAC lookback mode to normal mode */
+ tmpu4b = rtl_read_dword(rtlpriv, TCR);
+ rtl_write_dword(rtlpriv, TCR, (tmpu4b & (~TCR_ICV)));
+
+ tmpu4b = rtl_read_dword(rtlpriv, RCR);
+ rtl_write_dword(rtlpriv, RCR, (tmpu4b | RCR_APPFCS |
+ RCR_APP_ICV | RCR_APP_MIC));
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Current RCR settings(%#x)\n", tmpu4b));
+
+ /* Set to normal mode. */
+ rtl_write_byte(rtlpriv, LBKMD_SEL, LBK_NORMAL);
+ break;
+
+ default:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Unknown status check!\n"));
+ rtstatus = false;
+ break;
+ }
+
+status_check_fail:
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("loadfw_status(%d), "
+ "rtstatus(%x)\n", loadfw_status, rtstatus));
+ return rtstatus;
+}
+
+int rtl92s_download_fw(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rt_firmware *firmware = NULL;
+ struct fw_hdr *pfwheader;
+ struct fw_priv *pfw_priv = NULL;
+ u8 *puc_mappedfile = NULL;
+ u32 ul_filelength = 0;
+ u32 file_length = 0;
+ u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
+ u8 fwstatus = FW_STATUS_INIT;
+ bool rtstatus = true;
+
+ if (!rtlhal->pfirmware)
+ return 1;
+
+ firmware = (struct rt_firmware *)rtlhal->pfirmware;
+ firmware->fwstatus = FW_STATUS_INIT;
+
+ puc_mappedfile = firmware->sz_fw_tmpbuffer;
+ file_length = firmware->sz_fw_tmpbufferlen;
+
+ /* 1. Retrieve FW header. */
+ firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
+ pfwheader = firmware->pfwheader;
+ firmware->firmwareversion = byte(pfwheader->version, 0);
+ firmware->pfwheader->fwpriv.hci_sel = 1;/* pcie */
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("signature:%x, version:"
+ "%x, size:%x,"
+ "imemsize:%x, sram size:%x\n", pfwheader->signature,
+ pfwheader->version, pfwheader->dmem_size,
+ pfwheader->img_imem_size, pfwheader->img_sram_size));
+
+ /* 2. Retrieve IMEM image. */
+ if ((pfwheader->img_imem_size == 0) || (pfwheader->img_imem_size >
+ sizeof(firmware->fw_imem))) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("memory for data image is less than IMEM required\n"));
+ goto fail;
+ } else {
+ puc_mappedfile += fwhdr_size;
+
+ memcpy(firmware->fw_imem, puc_mappedfile,
+ pfwheader->img_imem_size);
+ firmware->fw_imem_len = pfwheader->img_imem_size;
+ }
+
+ /* 3. Retriecve EMEM image. */
+ if (pfwheader->img_sram_size > sizeof(firmware->fw_emem)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("memory for data image is less than EMEM required\n"));
+ goto fail;
+ } else {
+ puc_mappedfile += firmware->fw_imem_len;
+
+ memcpy(firmware->fw_emem, puc_mappedfile,
+ pfwheader->img_sram_size);
+ firmware->fw_emem_len = pfwheader->img_sram_size;
+ }
+
+ /* 4. download fw now */
+ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
+ while (fwstatus != FW_STATUS_READY) {
+ /* Image buffer redirection. */
+ switch (fwstatus) {
+ case FW_STATUS_LOAD_IMEM:
+ puc_mappedfile = firmware->fw_imem;
+ ul_filelength = firmware->fw_imem_len;
+ break;
+ case FW_STATUS_LOAD_EMEM:
+ puc_mappedfile = firmware->fw_emem;
+ ul_filelength = firmware->fw_emem_len;
+ break;
+ case FW_STATUS_LOAD_DMEM:
+ /* Partial update the content of header private. */
+ pfwheader = firmware->pfwheader;
+ pfw_priv = &pfwheader->fwpriv;
+ _rtl92s_firmwareheader_priveupdate(hw, pfw_priv);
+ puc_mappedfile = (u8 *)(firmware->pfwheader) +
+ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
+ ul_filelength = fwhdr_size -
+ RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unexpected Download step!!\n"));
+ goto fail;
+ break;
+ }
+
+ /* <2> Download image file */
+ rtstatus = _rtl92s_firmware_downloadcode(hw, puc_mappedfile,
+ ul_filelength);
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n"));
+ goto fail;
+ }
+
+ /* <3> Check whether load FW process is ready */
+ rtstatus = _rtl92s_firmware_checkready(hw, fwstatus);
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("fail!\n"));
+ goto fail;
+ }
+
+ fwstatus = _rtl92s_firmware_get_nextstatus(firmware->fwstatus);
+ }
+
+ return rtstatus;
+fail:
+ return 0;
+}
+
+static u32 _rtl92s_fill_h2c_cmd(struct sk_buff *skb, u32 h2cbufferlen,
+ u32 cmd_num, u32 *pelement_id, u32 *pcmd_len,
+ u8 **pcmb_buffer, u8 *cmd_start_seq)
+{
+ u32 totallen = 0, len = 0, tx_desclen = 0;
+ u32 pre_continueoffset = 0;
+ u8 *ph2c_buffer;
+ u8 i = 0;
+
+ do {
+ /* 8 - Byte aligment */
+ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
+
+ /* Buffer length is not enough */
+ if (h2cbufferlen < totallen + len + tx_desclen)
+ break;
+
+ /* Clear content */
+ ph2c_buffer = (u8 *)skb_put(skb, (u32)len);
+ memset((ph2c_buffer + totallen + tx_desclen), 0, len);
+
+ /* CMD len */
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 0, 16, pcmd_len[i]);
+
+ /* CMD ID */
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 16, 8, pelement_id[i]);
+
+ /* CMD Sequence */
+ *cmd_start_seq = *cmd_start_seq % 0x80;
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + totallen + tx_desclen),
+ 24, 7, *cmd_start_seq);
+ ++*cmd_start_seq;
+
+ /* Copy memory */
+ memcpy((ph2c_buffer + totallen + tx_desclen +
+ H2C_TX_CMD_HDR_LEN), pcmb_buffer[i], pcmd_len[i]);
+
+ /* CMD continue */
+ /* set the continue in prevoius cmd. */
+ if (i < cmd_num - 1)
+ SET_BITS_TO_LE_4BYTE((ph2c_buffer + pre_continueoffset),
+ 31, 1, 1);
+
+ pre_continueoffset = totallen;
+
+ totallen += len;
+ } while (++i < cmd_num);
+
+ return totallen;
+}
+
+static u32 _rtl92s_get_h2c_cmdlen(u32 h2cbufferlen, u32 cmd_num, u32 *pcmd_len)
+{
+ u32 totallen = 0, len = 0, tx_desclen = 0;
+ u8 i = 0;
+
+ do {
+ /* 8 - Byte aligment */
+ len = H2C_TX_CMD_HDR_LEN + N_BYTE_ALIGMENT(pcmd_len[i], 8);
+
+ /* Buffer length is not enough */
+ if (h2cbufferlen < totallen + len + tx_desclen)
+ break;
+
+ totallen += len;
+ } while (++i < cmd_num);
+
+ return totallen + tx_desclen;
+}
+
+static bool _rtl92s_firmware_set_h2c_cmd(struct ieee80211_hw *hw, u8 h2c_cmd,
+ u8 *pcmd_buffer)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_tcb_desc *cb_desc;
+ struct sk_buff *skb;
+ u32 element_id = 0;
+ u32 cmd_len = 0;
+ u32 len;
+
+ switch (h2c_cmd) {
+ case FW_H2C_SETPWRMODE:
+ element_id = H2C_SETPWRMODE_CMD ;
+ cmd_len = sizeof(struct h2c_set_pwrmode_parm);
+ break;
+ case FW_H2C_JOINBSSRPT:
+ element_id = H2C_JOINBSSRPT_CMD;
+ cmd_len = sizeof(struct h2c_joinbss_rpt_parm);
+ break;
+ case FW_H2C_WOWLAN_UPDATE_GTK:
+ element_id = H2C_WOWLAN_UPDATE_GTK_CMD;
+ cmd_len = sizeof(struct h2c_wpa_two_way_parm);
+ break;
+ case FW_H2C_WOWLAN_UPDATE_IV:
+ element_id = H2C_WOWLAN_UPDATE_IV_CMD;
+ cmd_len = sizeof(unsigned long long);
+ break;
+ case FW_H2C_WOWLAN_OFFLOAD:
+ element_id = H2C_WOWLAN_FW_OFFLOAD;
+ cmd_len = sizeof(u8);
+ break;
+ default:
+ break;
+ }
+
+ len = _rtl92s_get_h2c_cmdlen(MAX_TRANSMIT_BUFFER_SIZE, 1, &cmd_len);
+ skb = dev_alloc_skb(len);
+ cb_desc = (struct rtl_tcb_desc *)(skb->cb);
+ cb_desc->queue_index = TXCMD_QUEUE;
+ cb_desc->cmd_or_init = DESC_PACKET_TYPE_NORMAL;
+ cb_desc->last_inipkt = false;
+
+ _rtl92s_fill_h2c_cmd(skb, MAX_TRANSMIT_BUFFER_SIZE, 1, &element_id,
+ &cmd_len, &pcmd_buffer, &rtlhal->h2c_txcmd_seq);
+ _rtl92s_cmd_send_packet(hw, skb, false);
+ rtlpriv->cfg->ops->tx_polling(hw, TXCMD_QUEUE);
+
+ return true;
+}
+
+void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 Mode)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct h2c_set_pwrmode_parm pwrmode;
+ u16 max_wakeup_period = 0;
+
+ pwrmode.mode = Mode;
+ pwrmode.flag_low_traffic_en = 0;
+ pwrmode.flag_lpnav_en = 0;
+ pwrmode.flag_rf_low_snr_en = 0;
+ pwrmode.flag_dps_en = 0;
+ pwrmode.bcn_rx_en = 0;
+ pwrmode.bcn_to = 0;
+ SET_BITS_TO_LE_2BYTE((u8 *)(&pwrmode) + 8, 0, 16,
+ mac->vif->bss_conf.beacon_int);
+ pwrmode.app_itv = 0;
+ pwrmode.awake_bcn_itvl = ppsc->reg_max_lps_awakeintvl;
+ pwrmode.smart_ps = 1;
+ pwrmode.bcn_pass_period = 10;
+
+ /* Set beacon pass count */
+ if (pwrmode.mode == FW_PS_MIN_MODE)
+ max_wakeup_period = mac->vif->bss_conf.beacon_int;
+ else if (pwrmode.mode == FW_PS_MAX_MODE)
+ max_wakeup_period = mac->vif->bss_conf.beacon_int *
+ mac->vif->bss_conf.dtim_period;
+
+ if (max_wakeup_period >= 500)
+ pwrmode.bcn_pass_cnt = 1;
+ else if ((max_wakeup_period >= 300) && (max_wakeup_period < 500))
+ pwrmode.bcn_pass_cnt = 2;
+ else if ((max_wakeup_period >= 200) && (max_wakeup_period < 300))
+ pwrmode.bcn_pass_cnt = 3;
+ else if ((max_wakeup_period >= 20) && (max_wakeup_period < 200))
+ pwrmode.bcn_pass_cnt = 5;
+ else
+ pwrmode.bcn_pass_cnt = 1;
+
+ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_SETPWRMODE, (u8 *)&pwrmode);
+
+}
+
+void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus, u8 ps_qosinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct h2c_joinbss_rpt_parm joinbss_rpt;
+
+ joinbss_rpt.opmode = mstatus;
+ joinbss_rpt.ps_qos_info = ps_qosinfo;
+ joinbss_rpt.bssid[0] = mac->bssid[0];
+ joinbss_rpt.bssid[1] = mac->bssid[1];
+ joinbss_rpt.bssid[2] = mac->bssid[2];
+ joinbss_rpt.bssid[3] = mac->bssid[3];
+ joinbss_rpt.bssid[4] = mac->bssid[4];
+ joinbss_rpt.bssid[5] = mac->bssid[5];
+ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 8, 0, 16,
+ mac->vif->bss_conf.beacon_int);
+ SET_BITS_TO_LE_2BYTE((u8 *)(&joinbss_rpt) + 10, 0, 16, mac->assoc_id);
+
+ _rtl92s_firmware_set_h2c_cmd(hw, FW_H2C_JOINBSSRPT, (u8 *)&joinbss_rpt);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/fw.h b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
new file mode 100644
index 0000000..74cc503
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/fw.h
@@ -0,0 +1,375 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_FIRMWARE92S_H__
+#define __REALTEK_FIRMWARE92S_H__
+
+#define RTL8190_MAX_FIRMWARE_CODE_SIZE 64000
+#define RTL8190_CPU_START_OFFSET 0x80
+/* Firmware Local buffer size. 64k */
+#define MAX_FIRMWARE_CODE_SIZE 0xFF00
+
+#define RT_8192S_FIRMWARE_HDR_SIZE 80
+#define RT_8192S_FIRMWARE_HDR_EXCLUDE_PRI_SIZE 32
+
+/* support till 64 bit bus width OS */
+#define MAX_DEV_ADDR_SIZE 8
+#define MAX_FIRMWARE_INFORMATION_SIZE 32
+#define MAX_802_11_HEADER_LENGTH (40 + \
+ MAX_FIRMWARE_INFORMATION_SIZE)
+#define ENCRYPTION_MAX_OVERHEAD 128
+#define MAX_FRAGMENT_COUNT 8
+#define MAX_TRANSMIT_BUFFER_SIZE (1600 + \
+ (MAX_802_11_HEADER_LENGTH + \
+ ENCRYPTION_MAX_OVERHEAD) *\
+ MAX_FRAGMENT_COUNT)
+
+#define H2C_TX_CMD_HDR_LEN 8
+
+/* The following DM control code are for Reg0x364, */
+#define FW_DIG_ENABLE_CTL BIT(0)
+#define FW_HIGH_PWR_ENABLE_CTL BIT(1)
+#define FW_SS_CTL BIT(2)
+#define FW_RA_INIT_CTL BIT(3)
+#define FW_RA_BG_CTL BIT(4)
+#define FW_RA_N_CTL BIT(5)
+#define FW_PWR_TRK_CTL BIT(6)
+#define FW_IQK_CTL BIT(7)
+#define FW_FA_CTL BIT(8)
+#define FW_DRIVER_CTRL_DM_CTL BIT(9)
+#define FW_PAPE_CTL_BY_SW_HW BIT(10)
+#define FW_DISABLE_ALL_DM 0
+#define FW_PWR_TRK_PARAM_CLR 0x0000ffff
+#define FW_RA_PARAM_CLR 0xffff0000
+
+enum desc_packet_type {
+ DESC_PACKET_TYPE_INIT = 0,
+ DESC_PACKET_TYPE_NORMAL = 1,
+};
+
+/* 8-bytes alignment required */
+struct fw_priv {
+ /* --- long word 0 ---- */
+ /* 0x12: CE product, 0x92: IT product */
+ u8 signature_0;
+ /* 0x87: CE product, 0x81: IT product */
+ u8 signature_1;
+ /* 0x81: PCI-AP, 01:PCIe, 02: 92S-U,
+ * 0x82: USB-AP, 0x12: 72S-U, 03:SDIO */
+ u8 hci_sel;
+ /* the same value as reigster value */
+ u8 chip_version;
+ /* customer ID low byte */
+ u8 customer_id_0;
+ /* customer ID high byte */
+ u8 customer_id_1;
+ /* 0x11: 1T1R, 0x12: 1T2R,
+ * 0x92: 1T2R turbo, 0x22: 2T2R */
+ u8 rf_config;
+ /* 4: 4EP, 6: 6EP, 11: 11EP */
+ u8 usb_ep_num;
+
+ /* --- long word 1 ---- */
+ /* regulatory class bit map 0 */
+ u8 regulatory_class_0;
+ /* regulatory class bit map 1 */
+ u8 regulatory_class_1;
+ /* regulatory class bit map 2 */
+ u8 regulatory_class_2;
+ /* regulatory class bit map 3 */
+ u8 regulatory_class_3;
+ /* 0:SWSI, 1:HWSI, 2:HWPI */
+ u8 rfintfs;
+ u8 def_nettype;
+ u8 rsvd010;
+ u8 rsvd011;
+
+ /* --- long word 2 ---- */
+ /* 0x00: normal, 0x03: MACLBK, 0x01: PHYLBK */
+ u8 lbk_mode;
+ /* 1: for MP use, 0: for normal
+ * driver (to be discussed) */
+ u8 mp_mode;
+ u8 rsvd020;
+ u8 rsvd021;
+ u8 rsvd022;
+ u8 rsvd023;
+ u8 rsvd024;
+ u8 rsvd025;
+
+ /* --- long word 3 ---- */
+ /* QoS enable */
+ u8 qos_en;
+ /* 40MHz BW enable */
+ /* 4181 convert AMSDU to AMPDU, 0: disable */
+ u8 bw_40mhz_en;
+ u8 amsdu2ampdu_en;
+ /* 11n AMPDU enable */
+ u8 ampdu_en;
+ /* FW offloads, 0: driver handles */
+ u8 rate_control_offload;
+ /* FW offloads, 0: driver handles */
+ u8 aggregation_offload;
+ u8 rsvd030;
+ u8 rsvd031;
+
+ /* --- long word 4 ---- */
+ /* 1. FW offloads, 0: driver handles */
+ u8 beacon_offload;
+ /* 2. FW offloads, 0: driver handles */
+ u8 mlme_offload;
+ /* 3. FW offloads, 0: driver handles */
+ u8 hwpc_offload;
+ /* 4. FW offloads, 0: driver handles */
+ u8 tcp_checksum_offload;
+ /* 5. FW offloads, 0: driver handles */
+ u8 tcp_offload;
+ /* 6. FW offloads, 0: driver handles */
+ u8 ps_control_offload;
+ /* 7. FW offloads, 0: driver handles */
+ u8 wwlan_offload;
+ u8 rsvd040;
+
+ /* --- long word 5 ---- */
+ /* tcp tx packet length low byte */
+ u8 tcp_tx_frame_len_L;
+ /* tcp tx packet length high byte */
+ u8 tcp_tx_frame_len_H;
+ /* tcp rx packet length low byte */
+ u8 tcp_rx_frame_len_L;
+ /* tcp rx packet length high byte */
+ u8 tcp_rx_frame_len_H;
+ u8 rsvd050;
+ u8 rsvd051;
+ u8 rsvd052;
+ u8 rsvd053;
+};
+
+/* 8-byte alinment required */
+struct fw_hdr {
+
+ /* --- LONG WORD 0 ---- */
+ u16 signature;
+ /* 0x8000 ~ 0x8FFF for FPGA version,
+ * 0x0000 ~ 0x7FFF for ASIC version, */
+ u16 version;
+ /* define the size of boot loader */
+ u32 dmem_size;
+
+
+ /* --- LONG WORD 1 ---- */
+ /* define the size of FW in IMEM */
+ u32 img_imem_size;
+ /* define the size of FW in SRAM */
+ u32 img_sram_size;
+
+ /* --- LONG WORD 2 ---- */
+ /* define the size of DMEM variable */
+ u32 fw_priv_size;
+ u32 rsvd0;
+
+ /* --- LONG WORD 3 ---- */
+ u32 rsvd1;
+ u32 rsvd2;
+
+ struct fw_priv fwpriv;
+
+} ;
+
+enum fw_status {
+ FW_STATUS_INIT = 0,
+ FW_STATUS_LOAD_IMEM = 1,
+ FW_STATUS_LOAD_EMEM = 2,
+ FW_STATUS_LOAD_DMEM = 3,
+ FW_STATUS_READY = 4,
+};
+
+struct rt_firmware {
+ struct fw_hdr *pfwheader;
+ enum fw_status fwstatus;
+ u16 firmwareversion;
+ u8 fw_imem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
+ u8 fw_emem[RTL8190_MAX_FIRMWARE_CODE_SIZE];
+ u32 fw_imem_len;
+ u32 fw_emem_len;
+ u8 sz_fw_tmpbuffer[164000];
+ u32 sz_fw_tmpbufferlen;
+ u16 cmdpacket_fragthresold;
+};
+
+struct h2c_set_pwrmode_parm {
+ u8 mode;
+ u8 flag_low_traffic_en;
+ u8 flag_lpnav_en;
+ u8 flag_rf_low_snr_en;
+ /* 1: dps, 0: 32k */
+ u8 flag_dps_en;
+ u8 bcn_rx_en;
+ u8 bcn_pass_cnt;
+ /* beacon TO (ms). ¡§=0¡¨ no limit. */
+ u8 bcn_to;
+ u16 bcn_itv;
+ /* only for VOIP mode. */
+ u8 app_itv;
+ u8 awake_bcn_itvl;
+ u8 smart_ps;
+ /* unit: 100 ms */
+ u8 bcn_pass_period;
+};
+
+struct h2c_joinbss_rpt_parm {
+ u8 opmode;
+ u8 ps_qos_info;
+ u8 bssid[6];
+ u16 bcnitv;
+ u16 aid;
+} ;
+
+struct h2c_wpa_ptk {
+ /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kck[16];
+ /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 kek[16];
+ /* Temporal Key 1 (TK1) */
+ u8 tk1[16];
+ union {
+ /* Temporal Key 2 (TK2) */
+ u8 tk2[16];
+ struct {
+ u8 tx_mic_key[8];
+ u8 rx_mic_key[8];
+ } athu;
+ } u;
+};
+
+struct h2c_wpa_two_way_parm {
+ /* algorithm TKIP or AES */
+ u8 pairwise_en_alg;
+ u8 group_en_alg;
+ struct h2c_wpa_ptk wpa_ptk_value;
+} ;
+
+enum h2c_cmd {
+ FW_H2C_SETPWRMODE = 0,
+ FW_H2C_JOINBSSRPT = 1,
+ FW_H2C_WOWLAN_UPDATE_GTK = 2,
+ FW_H2C_WOWLAN_UPDATE_IV = 3,
+ FW_H2C_WOWLAN_OFFLOAD = 4,
+};
+
+enum fw_h2c_cmd {
+ H2C_READ_MACREG_CMD, /*0*/
+ H2C_WRITE_MACREG_CMD,
+ H2C_READBB_CMD,
+ H2C_WRITEBB_CMD,
+ H2C_READRF_CMD,
+ H2C_WRITERF_CMD, /*5*/
+ H2C_READ_EEPROM_CMD,
+ H2C_WRITE_EEPROM_CMD,
+ H2C_READ_EFUSE_CMD,
+ H2C_WRITE_EFUSE_CMD,
+ H2C_READ_CAM_CMD, /*10*/
+ H2C_WRITE_CAM_CMD,
+ H2C_SETBCNITV_CMD,
+ H2C_SETMBIDCFG_CMD,
+ H2C_JOINBSS_CMD,
+ H2C_DISCONNECT_CMD, /*15*/
+ H2C_CREATEBSS_CMD,
+ H2C_SETOPMode_CMD,
+ H2C_SITESURVEY_CMD,
+ H2C_SETAUTH_CMD,
+ H2C_SETKEY_CMD, /*20*/
+ H2C_SETSTAKEY_CMD,
+ H2C_SETASSOCSTA_CMD,
+ H2C_DELASSOCSTA_CMD,
+ H2C_SETSTAPWRSTATE_CMD,
+ H2C_SETBASICRATE_CMD, /*25*/
+ H2C_GETBASICRATE_CMD,
+ H2C_SETDATARATE_CMD,
+ H2C_GETDATARATE_CMD,
+ H2C_SETPHYINFO_CMD,
+ H2C_GETPHYINFO_CMD, /*30*/
+ H2C_SETPHY_CMD,
+ H2C_GETPHY_CMD,
+ H2C_READRSSI_CMD,
+ H2C_READGAIN_CMD,
+ H2C_SETATIM_CMD, /*35*/
+ H2C_SETPWRMODE_CMD,
+ H2C_JOINBSSRPT_CMD,
+ H2C_SETRATABLE_CMD,
+ H2C_GETRATABLE_CMD,
+ H2C_GETCCXREPORT_CMD, /*40*/
+ H2C_GETDTMREPORT_CMD,
+ H2C_GETTXRATESTATICS_CMD,
+ H2C_SETUSBSUSPEND_CMD,
+ H2C_SETH2CLBK_CMD,
+ H2C_TMP1, /*45*/
+ H2C_WOWLAN_UPDATE_GTK_CMD,
+ H2C_WOWLAN_FW_OFFLOAD,
+ H2C_TMP2,
+ H2C_TMP3,
+ H2C_WOWLAN_UPDATE_IV_CMD, /*50*/
+ H2C_TMP4,
+ MAX_H2CCMD /*52*/
+};
+
+/* The following macros are used for FW
+ * CMD map and parameter updated. */
+#define FW_CMD_IO_CLR(rtlpriv, _Bit) \
+ do { \
+ udelay(1000); \
+ rtlpriv->rtlhal.fwcmd_iomap &= (~_Bit); \
+ } while (0);
+
+#define FW_CMD_IO_UPDATE(rtlpriv, _val) \
+ rtlpriv->rtlhal.fwcmd_iomap = _val;
+
+#define FW_CMD_IO_SET(rtlpriv, _val) \
+ do { \
+ rtl_write_word(rtlpriv, LBUS_MON_ADDR, (u16)_val); \
+ FW_CMD_IO_UPDATE(rtlpriv, _val); \
+ } while (0);
+
+#define FW_CMD_PARA_SET(rtlpriv, _val) \
+ do { \
+ rtl_write_dword(rtlpriv, LBUS_ADDR_MASK, _val); \
+ rtlpriv->rtlhal.fwcmd_ioparam = _val; \
+ } while (0);
+
+#define FW_CMD_IO_QUERY(rtlpriv) \
+ (u16)(rtlpriv->rtlhal.fwcmd_iomap)
+#define FW_CMD_IO_PARA_QUERY(rtlpriv) \
+ ((u32)(rtlpriv->rtlhal.fwcmd_ioparam))
+
+int rtl92s_download_fw(struct ieee80211_hw *hw);
+void rtl92s_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl92s_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw,
+ u8 mstatus, u8 ps_qosinfo);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.c b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
new file mode 100644
index 0000000..2e9005d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.c
@@ -0,0 +1,2512 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+
+void rtl92se_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ switch (variable) {
+ case HW_VAR_RCR: {
+ *((u32 *) (val)) = rtlpci->receive_config;
+ break;
+ }
+ case HW_VAR_RF_STATE: {
+ *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS: {
+ *((bool *) (val)) = ppsc->fw_current_inpsmode;
+ break;
+ }
+ case HW_VAR_CORRECT_TSF: {
+ u64 tsf;
+ u32 *ptsf_low = (u32 *)&tsf;
+ u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+ *ptsf_high = rtl_read_dword(rtlpriv, (TSFR + 4));
+ *ptsf_low = rtl_read_dword(rtlpriv, TSFR);
+
+ *((u64 *) (val)) = tsf;
+
+ break;
+ }
+ case HW_VAR_MRC: {
+ *((bool *)(val)) = rtlpriv->dm.current_mrc_switch;
+ break;
+ }
+ default: {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ }
+}
+
+void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ switch (variable) {
+ case HW_VAR_ETHER_ADDR:{
+ rtl_write_dword(rtlpriv, IDR0, ((u32 *)(val))[0]);
+ rtl_write_word(rtlpriv, IDR4, ((u16 *)(val + 4))[0]);
+ break;
+ }
+ case HW_VAR_BASIC_RATE:{
+ u16 rate_cfg = ((u16 *) val)[0];
+ u8 rate_index = 0;
+
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rate_cfg = rate_cfg & 0x150;
+ else
+ rate_cfg = rate_cfg & 0x15f;
+
+ rate_cfg |= 0x01;
+
+ rtl_write_byte(rtlpriv, RRSR, rate_cfg & 0xff);
+ rtl_write_byte(rtlpriv, RRSR + 1,
+ (rate_cfg >> 8) & 0xff);
+
+ while (rate_cfg > 0x1) {
+ rate_cfg = (rate_cfg >> 1);
+ rate_index++;
+ }
+ rtl_write_byte(rtlpriv, INIRTSMCS_SEL, rate_index);
+
+ break;
+ }
+ case HW_VAR_BSSID:{
+ rtl_write_dword(rtlpriv, BSSIDR, ((u32 *)(val))[0]);
+ rtl_write_word(rtlpriv, BSSIDR + 4,
+ ((u16 *)(val + 4))[0]);
+ break;
+ }
+ case HW_VAR_SIFS:{
+ rtl_write_byte(rtlpriv, SIFS_OFDM, val[0]);
+ rtl_write_byte(rtlpriv, SIFS_OFDM + 1, val[1]);
+ break;
+ }
+ case HW_VAR_SLOT_TIME:{
+ u8 e_aci;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("HW_VAR_SLOT_TIME %x\n", val[0]));
+
+ rtl_write_byte(rtlpriv, SLOT_TIME, val[0]);
+
+ for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_AC_PARAM,
+ (u8 *)(&e_aci));
+ }
+ break;
+ }
+ case HW_VAR_ACK_PREAMBLE:{
+ u8 reg_tmp;
+ u8 short_preamble = (bool) (*(u8 *) val);
+ reg_tmp = (mac->cur_40_prime_sc) << 5;
+ if (short_preamble)
+ reg_tmp |= 0x80;
+
+ rtl_write_byte(rtlpriv, RRSR + 2, reg_tmp);
+ break;
+ }
+ case HW_VAR_AMPDU_MIN_SPACE:{
+ u8 min_spacing_to_set;
+ u8 sec_min_space;
+
+ min_spacing_to_set = *((u8 *)val);
+ if (min_spacing_to_set <= 7) {
+ if (rtlpriv->sec.pairwise_enc_algorithm ==
+ NO_ENCRYPTION)
+ sec_min_space = 0;
+ else
+ sec_min_space = 1;
+
+ if (min_spacing_to_set < sec_min_space)
+ min_spacing_to_set = sec_min_space;
+ if (min_spacing_to_set > 5)
+ min_spacing_to_set = 5;
+
+ mac->min_space_cfg =
+ ((mac->min_space_cfg & 0xf8) |
+ min_spacing_to_set);
+
+ *val = min_spacing_to_set;
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+ }
+ break;
+ }
+ case HW_VAR_SHORTGI_DENSITY:{
+ u8 density_to_set;
+
+ density_to_set = *((u8 *) val);
+ mac->min_space_cfg = rtlpriv->rtlhal.minspace_cfg;
+ mac->min_space_cfg |= (density_to_set << 3);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+ mac->min_space_cfg));
+
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE,
+ mac->min_space_cfg);
+
+ break;
+ }
+ case HW_VAR_AMPDU_FACTOR:{
+ u8 factor_toset;
+ u8 regtoset;
+ u8 factorlevel[18] = {
+ 2, 4, 4, 7, 7, 13, 13,
+ 13, 2, 7, 7, 13, 13,
+ 15, 15, 15, 15, 0};
+ u8 index = 0;
+
+ factor_toset = *((u8 *) val);
+ if (factor_toset <= 3) {
+ factor_toset = (1 << (factor_toset + 2));
+ if (factor_toset > 0xf)
+ factor_toset = 0xf;
+
+ for (index = 0; index < 17; index++) {
+ if (factorlevel[index] > factor_toset)
+ factorlevel[index] =
+ factor_toset;
+ }
+
+ for (index = 0; index < 8; index++) {
+ regtoset = ((factorlevel[index * 2]) |
+ (factorlevel[index *
+ 2 + 1] << 4));
+ rtl_write_byte(rtlpriv,
+ AGGLEN_LMT_L + index,
+ regtoset);
+ }
+
+ regtoset = ((factorlevel[16]) |
+ (factorlevel[17] << 4));
+ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, regtoset);
+
+ RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+ ("Set HW_VAR_AMPDU_FACTOR: %#x\n",
+ factor_toset));
+ }
+ break;
+ }
+ case HW_VAR_AC_PARAM:{
+ u8 e_aci = *((u8 *) val);
+ rtl92s_dm_init_edca_turbo(hw);
+
+ if (rtlpci->acm_method != eAcmWay2_SW)
+ rtlpriv->cfg->ops->set_hw_reg(hw,
+ HW_VAR_ACM_CTRL,
+ (u8 *)(&e_aci));
+ break;
+ }
+ case HW_VAR_ACM_CTRL:{
+ u8 e_aci = *((u8 *) val);
+ union aci_aifsn *p_aci_aifsn = (union aci_aifsn *)(&(
+ mac->ac[0].aifs));
+ u8 acm = p_aci_aifsn->f.acm;
+ u8 acm_ctrl = rtl_read_byte(rtlpriv, AcmHwCtrl);
+
+ acm_ctrl = acm_ctrl | ((rtlpci->acm_method == 2) ?
+ 0x0 : 0x1);
+
+ if (acm) {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl |= AcmHw_BeqEn;
+ break;
+ case AC2_VI:
+ acm_ctrl |= AcmHw_ViqEn;
+ break;
+ case AC3_VO:
+ acm_ctrl |= AcmHw_VoqEn;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("HW_VAR_ACM_CTRL acm set "
+ "failed: eACI is %d\n", acm));
+ break;
+ }
+ } else {
+ switch (e_aci) {
+ case AC0_BE:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ case AC2_VI:
+ acm_ctrl &= (~AcmHw_ViqEn);
+ break;
+ case AC3_VO:
+ acm_ctrl &= (~AcmHw_BeqEn);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+ ("HW_VAR_ACM_CTRL Write 0x%X\n", acm_ctrl));
+ rtl_write_byte(rtlpriv, AcmHwCtrl, acm_ctrl);
+ break;
+ }
+ case HW_VAR_RCR:{
+ rtl_write_dword(rtlpriv, RCR, ((u32 *) (val))[0]);
+ rtlpci->receive_config = ((u32 *) (val))[0];
+ break;
+ }
+ case HW_VAR_RETRY_LIMIT:{
+ u8 retry_limit = ((u8 *) (val))[0];
+
+ rtl_write_word(rtlpriv, RETRY_LIMIT,
+ retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+ retry_limit << RETRY_LIMIT_LONG_SHIFT);
+ break;
+ }
+ case HW_VAR_DUAL_TSF_RST: {
+ break;
+ }
+ case HW_VAR_EFUSE_BYTES: {
+ rtlefuse->efuse_usedbytes = *((u16 *) val);
+ break;
+ }
+ case HW_VAR_EFUSE_USAGE: {
+ rtlefuse->efuse_usedpercentage = *((u8 *) val);
+ break;
+ }
+ case HW_VAR_IO_CMD: {
+ break;
+ }
+ case HW_VAR_WPA_CONFIG: {
+ rtl_write_byte(rtlpriv, REG_SECR, *((u8 *) val));
+ break;
+ }
+ case HW_VAR_SET_RPWM:{
+ break;
+ }
+ case HW_VAR_H2C_FW_PWRMODE:{
+ break;
+ }
+ case HW_VAR_FW_PSMODE_STATUS: {
+ ppsc->fw_current_inpsmode = *((bool *) val);
+ break;
+ }
+ case HW_VAR_H2C_FW_JOINBSSRPT:{
+ break;
+ }
+ case HW_VAR_AID:{
+ break;
+ }
+ case HW_VAR_CORRECT_TSF:{
+ break;
+ }
+ case HW_VAR_MRC: {
+ bool bmrc_toset = *((bool *)val);
+ u8 u1bdata = 0;
+
+ if (bmrc_toset) {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x33);
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM1_TRXPATHENABLE,
+ MASKBYTE0);
+ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE,
+ MASKBYTE0,
+ ((u1bdata & 0xf0) | 0x03));
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM0_TRXPATHENABLE,
+ MASKBYTE1);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE1,
+ (u1bdata | 0x04));
+
+ /* Update current settings. */
+ rtlpriv->dm.current_mrc_switch = bmrc_toset;
+ } else {
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE0, 0x13);
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM1_TRXPATHENABLE,
+ MASKBYTE0);
+ rtl_set_bbreg(hw, ROFDM1_TRXPATHENABLE,
+ MASKBYTE0,
+ ((u1bdata & 0xf0) | 0x01));
+ u1bdata = (u8)rtl_get_bbreg(hw,
+ ROFDM0_TRXPATHENABLE,
+ MASKBYTE1);
+ rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE,
+ MASKBYTE1, (u1bdata & 0xfb));
+
+ /* Update current settings. */
+ rtlpriv->dm.current_mrc_switch = bmrc_toset;
+ }
+
+ break;
+ }
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+}
+
+void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 sec_reg_value = 0x0;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("PairwiseEncAlgorithm = %d "
+ "GroupEncAlgorithm = %d\n",
+ rtlpriv->sec.pairwise_enc_algorithm,
+ rtlpriv->sec.group_enc_algorithm));
+
+ if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("not open hw encryption\n"));
+ return;
+ }
+
+ sec_reg_value = SCR_TXENCENABLE | SCR_RXENCENABLE;
+
+ if (rtlpriv->sec.use_defaultkey) {
+ sec_reg_value |= SCR_TXUSEDK;
+ sec_reg_value |= SCR_RXUSEDK;
+ }
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, ("The SECR-value %x\n",
+ sec_reg_value));
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+
+}
+
+static u8 _rtl92ce_halset_sysclk(struct ieee80211_hw *hw, u8 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 waitcount = 100;
+ bool bresult = false;
+ u8 tmpvalue;
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data);
+
+ /* Wait the MAC synchronized. */
+ udelay(400);
+
+ /* Check if it is set ready. */
+ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ bresult = ((tmpvalue & BIT(7)) == (data & BIT(7)));
+
+ if ((data & (BIT(6) | BIT(7))) == false) {
+ waitcount = 100;
+ tmpvalue = 0;
+
+ while (1) {
+ waitcount--;
+
+ tmpvalue = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ if ((tmpvalue & BIT(6)))
+ break;
+
+ printk(KERN_ERR "wait for BIT(6) return value %x\n",
+ tmpvalue);
+ if (waitcount == 0)
+ break;
+
+ udelay(10);
+ }
+
+ if (waitcount == 0)
+ bresult = false;
+ else
+ bresult = true;
+ }
+
+ return bresult;
+}
+
+void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1tmp;
+
+ /* The following config GPIO function */
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO));
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL);
+
+ /* config GPIO3 to input */
+ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK;
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp);
+
+}
+
+static u8 _rtl92se_rf_onoff_detect(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1tmp;
+ u8 retval = ERFON;
+
+ /* The following config GPIO function */
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, (GPIOMUX_EN | GPIOSEL_GPIO));
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IO_SEL);
+
+ /* config GPIO3 to input */
+ u1tmp &= HAL_8192S_HW_GPIO_OFF_MASK;
+ rtl_write_byte(rtlpriv, GPIO_IO_SEL, u1tmp);
+
+ /* On some of the platform, driver cannot read correct
+ * value without delay between Write_GPIO_SEL and Read_GPIO_IN */
+ mdelay(10);
+
+ /* check GPIO3 */
+ u1tmp = rtl_read_byte(rtlpriv, GPIO_IN);
+ retval = (u1tmp & HAL_8192S_HW_GPIO_OFF_BIT) ? ERFON : ERFOFF;
+
+ return retval;
+}
+
+static void _rtl92se_macconfig_before_fwdownload(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ u8 i;
+ u8 tmpu1b;
+ u16 tmpu2b;
+ u8 pollingcnt = 20;
+
+ if (rtlpci->first_init) {
+ /* Reset PCIE Digital */
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmpu1b &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b);
+ udelay(1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b | BIT(0));
+ }
+
+ /* Switch to SW IO control */
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ if (tmpu1b & BIT(7)) {
+ tmpu1b &= ~(BIT(6) | BIT(7));
+
+ /* Set failed, return to prevent hang. */
+ if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ return;
+ }
+
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0);
+ udelay(50);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+ udelay(50);
+
+ /* Clear FW RPWM for FW control LPS.*/
+ rtl_write_byte(rtlpriv, RPWM, 0x0);
+
+ /* Reset MAC-IO and CPU and Core Digital BIT(10)/11/15 */
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmpu1b &= 0x73;
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b);
+ /* wait for BIT 10/11/15 to pull high automatically!! */
+ mdelay(1);
+
+ rtl_write_byte(rtlpriv, CMDR, 0);
+ rtl_write_byte(rtlpriv, TCR, 0);
+
+ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */
+ tmpu1b = rtl_read_byte(rtlpriv, 0x562);
+ tmpu1b |= 0x08;
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+ tmpu1b &= ~(BIT(3));
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+
+ /* Enable AFE clock source */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01));
+ /* Delay 1.5ms */
+ mdelay(2);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb));
+
+ /* Enable AFE Macro Block's Bandgap */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Enable AFE Mbias */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02));
+ mdelay(1);
+
+ /* Enable LDOA15 block */
+ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0)));
+
+ /* Set Digital Vdd to Retention isolation Path. */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_ISO_CTRL);
+ rtl_write_word(rtlpriv, REG_SYS_ISO_CTRL, (tmpu2b | BIT(11)));
+
+ /* For warm reboot NIC disappera bug. */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(13)));
+
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, 0x68);
+
+ /* Enable AFE PLL Macro Block */
+ /* We need to delay 100u before enabling PLL. */
+ udelay(200);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+
+ /* for divider reset */
+ udelay(100);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) |
+ BIT(4) | BIT(6)));
+ udelay(10);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+ udelay(10);
+
+ /* Enable MAC 80MHZ clock */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Release isolation AFE PLL & MD */
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, 0xA6);
+
+ /* Enable MAC clock */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11)));
+
+ /* Enable Core digital and enable IOREG R/W */
+ tmpu2b = rtl_read_word(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11)));
+
+ tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmpu1b & ~(BIT(7)));
+
+ /* enable REG_EN */
+ rtl_write_word(rtlpriv, REG_SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
+
+ /* Switch the control path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2))));
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
+ if (!_rtl92ce_halset_sysclk(hw, tmpu1b))
+ return; /* Set failed, return to prevent hang. */
+
+ rtl_write_word(rtlpriv, CMDR, 0x07FC);
+
+ /* MH We must enable the section of code to prevent load IMEM fail. */
+ /* Load MAC register from WMAc temporarily We simulate macreg. */
+ /* txt HW will provide MAC txt later */
+ rtl_write_byte(rtlpriv, 0x6, 0x30);
+ rtl_write_byte(rtlpriv, 0x49, 0xf0);
+
+ rtl_write_byte(rtlpriv, 0x4b, 0x81);
+
+ rtl_write_byte(rtlpriv, 0xb5, 0x21);
+
+ rtl_write_byte(rtlpriv, 0xdc, 0xff);
+ rtl_write_byte(rtlpriv, 0xdd, 0xff);
+ rtl_write_byte(rtlpriv, 0xde, 0xff);
+ rtl_write_byte(rtlpriv, 0xdf, 0xff);
+
+ rtl_write_byte(rtlpriv, 0x11a, 0x00);
+ rtl_write_byte(rtlpriv, 0x11b, 0x00);
+
+ for (i = 0; i < 32; i++)
+ rtl_write_byte(rtlpriv, INIMCS_SEL + i, 0x1b);
+
+ rtl_write_byte(rtlpriv, 0x236, 0xff);
+
+ rtl_write_byte(rtlpriv, 0x503, 0x22);
+
+ if (ppsc->support_aspm && !ppsc->support_backdoor)
+ rtl_write_byte(rtlpriv, 0x560, 0x40);
+ else
+ rtl_write_byte(rtlpriv, 0x560, 0x00);
+
+ rtl_write_byte(rtlpriv, DBG_PORT, 0x91);
+
+ /* Set RX Desc Address */
+ rtl_write_dword(rtlpriv, RDQDA, rtlpci->rx_ring[RX_MPDU_QUEUE].dma);
+ rtl_write_dword(rtlpriv, RCDA, rtlpci->rx_ring[RX_CMD_QUEUE].dma);
+
+ /* Set TX Desc Address */
+ rtl_write_dword(rtlpriv, TBKDA, rtlpci->tx_ring[BK_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TBEDA, rtlpci->tx_ring[BE_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TVIDA, rtlpci->tx_ring[VI_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TVODA, rtlpci->tx_ring[VO_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TBDA, rtlpci->tx_ring[BEACON_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TCDA, rtlpci->tx_ring[TXCMD_QUEUE].dma);
+ rtl_write_dword(rtlpriv, TMDA, rtlpci->tx_ring[MGNT_QUEUE].dma);
+ rtl_write_dword(rtlpriv, THPDA, rtlpci->tx_ring[HIGH_QUEUE].dma);
+ rtl_write_dword(rtlpriv, HDA, rtlpci->tx_ring[HCCA_QUEUE].dma);
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+
+ /* To make sure that TxDMA can ready to download FW. */
+ /* We should reset TxDMA if IMEM RPT was not ready. */
+ do {
+ tmpu1b = rtl_read_byte(rtlpriv, TCR);
+ if ((tmpu1b & TXDMA_INIT_VALUE) == TXDMA_INIT_VALUE)
+ break;
+
+ udelay(5);
+ } while (pollingcnt--);
+
+ if (pollingcnt <= 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Polling TXDMA_INIT_VALUE "
+ "timeout!! Current TCR(%#x)\n", tmpu1b));
+ tmpu1b = rtl_read_byte(rtlpriv, CMDR);
+ rtl_write_byte(rtlpriv, CMDR, tmpu1b & (~TXDMA_EN));
+ udelay(2);
+ /* Reset TxDMA */
+ rtl_write_byte(rtlpriv, CMDR, tmpu1b | TXDMA_EN);
+ }
+
+ /* After MACIO reset,we must refresh LED state. */
+ if ((ppsc->rfoff_reason == RF_CHANGE_BY_IPS) ||
+ (ppsc->rfoff_reason == 0)) {
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+ enum rf_pwrstate rfpwr_state_toset;
+ rfpwr_state_toset = _rtl92se_rf_onoff_detect(hw);
+
+ if (rfpwr_state_toset == ERFON)
+ rtl92se_sw_led_on(hw, pLed0);
+ }
+}
+
+static void _rtl92se_macconfig_after_fwdownload(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u8 i;
+ u16 tmpu2b;
+
+ /* 1. System Configure Register (Offset: 0x0000 - 0x003F) */
+
+ /* 2. Command Control Register (Offset: 0x0040 - 0x004F) */
+ /* Turn on 0x40 Command register */
+ rtl_write_word(rtlpriv, CMDR, (BBRSTN | BB_GLB_RSTN |
+ SCHEDULE_EN | MACRXEN | MACTXEN | DDMA_EN | FW2HW_EN |
+ RXDMA_EN | TXDMA_EN | HCI_RXDMA_EN | HCI_TXDMA_EN));
+
+ /* Set TCR TX DMA pre 2 FULL enable bit */
+ rtl_write_dword(rtlpriv, TCR, rtl_read_dword(rtlpriv, TCR) |
+ TXDMAPRE2FULL);
+
+ /* Set RCR */
+ rtl_write_dword(rtlpriv, RCR, rtlpci->receive_config);
+
+ /* 3. MACID Setting Register (Offset: 0x0050 - 0x007F) */
+
+ /* 4. Timing Control Register (Offset: 0x0080 - 0x009F) */
+ /* Set CCK/OFDM SIFS */
+ /* CCK SIFS shall always be 10us. */
+ rtl_write_word(rtlpriv, SIFS_CCK, 0x0a0a);
+ rtl_write_word(rtlpriv, SIFS_OFDM, 0x1010);
+
+ /* Set AckTimeout */
+ rtl_write_byte(rtlpriv, ACK_TIMEOUT, 0x40);
+
+ /* Beacon related */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, 100);
+ rtl_write_word(rtlpriv, ATIMWND, 2);
+
+ /* 5. FIFO Control Register (Offset: 0x00A0 - 0x015F) */
+ /* 5.1 Initialize Number of Reserved Pages in Firmware Queue */
+ /* Firmware allocate now, associate with FW internal setting.!!! */
+
+ /* 5.2 Setting TX/RX page size 0/1/2/3/4=64/128/256/512/1024 */
+ /* 5.3 Set driver info, we only accept PHY status now. */
+ /* 5.4 Set RXDMA arbitration to control RXDMA/MAC/FW R/W for RXFIFO */
+ rtl_write_byte(rtlpriv, RXDMA, rtl_read_byte(rtlpriv, RXDMA) | BIT(6));
+
+ /* 6. Adaptive Control Register (Offset: 0x0160 - 0x01CF) */
+ /* Set RRSR to all legacy rate and HT rate
+ * CCK rate is supported by default.
+ * CCK rate will be filtered out only when associated
+ * AP does not support it.
+ * Only enable ACK rate to OFDM 24M
+ * Disable RRSR for CCK rate in A-Cut */
+
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_byte(rtlpriv, RRSR, 0xf0);
+ else if (rtlhal->version == VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RRSR, 0xff);
+ rtl_write_byte(rtlpriv, RRSR + 1, 0x01);
+ rtl_write_byte(rtlpriv, RRSR + 2, 0x00);
+
+ /* A-Cut IC do not support CCK rate. We forbid ARFR to */
+ /* fallback to CCK rate */
+ for (i = 0; i < 8; i++) {
+ /*Disable RRSR for CCK rate in A-Cut */
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_dword(rtlpriv, ARFR0 + i * 4, 0x1f0ff0f0);
+ }
+
+ /* Different rate use different AMPDU size */
+ /* MCS32/ MCS15_SG use max AMPDU size 15*2=30K */
+ rtl_write_byte(rtlpriv, AGGLEN_LMT_H, 0x0f);
+ /* MCS0/1/2/3 use max AMPDU size 4*2=8K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L, 0x7442);
+ /* MCS4/5 use max AMPDU size 8*2=16K 6/7 use 10*2=20K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 2, 0xddd7);
+ /* MCS8/9 use max AMPDU size 8*2=16K 10/11 use 10*2=20K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 4, 0xd772);
+ /* MCS12/13/14/15 use max AMPDU size 15*2=30K */
+ rtl_write_word(rtlpriv, AGGLEN_LMT_L + 6, 0xfffd);
+
+ /* Set Data / Response auto rate fallack retry count */
+ rtl_write_dword(rtlpriv, DARFRC, 0x04010000);
+ rtl_write_dword(rtlpriv, DARFRC + 4, 0x09070605);
+ rtl_write_dword(rtlpriv, RARFRC, 0x04010000);
+ rtl_write_dword(rtlpriv, RARFRC + 4, 0x09070605);
+
+ /* 7. EDCA Setting Register (Offset: 0x01D0 - 0x01FF) */
+ /* Set all rate to support SG */
+ rtl_write_word(rtlpriv, SG_RATE, 0xFFFF);
+
+ /* 8. WMAC, BA, and CCX related Register (Offset: 0x0200 - 0x023F) */
+ /* Set NAV protection length */
+ rtl_write_word(rtlpriv, NAV_PROT_LEN, 0x0080);
+ /* CF-END Threshold */
+ rtl_write_byte(rtlpriv, CFEND_TH, 0xFF);
+ /* Set AMPDU minimum space */
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, 0x07);
+ /* Set TXOP stall control for several queue/HI/BCN/MGT/ */
+ rtl_write_byte(rtlpriv, TXOP_STALL_CTRL, 0x00);
+
+ /* 9. Security Control Register (Offset: 0x0240 - 0x025F) */
+ /* 10. Power Save Control Register (Offset: 0x0260 - 0x02DF) */
+ /* 11. General Purpose Register (Offset: 0x02E0 - 0x02FF) */
+ /* 12. Host Interrupt Status Register (Offset: 0x0300 - 0x030F) */
+ /* 13. Test Mode and Debug Control Register (Offset: 0x0310 - 0x034F) */
+
+ /* 14. Set driver info, we only accept PHY status now. */
+ rtl_write_byte(rtlpriv, RXDRVINFO_SZ, 4);
+
+ /* 15. For EEPROM R/W Workaround */
+ /* 16. For EFUSE to share REG_SYS_FUNC_EN with EEPROM!!! */
+ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, tmpu2b | BIT(13));
+ tmpu2b = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL);
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL, tmpu2b & (~BIT(8)));
+
+ /* 17. For EFUSE */
+ /* We may R/W EFUSE in EEPROM mode */
+ if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ u8 tempval;
+
+ tempval = rtl_read_byte(rtlpriv, REG_SYS_ISO_CTRL + 1);
+ tempval &= 0xFE;
+ rtl_write_byte(rtlpriv, REG_SYS_ISO_CTRL + 1, tempval);
+
+ /* Change Program timing */
+ rtl_write_byte(rtlpriv, REG_EFUSE_CTRL + 3, 0x72);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("EFUSE CONFIG OK\n"));
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n"));
+
+}
+
+static void _rtl92se_hw_configure(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ u8 reg_bw_opmode = 0;
+ u32 reg_ratr = 0, reg_rrsr = 0;
+ u8 regtmp = 0;
+
+ reg_bw_opmode = BW_OPMODE_20MHZ;
+ reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS |
+ RATE_ALL_OFDM_2SS;
+ reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+ regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL);
+ reg_rrsr = ((reg_rrsr & 0x000fffff) << 8) | regtmp;
+ rtl_write_dword(rtlpriv, INIRTSMCS_SEL, reg_rrsr);
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+
+ /* Set Retry Limit here */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RETRY_LIMIT,
+ (u8 *)(&rtlpci->shortretry_limit));
+
+ rtl_write_byte(rtlpriv, MLT, 0x8f);
+
+ /* For Min Spacing configuration. */
+ switch (rtlphy->rf_type) {
+ case RF_1T2R:
+ case RF_1T1R:
+ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_1T << 3);
+ break;
+ case RF_2T2R:
+ case RF_2T2R_GREEN:
+ rtlhal->minspace_cfg = (MAX_MSS_DENSITY_2T << 3);
+ break;
+ }
+ rtl_write_byte(rtlpriv, AMPDU_MIN_SPACE, rtlhal->minspace_cfg);
+}
+
+int rtl92se_hw_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 tmp_byte = 0;
+
+ bool rtstatus = true;
+ u8 tmp_u1b;
+ int err = false;
+ u8 i;
+ int wdcapra_add[] = {
+ EDCAPARA_BE, EDCAPARA_BK,
+ EDCAPARA_VI, EDCAPARA_VO};
+ u8 secr_value = 0x0;
+
+ rtlpci->being_init_adapter = true;
+
+ rtlpriv->intf_ops->disable_aspm(hw);
+
+ /* 1. MAC Initialize */
+ /* Before FW download, we have to set some MAC register */
+ _rtl92se_macconfig_before_fwdownload(hw);
+
+ rtlhal->version = (enum version_8192s)((rtl_read_dword(rtlpriv,
+ PMC_FSM) >> 16) & 0xF);
+
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+
+ /* 2. download firmware */
+ rtstatus = rtl92s_download_fw(hw);
+ if (!rtstatus) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("Failed to download FW. "
+ "Init HW without FW now.., Please copy FW into"
+ "/lib/firmware/rtlwifi\n"));
+ rtlhal->fw_ready = false;
+ } else {
+ rtlhal->fw_ready = true;
+ }
+
+ /* After FW download, we have to reset MAC register */
+ _rtl92se_macconfig_after_fwdownload(hw);
+
+ /*Retrieve default FW Cmd IO map. */
+ rtlhal->fwcmd_iomap = rtl_read_word(rtlpriv, LBUS_MON_ADDR);
+ rtlhal->fwcmd_ioparam = rtl_read_dword(rtlpriv, LBUS_ADDR_MASK);
+
+ /* 3. Initialize MAC/PHY Config by MACPHY_reg.txt */
+ if (rtl92s_phy_mac_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("MAC Config failed\n"));
+ return rtstatus;
+ }
+
+ /* Make sure BB/RF write OK. We should prevent enter IPS. radio off. */
+ /* We must set flag avoid BB/RF config period later!! */
+ rtl_write_dword(rtlpriv, CMDR, 0x37FC);
+
+ /* 4. Initialize BB After MAC Config PHY_reg.txt, AGC_Tab.txt */
+ if (rtl92s_phy_bb_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG, ("BB Config failed\n"));
+ return rtstatus;
+ }
+
+ /* 5. Initiailze RF RAIO_A.txt RF RAIO_B.txt */
+ /* Before initalizing RF. We can not use FW to do RF-R/W. */
+
+ rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+
+ /* RF Power Save */
+#if 0
+ /* H/W or S/W RF OFF before sleep. */
+ if (rtlpriv->psc.rfoff_reason > RF_CHANGE_BY_PS) {
+ u32 rfoffreason = rtlpriv->psc.rfoff_reason;
+
+ rtlpriv->psc.rfoff_reason = RF_CHANGE_BY_INIT;
+ rtlpriv->psc.rfpwr_state = ERFON;
+ rtl_ps_set_rf_state(hw, ERFOFF, rfoffreason, true);
+ } else {
+ /* gpio radio on/off is out of adapter start */
+ if (rtlpriv->psc.hwradiooff == false) {
+ rtlpriv->psc.rfpwr_state = ERFON;
+ rtlpriv->psc.rfoff_reason = 0;
+ }
+ }
+#endif
+
+ /* Before RF-R/W we must execute the IO from Scott's suggestion. */
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, 0xDB);
+ if (rtlhal->version == VERSION_8192S_ACUT)
+ rtl_write_byte(rtlpriv, SPS1_CTRL + 3, 0x07);
+ else
+ rtl_write_byte(rtlpriv, RF_CTRL, 0x07);
+
+ if (rtl92s_phy_rf_config(hw) != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("RF Config failed\n"));
+ return rtstatus;
+ }
+
+ /* After read predefined TXT, we must set BB/MAC/RF
+ * register as our requirement */
+
+ rtlphy->rfreg_chnlval[0] = rtl92s_phy_query_rf_reg(hw,
+ (enum radio_path)0,
+ RF_CHNLBW,
+ RFREG_OFFSET_MASK);
+ rtlphy->rfreg_chnlval[1] = rtl92s_phy_query_rf_reg(hw,
+ (enum radio_path)1,
+ RF_CHNLBW,
+ RFREG_OFFSET_MASK);
+
+ /*---- Set CCK and OFDM Block "ON"----*/
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+
+ /*3 Set Hardware(Do nothing now) */
+ _rtl92se_hw_configure(hw);
+
+ /* Read EEPROM TX power index and PHY_REG_PG.txt to capture correct */
+ /* TX power index for different rate set. */
+ /* Get original hw reg values */
+ rtl92s_phy_get_hw_reg_originalvalue(hw);
+ /* Write correct tx power index */
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+
+ /* We must set MAC address after firmware download. */
+ for (i = 0; i < 6; i++)
+ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]);
+
+ /* EEPROM R/W workaround */
+ tmp_u1b = rtl_read_byte(rtlpriv, MAC_PINMUX_CFG);
+ rtl_write_byte(rtlpriv, MAC_PINMUX_CFG, tmp_u1b & (~BIT(3)));
+
+ rtl_write_byte(rtlpriv, 0x4d, 0x0);
+
+ if (hal_get_firmwareversion(rtlpriv) >= 0x49) {
+ tmp_byte = rtl_read_byte(rtlpriv, FW_RSVD_PG_CRTL) & (~BIT(4));
+ tmp_byte = tmp_byte | BIT(5);
+ rtl_write_byte(rtlpriv, FW_RSVD_PG_CRTL, tmp_byte);
+ rtl_write_dword(rtlpriv, TXDESC_MSK, 0xFFFFCFFF);
+ }
+
+ /* We enable high power and RA related mechanism after NIC
+ * initialized. */
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_INIT);
+
+ /* Add to prevent ASPM bug. */
+ /* Always enable hst and NIC clock request. */
+ rtl92s_phy_switch_ephy_parameter(hw);
+
+ /* Security related
+ * 1. Clear all H/W keys.
+ * 2. Enable H/W encryption/decryption. */
+ rtl_cam_reset_all_entry(hw);
+ secr_value |= SCR_TXENCENABLE;
+ secr_value |= SCR_RXENCENABLE;
+ secr_value |= SCR_NOSKMC;
+ rtl_write_byte(rtlpriv, REG_SECR, secr_value);
+
+ for (i = 0; i < 4; i++)
+ rtl_write_dword(rtlpriv, wdcapra_add[i], 0x5e4322);
+
+ if (rtlphy->rf_type == RF_1T2R) {
+ bool mrc2set = true;
+ /* Turn on B-Path */
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_MRC, (u8 *)&mrc2set);
+ }
+
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_ON);
+ rtl92s_dm_init(hw);
+ rtlpci->being_init_adapter = false;
+
+ return err;
+}
+
+void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr)
+{
+}
+
+void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 reg_rcr = rtlpci->receive_config;
+
+ if (rtlpriv->psc.rfpwr_state != ERFON)
+ return;
+
+ if (check_bssid == true) {
+ reg_rcr |= (RCR_CBSSID);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr));
+ } else if (check_bssid == false) {
+ reg_rcr &= (~RCR_CBSSID);
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR, (u8 *)(®_rcr));
+ }
+
+}
+
+static int _rtl92se_set_media_status(struct ieee80211_hw *hw,
+ enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
+ enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+ u32 temp;
+ bt_msr &= ~MSR_LINK_MASK;
+
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to NO LINK!\n"));
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ bt_msr |= (MSR_LINK_ADHOC << MSR_LINK_SHIFT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to Ad Hoc!\n"));
+ break;
+ case NL80211_IFTYPE_STATION:
+ bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT);
+ ledaction = LED_CTL_LINK;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to STA!\n"));
+ break;
+ case NL80211_IFTYPE_AP:
+ bt_msr |= (MSR_LINK_MASTER << MSR_LINK_SHIFT);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+ ("Set Network type to AP!\n"));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Network type %d not support!\n", type));
+ return 1;
+ break;
+
+ }
+
+ rtl_write_byte(rtlpriv, (MSR), bt_msr);
+
+ temp = rtl_read_dword(rtlpriv, TCR);
+ rtl_write_dword(rtlpriv, TCR, temp & (~BIT(8)));
+ rtl_write_dword(rtlpriv, TCR, temp | BIT(8));
+
+
+ return 0;
+}
+
+/* HW_VAR_MEDIA_STATUS & HW_VAR_CECHK_BSSID */
+int rtl92se_set_network_type(struct ieee80211_hw *hw, enum nl80211_iftype type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (_rtl92se_set_media_status(hw, type))
+ return -EOPNOTSUPP;
+
+ if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+ if (type != NL80211_IFTYPE_AP)
+ rtl92se_set_check_bssid(hw, true);
+ } else {
+ rtl92se_set_check_bssid(hw, false);
+ }
+
+ return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl92se_set_qos(struct ieee80211_hw *hw, int aci)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl92s_dm_init_edca_turbo(hw);
+
+ switch (aci) {
+ case AC1_BK:
+ rtl_write_dword(rtlpriv, EDCAPARA_BK, 0xa44f);
+ break;
+ case AC0_BE:
+ /* rtl_write_dword(rtlpriv, EDCAPARA_BE, u4b_ac_param); */
+ break;
+ case AC2_VI:
+ rtl_write_dword(rtlpriv, EDCAPARA_VI, 0x5e4322);
+ break;
+ case AC3_VO:
+ rtl_write_dword(rtlpriv, EDCAPARA_VO, 0x2f3222);
+ break;
+ default:
+ RT_ASSERT(false, ("invalid aci: %d !\n", aci));
+ break;
+ }
+}
+
+void rtl92se_enable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, INTA_MASK, rtlpci->irq_mask[0]);
+ /* Support Bit 32-37(Assign as Bit 0-5) interrupt setting now */
+ rtl_write_dword(rtlpriv, INTA_MASK + 4, rtlpci->irq_mask[1] & 0x3F);
+
+ rtlpci->irq_enabled = true;
+}
+
+void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtl_write_dword(rtlpriv, INTA_MASK, 0);
+ rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
+
+ rtlpci->irq_enabled = false;
+}
+
+
+static u8 _rtl92s_set_sysclk(struct ieee80211_hw *hw, u8 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 waitcnt = 100;
+ bool result = false;
+ u8 tmp;
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, data);
+
+ /* Wait the MAC synchronized. */
+ udelay(400);
+
+ /* Check if it is set ready. */
+ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+ result = ((tmp & BIT(7)) == (data & BIT(7)));
+
+ if ((data & (BIT(6) | BIT(7))) == false) {
+ waitcnt = 100;
+ tmp = 0;
+
+ while (1) {
+ waitcnt--;
+ tmp = rtl_read_byte(rtlpriv, SYS_CLKR + 1);
+
+ if ((tmp & BIT(6)))
+ break;
+
+ printk(KERN_ERR "wait for BIT(6) return value %x\n",
+ tmp);
+
+ if (waitcnt == 0)
+ break;
+ udelay(10);
+ }
+
+ if (waitcnt == 0)
+ result = false;
+ else
+ result = true;
+ }
+
+ return result;
+}
+
+static void _rtl92s_phy_set_rfhalt(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ u8 u1btmp;
+
+ if (rtlhal->driver_going2unload)
+ rtl_write_byte(rtlpriv, 0x560, 0x0);
+
+ /* Power save for BB/RF */
+ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL);
+ u1btmp |= BIT(0);
+ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp);
+ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ udelay(100);
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x0);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ udelay(10);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ rtl_write_word(rtlpriv, CMDR, 0x0000);
+
+ if (rtlhal->driver_going2unload) {
+ u1btmp = rtl_read_byte(rtlpriv, (REG_SYS_FUNC_EN + 1));
+ u1btmp &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1btmp);
+ }
+
+ u1btmp = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+
+ /* Add description. After switch control path. register
+ * after page1 will be invisible. We can not do any IO
+ * for register>0x40. After resume&MACIO reset, we need
+ * to remember previous reg content. */
+ if (u1btmp & BIT(7)) {
+ u1btmp &= ~(BIT(6) | BIT(7));
+ if (!_rtl92s_set_sysclk(hw, u1btmp)) {
+ printk(KERN_ERR "Switch ctrl path fail\n");
+ return;
+ }
+ }
+
+ /* Power save for MAC */
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS &&
+ !rtlhal->driver_going2unload) {
+ /* enable LED function */
+ rtl_write_byte(rtlpriv, 0x03, 0xF9);
+ /* SW/HW radio off or halt adapter!! For example S3/S4 */
+ } else {
+ /* LED function disable. Power range is about 8mA now. */
+ /* if write 0xF1 disconnet_pci power
+ * ifconfig wlan0 down power are both high 35:70 */
+ /* if write oxF9 disconnet_pci power
+ * ifconfig wlan0 down power are both low 12:45*/
+ rtl_write_byte(rtlpriv, 0x03, 0xF9);
+ }
+
+ rtl_write_byte(rtlpriv, SYS_CLKR + 1, 0x70);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, 0x68);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x00);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, 0x0E);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+}
+
+static void _rtl92se_gen_refreshledstate(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+ if (rtlpci->up_first_time == 1)
+ return;
+
+ if (rtlpriv->psc.rfoff_reason == RF_CHANGE_BY_IPS)
+ rtl92se_sw_led_on(hw, pLed0);
+ else
+ rtl92se_sw_led_off(hw, pLed0);
+}
+
+
+static void _rtl92se_power_domain_init(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 tmpu2b;
+ u8 tmpu1b;
+
+ rtlpriv->psc.pwrdomain_protect = true;
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ if (tmpu1b & BIT(7)) {
+ tmpu1b &= ~(BIT(6) | BIT(7));
+ if (!_rtl92s_set_sysclk(hw, tmpu1b)) {
+ rtlpriv->psc.pwrdomain_protect = false;
+ return;
+ }
+ }
+
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, 0x34);
+
+ /* Reset MAC-IO and CPU and Core Digital BIT10/11/15 */
+ tmpu1b = rtl_read_byte(rtlpriv, SYS_FUNC_EN + 1);
+
+ /* If IPS we need to turn LED on. So we not
+ * not disable BIT 3/7 of reg3. */
+ if (rtlpriv->psc.rfoff_reason & (RF_CHANGE_BY_IPS | RF_CHANGE_BY_HW))
+ tmpu1b &= 0xFB;
+ else
+ tmpu1b &= 0x73;
+
+ rtl_write_byte(rtlpriv, SYS_FUNC_EN + 1, tmpu1b);
+ /* wait for BIT 10/11/15 to pull high automatically!! */
+ mdelay(1);
+
+ rtl_write_byte(rtlpriv, CMDR, 0);
+ rtl_write_byte(rtlpriv, TCR, 0);
+
+ /* Data sheet not define 0x562!!! Copy from WMAC!!!!! */
+ tmpu1b = rtl_read_byte(rtlpriv, 0x562);
+ tmpu1b |= 0x08;
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+ tmpu1b &= ~(BIT(3));
+ rtl_write_byte(rtlpriv, 0x562, tmpu1b);
+
+ /* Enable AFE clock source */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL, (tmpu1b | 0x01));
+ /* Delay 1.5ms */
+ udelay(1500);
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_XTAL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_XTAL_CTRL + 1, (tmpu1b & 0xfb));
+
+ /* Enable AFE Macro Block's Bandgap */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Enable AFE Mbias */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_MISC);
+ rtl_write_byte(rtlpriv, AFE_MISC, (tmpu1b | 0x02));
+ mdelay(1);
+
+ /* Enable LDOA15 block */
+ tmpu1b = rtl_read_byte(rtlpriv, LDOA15_CTRL);
+ rtl_write_byte(rtlpriv, LDOA15_CTRL, (tmpu1b | BIT(0)));
+
+ /* Set Digital Vdd to Retention isolation Path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_ISO_CTRL);
+ rtl_write_word(rtlpriv, SYS_ISO_CTRL, (tmpu2b | BIT(11)));
+
+
+ /* For warm reboot NIC disappera bug. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(13)));
+
+ rtl_write_byte(rtlpriv, SYS_ISO_CTRL + 1, 0x68);
+
+ /* Enable AFE PLL Macro Block */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL, (tmpu1b | BIT(0) | BIT(4)));
+ /* Enable MAC 80MHZ clock */
+ tmpu1b = rtl_read_byte(rtlpriv, AFE_PLL_CTRL + 1);
+ rtl_write_byte(rtlpriv, AFE_PLL_CTRL + 1, (tmpu1b | BIT(0)));
+ mdelay(1);
+
+ /* Release isolation AFE PLL & MD */
+ rtl_write_byte(rtlpriv, SYS_ISO_CTRL, 0xA6);
+
+ /* Enable MAC clock */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b | BIT(12) | BIT(11)));
+
+ /* Enable Core digital and enable IOREG R/W */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_FUNC_EN);
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11)));
+ /* enable REG_EN */
+ rtl_write_word(rtlpriv, SYS_FUNC_EN, (tmpu2b | BIT(11) | BIT(15)));
+
+ /* Switch the control path. */
+ tmpu2b = rtl_read_word(rtlpriv, SYS_CLKR);
+ rtl_write_word(rtlpriv, SYS_CLKR, (tmpu2b & (~BIT(2))));
+
+ tmpu1b = rtl_read_byte(rtlpriv, (SYS_CLKR + 1));
+ tmpu1b = ((tmpu1b | BIT(7)) & (~BIT(6)));
+ if (!_rtl92s_set_sysclk(hw, tmpu1b)) {
+ rtlpriv->psc.pwrdomain_protect = false;
+ return;
+ }
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+
+ /* After MACIO reset,we must refresh LED state. */
+ _rtl92se_gen_refreshledstate(hw);
+
+ rtlpriv->psc.pwrdomain_protect = false;
+}
+
+void rtl92se_card_disable(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ enum nl80211_iftype opmode;
+ u8 wait = 30;
+
+ rtlpriv->intf_ops->enable_aspm(hw);
+
+ if (rtlpci->driver_is_goingto_unload ||
+ ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+ rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+
+ /* we should chnge GPIO to input mode
+ * this will drop away current about 25mA*/
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+
+ /* this is very important for ips power save */
+ while (wait-- >= 10 && rtlpriv->psc.pwrdomain_protect) {
+ if (rtlpriv->psc.pwrdomain_protect)
+ mdelay(20);
+ else
+ break;
+ }
+
+ mac->link_state = MAC80211_NOLINK;
+ opmode = NL80211_IFTYPE_UNSPECIFIED;
+ _rtl92se_set_media_status(hw, opmode);
+
+ _rtl92s_phy_set_rfhalt(hw);
+ udelay(100);
+}
+
+void rtl92se_interrupt_recognized(struct ieee80211_hw *hw, u32 *p_inta,
+ u32 *p_intb)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ *p_inta = rtl_read_dword(rtlpriv, ISR) & rtlpci->irq_mask[0];
+ rtl_write_dword(rtlpriv, ISR, *p_inta);
+
+ *p_intb = rtl_read_dword(rtlpriv, ISR + 4) & rtlpci->irq_mask[1];
+ rtl_write_dword(rtlpriv, ISR + 4, *p_intb);
+}
+
+void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcntime_cfg = 0;
+ u16 bcn_cw = 6, bcn_ifs = 0xf;
+ u16 atim_window = 2;
+
+ /* ATIM Window (in unit of TU). */
+ rtl_write_word(rtlpriv, ATIMWND, atim_window);
+
+ /* Beacon interval (in unit of TU). */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, mac->beacon_interval);
+
+ /* DrvErlyInt (in unit of TU). (Time to send
+ * interrupt to notify driver to change
+ * beacon content) */
+ rtl_write_word(rtlpriv, BCN_DRV_EARLY_INT, 10 << 4);
+
+ /* BcnDMATIM(in unit of us). Indicates the
+ * time before TBTT to perform beacon queue DMA */
+ rtl_write_word(rtlpriv, BCN_DMATIME, 256);
+
+ /* Force beacon frame transmission even
+ * after receiving beacon frame from
+ * other ad hoc STA */
+ rtl_write_byte(rtlpriv, BCN_ERR_THRESH, 100);
+
+ /* Beacon Time Configuration */
+ if (mac->opmode == NL80211_IFTYPE_ADHOC)
+ bcntime_cfg |= (bcn_cw << BCN_TCFG_CW_SHIFT);
+
+ /* TODO: bcn_ifs may required to be changed on ASIC */
+ bcntime_cfg |= bcn_ifs << BCN_TCFG_IFS;
+
+ /*for beacon changed */
+ rtl92s_phy_set_beacon_hwreg(hw, mac->beacon_interval);
+}
+
+void rtl92se_set_beacon_interval(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 bcn_interval = mac->beacon_interval;
+
+ /* Beacon interval (in unit of TU). */
+ rtl_write_word(rtlpriv, BCN_INTERVAL, bcn_interval);
+ /* 2008.10.24 added by tynli for beacon changed. */
+ rtl92s_phy_set_beacon_hwreg(hw, bcn_interval);
+}
+
+void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+ ("add_msr:%x, rm_msr:%x\n", add_msr, rm_msr));
+
+ if (add_msr)
+ rtlpci->irq_mask[0] |= add_msr;
+
+ if (rm_msr)
+ rtlpci->irq_mask[0] &= (~rm_msr);
+
+ rtl92se_disable_interrupt(hw);
+ rtl92se_enable_interrupt(hw);
+}
+
+static void _rtl8192se_get_IC_Inferiority(struct ieee80211_hw *hw)
+{
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u8 efuse_id;
+
+ rtlhal->ic_class = IC_INFERIORITY_A;
+
+ /* Only retrieving while using EFUSE. */
+ if ((rtlefuse->epromtype == EEPROM_BOOT_EFUSE) &&
+ !rtlefuse->autoload_failflag) {
+ efuse_id = efuse_read_1byte(hw, EFUSE_IC_ID_OFFSET);
+
+ if (efuse_id == 0xfe)
+ rtlhal->ic_class = IC_INFERIORITY_B;
+ }
+}
+
+static void _rtl92se_read_adapter_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u16 i, usvalue;
+ u16 eeprom_id;
+ u8 tempval;
+ u8 hwinfo[HWSET_MAX_SIZE_92S];
+ u8 rf_path, index;
+
+ if (rtlefuse->epromtype == EEPROM_93C46) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("RTL819X Not boot from eeprom, check it !!"));
+ } else if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+ rtl_efuse_shadow_map_update(hw);
+
+ memcpy((void *)hwinfo, (void *)
+ &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+ HWSET_MAX_SIZE_92S);
+ }
+
+ RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+ hwinfo, HWSET_MAX_SIZE_92S);
+
+ eeprom_id = *((u16 *)&hwinfo[0]);
+ if (eeprom_id != RTL8190_EEPROM_ID) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("EEPROM ID(%#x) is invalid!!\n", eeprom_id));
+ rtlefuse->autoload_failflag = true;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ }
+
+ if (rtlefuse->autoload_failflag == true)
+ return;
+
+ _rtl8192se_get_IC_Inferiority(hw);
+
+ /* Read IC Version && Channel Plan */
+ /* VID, DID SE 0xA-D */
+ rtlefuse->eeprom_vid = *(u16 *)&hwinfo[EEPROM_VID];
+ rtlefuse->eeprom_did = *(u16 *)&hwinfo[EEPROM_DID];
+ rtlefuse->eeprom_svid = *(u16 *)&hwinfo[EEPROM_SVID];
+ rtlefuse->eeprom_smid = *(u16 *)&hwinfo[EEPROM_SMID];
+ rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROMId = 0x%4x\n", eeprom_id));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid));
+
+ for (i = 0; i < 6; i += 2) {
+ usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+ *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
+ }
+
+ for (i = 0; i < 6; i++)
+ rtl_write_byte(rtlpriv, MACIDR0 + i, rtlefuse->dev_addr[i]);
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ (MAC_FMT "\n", MAC_ARG(rtlefuse->dev_addr)));
+
+ /* Get Tx Power Level by Channel */
+ /* Read Tx power of Channel 1 ~ 14 from EEPROM. */
+ /* 92S suupport RF A & B */
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ /* Read CCK RF A & B Tx power */
+ rtlefuse->eeprom_chnlarea_txpwr_cck[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERBASE + rf_path * 3 + i];
+
+ /* Read OFDM RF A & B Tx power for 1T */
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s[rf_path][i] =
+ hwinfo[EEPROM_TXPOWERBASE + 6 + rf_path * 3 + i];
+
+ /* Read OFDM RF A & B Tx power for 2T */
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif[rf_path][i]
+ = hwinfo[EEPROM_TXPOWERBASE + 12 +
+ rf_path * 3 + i];
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path,
+ i, rtlefuse->eeprom_chnlarea_txpwr_cck
+ [rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+ [rf_path][i]));
+ for (rf_path = 0; rf_path < 2; rf_path++)
+ for (i = 0; i < 3; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+ ("RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
+ rf_path, i,
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+ [rf_path][i]));
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+
+ /* Assign dedicated channel tx power */
+ for (i = 0; i < 14; i++) {
+ /* channel 1~3 use the same Tx Power Level. */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-14 */
+ else
+ index = 2;
+
+ /* Record A & B CCK /OFDM - 1T/2T Channel area
+ * tx power */
+ rtlefuse->txpwrlevel_cck[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_cck
+ [rf_path][index];
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+ [rf_path][index];
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
+ rtlefuse->eeprom_chnlarea_txpwr_ht40_2sdiif
+ [rf_path][index];
+ }
+
+ for (i = 0; i < 14; i++) {
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
+ "[0x%x / 0x%x / 0x%x]\n", rf_path, i,
+ rtlefuse->txpwrlevel_cck[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
+ rtlefuse->txpwrlevel_ht40_2s[rf_path][i]));
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ for (i = 0; i < 3; i++) {
+ /* Read Power diff limit. */
+ rtlefuse->eeprom_pwrgroup[rf_path][i] =
+ hwinfo[EEPROM_TXPWRGROUP + rf_path * 3 + i];
+ }
+ }
+
+ for (rf_path = 0; rf_path < 2; rf_path++) {
+ /* Fill Pwr group */
+ for (i = 0; i < 14; i++) {
+ /* Chanel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-13 */
+ else
+ index = 2;
+
+ rtlefuse->pwrgroup_ht20[rf_path][i] =
+ (rtlefuse->eeprom_pwrgroup[rf_path][index] &
+ 0xf);
+ rtlefuse->pwrgroup_ht40[rf_path][i] =
+ ((rtlefuse->eeprom_pwrgroup[rf_path][index] &
+ 0xf0) >> 4);
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht20[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht20[rf_path][i]));
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-%d pwrgroup_ht40[%d] = 0x%x\n",
+ rf_path, i,
+ rtlefuse->pwrgroup_ht40[rf_path][i]));
+ }
+ }
+
+ for (i = 0; i < 14; i++) {
+ /* Read tx power difference between HT OFDM 20/40 MHZ */
+ /* channel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 1;
+ /* Channel 9-14 */
+ else
+ index = 2;
+
+ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_HT20_DIFF +
+ index]) & 0xff;
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF);
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+
+ /* Read OFDM<->HT tx power diff */
+ /* Channel 1-3 */
+ if (i < 3)
+ index = 0;
+ /* Channel 4-8 */
+ else if (i < 8)
+ index = 0x11;
+ /* Channel 9-14 */
+ else
+ index = 1;
+
+ tempval = (*(u8 *)&hwinfo[EEPROM_TX_PWR_OFDM_DIFF + index])
+ & 0xff;
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] =
+ (tempval & 0xF);
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] =
+ ((tempval >> 4) & 0xF);
+
+ tempval = (*(u8 *)&hwinfo[TX_PWR_SAFETY_CHK]);
+ rtlefuse->txpwr_safetyflag = (tempval & 0x01);
+ }
+
+ rtlefuse->eeprom_regulatory = 0;
+ if (rtlefuse->eeprom_version >= 2) {
+ /* BIT(0)~2 */
+ if (rtlefuse->eeprom_version >= 4)
+ rtlefuse->eeprom_regulatory =
+ (hwinfo[EEPROM_REGULATORY] & 0x7);
+ else /* BIT(0) */
+ rtlefuse->eeprom_regulatory =
+ (hwinfo[EEPROM_REGULATORY] & 0x1);
+ }
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory));
+
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]));
+ for (i = 0; i < 14; i++)
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+ ("RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]));
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPwrSafetyFlag = %d\n",
+ rtlefuse->txpwr_safetyflag));
+
+ /* Read RF-indication and Tx Power gain
+ * index diff of legacy to HT OFDM rate. */
+ tempval = (*(u8 *)&hwinfo[EEPROM_RFIND_POWERDIFF]) & 0xff;
+ rtlefuse->eeprom_txpowerdiff = tempval;
+ rtlefuse->legacy_httxpowerdiff =
+ rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][0];
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TxPowerDiff = %#x\n",
+ rtlefuse->eeprom_txpowerdiff));
+
+ /* Get TSSI value for each path. */
+ usvalue = *(u16 *)&hwinfo[EEPROM_TSSI_A];
+ rtlefuse->eeprom_tssi[RF90_PATH_A] = (u8)((usvalue & 0xff00) >> 8);
+ usvalue = *(u8 *)&hwinfo[EEPROM_TSSI_B];
+ rtlefuse->eeprom_tssi[RF90_PATH_B] = (u8)(usvalue & 0xff);
+
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+ rtlefuse->eeprom_tssi[RF90_PATH_A],
+ rtlefuse->eeprom_tssi[RF90_PATH_B]));
+
+ /* Read antenna tx power offset of B/C/D to A from EEPROM */
+ /* and read ThermalMeter from EEPROM */
+ tempval = *(u8 *)&hwinfo[EEPROM_THERMALMETER];
+ rtlefuse->eeprom_thermalmeter = tempval;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("thermalmeter = 0x%x\n",
+ rtlefuse->eeprom_thermalmeter));
+
+ /* ThermalMeter, BIT(0)~3 for RFIC1, BIT(4)~7 for RFIC2 */
+ rtlefuse->thermalmeter[0] = (rtlefuse->eeprom_thermalmeter & 0x1f);
+ rtlefuse->tssi_13dbm = rtlefuse->eeprom_thermalmeter * 100;
+
+ /* Read CrystalCap from EEPROM */
+ tempval = (*(u8 *)&hwinfo[EEPROM_CRYSTALCAP]) >> 4;
+ rtlefuse->eeprom_crystalcap = tempval;
+ /* CrystalCap, BIT(12)~15 */
+ rtlefuse->crystalcap = rtlefuse->eeprom_crystalcap;
+
+ /* Read IC Version && Channel Plan */
+ /* Version ID, Channel plan */
+ rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+ rtlefuse->txpwr_fromeprom = true;
+ RTPRINT(rtlpriv, FINIT, INIT_TxPower, ("EEPROM ChannelPlan = 0x%4x\n",
+ rtlefuse->eeprom_channelplan));
+
+ /* Read Customer ID or Board Type!!! */
+ tempval = *(u8 *)&hwinfo[EEPROM_BOARDTYPE];
+ /* Change RF type definition */
+ if (tempval == 0)
+ rtlphy->rf_type = RF_2T2R;
+ else if (tempval == 1)
+ rtlphy->rf_type = RF_1T2R;
+ else if (tempval == 2)
+ rtlphy->rf_type = RF_1T2R;
+ else if (tempval == 3)
+ rtlphy->rf_type = RF_1T1R;
+
+ /* 1T2R but 1SS (1x1 receive combining) */
+ rtlefuse->b1x1_recvcombine = false;
+ if (rtlphy->rf_type == RF_1T2R) {
+ tempval = rtl_read_byte(rtlpriv, 0x07);
+ if (!(tempval & BIT(0))) {
+ rtlefuse->b1x1_recvcombine = true;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("RF_TYPE=1T2R but only 1SS\n"));
+ }
+ }
+ rtlefuse->b1ss_support = rtlefuse->b1x1_recvcombine;
+ rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMID];
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("EEPROM Customer ID: 0x%2x",
+ rtlefuse->eeprom_oemid));
+
+ /* set channel paln to world wide 13 */
+ rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+}
+
+void rtl92se_read_eeprom_info(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 tmp_u1b = 0;
+
+ tmp_u1b = rtl_read_byte(rtlpriv, EPROM_CMD);
+
+ if (tmp_u1b & BIT(4)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EEPROM\n"));
+ rtlefuse->epromtype = EEPROM_93C46;
+ } else {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("Boot from EFUSE\n"));
+ rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+ }
+
+ if (tmp_u1b & BIT(5)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Autoload OK\n"));
+ rtlefuse->autoload_failflag = false;
+ _rtl92se_read_adapter_info(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Autoload ERR!!\n"));
+ rtlefuse->autoload_failflag = true;
+ }
+}
+
+static void rtl92se_update_hal_rate_table(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ u32 ratr_value;
+ u8 ratr_index = 0;
+ u8 nmode = mac->ht_enable;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+ u16 shortgi_rate = 0;
+ u32 tmp_ratr_value = 0;
+ u8 curtxbw_40mhz = mac->bw_40;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = mac->mode;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_value = sta->supp_rates[1] << 4;
+ else
+ ratr_value = sta->supp_rates[0];
+ ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ ratr_value &= 0x0000000D;
+ break;
+ case WIRELESS_MODE_G:
+ ratr_value &= 0x00000FF5;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ nmode = 1;
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ ratr_value &= 0x0007F005;
+ } else {
+ u32 ratr_mask;
+
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R) {
+ if (curtxbw_40mhz)
+ ratr_mask = 0x000ff015;
+ else
+ ratr_mask = 0x000ff005;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_mask = 0x0f0ff015;
+ else
+ ratr_mask = 0x0f0ff005;
+ }
+
+ ratr_value &= ratr_mask;
+ }
+ break;
+ default:
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_value &= 0x000ff0ff;
+ else
+ ratr_value &= 0x0f0ff0ff;
+
+ break;
+ }
+
+ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
+ ratr_value &= 0x0FFFFFFF;
+ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT)
+ ratr_value &= 0x0FFFFFF0;
+
+ if (nmode && ((curtxbw_40mhz &&
+ curshortgi_40mhz) || (!curtxbw_40mhz &&
+ curshortgi_20mhz))) {
+
+ ratr_value |= 0x10000000;
+ tmp_ratr_value = (ratr_value >> 12);
+
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & tmp_ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+
+ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate);
+ }
+
+ rtl_write_dword(rtlpriv, ARFR0 + ratr_index * 4, ratr_value);
+ if (ratr_value & 0xfffff000)
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_N);
+ else
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RA_REFRESH_BG);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+ ("%x\n", rtl_read_dword(rtlpriv, ARFR0)));
+}
+
+static void rtl92se_update_hal_rate_mask(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_sta_info *sta_entry = NULL;
+ u32 ratr_bitmap;
+ u8 ratr_index = 0;
+ u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+ ? 1 : 0;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+ 1 : 0;
+ u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+ 1 : 0;
+ enum wireless_mode wirelessmode = 0;
+ bool shortgi = false;
+ u32 ratr_value = 0;
+ u8 shortgi_rate = 0;
+ u32 mask = 0;
+ u32 band = 0;
+ bool bmulticast = false;
+ u8 macid = 0;
+ u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+ sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+ wirelessmode = sta_entry->wireless_mode;
+ if (mac->opmode == NL80211_IFTYPE_STATION)
+ curtxbw_40mhz = mac->bw_40;
+ else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC)
+ macid = sta->aid + 1;
+
+ if (rtlhal->current_bandtype == BAND_ON_5G)
+ ratr_bitmap = sta->supp_rates[1] << 4;
+ else
+ ratr_bitmap = sta->supp_rates[0];
+ ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+ sta->ht_cap.mcs.rx_mask[0] << 12);
+ switch (wirelessmode) {
+ case WIRELESS_MODE_B:
+ band |= WIRELESS_11B;
+ ratr_index = RATR_INX_WIRELESS_B;
+ if (ratr_bitmap & 0x0000000c)
+ ratr_bitmap &= 0x0000000d;
+ else
+ ratr_bitmap &= 0x0000000f;
+ break;
+ case WIRELESS_MODE_G:
+ band |= (WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_GB;
+
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00000f00;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x00000ff0;
+ else
+ ratr_bitmap &= 0x00000ff5;
+ break;
+ case WIRELESS_MODE_A:
+ band |= WIRELESS_11A;
+ ratr_index = RATR_INX_WIRELESS_A;
+ ratr_bitmap &= 0x00000ff0;
+ break;
+ case WIRELESS_MODE_N_24G:
+ case WIRELESS_MODE_N_5G:
+ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (mimo_ps == IEEE80211_SMPS_STATIC) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x00070000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0007f000;
+ else
+ ratr_bitmap &= 0x0007f005;
+ } else {
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (rssi_level == 1) {
+ ratr_bitmap &= 0x000f0000;
+ } else if (rssi_level == 3) {
+ ratr_bitmap &= 0x000fc000;
+ } else if (rssi_level == 5) {
+ ratr_bitmap &= 0x000ff000;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_bitmap &= 0x000ff015;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
+ } else {
+ if (rssi_level == 1) {
+ ratr_bitmap &= 0x0f8f0000;
+ } else if (rssi_level == 3) {
+ ratr_bitmap &= 0x0f8fc000;
+ } else if (rssi_level == 5) {
+ ratr_bitmap &= 0x0f8ff000;
+ } else {
+ if (curtxbw_40mhz)
+ ratr_bitmap &= 0x0f8ff015;
+ else
+ ratr_bitmap &= 0x0f8ff005;
+ }
+ }
+ }
+
+ if ((curtxbw_40mhz && curshortgi_40mhz) ||
+ (!curtxbw_40mhz && curshortgi_20mhz)) {
+ if (macid == 0)
+ shortgi = true;
+ else if (macid == 1)
+ shortgi = false;
+ }
+ break;
+ default:
+ band |= (WIRELESS_11N | WIRELESS_11G | WIRELESS_11B);
+ ratr_index = RATR_INX_WIRELESS_NGB;
+
+ if (rtlphy->rf_type == RF_1T2R)
+ ratr_bitmap &= 0x000ff0ff;
+ else
+ ratr_bitmap &= 0x0f8ff0ff;
+ break;
+ }
+
+ if (rtlpriv->rtlhal.version >= VERSION_8192S_BCUT)
+ ratr_bitmap &= 0x0FFFFFFF;
+ else if (rtlpriv->rtlhal.version == VERSION_8192S_ACUT)
+ ratr_bitmap &= 0x0FFFFFF0;
+
+ if (shortgi) {
+ ratr_bitmap |= 0x10000000;
+ /* Get MAX MCS available. */
+ ratr_value = (ratr_bitmap >> 12);
+ for (shortgi_rate = 15; shortgi_rate > 0; shortgi_rate--) {
+ if ((1 << shortgi_rate) & ratr_value)
+ break;
+ }
+
+ shortgi_rate = (shortgi_rate << 12) | (shortgi_rate << 8) |
+ (shortgi_rate << 4) | (shortgi_rate);
+ rtl_write_byte(rtlpriv, SG_RATE, shortgi_rate);
+ }
+
+ mask |= (bmulticast ? 1 : 0) << 9 | (macid & 0x1f) << 4 | (band & 0xf);
+
+ RT_TRACE(rtlpriv, COMP_RATR, DBG_TRACE, ("mask = %x, bitmap = %x\n",
+ mask, ratr_bitmap));
+ rtl_write_dword(rtlpriv, 0x2c4, ratr_bitmap);
+ rtl_write_dword(rtlpriv, WFM5, (FW_RA_UPDATE_MASK | (mask << 8)));
+
+ if (macid != 0)
+ sta_entry->ratr_index = ratr_index;
+}
+
+void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->dm.useramask)
+ rtl92se_update_hal_rate_mask(hw, sta, rssi_level);
+ else
+ rtl92se_update_hal_rate_table(hw, sta);
+}
+
+void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u16 sifs_timer;
+
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+ (u8 *)&mac->slot_time);
+ sifs_timer = 0x0e0e;
+ rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+
+}
+
+/* this ifunction is for RFKILL, it's different with windows,
+ * because UI will disable wireless when GPIO Radio Off.
+ * And here we not check or Disable/Enable ASPM like windows*/
+bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ enum rf_pwrstate rfpwr_toset, cur_rfstate;
+ unsigned long flag = 0;
+ bool actuallyset = false;
+ bool turnonbypowerdomain = false;
+
+ /* just 8191se can check gpio before firstup, 92c/92d have fixed it */
+ if ((rtlpci->up_first_time == 1) || (rtlpci->being_init_adapter))
+ return false;
+
+ if (ppsc->swrf_processing)
+ return false;
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ if (ppsc->rfchange_inprogress) {
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ return false;
+ } else {
+ ppsc->rfchange_inprogress = true;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ cur_rfstate = ppsc->rfpwr_state;
+
+ /* because after _rtl92s_phy_set_rfhalt, all power
+ * closed, so we must open some power for GPIO check,
+ * or we will always check GPIO RFOFF here,
+ * And we should close power after GPIO check */
+ if (RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+ _rtl92se_power_domain_init(hw);
+ turnonbypowerdomain = true;
+ }
+
+ rfpwr_toset = _rtl92se_rf_onoff_detect(hw);
+
+ if ((ppsc->hwradiooff == true) && (rfpwr_toset == ERFON)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("RFKILL-HW Radio ON, RF ON\n"));
+
+ rfpwr_toset = ERFON;
+ ppsc->hwradiooff = false;
+ actuallyset = true;
+ } else if ((ppsc->hwradiooff == false) && (rfpwr_toset == ERFOFF)) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("RFKILL-HW Radio OFF, RF OFF\n"));
+
+ rfpwr_toset = ERFOFF;
+ ppsc->hwradiooff = true;
+ actuallyset = true;
+ }
+
+ if (actuallyset) {
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+
+ /* this not include ifconfig wlan0 down case */
+ /* } else if (rfpwr_toset == ERFOFF || cur_rfstate == ERFOFF) { */
+ } else {
+ /* because power_domain_init may be happen when
+ * _rtl92s_phy_set_rfhalt, this will open some powers
+ * and cause current increasing about 40 mA for ips,
+ * rfoff and ifconfig down, so we set
+ * _rtl92s_phy_set_rfhalt again here */
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC &&
+ turnonbypowerdomain) {
+ _rtl92s_phy_set_rfhalt(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ }
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+ ppsc->rfchange_inprogress = false;
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+ }
+
+ *valid = 1;
+ return !ppsc->hwradiooff;
+
+}
+
+/* Is_wepkey just used for WEP used as group & pairwise key
+ * if pairwise is AES ang group is WEP Is_wepkey == false.*/
+void rtl92se_set_key(struct ieee80211_hw *hw, u32 key_index, u8 *p_macaddr,
+ bool is_group, u8 enc_algo, bool is_wepkey, bool clear_all)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 *macaddr = p_macaddr;
+
+ u32 entry_id = 0;
+ bool is_pairwise = false;
+
+ static u8 cam_const_addr[4][6] = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+ };
+ static u8 cam_const_broad[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+ if (clear_all) {
+ u8 idx = 0;
+ u8 cam_offset = 0;
+ u8 clear_number = 5;
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, ("clear_all\n"));
+
+ for (idx = 0; idx < clear_number; idx++) {
+ rtl_cam_mark_invalid(hw, cam_offset + idx);
+ rtl_cam_empty_entry(hw, cam_offset + idx);
+
+ if (idx < 5) {
+ memset(rtlpriv->sec.key_buf[idx], 0,
+ MAX_KEY_LEN);
+ rtlpriv->sec.key_len[idx] = 0;
+ }
+ }
+
+ } else {
+ switch (enc_algo) {
+ case WEP40_ENCRYPTION:
+ enc_algo = CAM_WEP40;
+ break;
+ case WEP104_ENCRYPTION:
+ enc_algo = CAM_WEP104;
+ break;
+ case TKIP_ENCRYPTION:
+ enc_algo = CAM_TKIP;
+ break;
+ case AESCCMP_ENCRYPTION:
+ enc_algo = CAM_AES;
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ enc_algo = CAM_TKIP;
+ break;
+ }
+
+ if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+ macaddr = cam_const_addr[key_index];
+ entry_id = key_index;
+ } else {
+ if (is_group) {
+ macaddr = cam_const_broad;
+ entry_id = key_index;
+ } else {
+ if (mac->opmode == NL80211_IFTYPE_AP) {
+ entry_id = rtl_cam_get_free_entry(hw,
+ p_macaddr);
+ if (entry_id >= TOTAL_CAM_ENTRY) {
+ RT_TRACE(rtlpriv,
+ COMP_SEC, DBG_EMERG,
+ ("Can not find free hw"
+ " security cam entry\n"));
+ return;
+ }
+ } else {
+ entry_id = CAM_PAIRWISE_KEY_POSITION;
+ }
+
+ key_index = PAIRWISE_KEYIDX;
+ is_pairwise = true;
+ }
+ }
+
+ if (rtlpriv->sec.key_len[key_index] == 0) {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("delete one entry, entry_id is %d\n",
+ entry_id));
+ if (mac->opmode == NL80211_IFTYPE_AP)
+ rtl_cam_del_entry(hw, p_macaddr);
+ rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY length is %d\n",
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]));
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
+ ("The insert KEY is %x %x\n",
+ rtlpriv->sec.key_buf[0][0],
+ rtlpriv->sec.key_buf[0][1]));
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("add one entry\n"));
+ if (is_pairwise) {
+ RT_PRINT_DATA(rtlpriv, COMP_SEC, DBG_LOUD,
+ "Pairwiase Key content :",
+ rtlpriv->sec.pairwise_key,
+ rtlpriv->sec.key_len[PAIRWISE_KEYIDX]);
+
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set Pairwiase key\n"));
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[key_index]);
+ } else {
+ RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+ ("set group key\n"));
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ rtl_cam_add_one_entry(hw,
+ rtlefuse->dev_addr,
+ PAIRWISE_KEYIDX,
+ CAM_PAIRWISE_KEY_POSITION,
+ enc_algo, CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+
+ rtl_cam_add_one_entry(hw, macaddr, key_index,
+ entry_id, enc_algo,
+ CAM_CONFIG_NO_USEDK,
+ rtlpriv->sec.key_buf[entry_id]);
+ }
+
+ }
+ }
+}
+
+void rtl92se_suspend(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ rtlpci->up_first_time = true;
+}
+
+void rtl92se_resume(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ u32 val;
+
+ pci_read_config_dword(rtlpci->pdev, 0x40, &val);
+ if ((val & 0x0000ff00) != 0)
+ pci_write_config_dword(rtlpci->pdev, 0x40,
+ val & 0xffff00ff);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/hw.h b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
new file mode 100644
index 0000000..6160a9b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/hw.h
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_HW_H__
+#define __REALTEK_PCI92SE_HW_H__
+
+#define MSR_LINK_MANAGED 2
+#define MSR_LINK_NONE 0
+#define MSR_LINK_SHIFT 0
+#define MSR_LINK_ADHOC 1
+#define MSR_LINK_MASTER 3
+
+enum WIRELESS_NETWORK_TYPE {
+ WIRELESS_11B = 1,
+ WIRELESS_11G = 2,
+ WIRELESS_11A = 4,
+ WIRELESS_11N = 8
+};
+
+void rtl92se_get_hw_reg(struct ieee80211_hw *hw,
+ u8 variable, u8 *val);
+void rtl92se_read_eeprom_info(struct ieee80211_hw *hw);
+void rtl92se_interrupt_recognized(struct ieee80211_hw *hw,
+ u32 *inta, u32 *intb);
+int rtl92se_hw_init(struct ieee80211_hw *hw);
+void rtl92se_card_disable(struct ieee80211_hw *hw);
+void rtl92se_enable_interrupt(struct ieee80211_hw *hw);
+void rtl92se_disable_interrupt(struct ieee80211_hw *hw);
+int rtl92se_set_network_type(struct ieee80211_hw *hw,
+ enum nl80211_iftype type);
+void rtl92se_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl92se_set_mac_addr(struct rtl_io *io, const u8 * addr);
+void rtl92se_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl92se_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl92se_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl92se_update_interrupt_mask(struct ieee80211_hw *hw,
+ u32 add_msr, u32 rm_msr);
+void rtl92se_set_hw_reg(struct ieee80211_hw *hw, u8 variable,
+ u8 *val);
+void rtl92se_update_hal_rate_tbl(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta, u8 rssi_level);
+void rtl92se_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw,
+ u8 *valid);
+void rtl8192se_gpiobit3_cfg_inputmode(struct ieee80211_hw *hw);
+void rtl92se_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl92se_set_key(struct ieee80211_hw *hw,
+ u32 key_index, u8 *macaddr, bool is_group,
+ u8 enc_algo, bool is_wepkey, bool clear_all);
+void rtl92se_suspend(struct ieee80211_hw *hw);
+void rtl92se_resume(struct ieee80211_hw *hw);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.c b/drivers/net/wireless/rtlwifi/rtl8192se/led.c
new file mode 100644
index 0000000..6d4f666
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.c
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl92se_init_led(struct ieee80211_hw *hw,
+ struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+ pled->hw = hw;
+ pled->ledpin = ledpin;
+ pled->ledon = false;
+}
+
+void rtl92se_init_sw_leds(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+ _rtl92se_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ u8 ledcfg;
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, LEDCFG);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0xf0);
+ break;
+ case LED_PIN_LED1:
+ rtl_write_byte(rtlpriv, LEDCFG, ledcfg & 0x0f);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->ledon = true;
+}
+
+void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ u8 ledcfg;
+
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+ ("LedAddr:%X ledpin=%d\n", LEDCFG, pled->ledpin));
+
+ ledcfg = rtl_read_byte(rtlpriv, LEDCFG);
+
+ switch (pled->ledpin) {
+ case LED_PIN_GPIO0:
+ break;
+ case LED_PIN_LED0:
+ ledcfg &= 0xf0;
+ if (pcipriv->ledctl.led_opendrain == true)
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(1)));
+ else
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3)));
+ break;
+ case LED_PIN_LED1:
+ ledcfg &= 0x0f;
+ rtl_write_byte(rtlpriv, LEDCFG, (ledcfg | BIT(3)));
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+ pled->ledon = false;
+}
+
+static void _rtl92se_sw_led_control(struct ieee80211_hw *hw,
+ enum led_ctl_mode ledaction)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+ switch (ledaction) {
+ case LED_CTL_POWER_ON:
+ case LED_CTL_LINK:
+ case LED_CTL_NO_LINK:
+ rtl92se_sw_led_on(hw, pLed0);
+ break;
+ case LED_CTL_POWER_OFF:
+ rtl92se_sw_led_off(hw, pLed0);
+ break;
+ default:
+ break;
+ }
+}
+
+void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+ (ledaction == LED_CTL_TX ||
+ ledaction == LED_CTL_RX ||
+ ledaction == LED_CTL_SITE_SURVEY ||
+ ledaction == LED_CTL_LINK ||
+ ledaction == LED_CTL_NO_LINK ||
+ ledaction == LED_CTL_START_TO_LINK ||
+ ledaction == LED_CTL_POWER_ON)) {
+ return;
+ }
+ RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, ("ledaction %d,\n",
+ ledaction));
+
+ _rtl92se_sw_led_control(hw, ledaction);
+}
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/led.h b/drivers/net/wireless/rtlwifi/rtl8192se/led.h
new file mode 100644
index 0000000..8cce387
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/led.h
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_LED_H__
+#define __REALTEK_PCI92SE_LED_H__
+
+void rtl92se_init_sw_leds(struct ieee80211_hw *hw);
+void rtl92se_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92se_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl92se_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
new file mode 100644
index 0000000..63b45e6
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c
@@ -0,0 +1,1740 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "fw.h"
+#include "hw.h"
+#include "table.h"
+
+static u32 _rtl92s_phy_calculate_bit_shift(u32 bitmask)
+{
+ u32 i;
+
+ for (i = 0; i <= 31; i++) {
+ if (((bitmask >> i) & 0x1) == 1)
+ break;
+ }
+
+ return i;
+}
+
+u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 returnvalue = 0, originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x)\n",
+ regaddr, bitmask));
+
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ returnvalue = (originalvalue & bitmask) >> bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+ ("BBR MASK=0x%x Addr[0x%x]=0x%x\n",
+ bitmask, regaddr, originalvalue));
+
+ return returnvalue;
+
+}
+
+void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 originalvalue, bitshift;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask, data));
+
+ if (bitmask != MASKDWORD) {
+ originalvalue = rtl_read_dword(rtlpriv, regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ data = ((originalvalue & (~bitmask)) | (data << bitshift));
+ }
+
+ rtl_write_dword(rtlpriv, regaddr, data);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x)\n", regaddr, bitmask, data));
+
+}
+
+static u32 _rtl92s_phy_rf_serial_read(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset)
+{
+
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 newoffset;
+ u32 tmplong, tmplong2;
+ u8 rfpi_enable = 0;
+ u32 retvalue = 0;
+
+ offset &= 0x3f;
+ newoffset = offset;
+
+ tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+
+ if (rfpath == RF90_PATH_A)
+ tmplong2 = tmplong;
+ else
+ tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+
+ tmplong2 = (tmplong2 & (~BLSSI_READADDRESS)) | (newoffset << 23) |
+ BLSSI_READEDGE;
+
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+ tmplong & (~BLSSI_READEDGE));
+
+ mdelay(1);
+
+ rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+ mdelay(1);
+
+ rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD, tmplong |
+ BLSSI_READEDGE);
+ mdelay(1);
+
+ if (rfpath == RF90_PATH_A)
+ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+ BIT(8));
+ else if (rfpath == RF90_PATH_B)
+ rfpi_enable = (u8)rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+ BIT(8));
+
+ if (rfpi_enable)
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readbackpi,
+ BLSSI_READBACK_DATA);
+ else
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+ BLSSI_READBACK_DATA);
+
+ retvalue = rtl_get_bbreg(hw, pphyreg->rflssi_readback,
+ BLSSI_READBACK_DATA);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFR-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rflssi_readback, retvalue));
+
+ return retvalue;
+
+}
+
+static void _rtl92s_phy_rf_serial_write(struct ieee80211_hw *hw,
+ enum radio_path rfpath, u32 offset,
+ u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+ u32 data_and_addr = 0;
+ u32 newoffset;
+
+ offset &= 0x3f;
+ newoffset = offset;
+
+ data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+ rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("RFW-%d Addr[0x%x]=0x%x\n",
+ rfpath, pphyreg->rf3wire_offset, data_and_addr));
+}
+
+
+u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 original_value, readback_value, bitshift;
+ unsigned long flags;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x)\n", regaddr, rfpath, bitmask));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr);
+
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ readback_value = (original_value & bitmask) >> bitshift;
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
+ "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath,
+ bitmask, original_value));
+
+ return readback_value;
+}
+
+void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 original_value, bitshift;
+ unsigned long flags;
+
+ if (!((rtlphy->rf_pathmap >> rfpath) & 0x1))
+ return;
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
+ " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
+
+ spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+ if (bitmask != RFREG_OFFSET_MASK) {
+ original_value = _rtl92s_phy_rf_serial_read(hw, rfpath,
+ regaddr);
+ bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
+ data = ((original_value & (~bitmask)) | (data << bitshift));
+ }
+
+ _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data);
+
+ spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+ RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), "
+ "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
+
+}
+
+void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw,
+ u8 operation)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+ if (!is_hal_stop(rtlhal)) {
+ switch (operation) {
+ case SCAN_OPT_BACKUP:
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_PAUSE_DM_BY_SCAN);
+ break;
+ case SCAN_OPT_RESTORE:
+ rtl92s_phy_set_fw_cmd(hw, FW_CMD_RESUME_DM_BY_SCAN);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Unknown operation.\n"));
+ break;
+ }
+ }
+}
+
+void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ u8 reg_bw_opmode;
+ u8 reg_prsr_rsc;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n",
+ rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+ "20MHz" : "40MHz"));
+
+ if (rtlphy->set_bwmode_inprogress)
+ return;
+ if (is_hal_stop(rtlhal))
+ return;
+
+ rtlphy->set_bwmode_inprogress = true;
+
+ reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE);
+ reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2);
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ reg_bw_opmode |= BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+ rtl_write_byte(rtlpriv, BW_OPMODE, reg_bw_opmode);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n",
+ rtlphy->current_chan_bw));
+ break;
+ }
+
+ switch (rtlphy->current_chan_bw) {
+ case HT_CHANNEL_WIDTH_20:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+
+ if (rtlhal->version >= VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x58);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+ rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+ rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+ (mac->cur_40_prime_sc >> 1));
+ rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+
+ if (rtlhal->version >= VERSION_8192S_BCUT)
+ rtl_write_byte(rtlpriv, RFPGA0_ANALOGPARAMETER2, 0x18);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n", rtlphy->current_chan_bw));
+ break;
+ }
+
+ rtl92s_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+ rtlphy->set_bwmode_inprogress = false;
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+}
+
+static bool _rtl92s_phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+ u32 cmdtableidx, u32 cmdtablesz, enum swchnlcmd_id cmdid,
+ u32 para1, u32 para2, u32 msdelay)
+{
+ struct swchnlcmd *pcmd;
+
+ if (cmdtable == NULL) {
+ RT_ASSERT(false, ("cmdtable cannot be NULL.\n"));
+ return false;
+ }
+
+ if (cmdtableidx >= cmdtablesz)
+ return false;
+
+ pcmd = cmdtable + cmdtableidx;
+ pcmd->cmdid = cmdid;
+ pcmd->para1 = para1;
+ pcmd->para2 = para2;
+ pcmd->msdelay = msdelay;
+
+ return true;
+}
+
+static bool _rtl92s_phy_sw_chnl_step_by_step(struct ieee80211_hw *hw,
+ u8 channel, u8 *stage, u8 *step, u32 *delay)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+ u32 precommoncmdcnt;
+ struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+ u32 postcommoncmdcnt;
+ struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+ u32 rfdependcmdcnt;
+ struct swchnlcmd *currentcmd = NULL;
+ u8 rfpath;
+ u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+ precommoncmdcnt = 0;
+ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL, 0, 0, 0);
+ _rtl92s_phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+ MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+
+ postcommoncmdcnt = 0;
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+ MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+
+ rfdependcmdcnt = 0;
+
+ RT_ASSERT((channel >= 1 && channel <= 14),
+ ("illegal channel for Zebra: %d\n", channel));
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+ RF_CHNLBW, channel, 10);
+
+ _rtl92s_phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+ MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+
+ do {
+ switch (*stage) {
+ case 0:
+ currentcmd = &precommoncmd[*step];
+ break;
+ case 1:
+ currentcmd = &rfdependcmd[*step];
+ break;
+ case 2:
+ currentcmd = &postcommoncmd[*step];
+ break;
+ }
+
+ if (currentcmd->cmdid == CMDID_END) {
+ if ((*stage) == 2) {
+ return true;
+ } else {
+ (*stage)++;
+ (*step) = 0;
+ continue;
+ }
+ }
+
+ switch (currentcmd->cmdid) {
+ case CMDID_SET_TXPOWEROWER_LEVEL:
+ rtl92s_phy_set_txpower(hw, channel);
+ break;
+ case CMDID_WRITEPORT_ULONG:
+ rtl_write_dword(rtlpriv, currentcmd->para1,
+ currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_USHORT:
+ rtl_write_word(rtlpriv, currentcmd->para1,
+ (u16)currentcmd->para2);
+ break;
+ case CMDID_WRITEPORT_UCHAR:
+ rtl_write_byte(rtlpriv, currentcmd->para1,
+ (u8)currentcmd->para2);
+ break;
+ case CMDID_RF_WRITEREG:
+ for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+ rtlphy->rfreg_chnlval[rfpath] =
+ ((rtlphy->rfreg_chnlval[rfpath] &
+ 0xfffffc00) | currentcmd->para2);
+ rtl_set_rfreg(hw, (enum radio_path)rfpath,
+ currentcmd->para1,
+ RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[rfpath]);
+ }
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ break;
+ }
+
+ break;
+ } while (true);
+
+ (*delay) = currentcmd->msdelay;
+ (*step)++;
+ return false;
+}
+
+u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 delay;
+ bool ret;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+ ("switch to channel%d\n",
+ rtlphy->current_channel));
+
+ if (rtlphy->sw_chnl_inprogress)
+ return 0;
+
+ if (rtlphy->set_bwmode_inprogress)
+ return 0;
+
+ if (is_hal_stop(rtlhal))
+ return 0;
+
+ rtlphy->sw_chnl_inprogress = true;
+ rtlphy->sw_chnl_stage = 0;
+ rtlphy->sw_chnl_step = 0;
+
+ do {
+ if (!rtlphy->sw_chnl_inprogress)
+ break;
+
+ ret = _rtl92s_phy_sw_chnl_step_by_step(hw,
+ rtlphy->current_channel,
+ &rtlphy->sw_chnl_stage,
+ &rtlphy->sw_chnl_step, &delay);
+ if (!ret) {
+ if (delay > 0)
+ mdelay(delay);
+ else
+ continue;
+ } else {
+ rtlphy->sw_chnl_inprogress = false;
+ }
+ break;
+ } while (true);
+
+ rtlphy->sw_chnl_inprogress = false;
+
+ RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("<==\n"));
+
+ return 1;
+}
+
+static void _rtl92se_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u8 u1btmp;
+
+ u1btmp = rtl_read_byte(rtlpriv, LDOV12D_CTRL);
+ u1btmp |= BIT(0);
+
+ rtl_write_byte(rtlpriv, LDOV12D_CTRL, u1btmp);
+ rtl_write_byte(rtlpriv, SPS1_CTRL, 0x0);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0xFF);
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+ udelay(100);
+
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x0);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x77FC);
+ udelay(10);
+
+ rtl_write_word(rtlpriv, CMDR, 0x57FC);
+
+ /* we should chnge GPIO to input mode
+ * this will drop away current about 25mA*/
+ rtl8192se_gpiobit3_cfg_inputmode(hw);
+}
+
+bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpwr_state)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+ bool bresult = true;
+ u8 i, queue_id;
+ struct rtl8192_tx_ring *ring = NULL;
+
+ if (rfpwr_state == ppsc->rfpwr_state)
+ return false;
+
+ ppsc->set_rfpowerstate_inprogress = true;
+
+ switch (rfpwr_state) {
+ case ERFON:{
+ if ((ppsc->rfpwr_state == ERFOFF) &&
+ RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+
+ bool rtstatus;
+ u32 InitializeCount = 0;
+ do {
+ InitializeCount++;
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic enable\n"));
+ rtstatus = rtl_ps_enable_nic(hw);
+ } while ((rtstatus != true) &&
+ (InitializeCount < 10));
+
+ RT_CLEAR_PS_LEVEL(ppsc,
+ RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("awake, sleeped:%d ms "
+ "state_inap:%x\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_sleep_jiffies),
+ rtlpriv->psc.state_inap));
+ ppsc->last_awake_jiffies = jiffies;
+ rtl_write_word(rtlpriv, CMDR, 0x37FC);
+ rtl_write_byte(rtlpriv, TXPAUSE, 0x00);
+ rtl_write_byte(rtlpriv, PHY_CCA, 0x3);
+ }
+
+ if (mac->link_state == MAC80211_LINKED)
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ break;
+ }
+ case ERFOFF:{
+ if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+ RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+ ("IPS Set eRf nic disable\n"));
+ rtl_ps_disable_nic(hw);
+ RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+ } else {
+ if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_NO_LINK);
+ else
+ rtlpriv->cfg->ops->led_control(hw,
+ LED_CTL_POWER_OFF);
+ }
+ break;
+ }
+ case ERFSLEEP:
+ if (ppsc->rfpwr_state == ERFOFF)
+ break;
+
+ for (queue_id = 0, i = 0;
+ queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+ ring = &pcipriv->dev.tx_ring[queue_id];
+ if (skb_queue_len(&ring->queue) == 0 ||
+ queue_id == BEACON_QUEUE) {
+ queue_id++;
+ continue;
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("eRf Off/Sleep: "
+ "%d times TcbBusyQueue[%d] = "
+ "%d before doze!\n",
+ (i + 1), queue_id,
+ skb_queue_len(&ring->queue)));
+
+ udelay(10);
+ i++;
+ }
+
+ if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ ("\nERFOFF: %d times"
+ "TcbBusyQueue[%d] = %d !\n",
+ MAX_DOZE_WAITING_TIMES_9x,
+ queue_id,
+ skb_queue_len(&ring->queue)));
+ break;
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("Set ERFSLEEP awaked:%d ms\n",
+ jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies)));
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_DMESG,
+ ("sleep awaked:%d ms "
+ "state_inap:%x\n", jiffies_to_msecs(jiffies -
+ ppsc->last_awake_jiffies),
+ rtlpriv->psc.state_inap));
+ ppsc->last_sleep_jiffies = jiffies;
+ _rtl92se_phy_set_rf_sleep(hw);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("switch case not process\n"));
+ bresult = false;
+ break;
+ }
+
+ if (bresult)
+ ppsc->rfpwr_state = rfpwr_state;
+
+ ppsc->set_rfpowerstate_inprogress = false;
+
+ return bresult;
+}
+
+static bool _rtl92s_phy_config_rfpa_bias_current(struct ieee80211_hw *hw,
+ enum radio_path rfpath)
+{
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ bool rtstatus = true;
+ u32 tmpval = 0;
+
+ /* If inferiority IC, we have to increase the PA bias current */
+ if (rtlhal->ic_class != IC_INFERIORITY_A) {
+ tmpval = rtl92s_phy_query_rf_reg(hw, rfpath, RF_IPA, 0xf);
+ rtl92s_phy_set_rf_reg(hw, rfpath, RF_IPA, 0xf, tmpval + 1);
+ }
+
+ return rtstatus;
+}
+
+static void _rtl92s_store_pwrindex_diffrate_offset(struct ieee80211_hw *hw,
+ u32 reg_addr, u32 bitmask, u32 data)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ if (reg_addr == RTXAGC_RATE18_06)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][0] =
+ data;
+ if (reg_addr == RTXAGC_RATE54_24)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][1] =
+ data;
+ if (reg_addr == RTXAGC_CCK_MCS32)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][6] =
+ data;
+ if (reg_addr == RTXAGC_MCS03_MCS00)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][2] =
+ data;
+ if (reg_addr == RTXAGC_MCS07_MCS04)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][3] =
+ data;
+ if (reg_addr == RTXAGC_MCS11_MCS08)
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][4] =
+ data;
+ if (reg_addr == RTXAGC_MCS15_MCS12) {
+ rtlphy->mcs_txpwrlevel_origoffset[rtlphy->pwrgroup_cnt][5] =
+ data;
+ rtlphy->pwrgroup_cnt++;
+ }
+}
+
+static void _rtl92s_phy_init_register_definition(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /*RF Interface Sowrtware Control */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+ /* RF Interface Readback Value */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+ /* RF Interface Output (and Enable) */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfo = RFPGA0_XC_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfo = RFPGA0_XD_RFINTERFACEOE;
+
+ /* RF Interface (Output and) Enable */
+ rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfintfe = RFPGA0_XC_RFINTERFACEOE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfintfe = RFPGA0_XD_RFINTERFACEOE;
+
+ /* Addr of LSSI. Wirte RF register by driver */
+ rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+ RFPGA0_XA_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+ RFPGA0_XB_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rf3wire_offset =
+ RFPGA0_XC_LSSIPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rf3wire_offset =
+ RFPGA0_XD_LSSIPARAMETER;
+
+ /* RF parameter */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = RFPGA0_XAB_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = RFPGA0_XCD_RFPARAMETER;
+
+ /* Tx AGC Gain Stage (same for all path. Should we remove this?) */
+ rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+ /* Tranceiver A~D HSSI Parameter-1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para1 = RFPGA0_XC_HSSIPARAMETER1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para1 = RFPGA0_XD_HSSIPARAMETER1;
+
+ /* Tranceiver A~D HSSI Parameter-2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfhssi_para2 = RFPGA0_XC_HSSIPARAMETER2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfhssi_para2 = RFPGA0_XD_HSSIPARAMETER2;
+
+ /* RF switch Control */
+ rtlphy->phyreg_def[RF90_PATH_A].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_B].rfswitch_control =
+ RFPGA0_XAB_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_C].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+ rtlphy->phyreg_def[RF90_PATH_D].rfswitch_control =
+ RFPGA0_XCD_SWITCHCONTROL;
+
+ /* AGC control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+ /* AGC control 2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+ rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+ /* RX AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbalance =
+ ROFDM0_XARXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbalance =
+ ROFDM0_XBRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbalance =
+ ROFDM0_XCRXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbalance =
+ ROFDM0_XDRXIQIMBALANCE;
+
+ /* RX AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+ /* Tx AFE control 1 */
+ rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbalance =
+ ROFDM0_XATXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbalance =
+ ROFDM0_XBTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbalance =
+ ROFDM0_XCTXIQIMBALANCE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbalance =
+ ROFDM0_XDTXIQIMBALANCE;
+
+ /* Tx AFE control 2 */
+ rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+ rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+ rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+ /* Tranceiver LSSI Readback */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readback =
+ RFPGA0_XA_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readback =
+ RFPGA0_XB_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_C].rflssi_readback =
+ RFPGA0_XC_LSSIREADBACK;
+ rtlphy->phyreg_def[RF90_PATH_D].rflssi_readback =
+ RFPGA0_XD_LSSIREADBACK;
+
+ /* Tranceiver LSSI Readback PI mode */
+ rtlphy->phyreg_def[RF90_PATH_A].rflssi_readbackpi =
+ TRANSCEIVERA_HSPI_READBACK;
+ rtlphy->phyreg_def[RF90_PATH_B].rflssi_readbackpi =
+ TRANSCEIVERB_HSPI_READBACK;
+}
+
+
+static bool _rtl92s_phy_config_bb(struct ieee80211_hw *hw, u8 configtype)
+{
+ int i;
+ u32 *phy_reg_table;
+ u32 *agc_table;
+ u16 phy_reg_len, agc_len;
+
+ agc_len = AGCTAB_ARRAYLENGTH;
+ agc_table = rtl8192seagctab_array;
+ /* Default RF_type: 2T2R */
+ phy_reg_len = PHY_REG_2T2RARRAYLENGTH;
+ phy_reg_table = rtl8192sephy_reg_2t2rarray;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_reg_len; i = i + 2) {
+ if (phy_reg_table[i] == 0xfe)
+ mdelay(50);
+ else if (phy_reg_table[i] == 0xfd)
+ mdelay(5);
+ else if (phy_reg_table[i] == 0xfc)
+ mdelay(1);
+ else if (phy_reg_table[i] == 0xfb)
+ udelay(50);
+ else if (phy_reg_table[i] == 0xfa)
+ udelay(5);
+ else if (phy_reg_table[i] == 0xf9)
+ udelay(1);
+
+ /* Add delay for ECS T20 & LG malow platform, */
+ udelay(1);
+
+ rtl92s_phy_set_bb_reg(hw, phy_reg_table[i], MASKDWORD,
+ phy_reg_table[i + 1]);
+ }
+ } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+ for (i = 0; i < agc_len; i = i + 2) {
+ rtl92s_phy_set_bb_reg(hw, agc_table[i], MASKDWORD,
+ agc_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_set_bb_to_diff_rf(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 *phy_regarray2xtxr_table;
+ u16 phy_regarray2xtxr_len;
+ int i;
+
+ if (rtlphy->rf_type == RF_1T1R) {
+ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t1rarray;
+ phy_regarray2xtxr_len = PHY_CHANGETO_1T1RARRAYLENGTH;
+ } else if (rtlphy->rf_type == RF_1T2R) {
+ phy_regarray2xtxr_table = rtl8192sephy_changeto_1t2rarray;
+ phy_regarray2xtxr_len = PHY_CHANGETO_1T2RARRAYLENGTH;
+ } else {
+ return false;
+ }
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_regarray2xtxr_len; i = i + 3) {
+ if (phy_regarray2xtxr_table[i] == 0xfe)
+ mdelay(50);
+ else if (phy_regarray2xtxr_table[i] == 0xfd)
+ mdelay(5);
+ else if (phy_regarray2xtxr_table[i] == 0xfc)
+ mdelay(1);
+ else if (phy_regarray2xtxr_table[i] == 0xfb)
+ udelay(50);
+ else if (phy_regarray2xtxr_table[i] == 0xfa)
+ udelay(5);
+ else if (phy_regarray2xtxr_table[i] == 0xf9)
+ udelay(1);
+
+ rtl92s_phy_set_bb_reg(hw, phy_regarray2xtxr_table[i],
+ phy_regarray2xtxr_table[i + 1],
+ phy_regarray2xtxr_table[i + 2]);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_config_bb_with_pg(struct ieee80211_hw *hw,
+ u8 configtype)
+{
+ int i;
+ u32 *phy_table_pg;
+ u16 phy_pg_len;
+
+ phy_pg_len = PHY_REG_ARRAY_PGLENGTH;
+ phy_table_pg = rtl8192sephy_reg_array_pg;
+
+ if (configtype == BASEBAND_CONFIG_PHY_REG) {
+ for (i = 0; i < phy_pg_len; i = i + 3) {
+ if (phy_table_pg[i] == 0xfe)
+ mdelay(50);
+ else if (phy_table_pg[i] == 0xfd)
+ mdelay(5);
+ else if (phy_table_pg[i] == 0xfc)
+ mdelay(1);
+ else if (phy_table_pg[i] == 0xfb)
+ udelay(50);
+ else if (phy_table_pg[i] == 0xfa)
+ udelay(5);
+ else if (phy_table_pg[i] == 0xf9)
+ udelay(1);
+
+ _rtl92s_store_pwrindex_diffrate_offset(hw,
+ phy_table_pg[i],
+ phy_table_pg[i + 1],
+ phy_table_pg[i + 2]);
+ rtl92s_phy_set_bb_reg(hw, phy_table_pg[i],
+ phy_table_pg[i + 1],
+ phy_table_pg[i + 2]);
+ }
+ }
+
+ return true;
+}
+
+static bool _rtl92s_phy_bb_config_parafile(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ bool rtstatus = true;
+
+ /* 1. Read PHY_REG.TXT BB INIT!! */
+ /* We will separate as 1T1R/1T2R/1T2R_GREEN/2T2R */
+ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_2T2R ||
+ rtlphy->rf_type == RF_1T1R || rtlphy->rf_type == RF_2T2R_GREEN) {
+ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_PHY_REG);
+
+ if (rtlphy->rf_type != RF_2T2R &&
+ rtlphy->rf_type != RF_2T2R_GREEN)
+ /* so we should reconfig BB reg with the right
+ * PHY parameters. */
+ rtstatus = _rtl92s_phy_set_bb_to_diff_rf(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ } else {
+ rtstatus = false;
+ }
+
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("Write BB Reg Fail!!"));
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* 2. If EEPROM or EFUSE autoload OK, We must config by
+ * PHY_REG_PG.txt */
+ if (rtlefuse->autoload_failflag == false) {
+ rtlphy->pwrgroup_cnt = 0;
+
+ rtstatus = _rtl92s_phy_config_bb_with_pg(hw,
+ BASEBAND_CONFIG_PHY_REG);
+ }
+ if (rtstatus != true) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("_rtl92s_phy_bb_config_parafile(): "
+ "BB_PG Reg Fail!!"));
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* 3. BB AGC table Initialization */
+ rtstatus = _rtl92s_phy_config_bb(hw, BASEBAND_CONFIG_AGC_TAB);
+
+ if (rtstatus != true) {
+ printk(KERN_ERR "_rtl92s_phy_bb_config_parafile(): "
+ "AGC Table Fail\n");
+ goto phy_BB8190_Config_ParaFile_Fail;
+ }
+
+ /* Check if the CCK HighPower is turned ON. */
+ /* This is used to calculate PWDB. */
+ rtlphy->cck_high_power = (bool)(rtl92s_phy_query_bb_reg(hw,
+ RFPGA0_XA_HSSIPARAMETER2, 0x200));
+
+phy_BB8190_Config_ParaFile_Fail:
+ return rtstatus;
+}
+
+u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ int i;
+ bool rtstatus = true;
+ u32 *radio_a_table;
+ u32 *radio_b_table;
+ u16 radio_a_tblen, radio_b_tblen;
+
+ radio_a_tblen = RADIOA_1T_ARRAYLENGTH;
+ radio_a_table = rtl8192seradioa_1t_array;
+
+ /* Using Green mode array table for RF_2T2R_GREEN */
+ if (rtlphy->rf_type == RF_2T2R_GREEN) {
+ radio_b_table = rtl8192seradiob_gm_array;
+ radio_b_tblen = RADIOB_GM_ARRAYLENGTH;
+ } else {
+ radio_b_table = rtl8192seradiob_array;
+ radio_b_tblen = RADIOB_ARRAYLENGTH;
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Radio No %x\n", rfpath));
+ rtstatus = true;
+
+ switch (rfpath) {
+ case RF90_PATH_A:
+ for (i = 0; i < radio_a_tblen; i = i + 2) {
+ if (radio_a_table[i] == 0xfe)
+ /* Delay specific ms. Only RF configuration
+ * requires delay. */
+ mdelay(50);
+ else if (radio_a_table[i] == 0xfd)
+ mdelay(5);
+ else if (radio_a_table[i] == 0xfc)
+ mdelay(1);
+ else if (radio_a_table[i] == 0xfb)
+ udelay(50);
+ else if (radio_a_table[i] == 0xfa)
+ udelay(5);
+ else if (radio_a_table[i] == 0xf9)
+ udelay(1);
+ else
+ rtl92s_phy_set_rf_reg(hw, rfpath,
+ radio_a_table[i],
+ MASK20BITS,
+ radio_a_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+
+ /* PA Bias current for inferiority IC */
+ _rtl92s_phy_config_rfpa_bias_current(hw, rfpath);
+ break;
+ case RF90_PATH_B:
+ for (i = 0; i < radio_b_tblen; i = i + 2) {
+ if (radio_b_table[i] == 0xfe)
+ /* Delay specific ms. Only RF configuration
+ * requires delay.*/
+ mdelay(50);
+ else if (radio_b_table[i] == 0xfd)
+ mdelay(5);
+ else if (radio_b_table[i] == 0xfc)
+ mdelay(1);
+ else if (radio_b_table[i] == 0xfb)
+ udelay(50);
+ else if (radio_b_table[i] == 0xfa)
+ udelay(5);
+ else if (radio_b_table[i] == 0xf9)
+ udelay(1);
+ else
+ rtl92s_phy_set_rf_reg(hw, rfpath,
+ radio_b_table[i],
+ MASK20BITS,
+ radio_b_table[i + 1]);
+
+ /* Add delay for ECS T20 & LG malow platform */
+ udelay(1);
+ }
+ break;
+ case RF90_PATH_C:
+ ;
+ break;
+ case RF90_PATH_D:
+ ;
+ break;
+ default:
+ break;
+ }
+
+ return rtstatus;
+}
+
+
+bool rtl92s_phy_mac_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 i;
+ u32 arraylength;
+ u32 *ptraArray;
+
+ arraylength = MAC_2T_ARRAYLENGTH;
+ ptraArray = rtl8192semac_2t_array;
+
+ for (i = 0; i < arraylength; i = i + 2)
+ rtl_write_byte(rtlpriv, ptraArray[i], (u8)ptraArray[i + 1]);
+
+ return true;
+}
+
+
+bool rtl92s_phy_bb_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ bool rtstatus = true;
+ u8 pathmap, index, rf_num = 0;
+ u8 path1, path2;
+
+ _rtl92s_phy_init_register_definition(hw);
+
+ /* Config BB and AGC */
+ rtstatus = _rtl92s_phy_bb_config_parafile(hw);
+
+
+ /* Check BB/RF confiuration setting. */
+ /* We only need to configure RF which is turned on. */
+ path1 = (u8)(rtl92s_phy_query_bb_reg(hw, RFPGA0_TXINFO, 0xf));
+ mdelay(10);
+ path2 = (u8)(rtl92s_phy_query_bb_reg(hw, ROFDM0_TRXPATHENABLE, 0xf));
+ pathmap = path1 | path2;
+
+ rtlphy->rf_pathmap = pathmap;
+ for (index = 0; index < 4; index++) {
+ if ((pathmap >> index) & 0x1)
+ rf_num++;
+ }
+
+ if ((rtlphy->rf_type == RF_1T1R && rf_num != 1) ||
+ (rtlphy->rf_type == RF_1T2R && rf_num != 2) ||
+ (rtlphy->rf_type == RF_2T2R && rf_num != 2) ||
+ (rtlphy->rf_type == RF_2T2R_GREEN && rf_num != 2)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("RF_Type(%x) does not match "
+ "RF_Num(%x)!!\n", rtlphy->rf_type, rf_num));
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_EMERG,
+ ("path1 0x%x, path2 0x%x, pathmap "
+ "0x%x\n", path1, path2, pathmap));
+ }
+
+ return rtstatus;
+}
+
+bool rtl92s_phy_rf_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* Initialize general global value */
+ if (rtlphy->rf_type == RF_1T1R)
+ rtlphy->num_total_rfpath = 1;
+ else
+ rtlphy->num_total_rfpath = 2;
+
+ /* Config BB and RF */
+ return rtl92s_phy_rf6052_config(hw);
+}
+
+void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ /* read rx initial gain */
+ rtlphy->default_initialgain[0] = rtl_get_bbreg(hw,
+ ROFDM0_XAAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[1] = rtl_get_bbreg(hw,
+ ROFDM0_XBAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[2] = rtl_get_bbreg(hw,
+ ROFDM0_XCAGCCORE1, MASKBYTE0);
+ rtlphy->default_initialgain[3] = rtl_get_bbreg(hw,
+ ROFDM0_XDAGCCORE1, MASKBYTE0);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("Default initial gain "
+ "(c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x)\n",
+ rtlphy->default_initialgain[0],
+ rtlphy->default_initialgain[1],
+ rtlphy->default_initialgain[2],
+ rtlphy->default_initialgain[3]));
+
+ /* read framesync */
+ rtlphy->framesync = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR3, MASKBYTE0);
+ rtlphy->framesync_c34 = rtl_get_bbreg(hw, ROFDM0_RXDETECTOR2,
+ MASKDWORD);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ ("Default framesync (0x%x) = 0x%x\n",
+ ROFDM0_RXDETECTOR3, rtlphy->framesync));
+
+}
+
+static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+ u8 *cckpowerlevel, u8 *ofdmpowerLevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 index = (channel - 1);
+
+ /* 1. CCK */
+ /* RF-A */
+ cckpowerlevel[0] = rtlefuse->txpwrlevel_cck[0][index];
+ /* RF-B */
+ cckpowerlevel[1] = rtlefuse->txpwrlevel_cck[1][index];
+
+ /* 2. OFDM for 1T or 2T */
+ if (rtlphy->rf_type == RF_1T2R || rtlphy->rf_type == RF_1T1R) {
+ /* Read HT 40 OFDM TX power */
+ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_1s[0][index];
+ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_1s[1][index];
+ } else if (rtlphy->rf_type == RF_2T2R) {
+ /* Read HT 40 OFDM TX power */
+ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index];
+ ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index];
+ }
+}
+
+static void _rtl92s_phy_ccxpower_indexcheck(struct ieee80211_hw *hw,
+ u8 channel, u8 *cckpowerlevel, u8 *ofdmpowerlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
+ rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+}
+
+void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ /* [0]:RF-A, [1]:RF-B */
+ u8 cckpowerlevel[2], ofdmpowerLevel[2];
+
+ if (rtlefuse->txpwr_fromeprom == false)
+ return;
+
+ /* Mainly we use RF-A Tx Power to write the Tx Power registers,
+ * but the RF-B Tx Power must be calculated by the antenna diff.
+ * So we have to rewrite Antenna gain offset register here.
+ * Please refer to BB register 0x80c
+ * 1. For CCK.
+ * 2. For OFDM 1T or 2T */
+ _rtl92s_phy_get_txpower_index(hw, channel, &cckpowerlevel[0],
+ &ofdmpowerLevel[0]);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Channel-%d, cckPowerLevel (A / B) = "
+ "0x%x / 0x%x, ofdmPowerLevel (A / B) = 0x%x / 0x%x\n",
+ channel, cckpowerlevel[0], cckpowerlevel[1],
+ ofdmpowerLevel[0], ofdmpowerLevel[1]));
+
+ _rtl92s_phy_ccxpower_indexcheck(hw, channel, &cckpowerlevel[0],
+ &ofdmpowerLevel[0]);
+
+ rtl92s_phy_rf6052_set_ccktxpower(hw, cckpowerlevel[0]);
+ rtl92s_phy_rf6052_set_ofdmtxpower(hw, &ofdmpowerLevel[0], channel);
+
+}
+
+void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u16 pollingcnt = 10000;
+ u32 tmpvalue;
+
+ /* Make sure that CMD IO has be accepted by FW. */
+ do {
+ udelay(10);
+
+ tmpvalue = rtl_read_dword(rtlpriv, WFM5);
+ if (tmpvalue == 0)
+ break;
+ } while (--pollingcnt);
+
+ if (pollingcnt == 0)
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, ("Set FW Cmd fail!!\n"));
+}
+
+
+static void _rtl92s_phy_set_fwcmd_io(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 input, current_aid = 0;
+
+ if (is_hal_stop(rtlhal))
+ return;
+
+ /* We re-map RA related CMD IO to combinational ones */
+ /* if FW version is v.52 or later. */
+ switch (rtlhal->current_fwcmd_io) {
+ case FW_CMD_RA_REFRESH_N:
+ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ rtlhal->current_fwcmd_io = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+
+ switch (rtlhal->current_fwcmd_io) {
+ case FW_CMD_RA_RESET:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_RESET\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_RESET);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_ACTIVE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_ACTIVE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ACTIVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_N:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_N\n"));
+ input = FW_RA_REFRESH;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_ENABLE_RSSI_MASK);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_BG\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_REFRESH);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ rtl_write_dword(rtlpriv, WFM5, FW_RA_DISABLE_RSSI_MASK);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_N_COMB:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_N_COMB\n"));
+ input = FW_RA_IOT_N_COMB;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_RA_REFRESH_BG_COMB:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_RA_REFRESH_BG_COMB\n"));
+ input = FW_RA_IOT_BG_COMB;
+ rtl_write_dword(rtlpriv, WFM5, input);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_IQK_ENABLE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_IQK_ENABLE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_IQK_ENABLE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_PAUSE_DM_BY_SCAN:
+ /* Lower initial gain */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17);
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40);
+ break;
+ case FW_CMD_RESUME_DM_BY_SCAN:
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+ rtl92s_phy_set_txpower(hw, rtlphy->current_channel);
+ break;
+ case FW_CMD_HIGH_PWR_DISABLE:
+ if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE)
+ break;
+
+ /* Lower initial gain */
+ rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0, 0x17);
+ rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0, 0x17);
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x40);
+ break;
+ case FW_CMD_HIGH_PWR_ENABLE:
+ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) ||
+ (rtlpriv->dm.dynamic_txpower_enable == true))
+ break;
+
+ /* CCA threshold */
+ rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+ break;
+ case FW_CMD_LPS_ENTER:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_LPS_ENTER\n"));
+ current_aid = rtlpriv->mac80211.assoc_id;
+ rtl_write_dword(rtlpriv, WFM5, (FW_LPS_ENTER |
+ ((current_aid | 0xc000) << 8)));
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ /* FW set TXOP disable here, so disable EDCA
+ * turbo mode until driver leave LPS */
+ break;
+ case FW_CMD_LPS_LEAVE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_LPS_LEAVE\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_LPS_LEAVE);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_ADD_A2_ENTRY:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_DMESG,
+ ("FW_CMD_ADD_A2_ENTRY\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_ADD_A2_ENTRY);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+ case FW_CMD_CTRL_DM_BY_DRIVER:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("FW_CMD_CTRL_DM_BY_DRIVER\n"));
+ rtl_write_dword(rtlpriv, WFM5, FW_CTRL_DM_BY_DRIVER);
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+ break;
+
+ default:
+ break;
+ }
+
+ rtl92s_phy_chk_fwcmd_iodone(hw);
+
+ /* Clear FW CMD operation flag. */
+ rtlhal->set_fwcmd_inprogress = false;
+}
+
+bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fw_cmdio)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 fw_param = FW_CMD_IO_PARA_QUERY(rtlpriv);
+ u16 fw_cmdmap = FW_CMD_IO_QUERY(rtlpriv);
+ bool bPostProcessing = false;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set FW Cmd(%#x), set_fwcmd_inprogress(%d)\n",
+ fw_cmdio, rtlhal->set_fwcmd_inprogress));
+
+ do {
+ /* We re-map to combined FW CMD ones if firmware version */
+ /* is v.53 or later. */
+ switch (fw_cmdio) {
+ case FW_CMD_RA_REFRESH_N:
+ fw_cmdio = FW_CMD_RA_REFRESH_N_COMB;
+ break;
+ case FW_CMD_RA_REFRESH_BG:
+ fw_cmdio = FW_CMD_RA_REFRESH_BG_COMB;
+ break;
+ default:
+ break;
+ }
+
+ /* If firmware version is v.62 or later,
+ * use FW_CMD_IO_SET for FW_CMD_CTRL_DM_BY_DRIVER */
+ if (hal_get_firmwareversion(rtlpriv) >= 0x3E) {
+ if (fw_cmdio == FW_CMD_CTRL_DM_BY_DRIVER)
+ fw_cmdio = FW_CMD_CTRL_DM_BY_DRIVER_NEW;
+ }
+
+
+ /* We shall revise all FW Cmd IO into Reg0x364
+ * DM map table in the future. */
+ switch (fw_cmdio) {
+ case FW_CMD_RA_INIT:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, ("RA init!!\n"));
+ fw_cmdmap |= FW_RA_INIT_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_INIT_CTL);
+ break;
+ case FW_CMD_DIG_DISABLE:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG disable!!\n"));
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_DIG_ENABLE:
+ case FW_CMD_DIG_RESUME:
+ if (!(rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE)) {
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG enable or resume!!\n"));
+ fw_cmdmap |= (FW_DIG_ENABLE_CTL | FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ }
+ break;
+ case FW_CMD_DIG_HALT:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set DIG halt!!\n"));
+ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL | FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_TXPWR_TRACK_THERMAL: {
+ u8 thermalval = 0;
+ fw_cmdmap |= FW_PWR_TRK_CTL;
+
+ /* Clear FW parameter in terms of thermal parts. */
+ fw_param &= FW_PWR_TRK_PARAM_CLR;
+
+ thermalval = rtlpriv->dm.thermalvalue;
+ fw_param |= ((thermalval << 24) |
+ (rtlefuse->thermalmeter[0] << 16));
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("Set TxPwr tracking!! "
+ "FwCmdMap(%#x), FwParam(%#x)\n",
+ fw_cmdmap, fw_param));
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_PWR_TRK_CTL);
+ }
+ break;
+ /* The following FW CMDs are only compatible to
+ * v.53 or later. */
+ case FW_CMD_RA_REFRESH_N_COMB:
+ fw_cmdmap |= FW_RA_N_CTL;
+
+ /* Clear RA BG mode control. */
+ fw_cmdmap &= ~(FW_RA_BG_CTL | FW_RA_INIT_CTL);
+
+ /* Clear FW parameter in terms of RA parts. */
+ fw_param &= FW_RA_PARAM_CLR;
+
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("[FW CMD] [New Version] "
+ "Set RA/IOT Comb in n mode!! FwCmdMap(%#x), "
+ "FwParam(%#x)\n", fw_cmdmap, fw_param));
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_N_CTL);
+ break;
+ case FW_CMD_RA_REFRESH_BG_COMB:
+ fw_cmdmap |= FW_RA_BG_CTL;
+
+ /* Clear RA n-mode control. */
+ fw_cmdmap &= ~(FW_RA_N_CTL | FW_RA_INIT_CTL);
+ /* Clear FW parameter in terms of RA parts. */
+ fw_param &= FW_RA_PARAM_CLR;
+
+ FW_CMD_PARA_SET(rtlpriv, fw_param);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_RA_BG_CTL);
+ break;
+ case FW_CMD_IQK_ENABLE:
+ fw_cmdmap |= FW_IQK_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ /* Clear control flag to sync with FW. */
+ FW_CMD_IO_CLR(rtlpriv, FW_IQK_CTL);
+ break;
+ /* The following FW CMD is compatible to v.62 or later. */
+ case FW_CMD_CTRL_DM_BY_DRIVER_NEW:
+ fw_cmdmap |= FW_DRIVER_CTRL_DM_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ /* The followed FW Cmds needs post-processing later. */
+ case FW_CMD_RESUME_DM_BY_SCAN:
+ fw_cmdmap |= (FW_DIG_ENABLE_CTL |
+ FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+
+ if (rtlpriv->dm.dm_flag & HAL_DM_DIG_DISABLE ||
+ !digtable.dig_enable_flag)
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+
+ if ((rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) ||
+ (rtlpriv->dm.dynamic_txpower_enable == true))
+ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
+
+ if ((digtable.dig_ext_port_stage ==
+ DIG_EXT_PORT_STAGE_0) ||
+ (digtable.dig_ext_port_stage ==
+ DIG_EXT_PORT_STAGE_1))
+ fw_cmdmap &= ~FW_DIG_ENABLE_CTL;
+
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_PAUSE_DM_BY_SCAN:
+ fw_cmdmap &= ~(FW_DIG_ENABLE_CTL |
+ FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_HIGH_PWR_DISABLE:
+ fw_cmdmap &= ~FW_HIGH_PWR_ENABLE_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ break;
+ case FW_CMD_HIGH_PWR_ENABLE:
+ if (!(rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) &&
+ (rtlpriv->dm.dynamic_txpower_enable != true)) {
+ fw_cmdmap |= (FW_HIGH_PWR_ENABLE_CTL |
+ FW_SS_CTL);
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ bPostProcessing = true;
+ }
+ break;
+ case FW_CMD_DIG_MODE_FA:
+ fw_cmdmap |= FW_FA_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_DIG_MODE_SS:
+ fw_cmdmap &= ~FW_FA_CTL;
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ case FW_CMD_PAPE_CONTROL:
+ RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+ ("[FW CMD] Set PAPE Control\n"));
+ fw_cmdmap &= ~FW_PAPE_CTL_BY_SW_HW;
+
+ FW_CMD_IO_SET(rtlpriv, fw_cmdmap);
+ break;
+ default:
+ /* Pass to original FW CMD processing callback
+ * routine. */
+ bPostProcessing = true;
+ break;
+ }
+ } while (false);
+
+ /* We shall post processing these FW CMD if
+ * variable bPostProcessing is set. */
+ if (bPostProcessing && !rtlhal->set_fwcmd_inprogress) {
+ rtlhal->set_fwcmd_inprogress = true;
+ /* Update current FW Cmd for callback use. */
+ rtlhal->current_fwcmd_io = fw_cmdio;
+ } else {
+ return false;
+ }
+
+ _rtl92s_phy_set_fwcmd_io(hw);
+ return true;
+}
+
+static void _rtl92s_phy_check_ephy_switchready(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 delay = 100;
+ u8 regu1;
+
+ regu1 = rtl_read_byte(rtlpriv, 0x554);
+ while ((regu1 & BIT(5)) && (delay > 0)) {
+ regu1 = rtl_read_byte(rtlpriv, 0x554);
+ delay--;
+ /* We delay only 50us to prevent
+ * being scheduled out. */
+ udelay(50);
+ }
+}
+
+void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+ /* The way to be capable to switch clock request
+ * when the PG setting does not support clock request.
+ * This is the backdoor solution to switch clock
+ * request before ASPM or D3. */
+ rtl_write_dword(rtlpriv, 0x540, 0x73c11);
+ rtl_write_dword(rtlpriv, 0x548, 0x2407c);
+
+ /* Switch EPHY parameter!!!! */
+ rtl_write_word(rtlpriv, 0x550, 0x1000);
+ rtl_write_byte(rtlpriv, 0x554, 0x20);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ rtl_write_word(rtlpriv, 0x550, 0xa0eb);
+ rtl_write_byte(rtlpriv, 0x554, 0x3e);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ rtl_write_word(rtlpriv, 0x550, 0xff80);
+ rtl_write_byte(rtlpriv, 0x554, 0x39);
+ _rtl92s_phy_check_ephy_switchready(hw);
+
+ /* Delay L1 enter time */
+ if (ppsc->support_aspm && !ppsc->support_backdoor)
+ rtl_write_byte(rtlpriv, 0x560, 0x40);
+ else
+ rtl_write_byte(rtlpriv, 0x560, 0x00);
+
+}
+
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 BeaconInterval)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl_write_dword(rtlpriv, WFM5, 0xF1000000 | (BeaconInterval << 8));
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.h b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
new file mode 100644
index 0000000..37e504a
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __RTL92S_PHY_H__
+#define __RTL92S_PHY_H__
+
+#define MAX_TXPWR_IDX_NMODE_92S 63
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+/* Channel switch:The size of
+ * command tables for switch channel */
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define RF90_PATH_MAX 4
+
+enum version_8192s {
+ VERSION_8192S_ACUT,
+ VERSION_8192S_BCUT,
+ VERSION_8192S_CCUT
+};
+
+enum swchnlcmd_id {
+ CMDID_END,
+ CMDID_SET_TXPOWEROWER_LEVEL,
+ CMDID_BBREGWRITE10,
+ CMDID_WRITEPORT_ULONG,
+ CMDID_WRITEPORT_USHORT,
+ CMDID_WRITEPORT_UCHAR,
+ CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+ enum swchnlcmd_id cmdid;
+ u32 para1;
+ u32 para2;
+ u32 msdelay;
+};
+
+enum baseband_config_type {
+ /* Radio Path A */
+ BASEBAND_CONFIG_PHY_REG = 0,
+ /* Radio Path B */
+ BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+#define hal_get_firmwareversion(rtlpriv) \
+ (((struct rt_firmware *)(rtlpriv->rtlhal.pfirmware))->firmwareversion)
+
+u32 rtl92s_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask);
+void rtl92s_phy_set_bb_reg(struct ieee80211_hw *hw, u32 regaddr, u32 bitmask,
+ u32 data);
+void rtl92s_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation);
+u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask);
+void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
+ u32 regaddr, u32 bitmask, u32 data);
+void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
+ enum nl80211_channel_type ch_type);
+u8 rtl92s_phy_sw_chnl(struct ieee80211_hw *hw);
+bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
+ enum rf_pwrstate rfpower_state);
+bool rtl92s_phy_mac_config(struct ieee80211_hw *hw);
+void rtl92s_phy_switch_ephy_parameter(struct ieee80211_hw *hw);
+bool rtl92s_phy_bb_config(struct ieee80211_hw *hw);
+bool rtl92s_phy_rf_config(struct ieee80211_hw *hw);
+void rtl92s_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+void rtl92s_phy_set_txpower(struct ieee80211_hw *hw, u8 channel);
+bool rtl92s_phy_set_fw_cmd(struct ieee80211_hw *hw, enum fwcmd_iotype fwcmd_io);
+void rtl92s_phy_chk_fwcmd_iodone(struct ieee80211_hw *hw);
+void rtl92s_phy_set_beacon_hwreg(struct ieee80211_hw *hw, u16 beaconinterval);
+u8 rtl92s_phy_config_rf(struct ieee80211_hw *hw, enum radio_path rfpath) ;
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/reg.h b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
new file mode 100644
index 0000000..0116ead
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/reg.h
@@ -0,0 +1,1188 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_92S_REG_H__
+#define __REALTEK_92S_REG_H__
+
+/* 1. System Configuration Registers */
+#define REG_SYS_ISO_CTRL 0x0000
+#define REG_SYS_FUNC_EN 0x0002
+#define PMC_FSM 0x0004
+#define SYS_CLKR 0x0008
+#define EPROM_CMD 0x000A
+#define EE_VPD 0x000C
+#define AFE_MISC 0x0010
+#define SPS0_CTRL 0x0011
+#define SPS1_CTRL 0x0018
+#define RF_CTRL 0x001F
+#define LDOA15_CTRL 0x0020
+#define LDOV12D_CTRL 0x0021
+#define LDOHCI12_CTRL 0x0022
+#define LDO_USB_SDIO 0x0023
+#define LPLDO_CTRL 0x0024
+#define AFE_XTAL_CTRL 0x0026
+#define AFE_PLL_CTRL 0x0028
+#define REG_EFUSE_CTRL 0x0030
+#define REG_EFUSE_TEST 0x0034
+#define PWR_DATA 0x0038
+#define DBG_PORT 0x003A
+#define DPS_TIMER 0x003C
+#define RCLK_MON 0x003E
+
+/* 2. Command Control Registers */
+#define CMDR 0x0040
+#define TXPAUSE 0x0042
+#define LBKMD_SEL 0x0043
+#define TCR 0x0044
+#define RCR 0x0048
+#define MSR 0x004C
+#define SYSF_CFG 0x004D
+#define RX_PKY_LIMIT 0x004E
+#define MBIDCTRL 0x004F
+
+/* 3. MACID Setting Registers */
+#define MACIDR 0x0050
+#define MACIDR0 0x0050
+#define MACIDR4 0x0054
+#define BSSIDR 0x0058
+#define HWVID 0x005E
+#define MAR 0x0060
+#define MBIDCAMCONTENT 0x0068
+#define MBIDCAMCFG 0x0070
+#define BUILDTIME 0x0074
+#define BUILDUSER 0x0078
+
+#define IDR0 MACIDR0
+#define IDR4 MACIDR4
+
+/* 4. Timing Control Registers */
+#define TSFR 0x0080
+#define SLOT_TIME 0x0089
+#define USTIME 0x008A
+#define SIFS_CCK 0x008C
+#define SIFS_OFDM 0x008E
+#define PIFS_TIME 0x0090
+#define ACK_TIMEOUT 0x0091
+#define EIFSTR 0x0092
+#define BCN_INTERVAL 0x0094
+#define ATIMWND 0x0096
+#define BCN_DRV_EARLY_INT 0x0098
+#define BCN_DMATIME 0x009A
+#define BCN_ERR_THRESH 0x009C
+#define MLT 0x009D
+#define RSVD_MAC_TUNE_US 0x009E
+
+/* 5. FIFO Control Registers */
+#define RQPN 0x00A0
+#define RQPN1 0x00A0
+#define RQPN2 0x00A1
+#define RQPN3 0x00A2
+#define RQPN4 0x00A3
+#define RQPN5 0x00A4
+#define RQPN6 0x00A5
+#define RQPN7 0x00A6
+#define RQPN8 0x00A7
+#define RQPN9 0x00A8
+#define RQPN10 0x00A9
+#define LD_RQPN 0x00AB
+#define RXFF_BNDY 0x00AC
+#define RXRPT_BNDY 0x00B0
+#define TXPKTBUF_PGBNDY 0x00B4
+#define PBP 0x00B5
+#define RXDRVINFO_SZ 0x00B6
+#define TXFF_STATUS 0x00B7
+#define RXFF_STATUS 0x00B8
+#define TXFF_EMPTY_TH 0x00B9
+#define SDIO_RX_BLKSZ 0x00BC
+#define RXDMA 0x00BD
+#define RXPKT_NUM 0x00BE
+#define C2HCMD_UDT_SIZE 0x00C0
+#define C2HCMD_UDT_ADDR 0x00C2
+#define FIFOPAGE1 0x00C4
+#define FIFOPAGE2 0x00C8
+#define FIFOPAGE3 0x00CC
+#define FIFOPAGE4 0x00D0
+#define FIFOPAGE5 0x00D4
+#define FW_RSVD_PG_CRTL 0x00D8
+#define RXDMA_AGG_PG_TH 0x00D9
+#define TXDESC_MSK 0x00DC
+#define TXRPTFF_RDPTR 0x00E0
+#define TXRPTFF_WTPTR 0x00E4
+#define C2HFF_RDPTR 0x00E8
+#define C2HFF_WTPTR 0x00EC
+#define RXFF0_RDPTR 0x00F0
+#define RXFF0_WTPTR 0x00F4
+#define RXFF1_RDPTR 0x00F8
+#define RXFF1_WTPTR 0x00FC
+#define RXRPT0_RDPTR 0x0100
+#define RXRPT0_WTPTR 0x0104
+#define RXRPT1_RDPTR 0x0108
+#define RXRPT1_WTPTR 0x010C
+#define RX0_UDT_SIZE 0x0110
+#define RX1PKTNUM 0x0114
+#define RXFILTERMAP 0x0116
+#define RXFILTERMAP_GP1 0x0118
+#define RXFILTERMAP_GP2 0x011A
+#define RXFILTERMAP_GP3 0x011C
+#define BCNQ_CTRL 0x0120
+#define MGTQ_CTRL 0x0124
+#define HIQ_CTRL 0x0128
+#define VOTID7_CTRL 0x012c
+#define VOTID6_CTRL 0x0130
+#define VITID5_CTRL 0x0134
+#define VITID4_CTRL 0x0138
+#define BETID3_CTRL 0x013c
+#define BETID0_CTRL 0x0140
+#define BKTID2_CTRL 0x0144
+#define BKTID1_CTRL 0x0148
+#define CMDQ_CTRL 0x014c
+#define TXPKT_NUM_CTRL 0x0150
+#define TXQ_PGADD 0x0152
+#define TXFF_PG_NUM 0x0154
+#define TRXDMA_STATUS 0x0156
+
+/* 6. Adaptive Control Registers */
+#define INIMCS_SEL 0x0160
+#define TX_RATE_REG INIMCS_SEL
+#define INIRTSMCS_SEL 0x0180
+#define RRSR 0x0181
+#define ARFR0 0x0184
+#define ARFR1 0x0188
+#define ARFR2 0x018C
+#define ARFR3 0x0190
+#define ARFR4 0x0194
+#define ARFR5 0x0198
+#define ARFR6 0x019C
+#define ARFR7 0x01A0
+#define AGGLEN_LMT_H 0x01A7
+#define AGGLEN_LMT_L 0x01A8
+#define DARFRC 0x01B0
+#define RARFRC 0x01B8
+#define MCS_TXAGC 0x01C0
+#define CCK_TXAGC 0x01C8
+
+/* 7. EDCA Setting Registers */
+#define EDCAPARA_VO 0x01D0
+#define EDCAPARA_VI 0x01D4
+#define EDCAPARA_BE 0x01D8
+#define EDCAPARA_BK 0x01DC
+#define BCNTCFG 0x01E0
+#define CWRR 0x01E2
+#define ACMAVG 0x01E4
+#define AcmHwCtrl 0x01E7
+#define VO_ADMTM 0x01E8
+#define VI_ADMTM 0x01EC
+#define BE_ADMTM 0x01F0
+#define RETRY_LIMIT 0x01F4
+#define SG_RATE 0x01F6
+
+/* 8. WMAC, BA and CCX related Register. */
+#define NAV_CTRL 0x0200
+#define BW_OPMODE 0x0203
+#define BACAMCMD 0x0204
+#define BACAMCONTENT 0x0208
+
+/* the 0x2xx register WMAC definition */
+#define LBDLY 0x0210
+#define FWDLY 0x0211
+#define HWPC_RX_CTRL 0x0218
+#define MQIR 0x0220
+#define MAIR 0x0222
+#define MSIR 0x0224
+#define CLM_RESULT 0x0227
+#define NHM_RPI_CNT 0x0228
+#define RXERR_RPT 0x0230
+#define NAV_PROT_LEN 0x0234
+#define CFEND_TH 0x0236
+#define AMPDU_MIN_SPACE 0x0237
+#define TXOP_STALL_CTRL 0x0238
+
+/* 9. Security Control Registers */
+#define REG_RWCAM 0x0240
+#define REG_WCAMI 0x0244
+#define REG_RCAMO 0x0248
+#define REG_CAMDBG 0x024C
+#define REG_SECR 0x0250
+
+/* 10. Power Save Control Registers */
+#define WOW_CTRL 0x0260
+#define PSSTATUS 0x0261
+#define PSSWITCH 0x0262
+#define MIMOPS_WAIT_PERIOD 0x0263
+#define LPNAV_CTRL 0x0264
+#define WFM0 0x0270
+#define WFM1 0x0280
+#define WFM2 0x0290
+#define WFM3 0x02A0
+#define WFM4 0x02B0
+#define WFM5 0x02C0
+#define WFCRC 0x02D0
+#define FW_RPT_REG 0x02c4
+
+/* 11. General Purpose Registers */
+#define PSTIME 0x02E0
+#define TIMER0 0x02E4
+#define TIMER1 0x02E8
+#define GPIO_CTRL 0x02EC
+#define GPIO_IN 0x02EC
+#define GPIO_OUT 0x02ED
+#define GPIO_IO_SEL 0x02EE
+#define GPIO_MOD 0x02EF
+#define GPIO_INTCTRL 0x02F0
+#define MAC_PINMUX_CFG 0x02F1
+#define LEDCFG 0x02F2
+#define PHY_REG 0x02F3
+#define PHY_REG_DATA 0x02F4
+#define REG_EFUSE_CLK 0x02F8
+
+/* 12. Host Interrupt Status Registers */
+#define INTA_MASK 0x0300
+#define ISR 0x0308
+
+/* 13. Test Mode and Debug Control Registers */
+#define DBG_PORT_SWITCH 0x003A
+#define BIST 0x0310
+#define DBS 0x0314
+#define CPUINST 0x0318
+#define CPUCAUSE 0x031C
+#define LBUS_ERR_ADDR 0x0320
+#define LBUS_ERR_CMD 0x0324
+#define LBUS_ERR_DATA_L 0x0328
+#define LBUS_ERR_DATA_H 0x032C
+#define LX_EXCEPTION_ADDR 0x0330
+#define WDG_CTRL 0x0334
+#define INTMTU 0x0338
+#define INTM 0x033A
+#define FDLOCKTURN0 0x033C
+#define FDLOCKTURN1 0x033D
+#define TRXPKTBUF_DBG_DATA 0x0340
+#define TRXPKTBUF_DBG_CTRL 0x0348
+#define DPLL 0x034A
+#define CBUS_ERR_ADDR 0x0350
+#define CBUS_ERR_CMD 0x0354
+#define CBUS_ERR_DATA_L 0x0358
+#define CBUS_ERR_DATA_H 0x035C
+#define USB_SIE_INTF_ADDR 0x0360
+#define USB_SIE_INTF_WD 0x0361
+#define USB_SIE_INTF_RD 0x0362
+#define USB_SIE_INTF_CTRL 0x0363
+#define LBUS_MON_ADDR 0x0364
+#define LBUS_ADDR_MASK 0x0368
+
+/* Boundary is 0x37F */
+
+/* 14. PCIE config register */
+#define TP_POLL 0x0500
+#define PM_CTRL 0x0502
+#define PCIF 0x0503
+
+#define THPDA 0x0514
+#define TMDA 0x0518
+#define TCDA 0x051C
+#define HDA 0x0520
+#define TVODA 0x0524
+#define TVIDA 0x0528
+#define TBEDA 0x052C
+#define TBKDA 0x0530
+#define TBDA 0x0534
+#define RCDA 0x0538
+#define RDQDA 0x053C
+#define DBI_WDATA 0x0540
+#define DBI_RDATA 0x0544
+#define DBI_CTRL 0x0548
+#define MDIO_DATA 0x0550
+#define MDIO_CTRL 0x0554
+#define PCI_RPWM 0x0561
+#define PCI_CPWM 0x0563
+
+/* Config register (Offset 0x800-) */
+#define PHY_CCA 0x803
+
+/* Min Spacing related settings. */
+#define MAX_MSS_DENSITY_2T 0x13
+#define MAX_MSS_DENSITY_1T 0x0A
+
+/* Rx DMA Control related settings */
+#define RXDMA_AGG_EN BIT(7)
+
+#define RPWM PCI_RPWM
+
+/* Regsiter Bit and Content definition */
+
+#define ISO_MD2PP BIT(0)
+#define ISO_PA2PCIE BIT(3)
+#define ISO_PLL2MD BIT(4)
+#define ISO_PWC_DV2RP BIT(11)
+#define ISO_PWC_RV2RP BIT(12)
+
+
+#define FEN_MREGEN BIT(15)
+#define FEN_DCORE BIT(11)
+#define FEN_CPUEN BIT(10)
+
+#define PAD_HWPD_IDN BIT(22)
+
+#define SYS_CLKSEL_80M BIT(0)
+#define SYS_PS_CLKSEL BIT(1)
+#define SYS_CPU_CLKSEL BIT(2)
+#define SYS_MAC_CLK_EN BIT(11)
+#define SYS_SWHW_SEL BIT(14)
+#define SYS_FWHW_SEL BIT(15)
+
+#define CmdEEPROM_En BIT(5)
+#define CmdEERPOMSEL BIT(4)
+#define Cmd9346CR_9356SEL BIT(4)
+
+#define AFE_MBEN BIT(1)
+#define AFE_BGEN BIT(0)
+
+#define SPS1_SWEN BIT(1)
+#define SPS1_LDEN BIT(0)
+
+#define RF_EN BIT(0)
+#define RF_RSTB BIT(1)
+#define RF_SDMRSTB BIT(2)
+
+#define LDA15_EN BIT(0)
+
+#define LDV12_EN BIT(0)
+#define LDV12_SDBY BIT(1)
+
+#define XTAL_GATE_AFE BIT(10)
+
+#define APLL_EN BIT(0)
+
+#define AFR_CardBEn BIT(0)
+#define AFR_CLKRUN_SEL BIT(1)
+#define AFR_FuncRegEn BIT(2)
+
+#define APSDOFF_STATUS BIT(15)
+#define APSDOFF BIT(14)
+#define BBRSTN BIT(13)
+#define BB_GLB_RSTN BIT(12)
+#define SCHEDULE_EN BIT(10)
+#define MACRXEN BIT(9)
+#define MACTXEN BIT(8)
+#define DDMA_EN BIT(7)
+#define FW2HW_EN BIT(6)
+#define RXDMA_EN BIT(5)
+#define TXDMA_EN BIT(4)
+#define HCI_RXDMA_EN BIT(3)
+#define HCI_TXDMA_EN BIT(2)
+
+#define StopHCCA BIT(6)
+#define StopHigh BIT(5)
+#define StopMgt BIT(4)
+#define StopVO BIT(3)
+#define StopVI BIT(2)
+#define StopBE BIT(1)
+#define StopBK BIT(0)
+
+#define LBK_NORMAL 0x00
+#define LBK_MAC_LB (BIT(0) | BIT(1) | BIT(3))
+#define LBK_MAC_DLB (BIT(0) | BIT(1))
+#define LBK_DMA_LB (BIT(0) | BIT(1) | BIT(2))
+
+#define TCP_OFDL_EN BIT(25)
+#define HWPC_TX_EN BIT(24)
+#define TXDMAPRE2FULL BIT(23)
+#define DISCW BIT(20)
+#define TCRICV BIT(19)
+#define CfendForm BIT(17)
+#define TCRCRC BIT(16)
+#define FAKE_IMEM_EN BIT(15)
+#define TSFRST BIT(9)
+#define TSFEN BIT(8)
+#define FWALLRDY (BIT(0) | BIT(1) | BIT(2) | \
+ BIT(3) | BIT(4) | BIT(5) | \
+ BIT(6) | BIT(7))
+#define FWRDY BIT(7)
+#define BASECHG BIT(6)
+#define IMEM BIT(5)
+#define DMEM_CODE_DONE BIT(4)
+#define EXT_IMEM_CHK_RPT BIT(3)
+#define EXT_IMEM_CODE_DONE BIT(2)
+#define IMEM_CHK_RPT BIT(1)
+#define IMEM_CODE_DONE BIT(0)
+#define IMEM_CODE_DONE BIT(0)
+#define IMEM_CHK_RPT BIT(1)
+#define EMEM_CODE_DONE BIT(2)
+#define EMEM_CHK_RPT BIT(3)
+#define DMEM_CODE_DONE BIT(4)
+#define IMEM_RDY BIT(5)
+#define BASECHG BIT(6)
+#define FWRDY BIT(7)
+#define LOAD_FW_READY (IMEM_CODE_DONE | \
+ IMEM_CHK_RPT | \
+ EMEM_CODE_DONE | \
+ EMEM_CHK_RPT | \
+ DMEM_CODE_DONE | \
+ IMEM_RDY | \
+ BASECHG | \
+ FWRDY)
+#define TCR_TSFEN BIT(8)
+#define TCR_TSFRST BIT(9)
+#define TCR_FAKE_IMEM_EN BIT(15)
+#define TCR_CRC BIT(16)
+#define TCR_ICV BIT(19)
+#define TCR_DISCW BIT(20)
+#define TCR_HWPC_TX_EN BIT(24)
+#define TCR_TCP_OFDL_EN BIT(25)
+#define TXDMA_INIT_VALUE (IMEM_CHK_RPT | \
+ EXT_IMEM_CHK_RPT)
+
+#define RCR_APPFCS BIT(31)
+#define RCR_DIS_ENC_2BYTE BIT(30)
+#define RCR_DIS_AES_2BYTE BIT(29)
+#define RCR_HTC_LOC_CTRL BIT(28)
+#define RCR_ENMBID BIT(27)
+#define RCR_RX_TCPOFDL_EN BIT(26)
+#define RCR_APP_PHYST_RXFF BIT(25)
+#define RCR_APP_PHYST_STAFF BIT(24)
+#define RCR_CBSSID BIT(23)
+#define RCR_APWRMGT BIT(22)
+#define RCR_ADD3 BIT(21)
+#define RCR_AMF BIT(20)
+#define RCR_ACF BIT(19)
+#define RCR_ADF BIT(18)
+#define RCR_APP_MIC BIT(17)
+#define RCR_APP_ICV BIT(16)
+#define RCR_RXFTH BIT(13)
+#define RCR_AICV BIT(12)
+#define RCR_RXDESC_LK_EN BIT(11)
+#define RCR_APP_BA_SSN BIT(6)
+#define RCR_ACRC32 BIT(5)
+#define RCR_RXSHFT_EN BIT(4)
+#define RCR_AB BIT(3)
+#define RCR_AM BIT(2)
+#define RCR_APM BIT(1)
+#define RCR_AAP BIT(0)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+
+
+#define MSR_LINK_MASK ((1 << 0) | (1 << 1))
+#define MSR_LINK_MANAGED 2
+#define MSR_LINK_NONE 0
+#define MSR_LINK_SHIFT 0
+#define MSR_LINK_ADHOC 1
+#define MSR_LINK_MASTER 3
+#define MSR_NOLINK 0x00
+#define MSR_ADHOC 0x01
+#define MSR_INFRA 0x02
+#define MSR_AP 0x03
+
+#define ENUART BIT(7)
+#define ENJTAG BIT(3)
+#define BTMODE (BIT(2) | BIT(1))
+#define ENBT BIT(0)
+
+#define ENMBID BIT(7)
+#define BCNUM (BIT(6) | BIT(5) | BIT(4))
+
+#define USTIME_EDCA 0xFF00
+#define USTIME_TSF 0x00FF
+
+#define SIFS_TRX 0xFF00
+#define SIFS_CTX 0x00FF
+
+#define ENSWBCN BIT(15)
+#define DRVERLY_TU 0x0FF0
+#define DRVERLY_US 0x000F
+#define BCN_TCFG_CW_SHIFT 8
+#define BCN_TCFG_IFS 0
+
+#define RRSR_RSC_OFFSET 21
+#define RRSR_SHORT_OFFSET 23
+#define RRSR_RSC_BW_40M 0x600000
+#define RRSR_RSC_UPSUBCHNL 0x400000
+#define RRSR_RSC_LOWSUBCHNL 0x200000
+#define RRSR_SHORT 0x800000
+#define RRSR_1M BIT(0)
+#define RRSR_2M BIT(1)
+#define RRSR_5_5M BIT(2)
+#define RRSR_11M BIT(3)
+#define RRSR_6M BIT(4)
+#define RRSR_9M BIT(5)
+#define RRSR_12M BIT(6)
+#define RRSR_18M BIT(7)
+#define RRSR_24M BIT(8)
+#define RRSR_36M BIT(9)
+#define RRSR_48M BIT(10)
+#define RRSR_54M BIT(11)
+#define RRSR_MCS0 BIT(12)
+#define RRSR_MCS1 BIT(13)
+#define RRSR_MCS2 BIT(14)
+#define RRSR_MCS3 BIT(15)
+#define RRSR_MCS4 BIT(16)
+#define RRSR_MCS5 BIT(17)
+#define RRSR_MCS6 BIT(18)
+#define RRSR_MCS7 BIT(19)
+#define BRSR_AckShortPmb BIT(23)
+
+#define RATR_1M 0x00000001
+#define RATR_2M 0x00000002
+#define RATR_55M 0x00000004
+#define RATR_11M 0x00000008
+#define RATR_6M 0x00000010
+#define RATR_9M 0x00000020
+#define RATR_12M 0x00000040
+#define RATR_18M 0x00000080
+#define RATR_24M 0x00000100
+#define RATR_36M 0x00000200
+#define RATR_48M 0x00000400
+#define RATR_54M 0x00000800
+#define RATR_MCS0 0x00001000
+#define RATR_MCS1 0x00002000
+#define RATR_MCS2 0x00004000
+#define RATR_MCS3 0x00008000
+#define RATR_MCS4 0x00010000
+#define RATR_MCS5 0x00020000
+#define RATR_MCS6 0x00040000
+#define RATR_MCS7 0x00080000
+#define RATR_MCS8 0x00100000
+#define RATR_MCS9 0x00200000
+#define RATR_MCS10 0x00400000
+#define RATR_MCS11 0x00800000
+#define RATR_MCS12 0x01000000
+#define RATR_MCS13 0x02000000
+#define RATR_MCS14 0x04000000
+#define RATR_MCS15 0x08000000
+
+#define RATE_ALL_CCK (RATR_1M | RATR_2M | \
+ RATR_55M | RATR_11M)
+#define RATE_ALL_OFDM_AG (RATR_6M | RATR_9M | \
+ RATR_12M | RATR_18M | \
+ RATR_24M | RATR_36M | \
+ RATR_48M | RATR_54M)
+#define RATE_ALL_OFDM_1SS (RATR_MCS0 | RATR_MCS1 | \
+ RATR_MCS2 | RATR_MCS3 | \
+ RATR_MCS4 | RATR_MCS5 | \
+ RATR_MCS6 | RATR_MCS7)
+#define RATE_ALL_OFDM_2SS (RATR_MCS8 | RATR_MCS9 | \
+ RATR_MCS10 | RATR_MCS11 | \
+ RATR_MCS12 | RATR_MCS13 | \
+ RATR_MCS14 | RATR_MCS15)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET 16
+#define AC_PARAM_ECW_MAX_OFFSET 12
+#define AC_PARAM_ECW_MIN_OFFSET 8
+#define AC_PARAM_AIFS_OFFSET 0
+
+#define AcmHw_HwEn BIT(0)
+#define AcmHw_BeqEn BIT(1)
+#define AcmHw_ViqEn BIT(2)
+#define AcmHw_VoqEn BIT(3)
+#define AcmHw_BeqStatus BIT(4)
+#define AcmHw_ViqStatus BIT(5)
+#define AcmHw_VoqStatus BIT(6)
+
+#define RETRY_LIMIT_SHORT_SHIFT 8
+#define RETRY_LIMIT_LONG_SHIFT 0
+
+#define NAV_UPPER_EN BIT(16)
+#define NAV_UPPER 0xFF00
+#define NAV_RTSRST 0xFF
+
+#define BW_OPMODE_20MHZ BIT(2)
+#define BW_OPMODE_5G BIT(1)
+#define BW_OPMODE_11J BIT(0)
+
+#define RXERR_RPT_RST BIT(27)
+#define RXERR_OFDM_PPDU 0
+#define RXERR_OFDM_FALSE_ALARM 1
+#define RXERR_OFDM_MPDU_OK 2
+#define RXERR_OFDM_MPDU_FAIL 3
+#define RXERR_CCK_PPDU 4
+#define RXERR_CCK_FALSE_ALARM 5
+#define RXERR_CCK_MPDU_OK 6
+#define RXERR_CCK_MPDU_FAIL 7
+#define RXERR_HT_PPDU 8
+#define RXERR_HT_FALSE_ALARM 9
+#define RXERR_HT_MPDU_TOTAL 10
+#define RXERR_HT_MPDU_OK 11
+#define RXERR_HT_MPDU_FAIL 12
+#define RXERR_RX_FULL_DROP 15
+
+#define SCR_TXUSEDK BIT(0)
+#define SCR_RXUSEDK BIT(1)
+#define SCR_TXENCENABLE BIT(2)
+#define SCR_RXENCENABLE BIT(3)
+#define SCR_SKBYA2 BIT(4)
+#define SCR_NOSKMC BIT(5)
+
+#define CAM_VALID BIT(15)
+#define CAM_NOTVALID 0x0000
+#define CAM_USEDK BIT(5)
+
+#define CAM_NONE 0x0
+#define CAM_WEP40 0x01
+#define CAM_TKIP 0x02
+#define CAM_AES 0x04
+#define CAM_WEP104 0x05
+
+#define TOTAL_CAM_ENTRY 32
+#define HALF_CAM_ENTRY 16
+
+#define CAM_WRITE BIT(16)
+#define CAM_READ 0x00000000
+#define CAM_POLLINIG BIT(31)
+
+#define WOW_PMEN BIT(0)
+#define WOW_WOMEN BIT(1)
+#define WOW_MAGIC BIT(2)
+#define WOW_UWF BIT(3)
+
+#define GPIOMUX_EN BIT(3)
+#define GPIOSEL_GPIO 0
+#define GPIOSEL_PHYDBG 1
+#define GPIOSEL_BT 2
+#define GPIOSEL_WLANDBG 3
+#define GPIOSEL_GPIO_MASK (~(BIT(0)|BIT(1)))
+
+#define HST_RDBUSY BIT(0)
+#define CPU_WTBUSY BIT(1)
+
+#define IMR8190_DISABLED 0x0
+#define IMR_CPUERR BIT(5)
+#define IMR_ATIMEND BIT(4)
+#define IMR_TBDOK BIT(3)
+#define IMR_TBDER BIT(2)
+#define IMR_BCNDMAINT8 BIT(1)
+#define IMR_BCNDMAINT7 BIT(0)
+#define IMR_BCNDMAINT6 BIT(31)
+#define IMR_BCNDMAINT5 BIT(30)
+#define IMR_BCNDMAINT4 BIT(29)
+#define IMR_BCNDMAINT3 BIT(28)
+#define IMR_BCNDMAINT2 BIT(27)
+#define IMR_BCNDMAINT1 BIT(26)
+#define IMR_BCNDOK8 BIT(25)
+#define IMR_BCNDOK7 BIT(24)
+#define IMR_BCNDOK6 BIT(23)
+#define IMR_BCNDOK5 BIT(22)
+#define IMR_BCNDOK4 BIT(21)
+#define IMR_BCNDOK3 BIT(20)
+#define IMR_BCNDOK2 BIT(19)
+#define IMR_BCNDOK1 BIT(18)
+#define IMR_TIMEOUT2 BIT(17)
+#define IMR_TIMEOUT1 BIT(16)
+#define IMR_TXFOVW BIT(15)
+#define IMR_PSTIMEOUT BIT(14)
+#define IMR_BCNINT BIT(13)
+#define IMR_RXFOVW BIT(12)
+#define IMR_RDU BIT(11)
+#define IMR_RXCMDOK BIT(10)
+#define IMR_BDOK BIT(9)
+#define IMR_HIGHDOK BIT(8)
+#define IMR_COMDOK BIT(7)
+#define IMR_MGNTDOK BIT(6)
+#define IMR_HCCADOK BIT(5)
+#define IMR_BKDOK BIT(4)
+#define IMR_BEDOK BIT(3)
+#define IMR_VIDOK BIT(2)
+#define IMR_VODOK BIT(1)
+#define IMR_ROK BIT(0)
+
+#define TPPOLL_BKQ BIT(0)
+#define TPPOLL_BEQ BIT(1)
+#define TPPOLL_VIQ BIT(2)
+#define TPPOLL_VOQ BIT(3)
+#define TPPOLL_BQ BIT(4)
+#define TPPOLL_CQ BIT(5)
+#define TPPOLL_MQ BIT(6)
+#define TPPOLL_HQ BIT(7)
+#define TPPOLL_HCCAQ BIT(8)
+#define TPPOLL_STOPBK BIT(9)
+#define TPPOLL_STOPBE BIT(10)
+#define TPPOLL_STOPVI BIT(11)
+#define TPPOLL_STOPVO BIT(12)
+#define TPPOLL_STOPMGT BIT(13)
+#define TPPOLL_STOPHIGH BIT(14)
+#define TPPOLL_STOPHCCA BIT(15)
+#define TPPOLL_SHIFT 8
+
+#define CCX_CMD_CLM_ENABLE BIT(0)
+#define CCX_CMD_NHM_ENABLE BIT(1)
+#define CCX_CMD_FUNCTION_ENABLE BIT(8)
+#define CCX_CMD_IGNORE_CCA BIT(9)
+#define CCX_CMD_IGNORE_TXON BIT(10)
+#define CCX_CLM_RESULT_READY BIT(16)
+#define CCX_NHM_RESULT_READY BIT(16)
+#define CCX_CMD_RESET 0x0
+
+
+#define HWSET_MAX_SIZE_92S 128
+#define EFUSE_MAX_SECTION 16
+#define EFUSE_REAL_CONTENT_LEN 512
+
+#define RTL8190_EEPROM_ID 0x8129
+#define EEPROM_HPON 0x02
+#define EEPROM_CLK 0x06
+#define EEPROM_TESTR 0x08
+
+#define EEPROM_VID 0x0A
+#define EEPROM_DID 0x0C
+#define EEPROM_SVID 0x0E
+#define EEPROM_SMID 0x10
+
+#define EEPROM_MAC_ADDR 0x12
+#define EEPROM_NODE_ADDRESS_BYTE_0 0x12
+
+#define EEPROM_PWDIFF 0x54
+
+#define EEPROM_TXPOWERBASE 0x50
+#define EEPROM_TX_PWR_INDEX_RANGE 28
+
+#define EEPROM_TX_PWR_HT20_DIFF 0x62
+#define DEFAULT_HT20_TXPWR_DIFF 2
+#define EEPROM_TX_PWR_OFDM_DIFF 0x65
+
+#define EEPROM_TXPWRGROUP 0x67
+#define EEPROM_REGULATORY 0x6D
+
+#define TX_PWR_SAFETY_CHK 0x6D
+#define EEPROM_TXPWINDEX_CCK_24G 0x5D
+#define EEPROM_TXPWINDEX_OFDM_24G 0x6B
+#define EEPROM_HT2T_CH1_A 0x6c
+#define EEPROM_HT2T_CH7_A 0x6d
+#define EEPROM_HT2T_CH13_A 0x6e
+#define EEPROM_HT2T_CH1_B 0x6f
+#define EEPROM_HT2T_CH7_B 0x70
+#define EEPROM_HT2T_CH13_B 0x71
+
+#define EEPROM_TSSI_A 0x74
+#define EEPROM_TSSI_B 0x75
+
+#define EEPROM_RFIND_POWERDIFF 0x76
+#define EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF 0x3
+
+#define EEPROM_THERMALMETER 0x77
+#define EEPROM_BLUETOOTH_COEXIST 0x78
+#define EEPROM_BLUETOOTH_TYPE 0x4f
+
+#define EEPROM_OPTIONAL 0x78
+#define EEPROM_WOWLAN 0x78
+
+#define EEPROM_CRYSTALCAP 0x79
+#define EEPROM_CHANNELPLAN 0x7B
+#define EEPROM_VERSION 0x7C
+#define EEPROM_CUSTOMID 0x7A
+#define EEPROM_BOARDTYPE 0x7E
+
+#define EEPROM_CHANNEL_PLAN_FCC 0x0
+#define EEPROM_CHANNEL_PLAN_IC 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI 0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN 0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE 0x4
+#define EEPROM_CHANNEL_PLAN_MKK 0x5
+#define EEPROM_CHANNEL_PLAN_MKK1 0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL 0x7
+#define EEPROM_CHANNEL_PLAN_TELEC 0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN 0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13 0xA
+#define EEPROM_CHANNEL_PLAN_NCC 0xB
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK 0x80
+
+#define FW_DIG_DISABLE 0xfd00cc00
+#define FW_DIG_ENABLE 0xfd000000
+#define FW_DIG_HALT 0xfd000001
+#define FW_DIG_RESUME 0xfd000002
+#define FW_HIGH_PWR_DISABLE 0xfd000008
+#define FW_HIGH_PWR_ENABLE 0xfd000009
+#define FW_ADD_A2_ENTRY 0xfd000016
+#define FW_TXPWR_TRACK_ENABLE 0xfd000017
+#define FW_TXPWR_TRACK_DISABLE 0xfd000018
+#define FW_TXPWR_TRACK_THERMAL 0xfd000019
+#define FW_TXANT_SWITCH_ENABLE 0xfd000023
+#define FW_TXANT_SWITCH_DISABLE 0xfd000024
+#define FW_RA_INIT 0xfd000026
+#define FW_CTRL_DM_BY_DRIVER 0Xfd00002a
+#define FW_RA_IOT_BG_COMB 0xfd000030
+#define FW_RA_IOT_N_COMB 0xfd000031
+#define FW_RA_REFRESH 0xfd0000a0
+#define FW_RA_UPDATE_MASK 0xfd0000a2
+#define FW_RA_DISABLE 0xfd0000a4
+#define FW_RA_ACTIVE 0xfd0000a6
+#define FW_RA_DISABLE_RSSI_MASK 0xfd0000ac
+#define FW_RA_ENABLE_RSSI_MASK 0xfd0000ad
+#define FW_RA_RESET 0xfd0000af
+#define FW_DM_DISABLE 0xfd00aa00
+#define FW_IQK_ENABLE 0xf0000020
+#define FW_IQK_SUCCESS 0x0000dddd
+#define FW_IQK_FAIL 0x0000ffff
+#define FW_OP_FAILURE 0xffffffff
+#define FW_TX_FEEDBACK_NONE 0xfb000000
+#define FW_TX_FEEDBACK_DTM_ENABLE (FW_TX_FEEDBACK_NONE | 0x1)
+#define FW_TX_FEEDBACK_CCX_ENABL (FW_TX_FEEDBACK_NONE | 0x2)
+#define FW_BB_RESET_ENABLE 0xff00000d
+#define FW_BB_RESET_DISABLE 0xff00000e
+#define FW_CCA_CHK_ENABLE 0xff000011
+#define FW_CCK_RESET_CNT 0xff000013
+#define FW_LPS_ENTER 0xfe000010
+#define FW_LPS_LEAVE 0xfe000011
+#define FW_INDIRECT_READ 0xf2000000
+#define FW_INDIRECT_WRITE 0xf2000001
+#define FW_CHAN_SET 0xf3000001
+
+#define RFPC 0x5F
+#define RCR_9356SEL BIT(6)
+#define TCR_LRL_OFFSET 0
+#define TCR_SRL_OFFSET 8
+#define TCR_MXDMA_OFFSET 21
+#define TCR_SAT BIT(24)
+#define RCR_MXDMA_OFFSET 8
+#define RCR_FIFO_OFFSET 13
+#define RCR_OnlyErlPkt BIT(31)
+#define CWR 0xDC
+#define RETRYCTR 0xDE
+
+#define CPU_GEN_SYSTEM_RESET 0x00000001
+
+#define CCX_COMMAND_REG 0x890
+#define CLM_PERIOD_REG 0x894
+#define NHM_PERIOD_REG 0x896
+
+#define NHM_THRESHOLD0 0x898
+#define NHM_THRESHOLD1 0x899
+#define NHM_THRESHOLD2 0x89A
+#define NHM_THRESHOLD3 0x89B
+#define NHM_THRESHOLD4 0x89C
+#define NHM_THRESHOLD5 0x89D
+#define NHM_THRESHOLD6 0x89E
+#define CLM_RESULT_REG 0x8D0
+#define NHM_RESULT_REG 0x8D4
+#define NHM_RPI_COUNTER0 0x8D8
+#define NHM_RPI_COUNTER1 0x8D9
+#define NHM_RPI_COUNTER2 0x8DA
+#define NHM_RPI_COUNTER3 0x8DB
+#define NHM_RPI_COUNTER4 0x8DC
+#define NHM_RPI_COUNTER5 0x8DD
+#define NHM_RPI_COUNTER6 0x8DE
+#define NHM_RPI_COUNTER7 0x8DF
+
+#define HAL_8192S_HW_GPIO_OFF_BIT BIT(3)
+#define HAL_8192S_HW_GPIO_OFF_MASK 0xF7
+#define HAL_8192S_HW_GPIO_WPS_BIT BIT(4)
+
+#define RPMAC_RESET 0x100
+#define RPMAC_TXSTART 0x104
+#define RPMAC_TXLEGACYSIG 0x108
+#define RPMAC_TXHTSIG1 0x10c
+#define RPMAC_TXHTSIG2 0x110
+#define RPMAC_PHYDEBUG 0x114
+#define RPMAC_TXPACKETNNM 0x118
+#define RPMAC_TXIDLE 0x11c
+#define RPMAC_TXMACHEADER0 0x120
+#define RPMAC_TXMACHEADER1 0x124
+#define RPMAC_TXMACHEADER2 0x128
+#define RPMAC_TXMACHEADER3 0x12c
+#define RPMAC_TXMACHEADER4 0x130
+#define RPMAC_TXMACHEADER5 0x134
+#define RPMAC_TXDATATYPE 0x138
+#define RPMAC_TXRANDOMSEED 0x13c
+#define RPMAC_CCKPLCPPREAMBLE 0x140
+#define RPMAC_CCKPLCPHEADER 0x144
+#define RPMAC_CCKCRC16 0x148
+#define RPMAC_OFDMRXCRC32OK 0x170
+#define RPMAC_OFDMRXCRC32ER 0x174
+#define RPMAC_OFDMRXPARITYER 0x178
+#define RPMAC_OFDMRXCRC8ER 0x17c
+#define RPMAC_CCKCRXRC16ER 0x180
+#define RPMAC_CCKCRXRC32ER 0x184
+#define RPMAC_CCKCRXRC32OK 0x188
+#define RPMAC_TXSTATUS 0x18c
+
+#define RF_BB_CMD_ADDR 0x02c0
+#define RF_BB_CMD_DATA 0x02c4
+
+#define RFPGA0_RFMOD 0x800
+
+#define RFPGA0_TXINFO 0x804
+#define RFPGA0_PSDFUNCTION 0x808
+
+#define RFPGA0_TXGAINSTAGE 0x80c
+
+#define RFPGA0_RFTIMING1 0x810
+#define RFPGA0_RFTIMING2 0x814
+#define RFPGA0_XA_HSSIPARAMETER1 0x820
+#define RFPGA0_XA_HSSIPARAMETER2 0x824
+#define RFPGA0_XB_HSSIPARAMETER1 0x828
+#define RFPGA0_XB_HSSIPARAMETER2 0x82c
+#define RFPGA0_XC_HSSIPARAMETER1 0x830
+#define RFPGA0_XC_HSSIPARAMETER2 0x834
+#define RFPGA0_XD_HSSIPARAMETER1 0x838
+#define RFPGA0_XD_HSSIPARAMETER2 0x83c
+#define RFPGA0_XA_LSSIPARAMETER 0x840
+#define RFPGA0_XB_LSSIPARAMETER 0x844
+#define RFPGA0_XC_LSSIPARAMETER 0x848
+#define RFPGA0_XD_LSSIPARAMETER 0x84c
+
+#define RFPGA0_RFWAKEUP_PARAMETER 0x850
+#define RFPGA0_RFSLEEPUP_PARAMETER 0x854
+
+#define RFPGA0_XAB_SWITCHCONTROL 0x858
+#define RFPGA0_XCD_SWITCHCONTROL 0x85c
+
+#define RFPGA0_XA_RFINTERFACEOE 0x860
+#define RFPGA0_XB_RFINTERFACEOE 0x864
+#define RFPGA0_XC_RFINTERFACEOE 0x868
+#define RFPGA0_XD_RFINTERFACEOE 0x86c
+
+#define RFPGA0_XAB_RFINTERFACESW 0x870
+#define RFPGA0_XCD_RFINTERFACESW 0x874
+
+#define RFPGA0_XAB_RFPARAMETER 0x878
+#define RFPGA0_XCD_RFPARAMETER 0x87c
+
+#define RFPGA0_ANALOGPARAMETER1 0x880
+#define RFPGA0_ANALOGPARAMETER2 0x884
+#define RFPGA0_ANALOGPARAMETER3 0x888
+#define RFPGA0_ANALOGPARAMETER4 0x88c
+
+#define RFPGA0_XA_LSSIREADBACK 0x8a0
+#define RFPGA0_XB_LSSIREADBACK 0x8a4
+#define RFPGA0_XC_LSSIREADBACK 0x8a8
+#define RFPGA0_XD_LSSIREADBACK 0x8ac
+
+#define RFPGA0_PSDREPORT 0x8b4
+#define TRANSCEIVERA_HSPI_READBACK 0x8b8
+#define TRANSCEIVERB_HSPI_READBACK 0x8bc
+#define RFPGA0_XAB_RFINTERFACERB 0x8e0
+#define RFPGA0_XCD_RFINTERFACERB 0x8e4
+#define RFPGA1_RFMOD 0x900
+
+#define RFPGA1_TXBLOCK 0x904
+#define RFPGA1_DEBUGSELECT 0x908
+#define RFPGA1_TXINFO 0x90c
+
+#define RCCK0_SYSTEM 0xa00
+
+#define RCCK0_AFESETTING 0xa04
+#define RCCK0_CCA 0xa08
+
+#define RCCK0_RXAGC1 0xa0c
+#define RCCK0_RXAGC2 0xa10
+
+#define RCCK0_RXHP 0xa14
+
+#define RCCK0_DSPPARAMETER1 0xa18
+#define RCCK0_DSPPARAMETER2 0xa1c
+
+#define RCCK0_TXFILTER1 0xa20
+#define RCCK0_TXFILTER2 0xa24
+#define RCCK0_DEBUGPORT 0xa28
+#define RCCK0_FALSEALARMREPORT 0xa2c
+#define RCCK0_TRSSIREPORT 0xa50
+#define RCCK0_RXREPORT 0xa54
+#define RCCK0_FACOUNTERLOWER 0xa5c
+#define RCCK0_FACOUNTERUPPER 0xa58
+
+#define ROFDM0_LSTF 0xc00
+
+#define ROFDM0_TRXPATHENABLE 0xc04
+#define ROFDM0_TRMUXPAR 0xc08
+#define ROFDM0_TRSWISOLATION 0xc0c
+
+#define ROFDM0_XARXAFE 0xc10
+#define ROFDM0_XARXIQIMBALANCE 0xc14
+#define ROFDM0_XBRXAFE 0xc18
+#define ROFDM0_XBRXIQIMBALANCE 0xc1c
+#define ROFDM0_XCRXAFE 0xc20
+#define ROFDM0_XCRXIQIMBALANCE 0xc24
+#define ROFDM0_XDRXAFE 0xc28
+#define ROFDM0_XDRXIQIMBALANCE 0xc2c
+
+#define ROFDM0_RXDETECTOR1 0xc30
+#define ROFDM0_RXDETECTOR2 0xc34
+#define ROFDM0_RXDETECTOR3 0xc38
+#define ROFDM0_RXDETECTOR4 0xc3c
+
+#define ROFDM0_RXDSP 0xc40
+#define ROFDM0_CFO_AND_DAGC 0xc44
+#define ROFDM0_CCADROP_THRESHOLD 0xc48
+#define ROFDM0_ECCA_THRESHOLD 0xc4c
+
+#define ROFDM0_XAAGCCORE1 0xc50
+#define ROFDM0_XAAGCCORE2 0xc54
+#define ROFDM0_XBAGCCORE1 0xc58
+#define ROFDM0_XBAGCCORE2 0xc5c
+#define ROFDM0_XCAGCCORE1 0xc60
+#define ROFDM0_XCAGCCORE2 0xc64
+#define ROFDM0_XDAGCCORE1 0xc68
+#define ROFDM0_XDAGCCORE2 0xc6c
+
+#define ROFDM0_AGCPARAMETER1 0xc70
+#define ROFDM0_AGCPARAMETER2 0xc74
+#define ROFDM0_AGCRSSITABLE 0xc78
+#define ROFDM0_HTSTFAGC 0xc7c
+
+#define ROFDM0_XATXIQIMBALANCE 0xc80
+#define ROFDM0_XATXAFE 0xc84
+#define ROFDM0_XBTXIQIMBALANCE 0xc88
+#define ROFDM0_XBTXAFE 0xc8c
+#define ROFDM0_XCTXIQIMBALANCE 0xc90
+#define ROFDM0_XCTXAFE 0xc94
+#define ROFDM0_XDTXIQIMBALANCE 0xc98
+#define ROFDM0_XDTXAFE 0xc9c
+
+#define ROFDM0_RXHP_PARAMETER 0xce0
+#define ROFDM0_TXPSEUDO_NOISE_WGT 0xce4
+#define ROFDM0_FRAME_SYNC 0xcf0
+#define ROFDM0_DFSREPORT 0xcf4
+#define ROFDM0_TXCOEFF1 0xca4
+#define ROFDM0_TXCOEFF2 0xca8
+#define ROFDM0_TXCOEFF3 0xcac
+#define ROFDM0_TXCOEFF4 0xcb0
+#define ROFDM0_TXCOEFF5 0xcb4
+#define ROFDM0_TXCOEFF6 0xcb8
+
+
+#define ROFDM1_LSTF 0xd00
+#define ROFDM1_TRXPATHENABLE 0xd04
+
+#define ROFDM1_CFO 0xd08
+#define ROFDM1_CSI1 0xd10
+#define ROFDM1_SBD 0xd14
+#define ROFDM1_CSI2 0xd18
+#define ROFDM1_CFOTRACKING 0xd2c
+#define ROFDM1_TRXMESAURE1 0xd34
+#define ROFDM1_INTF_DET 0xd3c
+#define ROFDM1_PSEUDO_NOISESTATEAB 0xd50
+#define ROFDM1_PSEUDO_NOISESTATECD 0xd54
+#define ROFDM1_RX_PSEUDO_NOISE_WGT 0xd58
+
+#define ROFDM_PHYCOUNTER1 0xda0
+#define ROFDM_PHYCOUNTER2 0xda4
+#define ROFDM_PHYCOUNTER3 0xda8
+
+#define ROFDM_SHORT_CFOAB 0xdac
+#define ROFDM_SHORT_CFOCD 0xdb0
+#define ROFDM_LONG_CFOAB 0xdb4
+#define ROFDM_LONG_CFOCD 0xdb8
+#define ROFDM_TAIL_CFOAB 0xdbc
+#define ROFDM_TAIL_CFOCD 0xdc0
+#define ROFDM_PW_MEASURE1 0xdc4
+#define ROFDM_PW_MEASURE2 0xdc8
+#define ROFDM_BW_REPORT 0xdcc
+#define ROFDM_AGC_REPORT 0xdd0
+#define ROFDM_RXSNR 0xdd4
+#define ROFDM_RXEVMCSI 0xdd8
+#define ROFDM_SIG_REPORT 0xddc
+
+
+#define RTXAGC_RATE18_06 0xe00
+#define RTXAGC_RATE54_24 0xe04
+#define RTXAGC_CCK_MCS32 0xe08
+#define RTXAGC_MCS03_MCS00 0xe10
+#define RTXAGC_MCS07_MCS04 0xe14
+#define RTXAGC_MCS11_MCS08 0xe18
+#define RTXAGC_MCS15_MCS12 0xe1c
+
+
+#define RF_AC 0x00
+#define RF_IQADJ_G1 0x01
+#define RF_IQADJ_G2 0x02
+#define RF_POW_TRSW 0x05
+#define RF_GAIN_RX 0x06
+#define RF_GAIN_TX 0x07
+#define RF_TXM_IDAC 0x08
+#define RF_BS_IQGEN 0x0F
+
+#define RF_MODE1 0x10
+#define RF_MODE2 0x11
+#define RF_RX_AGC_HP 0x12
+#define RF_TX_AGC 0x13
+#define RF_BIAS 0x14
+#define RF_IPA 0x15
+#define RF_POW_ABILITY 0x17
+#define RF_MODE_AG 0x18
+#define RF_CHANNEL 0x18
+#define RF_CHNLBW 0x18
+#define RF_TOP 0x19
+#define RF_RX_G1 0x1A
+#define RF_RX_G2 0x1B
+#define RF_RX_BB2 0x1C
+#define RF_RX_BB1 0x1D
+#define RF_RCK1 0x1E
+#define RF_RCK2 0x1F
+
+#define RF_TX_G1 0x20
+#define RF_TX_G2 0x21
+#define RF_TX_G3 0x22
+#define RF_TX_BB1 0x23
+#define RF_T_METER 0x24
+#define RF_SYN_G1 0x25
+#define RF_SYN_G2 0x26
+#define RF_SYN_G3 0x27
+#define RF_SYN_G4 0x28
+#define RF_SYN_G5 0x29
+#define RF_SYN_G6 0x2A
+#define RF_SYN_G7 0x2B
+#define RF_SYN_G8 0x2C
+
+#define RF_RCK_OS 0x30
+#define RF_TXPA_G1 0x31
+#define RF_TXPA_G2 0x32
+#define RF_TXPA_G3 0x33
+
+#define BRFMOD 0x1
+#define BCCKEN 0x1000000
+#define BOFDMEN 0x2000000
+
+#define BXBTXAGC 0xf00
+#define BXCTXAGC 0xf000
+#define BXDTXAGC 0xf0000
+
+#define B3WIRE_DATALENGTH 0x800
+#define B3WIRE_ADDRESSLENGTH 0x400
+
+#define BRFSI_RFENV 0x10
+
+#define BLSSI_READADDRESS 0x7f800000
+#define BLSSI_READEDGE 0x80000000
+#define BLSSI_READBACK_DATA 0xfffff
+
+#define BADCLKPHASE 0x4000000
+
+#define BCCK_SIDEBAND 0x10
+
+#define BTX_AGCRATECCK 0x7f00
+
+#define MASKBYTE0 0xff
+#define MASKBYTE1 0xff00
+#define MASKBYTE2 0xff0000
+#define MASKBYTE3 0xff000000
+#define MASKHWORD 0xffff0000
+#define MASKLWORD 0x0000ffff
+#define MASKDWORD 0xffffffff
+
+#define MAKS12BITS 0xfffff
+#define MASK20BITS 0xfffff
+#define RFREG_OFFSET_MASK 0xfffff
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.c b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
new file mode 100644
index 0000000..1d3a483
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.c
@@ -0,0 +1,546 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+
+static void _rtl92s_get_powerbase(struct ieee80211_hw *hw, u8 *p_pwrlevel,
+ u8 chnl, u32 *ofdmbase, u32 *mcsbase,
+ u8 *p_final_pwridx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 pwrbase0, pwrbase1;
+ u8 legacy_pwrdiff = 0, ht20_pwrdiff = 0;
+ u8 i, pwrlevel[4];
+
+ for (i = 0; i < 2; i++)
+ pwrlevel[i] = p_pwrlevel[i];
+
+ /* We only care about the path A for legacy. */
+ if (rtlefuse->eeprom_version < 2) {
+ pwrbase0 = pwrlevel[0] + (rtlefuse->legacy_httxpowerdiff & 0xf);
+ } else if (rtlefuse->eeprom_version >= 2) {
+ legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff
+ [RF90_PATH_A][chnl - 1];
+
+ /* For legacy OFDM, tx pwr always > HT OFDM pwr.
+ * We do not care Path B
+ * legacy OFDM pwr diff. NO BB register
+ * to notify HW. */
+ pwrbase0 = pwrlevel[0] + legacy_pwrdiff;
+ }
+
+ pwrbase0 = (pwrbase0 << 24) | (pwrbase0 << 16) | (pwrbase0 << 8) |
+ pwrbase0;
+ *ofdmbase = pwrbase0;
+
+ /* MCS rates */
+ if (rtlefuse->eeprom_version >= 2) {
+ /* Check HT20 to HT40 diff */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
+ for (i = 0; i < 2; i++) {
+ /* rf-A, rf-B */
+ /* HT 20<->40 pwr diff */
+ ht20_pwrdiff = rtlefuse->txpwr_ht20diff
+ [i][chnl - 1];
+
+ if (ht20_pwrdiff < 8) /* 0~+7 */
+ pwrlevel[i] += ht20_pwrdiff;
+ else /* index8-15=-8~-1 */
+ pwrlevel[i] -= (16 - ht20_pwrdiff);
+ }
+ }
+ }
+
+ /* use index of rf-A */
+ pwrbase1 = pwrlevel[0];
+ pwrbase1 = (pwrbase1 << 24) | (pwrbase1 << 16) | (pwrbase1 << 8) |
+ pwrbase1;
+ *mcsbase = pwrbase1;
+
+ /* The following is for Antenna
+ * diff from Ant-B to Ant-A */
+ p_final_pwridx[0] = pwrlevel[0];
+ p_final_pwridx[1] = pwrlevel[1];
+
+ switch (rtlefuse->eeprom_regulatory) {
+ case 3:
+ /* The following is for calculation
+ * of the power diff for Ant-B to Ant-A. */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ p_final_pwridx[0] += rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][
+ chnl - 1];
+ p_final_pwridx[1] += rtlefuse->pwrgroup_ht40
+ [RF90_PATH_B][
+ chnl - 1];
+ } else {
+ p_final_pwridx[0] += rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][
+ chnl - 1];
+ p_final_pwridx[1] += rtlefuse->pwrgroup_ht20
+ [RF90_PATH_B][
+ chnl - 1];
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("40MHz finalpwr_idx "
+ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0],
+ p_final_pwridx[1]));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, ("20MHz finalpwr_idx "
+ "(A / B) = 0x%x / 0x%x\n", p_final_pwridx[0],
+ p_final_pwridx[1]));
+ }
+}
+
+static void _rtl92s_set_antennadiff(struct ieee80211_hw *hw,
+ u8 *p_final_pwridx)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ char ant_pwr_diff = 0;
+ u32 u4reg_val = 0;
+
+ if (rtlphy->rf_type == RF_2T2R) {
+ ant_pwr_diff = p_final_pwridx[1] - p_final_pwridx[0];
+
+ /* range is from 7~-8,
+ * index = 0x0~0xf */
+ if (ant_pwr_diff > 7)
+ ant_pwr_diff = 7;
+ if (ant_pwr_diff < -8)
+ ant_pwr_diff = -8;
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Antenna Diff from RF-B "
+ "to RF-A = %d (0x%x)\n", ant_pwr_diff,
+ ant_pwr_diff & 0xf));
+
+ ant_pwr_diff &= 0xf;
+ }
+
+ /* Antenna TX power difference */
+ rtlefuse->antenna_txpwdiff[2] = 0;/* RF-D, don't care */
+ rtlefuse->antenna_txpwdiff[1] = 0;/* RF-C, don't care */
+ rtlefuse->antenna_txpwdiff[0] = (u8)(ant_pwr_diff); /* RF-B */
+
+ u4reg_val = rtlefuse->antenna_txpwdiff[2] << 8 |
+ rtlefuse->antenna_txpwdiff[1] << 4 |
+ rtlefuse->antenna_txpwdiff[0];
+
+ rtl_set_bbreg(hw, RFPGA0_TXGAINSTAGE, (BXBTXAGC | BXCTXAGC | BXDTXAGC),
+ u4reg_val);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Write BCD-Diff(0x%x) = 0x%x\n",
+ RFPGA0_TXGAINSTAGE, u4reg_val));
+}
+
+static void _rtl92s_get_txpower_writeval_byregulatory(struct ieee80211_hw *hw,
+ u8 chnl, u8 index,
+ u32 pwrbase0,
+ u32 pwrbase1,
+ u32 *p_outwrite_val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u8 i, chnlgroup, pwrdiff_limit[4];
+ u32 writeval, customer_limit;
+
+ /* Index 0 & 1= legacy OFDM, 2-5=HT_MCS rate */
+ switch (rtlefuse->eeprom_regulatory) {
+ case 0:
+ /* Realtek better performance increase power diff
+ * defined by Realtek for large power */
+ chnlgroup = 0;
+
+ writeval = rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index] +
+ ((index < 2) ? pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("RTK better performance, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ case 1:
+ /* Realtek regulatory increase power diff defined
+ * by Realtek for regulatory */
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ writeval = ((index < 2) ? pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Realtek regulatory, "
+ "40MHz, writeval = 0x%x\n", writeval));
+ } else {
+ if (rtlphy->pwrgroup_cnt == 1)
+ chnlgroup = 0;
+
+ if (rtlphy->pwrgroup_cnt >= 3) {
+ if (chnl <= 3)
+ chnlgroup = 0;
+ else if (chnl >= 4 && chnl <= 8)
+ chnlgroup = 1;
+ else if (chnl > 8)
+ chnlgroup = 2;
+ if (rtlphy->pwrgroup_cnt == 4)
+ chnlgroup++;
+ }
+
+ writeval = rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index]
+ + ((index < 2) ?
+ pwrbase0 : pwrbase1);
+
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Realtek regulatory, "
+ "20MHz, writeval = 0x%x\n", writeval));
+ }
+ break;
+ case 2:
+ /* Better regulatory don't increase any power diff */
+ writeval = ((index < 2) ? pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Better regulatory, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ case 3:
+ /* Customer defined power diff. increase power diff
+ defined by customer. */
+ chnlgroup = 0;
+
+ if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("customer's limit, 40MHz = 0x%x\n",
+ rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][chnl - 1]));
+ } else {
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("customer's limit, 20MHz = 0x%x\n",
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1]));
+ }
+
+ for (i = 0; i < 4; i++) {
+ pwrdiff_limit[i] =
+ (u8)((rtlphy->mcs_txpwrlevel_origoffset
+ [chnlgroup][index] & (0x7f << (i * 8)))
+ >> (i * 8));
+
+ if (rtlphy->current_chan_bw ==
+ HT_CHANNEL_WIDTH_20_40) {
+ if (pwrdiff_limit[i] >
+ rtlefuse->pwrgroup_ht40
+ [RF90_PATH_A][chnl - 1]) {
+ pwrdiff_limit[i] =
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1];
+ }
+ } else {
+ if (pwrdiff_limit[i] >
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1]) {
+ pwrdiff_limit[i] =
+ rtlefuse->pwrgroup_ht20
+ [RF90_PATH_A][chnl - 1];
+ }
+ }
+ }
+
+ customer_limit = (pwrdiff_limit[3] << 24) |
+ (pwrdiff_limit[2] << 16) |
+ (pwrdiff_limit[1] << 8) |
+ (pwrdiff_limit[0]);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Customer's limit = 0x%x\n",
+ customer_limit));
+
+ writeval = customer_limit + ((index < 2) ?
+ pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("Customer, writeval = "
+ "0x%x\n", writeval));
+ break;
+ default:
+ chnlgroup = 0;
+ writeval = rtlphy->mcs_txpwrlevel_origoffset[chnlgroup][index] +
+ ((index < 2) ? pwrbase0 : pwrbase1);
+ RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+ ("RTK better performance, "
+ "writeval = 0x%x\n", writeval));
+ break;
+ }
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl == TX_HIGH_PWR_LEVEL_LEVEL1)
+ writeval = 0x10101010;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL2)
+ writeval = 0x0;
+
+ *p_outwrite_val = writeval;
+
+}
+
+static void _rtl92s_write_ofdm_powerreg(struct ieee80211_hw *hw,
+ u8 index, u32 val)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u16 regoffset[6] = {0xe00, 0xe04, 0xe10, 0xe14, 0xe18, 0xe1c};
+ u8 i, rfa_pwr[4];
+ u8 rfa_lower_bound = 0, rfa_upper_bound = 0, rf_pwr_diff = 0;
+ u32 writeval = val;
+
+ /* If path A and Path B coexist, we must limit Path A tx power.
+ * Protect Path B pwr over or under flow. We need to calculate
+ * upper and lower bound of path A tx power. */
+ if (rtlphy->rf_type == RF_2T2R) {
+ rf_pwr_diff = rtlefuse->antenna_txpwdiff[0];
+
+ /* Diff=-8~-1 */
+ if (rf_pwr_diff >= 8) {
+ /* Prevent underflow!! */
+ rfa_lower_bound = 0x10 - rf_pwr_diff;
+ /* if (rf_pwr_diff >= 0) Diff = 0-7 */
+ } else {
+ rfa_upper_bound = RF6052_MAX_TX_PWR - rf_pwr_diff;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ rfa_pwr[i] = (u8)((writeval & (0x7f << (i * 8))) >> (i * 8));
+ if (rfa_pwr[i] > RF6052_MAX_TX_PWR)
+ rfa_pwr[i] = RF6052_MAX_TX_PWR;
+
+ /* If path A and Path B coexist, we must limit Path A tx power.
+ * Protect Path B pwr over or under flow. We need to calculate
+ * upper and lower bound of path A tx power. */
+ if (rtlphy->rf_type == RF_2T2R) {
+ /* Diff=-8~-1 */
+ if (rf_pwr_diff >= 8) {
+ /* Prevent underflow!! */
+ if (rfa_pwr[i] < rfa_lower_bound)
+ rfa_pwr[i] = rfa_lower_bound;
+ /* Diff = 0-7 */
+ } else if (rf_pwr_diff >= 1) {
+ /* Prevent overflow */
+ if (rfa_pwr[i] > rfa_upper_bound)
+ rfa_pwr[i] = rfa_upper_bound;
+ }
+ }
+
+ }
+
+ writeval = (rfa_pwr[3] << 24) | (rfa_pwr[2] << 16) | (rfa_pwr[1] << 8) |
+ rfa_pwr[0];
+
+ rtl_set_bbreg(hw, regoffset[index], 0x7f7f7f7f, writeval);
+}
+
+void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
+ u8 *p_pwrlevel, u8 chnl)
+{
+ u32 writeval, pwrbase0, pwrbase1;
+ u8 index = 0;
+ u8 finalpwr_idx[4];
+
+ _rtl92s_get_powerbase(hw, p_pwrlevel, chnl, &pwrbase0, &pwrbase1,
+ &finalpwr_idx[0]);
+ _rtl92s_set_antennadiff(hw, &finalpwr_idx[0]);
+
+ for (index = 0; index < 6; index++) {
+ _rtl92s_get_txpower_writeval_byregulatory(hw, chnl, index,
+ pwrbase0, pwrbase1, &writeval);
+
+ _rtl92s_write_ofdm_powerreg(hw, index, writeval);
+ }
+}
+
+void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw, u8 pwrlevel)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+ u32 txagc = 0;
+ bool dont_inc_cck_or_turboscanoff = false;
+
+ if (((rtlefuse->eeprom_version >= 2) &&
+ (rtlefuse->txpwr_safetyflag == 1)) ||
+ ((rtlefuse->eeprom_version >= 2) &&
+ (rtlefuse->eeprom_regulatory != 0)))
+ dont_inc_cck_or_turboscanoff = true;
+
+ if (mac->act_scanning == true) {
+ txagc = 0x3f;
+ if (dont_inc_cck_or_turboscanoff)
+ txagc = pwrlevel;
+ } else {
+ txagc = pwrlevel;
+
+ if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL1)
+ txagc = 0x10;
+ else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+ TX_HIGH_PWR_LEVEL_LEVEL2)
+ txagc = 0x0;
+ }
+
+ if (txagc > RF6052_MAX_TX_PWR)
+ txagc = RF6052_MAX_TX_PWR;
+
+ rtl_set_bbreg(hw, RTXAGC_CCK_MCS32, BTX_AGCRATECCK, txagc);
+
+}
+
+bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u32 u4reg_val = 0;
+ u8 rfpath;
+ bool rtstatus = true;
+ struct bb_reg_def *pphyreg;
+
+ /* Initialize RF */
+ for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+
+ pphyreg = &rtlphy->phyreg_def[rfpath];
+
+ /* Store original RFENV control type */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ u4reg_val = rtl92s_phy_query_bb_reg(hw,
+ pphyreg->rfintfs,
+ BRFSI_RFENV);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ u4reg_val = rtl92s_phy_query_bb_reg(hw,
+ pphyreg->rfintfs,
+ BRFSI_RFENV << 16);
+ break;
+ }
+
+ /* Set RF_ENV enable */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfe,
+ BRFSI_RFENV << 16, 0x1);
+
+ /* Set RF_ENV output high */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+
+ /* Set bit number of Address and Data for RF register */
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
+ B3WIRE_ADDRESSLENGTH, 0x0);
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfhssi_para2,
+ B3WIRE_DATALENGTH, 0x0);
+
+ /* Initialize RF fom connfiguration file */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ rtstatus = rtl92s_phy_config_rf(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_B:
+ rtstatus = rtl92s_phy_config_rf(hw,
+ (enum radio_path)rfpath);
+ break;
+ case RF90_PATH_C:
+ break;
+ case RF90_PATH_D:
+ break;
+ }
+
+ /* Restore RFENV control type */
+ switch (rfpath) {
+ case RF90_PATH_A:
+ case RF90_PATH_C:
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs, BRFSI_RFENV,
+ u4reg_val);
+ break;
+ case RF90_PATH_B:
+ case RF90_PATH_D:
+ rtl92s_phy_set_bb_reg(hw, pphyreg->rfintfs,
+ BRFSI_RFENV << 16,
+ u4reg_val);
+ break;
+ }
+
+ if (rtstatus != true) {
+ printk(KERN_ERR "Radio[%d] Fail!!", rfpath);
+ goto fail;
+ }
+
+ }
+
+ return rtstatus;
+
+fail:
+ return rtstatus;
+}
+
+void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+ switch (bandwidth) {
+ case HT_CHANNEL_WIDTH_20:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff) | 0x0400);
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ case HT_CHANNEL_WIDTH_20_40:
+ rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+ 0xfffff3ff));
+ rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+ rtlphy->rfreg_chnlval[0]);
+ break;
+ default:
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("unknown bandwidth: %#X\n",
+ bandwidth));
+ break;
+ }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/rf.h b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h
new file mode 100644
index 0000000..3843baa
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/rf.h
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __INC_RTL92S_RF_H
+#define __INC_RTL92S_RF_H
+
+#define RF6052_MAX_TX_PWR 0x3F
+
+void rtl92s_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+ u8 bandwidth);
+bool rtl92s_phy_rf6052_config(struct ieee80211_hw *hw) ;
+void rtl92s_phy_rf6052_set_ccktxpower(struct ieee80211_hw *hw,
+ u8 powerlevel);
+void rtl92s_phy_rf6052_set_ofdmtxpower(struct ieee80211_hw *hw,
+ u8 *p_pwrlevel, u8 chnl);
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
new file mode 100644
index 0000000..1c6cb1d
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -0,0 +1,423 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include <linux/vmalloc.h>
+
+#include "../wifi.h"
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+
+static void rtl92s_init_aspm_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+ /*close ASPM for AMD defaultly */
+ rtlpci->const_amdpci_aspm = 0;
+
+ /*
+ * ASPM PS mode.
+ * 0 - Disable ASPM,
+ * 1 - Enable ASPM without Clock Req,
+ * 2 - Enable ASPM with Clock Req,
+ * 3 - Alwyas Enable ASPM with Clock Req,
+ * 4 - Always Enable ASPM without Clock Req.
+ * set defult to RTL8192CE:3 RTL8192E:2
+ * */
+ rtlpci->const_pci_aspm = 2;
+
+ /*Setting for PCI-E device */
+ rtlpci->const_devicepci_aspm_setting = 0x03;
+
+ /*Setting for PCI-E bridge */
+ rtlpci->const_hostpci_aspm_setting = 0x02;
+
+ /*
+ * In Hw/Sw Radio Off situation.
+ * 0 - Default,
+ * 1 - From ASPM setting without low Mac Pwr,
+ * 2 - From ASPM setting with low Mac Pwr,
+ * 3 - Bus D3
+ * set default to RTL8192CE:0 RTL8192SE:2
+ */
+ rtlpci->const_hwsw_rfoff_d3 = 2;
+
+ /*
+ * This setting works for those device with
+ * backdoor ASPM setting such as EPHY setting.
+ * 0 - Not support ASPM,
+ * 1 - Support ASPM,
+ * 2 - According to chipset.
+ */
+ rtlpci->const_support_pciaspm = 2;
+}
+
+static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ const struct firmware *firmware;
+ struct rt_firmware *pfirmware = NULL;
+ int err = 0;
+ u16 earlyrxthreshold = 7;
+
+ rtlpriv->dm.dm_initialgain_enable = 1;
+ rtlpriv->dm.dm_flag = 0;
+ rtlpriv->dm.disable_framebursting = 0;
+ rtlpriv->dm.thermalvalue = 0;
+ rtlpriv->dm.useramask = true;
+
+ /* compatible 5G band 91se just 2.4G band & smsp */
+ rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+ rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+ rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+ rtlpci->transmit_config = 0;
+
+ rtlpci->receive_config =
+ RCR_APPFCS |
+ RCR_APWRMGT |
+ /*RCR_ADD3 |*/
+ RCR_AMF |
+ RCR_ADF |
+ RCR_APP_MIC |
+ RCR_APP_ICV |
+ RCR_AICV |
+ /* Accept ICV error, CRC32 Error */
+ RCR_ACRC32 |
+ RCR_AB |
+ /* Accept Broadcast, Multicast */
+ RCR_AM |
+ /* Accept Physical match */
+ RCR_APM |
+ /* Accept Destination Address packets */
+ /*RCR_AAP |*/
+ RCR_APP_PHYST_STAFF |
+ /* Accept PHY status */
+ RCR_APP_PHYST_RXFF |
+ (earlyrxthreshold << RCR_FIFO_OFFSET);
+
+ rtlpci->irq_mask[0] = (u32)
+ (IMR_ROK |
+ IMR_VODOK |
+ IMR_VIDOK |
+ IMR_BEDOK |
+ IMR_BKDOK |
+ IMR_HCCADOK |
+ IMR_MGNTDOK |
+ IMR_COMDOK |
+ IMR_HIGHDOK |
+ IMR_BDOK |
+ IMR_RXCMDOK |
+ /*IMR_TIMEOUT0 |*/
+ IMR_RDU |
+ IMR_RXFOVW |
+ IMR_BCNINT
+ /*| IMR_TXFOVW*/
+ /*| IMR_TBDOK |
+ IMR_TBDER*/);
+
+ rtlpci->irq_mask[1] = (u32) 0;
+
+ rtlpci->shortretry_limit = 0x30;
+ rtlpci->longretry_limit = 0x30;
+
+ rtlpci->first_init = true;
+
+ /* for LPS & IPS */
+ rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+ rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+ rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+ rtlpriv->psc.reg_fwctrl_lps = 3;
+ rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+ /* for ASPM, you can close aspm through
+ * set const_support_pciaspm = 0 */
+ rtl92s_init_aspm_vars(hw);
+
+ if (rtlpriv->psc.reg_fwctrl_lps == 1)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+ else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+ rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+ /* for firmware buf */
+ rtlpriv->rtlhal.pfirmware = vzalloc(sizeof(struct rt_firmware));
+ if (!rtlpriv->rtlhal.pfirmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Can't alloc buffer for fw.\n"));
+ return 1;
+ }
+
+ printk(KERN_INFO "rtl8192se: Driver for Realtek RTL8192SE/RTL8191SE\n"
+ " Loading firmware %s\n", rtlpriv->cfg->fw_name);
+ /* request fw */
+ err = request_firmware(&firmware, rtlpriv->cfg->fw_name,
+ rtlpriv->io.dev);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Failed to request firmware!\n"));
+ return 1;
+ }
+ if (firmware->size > sizeof(struct rt_firmware)) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ ("Firmware is too big!\n"));
+ release_firmware(firmware);
+ return 1;
+ }
+
+ pfirmware = (struct rt_firmware *)rtlpriv->rtlhal.pfirmware;
+ memcpy(pfirmware->sz_fw_tmpbuffer, firmware->data, firmware->size);
+ pfirmware->sz_fw_tmpbufferlen = firmware->size;
+ release_firmware(firmware);
+
+ return err;
+}
+
+static void rtl92s_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+ if (rtlpriv->rtlhal.pfirmware) {
+ vfree(rtlpriv->rtlhal.pfirmware);
+ rtlpriv->rtlhal.pfirmware = NULL;
+ }
+}
+
+static struct rtl_hal_ops rtl8192se_hal_ops = {
+ .init_sw_vars = rtl92s_init_sw_vars,
+ .deinit_sw_vars = rtl92s_deinit_sw_vars,
+ .read_eeprom_info = rtl92se_read_eeprom_info,
+ .interrupt_recognized = rtl92se_interrupt_recognized,
+ .hw_init = rtl92se_hw_init,
+ .hw_disable = rtl92se_card_disable,
+ .hw_suspend = rtl92se_suspend,
+ .hw_resume = rtl92se_resume,
+ .enable_interrupt = rtl92se_enable_interrupt,
+ .disable_interrupt = rtl92se_disable_interrupt,
+ .set_network_type = rtl92se_set_network_type,
+ .set_chk_bssid = rtl92se_set_check_bssid,
+ .set_qos = rtl92se_set_qos,
+ .set_bcn_reg = rtl92se_set_beacon_related_registers,
+ .set_bcn_intv = rtl92se_set_beacon_interval,
+ .update_interrupt_mask = rtl92se_update_interrupt_mask,
+ .get_hw_reg = rtl92se_get_hw_reg,
+ .set_hw_reg = rtl92se_set_hw_reg,
+ .update_rate_tbl = rtl92se_update_hal_rate_tbl,
+ .fill_tx_desc = rtl92se_tx_fill_desc,
+ .fill_tx_cmddesc = rtl92se_tx_fill_cmddesc,
+ .query_rx_desc = rtl92se_rx_query_desc,
+ .set_channel_access = rtl92se_update_channel_access_setting,
+ .radio_onoff_checking = rtl92se_gpio_radio_on_off_checking,
+ .set_bw_mode = rtl92s_phy_set_bw_mode,
+ .switch_channel = rtl92s_phy_sw_chnl,
+ .dm_watchdog = rtl92s_dm_watchdog,
+ .scan_operation_backup = rtl92s_phy_scan_operation_backup,
+ .set_rf_power_state = rtl92s_phy_set_rf_power_state,
+ .led_control = rtl92se_led_control,
+ .set_desc = rtl92se_set_desc,
+ .get_desc = rtl92se_get_desc,
+ .tx_polling = rtl92se_tx_polling,
+ .enable_hw_sec = rtl92se_enable_hw_security_config,
+ .set_key = rtl92se_set_key,
+ .init_sw_leds = rtl92se_init_sw_leds,
+ .get_bbreg = rtl92s_phy_query_bb_reg,
+ .set_bbreg = rtl92s_phy_set_bb_reg,
+ .get_rfreg = rtl92s_phy_query_rf_reg,
+ .set_rfreg = rtl92s_phy_set_rf_reg,
+};
+
+static struct rtl_mod_params rtl92se_mod_params = {
+ .sw_crypto = false,
+ .inactiveps = true,
+ .swctrl_lps = true,
+ .fwctrl_lps = false,
+};
+
+/* Because memory R/W bursting will cause system hang/crash
+ * for 92se, so we don't read back after every write action */
+static struct rtl_hal_cfg rtl92se_hal_cfg = {
+ .bar_id = 1,
+ .write_readback = false,
+ .name = "rtl92s_pci",
+ .fw_name = "rtlwifi/rtl8192sefw.bin",
+ .ops = &rtl8192se_hal_ops,
+ .mod_params = &rtl92se_mod_params,
+
+ .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+ .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+ .maps[SYS_CLK] = SYS_CLKR,
+ .maps[MAC_RCR_AM] = RCR_AM,
+ .maps[MAC_RCR_AB] = RCR_AB,
+ .maps[MAC_RCR_ACRC32] = RCR_ACRC32,
+ .maps[MAC_RCR_ACF] = RCR_ACF,
+ .maps[MAC_RCR_AAP] = RCR_AAP,
+
+ .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+ .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_CLK] = REG_EFUSE_CLK,
+ .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+ .maps[EFUSE_PWC_EV12V] = 0, /* nouse for 8192se */
+ .maps[EFUSE_FEN_ELDR] = 0, /* nouse for 8192se */
+ .maps[EFUSE_LOADER_CLK_EN] = 0,/* nouse for 8192se */
+ .maps[EFUSE_ANA8M] = EFUSE_ANA8M,
+ .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE_92S,
+ .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+ .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+
+ .maps[RWCAM] = REG_RWCAM,
+ .maps[WCAMI] = REG_WCAMI,
+ .maps[RCAMO] = REG_RCAMO,
+ .maps[CAMDBG] = REG_CAMDBG,
+ .maps[SECR] = REG_SECR,
+ .maps[SEC_CAM_NONE] = CAM_NONE,
+ .maps[SEC_CAM_WEP40] = CAM_WEP40,
+ .maps[SEC_CAM_TKIP] = CAM_TKIP,
+ .maps[SEC_CAM_AES] = CAM_AES,
+ .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+ .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+ .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+ .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+ .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+ .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+ .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+ .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,
+ .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+ .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+ .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+ .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+ .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+ .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+ .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+ .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,
+ .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,
+
+ .maps[RTL_IMR_TXFOVW] = IMR_TXFOVW,
+ .maps[RTL_IMR_PSTIMEOUT] = IMR_PSTIMEOUT,
+ .maps[RTL_IMR_BcnInt] = IMR_BCNINT,
+ .maps[RTL_IMR_RXFOVW] = IMR_RXFOVW,
+ .maps[RTL_IMR_RDU] = IMR_RDU,
+ .maps[RTL_IMR_ATIMEND] = IMR_ATIMEND,
+ .maps[RTL_IMR_BDOK] = IMR_BDOK,
+ .maps[RTL_IMR_MGNTDOK] = IMR_MGNTDOK,
+ .maps[RTL_IMR_TBDER] = IMR_TBDER,
+ .maps[RTL_IMR_HIGHDOK] = IMR_HIGHDOK,
+ .maps[RTL_IMR_COMDOK] = IMR_COMDOK,
+ .maps[RTL_IMR_TBDOK] = IMR_TBDOK,
+ .maps[RTL_IMR_BKDOK] = IMR_BKDOK,
+ .maps[RTL_IMR_BEDOK] = IMR_BEDOK,
+ .maps[RTL_IMR_VIDOK] = IMR_VIDOK,
+ .maps[RTL_IMR_VODOK] = IMR_VODOK,
+ .maps[RTL_IMR_ROK] = IMR_ROK,
+ .maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
+
+ .maps[RTL_RC_CCK_RATE1M] = DESC92S_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC92S_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC92S_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC92S_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC92S_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC92S_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC92S_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC92S_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC92S_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC92S_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC92S_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC92S_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC92S_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC92S_RATEMCS15,
+};
+
+static struct pci_device_id rtl92se_pci_ids[] __devinitdata = {
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8192, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8171, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8172, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8173, rtl92se_hal_cfg)},
+ {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8174, rtl92se_hal_cfg)},
+ {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids);
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin");
+
+module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444);
+module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
+MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
+MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is "
+ "open)\n");
+
+
+static struct pci_driver rtl92se_driver = {
+ .name = KBUILD_MODNAME,
+ .id_table = rtl92se_pci_ids,
+ .probe = rtl_pci_probe,
+ .remove = rtl_pci_disconnect,
+
+#ifdef CONFIG_PM
+ .suspend = rtl_pci_suspend,
+ .resume = rtl_pci_resume,
+#endif
+
+};
+
+static int __init rtl92se_module_init(void)
+{
+ int ret = 0;
+
+ ret = pci_register_driver(&rtl92se_driver);
+ if (ret)
+ RT_ASSERT(false, (": No device found\n"));
+
+ return ret;
+}
+
+static void __exit rtl92se_module_exit(void)
+{
+ pci_unregister_driver(&rtl92se_driver);
+}
+
+module_init(rtl92se_module_init);
+module_exit(rtl92se_module_exit);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.h b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h
new file mode 100644
index 0000000..fc4eb28
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.h
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_SW_H__
+#define __REALTEK_PCI92SE_SW_H__
+
+#define EFUSE_MAX_SECTION 16
+
+int rtl92se_init_sw(struct ieee80211_hw *hw);
+void rtl92se_deinit_sw(struct ieee80211_hw *hw);
+void rtl92se_init_var_map(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.c b/drivers/net/wireless/rtlwifi/rtl8192se/table.c
new file mode 100644
index 0000000..154185b
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.c
@@ -0,0 +1,634 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ * Created on 2010/ 5/18, 1:41
+ *****************************************************************************/
+
+#include "table.h"
+
+u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH] = {
+ 0x01c, 0x07000000,
+ 0x800, 0x00040000,
+ 0x804, 0x00008003,
+ 0x808, 0x0000fc00,
+ 0x80c, 0x0000000a,
+ 0x810, 0x10005088,
+ 0x814, 0x020c3d10,
+ 0x818, 0x00200185,
+ 0x81c, 0x00000000,
+ 0x820, 0x01000000,
+ 0x824, 0x00390004,
+ 0x828, 0x01000000,
+ 0x82c, 0x00390004,
+ 0x830, 0x00000004,
+ 0x834, 0x00690200,
+ 0x838, 0x00000004,
+ 0x83c, 0x00690200,
+ 0x840, 0x00010000,
+ 0x844, 0x00010000,
+ 0x848, 0x00000000,
+ 0x84c, 0x00000000,
+ 0x850, 0x00000000,
+ 0x854, 0x00000000,
+ 0x858, 0x48484848,
+ 0x85c, 0x65a965a9,
+ 0x860, 0x0f7f0130,
+ 0x864, 0x0f7f0130,
+ 0x868, 0x0f7f0130,
+ 0x86c, 0x0f7f0130,
+ 0x870, 0x03000700,
+ 0x874, 0x03000300,
+ 0x878, 0x00020002,
+ 0x87c, 0x004f0201,
+ 0x880, 0xa8300ac1,
+ 0x884, 0x00000058,
+ 0x888, 0x00000008,
+ 0x88c, 0x00000004,
+ 0x890, 0x00000000,
+ 0x894, 0xfffffffe,
+ 0x898, 0x40302010,
+ 0x89c, 0x00706050,
+ 0x8b0, 0x00000000,
+ 0x8e0, 0x00000000,
+ 0x8e4, 0x00000000,
+ 0xe00, 0x30333333,
+ 0xe04, 0x2a2d2e2f,
+ 0xe08, 0x00003232,
+ 0xe10, 0x30333333,
+ 0xe14, 0x2a2d2e2f,
+ 0xe18, 0x30333333,
+ 0xe1c, 0x2a2d2e2f,
+ 0xe30, 0x01007c00,
+ 0xe34, 0x01004800,
+ 0xe38, 0x1000dc1f,
+ 0xe3c, 0x10008c1f,
+ 0xe40, 0x021400a0,
+ 0xe44, 0x281600a0,
+ 0xe48, 0xf8000001,
+ 0xe4c, 0x00002910,
+ 0xe50, 0x01007c00,
+ 0xe54, 0x01004800,
+ 0xe58, 0x1000dc1f,
+ 0xe5c, 0x10008c1f,
+ 0xe60, 0x021400a0,
+ 0xe64, 0x281600a0,
+ 0xe6c, 0x00002910,
+ 0xe70, 0x31ed92fb,
+ 0xe74, 0x361536fb,
+ 0xe78, 0x361536fb,
+ 0xe7c, 0x361536fb,
+ 0xe80, 0x361536fb,
+ 0xe84, 0x000d92fb,
+ 0xe88, 0x000d92fb,
+ 0xe8c, 0x31ed92fb,
+ 0xed0, 0x31ed92fb,
+ 0xed4, 0x31ed92fb,
+ 0xed8, 0x000d92fb,
+ 0xedc, 0x000d92fb,
+ 0xee0, 0x000d92fb,
+ 0xee4, 0x015e5448,
+ 0xee8, 0x21555448,
+ 0x900, 0x00000000,
+ 0x904, 0x00000023,
+ 0x908, 0x00000000,
+ 0x90c, 0x01121313,
+ 0xa00, 0x00d047c8,
+ 0xa04, 0x80ff0008,
+ 0xa08, 0x8ccd8300,
+ 0xa0c, 0x2e62120f,
+ 0xa10, 0x9500bb78,
+ 0xa14, 0x11144028,
+ 0xa18, 0x00881117,
+ 0xa1c, 0x89140f00,
+ 0xa20, 0x1a1b0000,
+ 0xa24, 0x090e1317,
+ 0xa28, 0x00000204,
+ 0xa2c, 0x10d30000,
+ 0xc00, 0x40071d40,
+ 0xc04, 0x00a05633,
+ 0xc08, 0x000000e4,
+ 0xc0c, 0x6c6c6c6c,
+ 0xc10, 0x08800000,
+ 0xc14, 0x40000100,
+ 0xc18, 0x08000000,
+ 0xc1c, 0x40000100,
+ 0xc20, 0x08000000,
+ 0xc24, 0x40000100,
+ 0xc28, 0x08000000,
+ 0xc2c, 0x40000100,
+ 0xc30, 0x6de9ac44,
+ 0xc34, 0x469652cf,
+ 0xc38, 0x49795994,
+ 0xc3c, 0x0a979764,
+ 0xc40, 0x1f7c403f,
+ 0xc44, 0x000100b7,
+ 0xc48, 0xec020000,
+ 0xc4c, 0x007f037f,
+ 0xc50, 0x69543420,
+ 0xc54, 0x433c0094,
+ 0xc58, 0x69543420,
+ 0xc5c, 0x433c0094,
+ 0xc60, 0x69543420,
+ 0xc64, 0x433c0094,
+ 0xc68, 0x69543420,
+ 0xc6c, 0x433c0094,
+ 0xc70, 0x2c7f000d,
+ 0xc74, 0x0186155b,
+ 0xc78, 0x0000001f,
+ 0xc7c, 0x00b91612,
+ 0xc80, 0x40000100,
+ 0xc84, 0x20f60000,
+ 0xc88, 0x20000080,
+ 0xc8c, 0x20200000,
+ 0xc90, 0x40000100,
+ 0xc94, 0x00000000,
+ 0xc98, 0x40000100,
+ 0xc9c, 0x00000000,
+ 0xca0, 0x00492492,
+ 0xca4, 0x00000000,
+ 0xca8, 0x00000000,
+ 0xcac, 0x00000000,
+ 0xcb0, 0x00000000,
+ 0xcb4, 0x00000000,
+ 0xcb8, 0x00000000,
+ 0xcbc, 0x28000000,
+ 0xcc0, 0x00000000,
+ 0xcc4, 0x00000000,
+ 0xcc8, 0x00000000,
+ 0xccc, 0x00000000,
+ 0xcd0, 0x00000000,
+ 0xcd4, 0x00000000,
+ 0xcd8, 0x64b22427,
+ 0xcdc, 0x00766932,
+ 0xce0, 0x00222222,
+ 0xce4, 0x00000000,
+ 0xce8, 0x37644302,
+ 0xcec, 0x2f97d40c,
+ 0xd00, 0x00000750,
+ 0xd04, 0x00000403,
+ 0xd08, 0x0000907f,
+ 0xd0c, 0x00000001,
+ 0xd10, 0xa0633333,
+ 0xd14, 0x33333c63,
+ 0xd18, 0x6a8f5b6b,
+ 0xd1c, 0x00000000,
+ 0xd20, 0x00000000,
+ 0xd24, 0x00000000,
+ 0xd28, 0x00000000,
+ 0xd2c, 0xcc979975,
+ 0xd30, 0x00000000,
+ 0xd34, 0x00000000,
+ 0xd38, 0x00000000,
+ 0xd3c, 0x00027293,
+ 0xd40, 0x00000000,
+ 0xd44, 0x00000000,
+ 0xd48, 0x00000000,
+ 0xd50, 0x6437140a,
+ 0xd54, 0x024dbd02,
+ 0xd58, 0x00000000,
+ 0xd5c, 0x30032064,
+ 0xd60, 0x4653de68,
+ 0xd64, 0x00518a3c,
+ 0xd68, 0x00002101,
+ 0xf14, 0x00000003,
+ 0xf4c, 0x00000000,
+ 0xf00, 0x00000300,
+};
+
+u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH] = {
+ 0x844, 0xffffffff, 0x00010000,
+ 0x804, 0x0000000f, 0x00000001,
+ 0x824, 0x00f0000f, 0x00300004,
+ 0x82c, 0x00f0000f, 0x00100002,
+ 0x870, 0x04000000, 0x00000001,
+ 0x864, 0x00000400, 0x00000000,
+ 0x878, 0x000f000f, 0x00000002,
+ 0xe74, 0x0f000000, 0x00000002,
+ 0xe78, 0x0f000000, 0x00000002,
+ 0xe7c, 0x0f000000, 0x00000002,
+ 0xe80, 0x0f000000, 0x00000002,
+ 0x90c, 0x000000ff, 0x00000011,
+ 0xc04, 0x000000ff, 0x00000011,
+ 0xd04, 0x0000000f, 0x00000001,
+ 0x1f4, 0xffff0000, 0x00007777,
+ 0x234, 0xf8000000, 0x0000000a,
+};
+
+u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH] = {
+ 0x804, 0x0000000f, 0x00000003,
+ 0x824, 0x00f0000f, 0x00300004,
+ 0x82c, 0x00f0000f, 0x00300002,
+ 0x870, 0x04000000, 0x00000001,
+ 0x864, 0x00000400, 0x00000000,
+ 0x878, 0x000f000f, 0x00000002,
+ 0xe74, 0x0f000000, 0x00000002,
+ 0xe78, 0x0f000000, 0x00000002,
+ 0xe7c, 0x0f000000, 0x00000002,
+ 0xe80, 0x0f000000, 0x00000002,
+ 0x90c, 0x000000ff, 0x00000011,
+ 0xc04, 0x000000ff, 0x00000033,
+ 0xd04, 0x0000000f, 0x00000003,
+ 0x1f4, 0xffff0000, 0x00007777,
+ 0x234, 0xf8000000, 0x0000000a,
+};
+
+u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH] = {
+ 0xe00, 0xffffffff, 0x06090909,
+ 0xe04, 0xffffffff, 0x00030406,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x0a0c0d0e,
+ 0xe14, 0xffffffff, 0x04070809,
+ 0xe18, 0xffffffff, 0x0a0c0d0e,
+ 0xe1c, 0xffffffff, 0x04070809,
+ 0xe00, 0xffffffff, 0x04040404,
+ 0xe04, 0xffffffff, 0x00020204,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02040404,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02040404,
+ 0xe1c, 0xffffffff, 0x00000002,
+ 0xe00, 0xffffffff, 0x04040404,
+ 0xe04, 0xffffffff, 0x00020204,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02040404,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02040404,
+ 0xe1c, 0xffffffff, 0x00000002,
+ 0xe00, 0xffffffff, 0x02020202,
+ 0xe04, 0xffffffff, 0x00020202,
+ 0xe08, 0x0000ff00, 0x00000000,
+ 0xe10, 0xffffffff, 0x02020202,
+ 0xe14, 0xffffffff, 0x00000002,
+ 0xe18, 0xffffffff, 0x02020202,
+ 0xe1c, 0xffffffff, 0x00000002,
+};
+
+u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00030250,
+ 0x002, 0x00010000,
+ 0x010, 0x0008000f,
+ 0x011, 0x000231fc,
+ 0x010, 0x000c000f,
+ 0x011, 0x0003f9f8,
+ 0x010, 0x0002000f,
+ 0x011, 0x00020101,
+ 0x014, 0x0001093e,
+ 0x014, 0x0009093e,
+ 0x015, 0x0000f8f4,
+ 0x017, 0x000f6500,
+ 0x01a, 0x00013056,
+ 0x01b, 0x00060000,
+ 0x01c, 0x00000300,
+ 0x01e, 0x00031059,
+ 0x021, 0x00054000,
+ 0x022, 0x0000083c,
+ 0x023, 0x00001558,
+ 0x024, 0x00000060,
+ 0x025, 0x00022583,
+ 0x026, 0x0000f200,
+ 0x027, 0x000eacf1,
+ 0x028, 0x0009bd54,
+ 0x029, 0x00004582,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00021334,
+ 0x02a, 0x00000000,
+ 0x02b, 0x0000000a,
+ 0x02a, 0x00000001,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000c,
+ 0x02a, 0x00000002,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000003,
+ 0x02b, 0x00000808,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000004,
+ 0x02b, 0x00000808,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000005,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000006,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000007,
+ 0x02b, 0x00000709,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000008,
+ 0x02b, 0x00000709,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x00000009,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000a,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0005b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000b,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x00063333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000c,
+ 0x02b, 0x0000060a,
+ 0x02b, 0x0006b333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000d,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00053333,
+ 0x02c, 0x0000000d,
+ 0x02a, 0x0000000e,
+ 0x02b, 0x0000050b,
+ 0x02b, 0x00066623,
+ 0x02c, 0x0000001a,
+ 0x02a, 0x000e4000,
+ 0x030, 0x00020000,
+ 0x031, 0x000b9631,
+ 0x032, 0x0000130d,
+ 0x033, 0x00000187,
+ 0x013, 0x00019e6c,
+ 0x013, 0x00015e94,
+ 0x000, 0x00010159,
+ 0x018, 0x0000f401,
+ 0x0fe, 0x00000000,
+ 0x01e, 0x0003105b,
+ 0x0fe, 0x00000000,
+ 0x000, 0x00030159,
+ 0x010, 0x0004000f,
+ 0x011, 0x000203f9,
+};
+
+u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00001041,
+ 0x002, 0x00011000,
+ 0x005, 0x00080fc0,
+ 0x007, 0x000fc803,
+ 0x013, 0x00017cb0,
+ 0x013, 0x00011cc0,
+ 0x013, 0x0000dc60,
+ 0x013, 0x00008c60,
+ 0x013, 0x00004450,
+ 0x013, 0x00000020,
+};
+
+u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH] = {
+ 0x000, 0x00030159,
+ 0x001, 0x00001041,
+ 0x002, 0x00011000,
+ 0x005, 0x00080fc0,
+ 0x007, 0x000fc803,
+};
+
+u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH] = {
+ 0x020, 0x00000035,
+ 0x048, 0x0000000e,
+ 0x049, 0x000000f0,
+ 0x04a, 0x00000077,
+ 0x04b, 0x00000083,
+ 0x0b5, 0x00000021,
+ 0x0dc, 0x000000ff,
+ 0x0dd, 0x000000ff,
+ 0x0de, 0x000000ff,
+ 0x0df, 0x000000ff,
+ 0x116, 0x00000000,
+ 0x117, 0x00000000,
+ 0x118, 0x00000000,
+ 0x119, 0x00000000,
+ 0x11a, 0x00000000,
+ 0x11b, 0x00000000,
+ 0x11c, 0x00000000,
+ 0x11d, 0x00000000,
+ 0x160, 0x0000000b,
+ 0x161, 0x0000000b,
+ 0x162, 0x0000000b,
+ 0x163, 0x0000000b,
+ 0x164, 0x0000000b,
+ 0x165, 0x0000000b,
+ 0x166, 0x0000000b,
+ 0x167, 0x0000000b,
+ 0x168, 0x0000000b,
+ 0x169, 0x0000000b,
+ 0x16a, 0x0000000b,
+ 0x16b, 0x0000000b,
+ 0x16c, 0x0000000b,
+ 0x16d, 0x0000000b,
+ 0x16e, 0x0000000b,
+ 0x16f, 0x0000000b,
+ 0x170, 0x0000000b,
+ 0x171, 0x0000000b,
+ 0x172, 0x0000000b,
+ 0x173, 0x0000000b,
+ 0x174, 0x0000000b,
+ 0x175, 0x0000000b,
+ 0x176, 0x0000000b,
+ 0x177, 0x0000000b,
+ 0x178, 0x0000000b,
+ 0x179, 0x0000000b,
+ 0x17a, 0x0000000b,
+ 0x17b, 0x0000000b,
+ 0x17c, 0x0000000b,
+ 0x17d, 0x0000000b,
+ 0x17e, 0x0000000b,
+ 0x17f, 0x0000000b,
+ 0x236, 0x0000000c,
+ 0x503, 0x00000022,
+ 0x560, 0x00000000,
+};
+
+u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH] = {
+ 0xc78, 0x7f000001,
+ 0xc78, 0x7f010001,
+ 0xc78, 0x7e020001,
+ 0xc78, 0x7d030001,
+ 0xc78, 0x7c040001,
+ 0xc78, 0x7b050001,
+ 0xc78, 0x7a060001,
+ 0xc78, 0x79070001,
+ 0xc78, 0x78080001,
+ 0xc78, 0x77090001,
+ 0xc78, 0x760a0001,
+ 0xc78, 0x750b0001,
+ 0xc78, 0x740c0001,
+ 0xc78, 0x730d0001,
+ 0xc78, 0x720e0001,
+ 0xc78, 0x710f0001,
+ 0xc78, 0x70100001,
+ 0xc78, 0x6f110001,
+ 0xc78, 0x6f120001,
+ 0xc78, 0x6e130001,
+ 0xc78, 0x6d140001,
+ 0xc78, 0x6d150001,
+ 0xc78, 0x6c160001,
+ 0xc78, 0x6b170001,
+ 0xc78, 0x6a180001,
+ 0xc78, 0x6a190001,
+ 0xc78, 0x691a0001,
+ 0xc78, 0x681b0001,
+ 0xc78, 0x671c0001,
+ 0xc78, 0x661d0001,
+ 0xc78, 0x651e0001,
+ 0xc78, 0x641f0001,
+ 0xc78, 0x63200001,
+ 0xc78, 0x4c210001,
+ 0xc78, 0x4b220001,
+ 0xc78, 0x4a230001,
+ 0xc78, 0x49240001,
+ 0xc78, 0x48250001,
+ 0xc78, 0x47260001,
+ 0xc78, 0x46270001,
+ 0xc78, 0x45280001,
+ 0xc78, 0x44290001,
+ 0xc78, 0x2c2a0001,
+ 0xc78, 0x2b2b0001,
+ 0xc78, 0x2a2c0001,
+ 0xc78, 0x292d0001,
+ 0xc78, 0x282e0001,
+ 0xc78, 0x272f0001,
+ 0xc78, 0x26300001,
+ 0xc78, 0x25310001,
+ 0xc78, 0x24320001,
+ 0xc78, 0x23330001,
+ 0xc78, 0x22340001,
+ 0xc78, 0x09350001,
+ 0xc78, 0x08360001,
+ 0xc78, 0x07370001,
+ 0xc78, 0x06380001,
+ 0xc78, 0x05390001,
+ 0xc78, 0x043a0001,
+ 0xc78, 0x033b0001,
+ 0xc78, 0x023c0001,
+ 0xc78, 0x013d0001,
+ 0xc78, 0x003e0001,
+ 0xc78, 0x003f0001,
+ 0xc78, 0x7f400001,
+ 0xc78, 0x7f410001,
+ 0xc78, 0x7e420001,
+ 0xc78, 0x7d430001,
+ 0xc78, 0x7c440001,
+ 0xc78, 0x7b450001,
+ 0xc78, 0x7a460001,
+ 0xc78, 0x79470001,
+ 0xc78, 0x78480001,
+ 0xc78, 0x77490001,
+ 0xc78, 0x764a0001,
+ 0xc78, 0x754b0001,
+ 0xc78, 0x744c0001,
+ 0xc78, 0x734d0001,
+ 0xc78, 0x724e0001,
+ 0xc78, 0x714f0001,
+ 0xc78, 0x70500001,
+ 0xc78, 0x6f510001,
+ 0xc78, 0x6f520001,
+ 0xc78, 0x6e530001,
+ 0xc78, 0x6d540001,
+ 0xc78, 0x6d550001,
+ 0xc78, 0x6c560001,
+ 0xc78, 0x6b570001,
+ 0xc78, 0x6a580001,
+ 0xc78, 0x6a590001,
+ 0xc78, 0x695a0001,
+ 0xc78, 0x685b0001,
+ 0xc78, 0x675c0001,
+ 0xc78, 0x665d0001,
+ 0xc78, 0x655e0001,
+ 0xc78, 0x645f0001,
+ 0xc78, 0x63600001,
+ 0xc78, 0x4c610001,
+ 0xc78, 0x4b620001,
+ 0xc78, 0x4a630001,
+ 0xc78, 0x49640001,
+ 0xc78, 0x48650001,
+ 0xc78, 0x47660001,
+ 0xc78, 0x46670001,
+ 0xc78, 0x45680001,
+ 0xc78, 0x44690001,
+ 0xc78, 0x2c6a0001,
+ 0xc78, 0x2b6b0001,
+ 0xc78, 0x2a6c0001,
+ 0xc78, 0x296d0001,
+ 0xc78, 0x286e0001,
+ 0xc78, 0x276f0001,
+ 0xc78, 0x26700001,
+ 0xc78, 0x25710001,
+ 0xc78, 0x24720001,
+ 0xc78, 0x23730001,
+ 0xc78, 0x22740001,
+ 0xc78, 0x09750001,
+ 0xc78, 0x08760001,
+ 0xc78, 0x07770001,
+ 0xc78, 0x06780001,
+ 0xc78, 0x05790001,
+ 0xc78, 0x047a0001,
+ 0xc78, 0x037b0001,
+ 0xc78, 0x027c0001,
+ 0xc78, 0x017d0001,
+ 0xc78, 0x007e0001,
+ 0xc78, 0x007f0001,
+ 0xc78, 0x3000001e,
+ 0xc78, 0x3001001e,
+ 0xc78, 0x3002001e,
+ 0xc78, 0x3003001e,
+ 0xc78, 0x3004001e,
+ 0xc78, 0x3405001e,
+ 0xc78, 0x3806001e,
+ 0xc78, 0x3e07001e,
+ 0xc78, 0x3e08001e,
+ 0xc78, 0x4409001e,
+ 0xc78, 0x460a001e,
+ 0xc78, 0x480b001e,
+ 0xc78, 0x480c001e,
+ 0xc78, 0x4e0d001e,
+ 0xc78, 0x560e001e,
+ 0xc78, 0x5a0f001e,
+ 0xc78, 0x5e10001e,
+ 0xc78, 0x6211001e,
+ 0xc78, 0x6c12001e,
+ 0xc78, 0x7213001e,
+ 0xc78, 0x7214001e,
+ 0xc78, 0x7215001e,
+ 0xc78, 0x7216001e,
+ 0xc78, 0x7217001e,
+ 0xc78, 0x7218001e,
+ 0xc78, 0x7219001e,
+ 0xc78, 0x721a001e,
+ 0xc78, 0x721b001e,
+ 0xc78, 0x721c001e,
+ 0xc78, 0x721d001e,
+ 0xc78, 0x721e001e,
+ 0xc78, 0x721f001e,
+};
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/table.h b/drivers/net/wireless/rtlwifi/rtl8192se/table.h
new file mode 100644
index 0000000..b4ed6d95
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/table.h
@@ -0,0 +1,49 @@
+/******************************************************************************
+ * Copyright(c) 2008 - 2010 Realtek Corporation. All rights reserved.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8192SE_FW_IMG_H
+#define __INC_HAL8192SE_FW_IMG_H
+
+#include <linux/types.h>
+
+/*Created on 2010/ 4/12, 5:56*/
+
+#define PHY_REG_2T2RARRAYLENGTH 372
+extern u32 rtl8192sephy_reg_2t2rarray[PHY_REG_2T2RARRAYLENGTH];
+#define PHY_CHANGETO_1T1RARRAYLENGTH 48
+extern u32 rtl8192sephy_changeto_1t1rarray[PHY_CHANGETO_1T1RARRAYLENGTH];
+#define PHY_CHANGETO_1T2RARRAYLENGTH 45
+extern u32 rtl8192sephy_changeto_1t2rarray[PHY_CHANGETO_1T2RARRAYLENGTH];
+#define PHY_REG_ARRAY_PGLENGTH 84
+extern u32 rtl8192sephy_reg_array_pg[PHY_REG_ARRAY_PGLENGTH];
+#define RADIOA_1T_ARRAYLENGTH 202
+extern u32 rtl8192seradioa_1t_array[RADIOA_1T_ARRAYLENGTH];
+#define RADIOB_ARRAYLENGTH 22
+extern u32 rtl8192seradiob_array[RADIOB_ARRAYLENGTH];
+#define RADIOB_GM_ARRAYLENGTH 10
+extern u32 rtl8192seradiob_gm_array[RADIOB_GM_ARRAYLENGTH];
+#define MAC_2T_ARRAYLENGTH 106
+extern u32 rtl8192semac_2t_array[MAC_2T_ARRAYLENGTH];
+#define AGCTAB_ARRAYLENGTH 320
+extern u32 rtl8192seagctab_array[AGCTAB_ARRAYLENGTH];
+
+#endif
+
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
new file mode 100644
index 0000000..5cf4423
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -0,0 +1,976 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "fw.h"
+#include "trx.h"
+#include "led.h"
+
+static u8 _rtl92se_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 skb_queue)
+{
+ __le16 fc = rtl_get_fc(skb);
+
+ if (unlikely(ieee80211_is_beacon(fc)))
+ return QSLT_BEACON;
+ if (ieee80211_is_mgmt(fc))
+ return QSLT_MGNT;
+ if (ieee80211_is_nullfunc(fc))
+ return QSLT_HIGH;
+
+ return skb->priority;
+}
+
+static int _rtl92se_rate_mapping(bool isht, u8 desc_rate, bool first_ampdu)
+{
+ int rate_idx = 0;
+
+ if (first_ampdu) {
+ if (false == isht) {
+ switch (desc_rate) {
+ case DESC92S_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92S_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92S_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92S_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92S_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92S_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92S_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92S_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92S_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92S_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92S_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92S_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ } else {
+ rate_idx = 11;
+ }
+
+ return rate_idx;
+ }
+
+ switch (desc_rate) {
+ case DESC92S_RATE1M:
+ rate_idx = 0;
+ break;
+ case DESC92S_RATE2M:
+ rate_idx = 1;
+ break;
+ case DESC92S_RATE5_5M:
+ rate_idx = 2;
+ break;
+ case DESC92S_RATE11M:
+ rate_idx = 3;
+ break;
+ case DESC92S_RATE6M:
+ rate_idx = 4;
+ break;
+ case DESC92S_RATE9M:
+ rate_idx = 5;
+ break;
+ case DESC92S_RATE12M:
+ rate_idx = 6;
+ break;
+ case DESC92S_RATE18M:
+ rate_idx = 7;
+ break;
+ case DESC92S_RATE24M:
+ rate_idx = 8;
+ break;
+ case DESC92S_RATE36M:
+ rate_idx = 9;
+ break;
+ case DESC92S_RATE48M:
+ rate_idx = 10;
+ break;
+ case DESC92S_RATE54M:
+ rate_idx = 11;
+ break;
+ default:
+ rate_idx = 11;
+ break;
+ }
+ return rate_idx;
+}
+
+static u8 _rtl92s_query_rxpwrpercentage(char antpower)
+{
+ if ((antpower <= -100) || (antpower >= 20))
+ return 0;
+ else if (antpower >= 0)
+ return 100;
+ else
+ return 100 + antpower;
+}
+
+static u8 _rtl92s_evm_db_to_percentage(char value)
+{
+ char ret_val;
+ ret_val = value;
+
+ if (ret_val >= 0)
+ ret_val = 0;
+
+ if (ret_val <= -33)
+ ret_val = -33;
+
+ ret_val = 0 - ret_val;
+ ret_val *= 3;
+
+ if (ret_val == 99)
+ ret_val = 100;
+
+ return ret_val;
+}
+
+static long _rtl92se_translate_todbm(struct ieee80211_hw *hw,
+ u8 signal_strength_index)
+{
+ long signal_power;
+
+ signal_power = (long)((signal_strength_index + 1) >> 1);
+ signal_power -= 95;
+ return signal_power;
+}
+
+static long _rtl92se_signal_scale_mapping(struct ieee80211_hw *hw,
+ long currsig)
+{
+ long retsig = 0;
+
+ /* Step 1. Scale mapping. */
+ if (currsig > 47)
+ retsig = 100;
+ else if (currsig > 14 && currsig <= 47)
+ retsig = 100 - ((47 - currsig) * 3) / 2;
+ else if (currsig > 2 && currsig <= 14)
+ retsig = 48 - ((14 - currsig) * 15) / 7;
+ else if (currsig >= 0)
+ retsig = currsig * 9 + 1;
+
+ return retsig;
+}
+
+
+static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats, u8 *pdesc,
+ struct rx_fwinfo *p_drvinfo,
+ bool packet_match_bssid,
+ bool packet_toself,
+ bool packet_beacon)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct phy_sts_cck_8192s_t *cck_buf;
+ s8 rx_pwr_all = 0, rx_pwr[4];
+ u8 rf_rx_num = 0, evm, pwdb_all;
+ u8 i, max_spatial_stream;
+ u32 rssi, total_rssi = 0;
+ bool in_powersavemode = false;
+ bool is_cck_rate;
+
+ is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+ pstats->packet_matchbssid = packet_match_bssid;
+ pstats->packet_toself = packet_toself;
+ pstats->is_cck = is_cck_rate;
+ pstats->packet_beacon = packet_beacon;
+ pstats->is_cck = is_cck_rate;
+ pstats->rx_mimo_signalquality[0] = -1;
+ pstats->rx_mimo_signalquality[1] = -1;
+
+ if (is_cck_rate) {
+ u8 report, cck_highpwr;
+ cck_buf = (struct phy_sts_cck_8192s_t *)p_drvinfo;
+
+ if (!in_powersavemode)
+ cck_highpwr = (u8) rtl_get_bbreg(hw,
+ RFPGA0_XA_HSSIPARAMETER2,
+ 0x200);
+ else
+ cck_highpwr = false;
+
+ if (!cck_highpwr) {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = cck_buf->cck_agc_rpt & 0xc0;
+ report = report >> 6;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -40 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x2:
+ rx_pwr_all = -20 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x1:
+ rx_pwr_all = -2 - (cck_agc_rpt & 0x3e);
+ break;
+ case 0x0:
+ rx_pwr_all = 14 - (cck_agc_rpt & 0x3e);
+ break;
+ }
+ } else {
+ u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+ report = p_drvinfo->cfosho[0] & 0x60;
+ report = report >> 5;
+ switch (report) {
+ case 0x3:
+ rx_pwr_all = -40 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x2:
+ rx_pwr_all = -20 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x1:
+ rx_pwr_all = -2 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ case 0x0:
+ rx_pwr_all = 14 - ((cck_agc_rpt & 0x1f) << 1);
+ break;
+ }
+ }
+
+ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+
+ /* CCK gain is smaller than OFDM/MCS gain, */
+ /* so we add gain diff by experiences, the val is 6 */
+ pwdb_all += 6;
+ if (pwdb_all > 100)
+ pwdb_all = 100;
+ /* modify the offset to make the same gain index with OFDM. */
+ if (pwdb_all > 34 && pwdb_all <= 42)
+ pwdb_all -= 2;
+ else if (pwdb_all > 26 && pwdb_all <= 34)
+ pwdb_all -= 6;
+ else if (pwdb_all > 14 && pwdb_all <= 26)
+ pwdb_all -= 8;
+ else if (pwdb_all > 4 && pwdb_all <= 14)
+ pwdb_all -= 4;
+
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (packet_match_bssid) {
+ u8 sq;
+ if (pstats->rx_pwdb_all > 40) {
+ sq = 100;
+ } else {
+ sq = cck_buf->sq_rpt;
+ if (sq > 64)
+ sq = 0;
+ else if (sq < 20)
+ sq = 100;
+ else
+ sq = ((64 - sq) * 100) / 44;
+ }
+
+ pstats->signalquality = sq;
+ pstats->rx_mimo_signalquality[0] = sq;
+ pstats->rx_mimo_signalquality[1] = -1;
+ }
+ } else {
+ rtlpriv->dm.rfpath_rxenable[0] =
+ rtlpriv->dm.rfpath_rxenable[1] = true;
+ for (i = RF90_PATH_A; i < RF90_PATH_MAX; i++) {
+ if (rtlpriv->dm.rfpath_rxenable[i])
+ rf_rx_num++;
+
+ rx_pwr[i] = ((p_drvinfo->gain_trsw[i] &
+ 0x3f) * 2) - 110;
+ rssi = _rtl92s_query_rxpwrpercentage(rx_pwr[i]);
+ total_rssi += rssi;
+ rtlpriv->stats.rx_snr_db[i] =
+ (long)(p_drvinfo->rxsnr[i] / 2);
+
+ if (packet_match_bssid)
+ pstats->rx_mimo_signalstrength[i] = (u8) rssi;
+ }
+
+ rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+ pwdb_all = _rtl92s_query_rxpwrpercentage(rx_pwr_all);
+ pstats->rx_pwdb_all = pwdb_all;
+ pstats->rxpower = rx_pwr_all;
+ pstats->recvsignalpower = rx_pwr_all;
+
+ if (GET_RX_STATUS_DESC_RX_HT(pdesc) &&
+ GET_RX_STATUS_DESC_RX_MCS(pdesc) >= DESC92S_RATEMCS8 &&
+ GET_RX_STATUS_DESC_RX_MCS(pdesc) <= DESC92S_RATEMCS15)
+ max_spatial_stream = 2;
+ else
+ max_spatial_stream = 1;
+
+ for (i = 0; i < max_spatial_stream; i++) {
+ evm = _rtl92s_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+ if (packet_match_bssid) {
+ if (i == 0)
+ pstats->signalquality = (u8)(evm &
+ 0xff);
+ pstats->rx_mimo_signalquality[i] =
+ (u8) (evm & 0xff);
+ }
+ }
+ }
+
+ if (is_cck_rate)
+ pstats->signalstrength = (u8)(_rtl92se_signal_scale_mapping(hw,
+ pwdb_all));
+ else if (rf_rx_num != 0)
+ pstats->signalstrength = (u8) (_rtl92se_signal_scale_mapping(hw,
+ total_rssi /= rf_rx_num));
+}
+
+static void _rtl92se_process_ui_rssi(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_phy *rtlphy = &(rtlpriv->phy);
+ u8 rfpath;
+ u32 last_rssi, tmpval;
+
+ if (pstats->packet_toself || pstats->packet_beacon) {
+ rtlpriv->stats.rssi_calculate_cnt++;
+
+ if (rtlpriv->stats.ui_rssi.total_num++ >=
+ PHY_RSSI_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_rssi.total_num =
+ PHY_RSSI_SLID_WIN_MAX;
+ last_rssi = rtlpriv->stats.ui_rssi.elements[
+ rtlpriv->stats.ui_rssi.index];
+ rtlpriv->stats.ui_rssi.total_val -= last_rssi;
+ }
+
+ rtlpriv->stats.ui_rssi.total_val += pstats->signalstrength;
+ rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++]
+ = pstats->signalstrength;
+
+ if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
+ rtlpriv->stats.ui_rssi.index = 0;
+
+ tmpval = rtlpriv->stats.ui_rssi.total_val /
+ rtlpriv->stats.ui_rssi.total_num;
+ rtlpriv->stats.signal_strength = _rtl92se_translate_todbm(hw,
+ (u8) tmpval);
+ pstats->rssi = rtlpriv->stats.signal_strength;
+ }
+
+ if (!pstats->is_cck && pstats->packet_toself) {
+ for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+ rfpath++) {
+ if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ pstats->rx_mimo_signalstrength[rfpath];
+
+ }
+
+ if (pstats->rx_mimo_signalstrength[rfpath] >
+ rtlpriv->stats.rx_rssi_percentage[rfpath]) {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.rx_rssi_percentage[rfpath]
+ * (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ rtlpriv->stats.rx_rssi_percentage[rfpath]
+ + 1;
+ } else {
+ rtlpriv->stats.rx_rssi_percentage[rfpath] =
+ ((rtlpriv->stats.rx_rssi_percentage[rfpath]
+ * (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalstrength[rfpath])) /
+ (RX_SMOOTH_FACTOR);
+ }
+
+ }
+ }
+}
+
+static void _rtl92se_update_rxsignalstatistics(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ int weighting = 0;
+
+ if (rtlpriv->stats.recv_signal_power == 0)
+ rtlpriv->stats.recv_signal_power = pstats->recvsignalpower;
+
+ if (pstats->recvsignalpower > rtlpriv->stats.recv_signal_power)
+ weighting = 5;
+ else if (pstats->recvsignalpower < rtlpriv->stats.recv_signal_power)
+ weighting = (-5);
+
+ rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power * 5
+ + pstats->recvsignalpower +
+ weighting) / 6;
+}
+
+static void _rtl92se_process_pwdb(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ long undec_sm_pwdb = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+ return;
+ } else {
+ undec_sm_pwdb =
+ rtlpriv->dm.undecorated_smoothed_pwdb;
+ }
+
+ if (pstats->packet_toself || pstats->packet_beacon) {
+ if (undec_sm_pwdb < 0)
+ undec_sm_pwdb = pstats->rx_pwdb_all;
+
+ if (pstats->rx_pwdb_all > (u32) undec_sm_pwdb) {
+ undec_sm_pwdb =
+ (((undec_sm_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+
+ undec_sm_pwdb = undec_sm_pwdb + 1;
+ } else {
+ undec_sm_pwdb = (((undec_sm_pwdb) *
+ (RX_SMOOTH_FACTOR - 1)) + (pstats->rx_pwdb_all)) /
+ (RX_SMOOTH_FACTOR);
+ }
+
+ rtlpriv->dm.undecorated_smoothed_pwdb = undec_sm_pwdb;
+ _rtl92se_update_rxsignalstatistics(hw, pstats);
+ }
+}
+
+static void rtl_92s_process_streams(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 stream;
+
+ for (stream = 0; stream < 2; stream++) {
+ if (pstats->rx_mimo_signalquality[stream] != -1) {
+ if (rtlpriv->stats.rx_evm_percentage[stream] == 0) {
+ rtlpriv->stats.rx_evm_percentage[stream] =
+ pstats->rx_mimo_signalquality[stream];
+ }
+
+ rtlpriv->stats.rx_evm_percentage[stream] =
+ ((rtlpriv->stats.rx_evm_percentage[stream] *
+ (RX_SMOOTH_FACTOR - 1)) +
+ (pstats->rx_mimo_signalquality[stream] *
+ 1)) / (RX_SMOOTH_FACTOR);
+ }
+ }
+}
+
+static void _rtl92se_process_ui_link_quality(struct ieee80211_hw *hw,
+ struct rtl_stats *pstats)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 last_evm = 0, tmpval;
+
+ if (pstats->signalquality != 0) {
+ if (pstats->packet_toself || pstats->packet_beacon) {
+
+ if (rtlpriv->stats.ui_link_quality.total_num++ >=
+ PHY_LINKQUALITY_SLID_WIN_MAX) {
+ rtlpriv->stats.ui_link_quality.total_num =
+ PHY_LINKQUALITY_SLID_WIN_MAX;
+ last_evm =
+ rtlpriv->stats.ui_link_quality.elements[
+ rtlpriv->stats.ui_link_quality.index];
+ rtlpriv->stats.ui_link_quality.total_val -=
+ last_evm;
+ }
+
+ rtlpriv->stats.ui_link_quality.total_val +=
+ pstats->signalquality;
+ rtlpriv->stats.ui_link_quality.elements[
+ rtlpriv->stats.ui_link_quality.index++] =
+ pstats->signalquality;
+
+ if (rtlpriv->stats.ui_link_quality.index >=
+ PHY_LINKQUALITY_SLID_WIN_MAX)
+ rtlpriv->stats.ui_link_quality.index = 0;
+
+ tmpval = rtlpriv->stats.ui_link_quality.total_val /
+ rtlpriv->stats.ui_link_quality.total_num;
+ rtlpriv->stats.signal_quality = tmpval;
+
+ rtlpriv->stats.last_sigstrength_inpercent = tmpval;
+
+ rtl_92s_process_streams(hw, pstats);
+
+ }
+ }
+}
+
+static void _rtl92se_process_phyinfo(struct ieee80211_hw *hw,
+ u8 *buffer,
+ struct rtl_stats *pcurrent_stats)
+{
+
+ if (!pcurrent_stats->packet_matchbssid &&
+ !pcurrent_stats->packet_beacon)
+ return;
+
+ _rtl92se_process_ui_rssi(hw, pcurrent_stats);
+ _rtl92se_process_pwdb(hw, pcurrent_stats);
+ _rtl92se_process_ui_link_quality(hw, pcurrent_stats);
+}
+
+static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+ struct sk_buff *skb, struct rtl_stats *pstats,
+ u8 *pdesc, struct rx_fwinfo *p_drvinfo)
+{
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+
+ struct ieee80211_hdr *hdr;
+ u8 *tmp_buf;
+ u8 *praddr;
+ u8 *psaddr;
+ __le16 fc;
+ u16 type, cfc;
+ bool packet_matchbssid, packet_toself, packet_beacon;
+
+ tmp_buf = skb->data + pstats->rx_drvinfo_size + pstats->rx_bufshift;
+
+ hdr = (struct ieee80211_hdr *)tmp_buf;
+ fc = hdr->frame_control;
+ cfc = le16_to_cpu(fc);
+ type = WLAN_FC_GET_TYPE(fc);
+ praddr = hdr->addr1;
+ psaddr = hdr->addr2;
+
+ packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+ (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ?
+ hdr->addr1 : (cfc & IEEE80211_FCTL_FROMDS) ?
+ hdr->addr2 : hdr->addr3)) && (!pstats->hwerror) &&
+ (!pstats->crc) && (!pstats->icv));
+
+ packet_toself = packet_matchbssid &&
+ (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+
+ if (ieee80211_is_beacon(fc))
+ packet_beacon = true;
+
+ _rtl92se_query_rxphystatus(hw, pstats, pdesc, p_drvinfo,
+ packet_matchbssid, packet_toself, packet_beacon);
+ _rtl92se_process_phyinfo(hw, tmp_buf, pstats);
+}
+
+bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status, u8 *pdesc,
+ struct sk_buff *skb)
+{
+ struct rx_fwinfo *p_drvinfo;
+ u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc);
+
+ stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc);
+ stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8;
+ stats->rx_bufshift = (u8)(GET_RX_STATUS_DESC_SHIFT(pdesc) & 0x03);
+ stats->icv = (u16)GET_RX_STATUS_DESC_ICV(pdesc);
+ stats->crc = (u16)GET_RX_STATUS_DESC_CRC32(pdesc);
+ stats->hwerror = (u16)(stats->crc | stats->icv);
+ stats->decrypted = !GET_RX_STATUS_DESC_SWDEC(pdesc);
+
+ stats->rate = (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc);
+ stats->shortpreamble = (u16)GET_RX_STATUS_DESC_SPLCP(pdesc);
+ stats->isampdu = (bool)(GET_RX_STATUS_DESC_PAGGR(pdesc) == 1);
+ stats->timestamp_low = GET_RX_STATUS_DESC_TSFL(pdesc);
+ stats->rx_is40Mhzpacket = (bool)GET_RX_STATUS_DESC_BW(pdesc);
+
+ if (stats->hwerror)
+ return false;
+
+ rx_status->freq = hw->conf.channel->center_freq;
+ rx_status->band = hw->conf.channel->band;
+
+ if (GET_RX_STATUS_DESC_CRC32(pdesc))
+ rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+ if (!GET_RX_STATUS_DESC_SWDEC(pdesc))
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ if (GET_RX_STATUS_DESC_BW(pdesc))
+ rx_status->flag |= RX_FLAG_40MHZ;
+
+ if (GET_RX_STATUS_DESC_RX_HT(pdesc))
+ rx_status->flag |= RX_FLAG_HT;
+
+ rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+
+ if (stats->decrypted)
+ rx_status->flag |= RX_FLAG_DECRYPTED;
+
+ rx_status->rate_idx = _rtl92se_rate_mapping((bool)
+ GET_RX_STATUS_DESC_RX_HT(pdesc),
+ (u8)GET_RX_STATUS_DESC_RX_MCS(pdesc),
+ (bool)GET_RX_STATUS_DESC_PAGGR(pdesc));
+
+
+ rx_status->mactime = GET_RX_STATUS_DESC_TSFL(pdesc);
+ if (phystatus == true) {
+ p_drvinfo = (struct rx_fwinfo *)(skb->data +
+ stats->rx_bufshift);
+ _rtl92se_translate_rx_signal_stuff(hw, skb, stats, pdesc,
+ p_drvinfo);
+ }
+
+ /*rx_status->qual = stats->signal; */
+ rx_status->signal = stats->rssi + 10;
+ /*rx_status->noise = -stats->noise; */
+
+ return true;
+}
+
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
+ struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+ struct ieee80211_tx_info *info, struct sk_buff *skb,
+ u8 hw_queue, struct rtl_tcb_desc *ptcb_desc)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct ieee80211_sta *sta = info->control.sta;
+ u8 *pdesc = (u8 *) pdesc_tx;
+ u16 seq_number;
+ __le16 fc = hdr->frame_control;
+ u8 reserved_macid = 0;
+ u8 fw_qsel = _rtl92se_map_hwqueue_to_fwqueue(skb, hw_queue);
+ bool firstseg = (!(hdr->seq_ctrl & cpu_to_le16(IEEE80211_SCTL_FRAG)));
+ bool lastseg = (!(hdr->frame_control &
+ cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)));
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+ u8 bw_40 = 0;
+
+ if (mac->opmode == NL80211_IFTYPE_STATION) {
+ bw_40 = mac->bw_40;
+ } else if (mac->opmode == NL80211_IFTYPE_AP ||
+ mac->opmode == NL80211_IFTYPE_ADHOC) {
+ if (sta)
+ bw_40 = sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ }
+
+ seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+
+ rtl_get_tcb_desc(hw, info, sta, skb, ptcb_desc);
+
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE_RTL8192S);
+
+ if (firstseg) {
+ if (rtlpriv->dm.useramask) {
+ /* set txdesc macId */
+ if (ptcb_desc->mac_id < 32) {
+ SET_TX_DESC_MACID(pdesc, ptcb_desc->mac_id);
+ reserved_macid |= ptcb_desc->mac_id;
+ }
+ }
+ SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid);
+
+ SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >=
+ DESC92S_RATEMCS0) ? 1 : 0));
+
+ if (rtlhal->version == VERSION_8192S_ACUT) {
+ if (ptcb_desc->hw_rate == DESC92S_RATE1M ||
+ ptcb_desc->hw_rate == DESC92S_RATE2M ||
+ ptcb_desc->hw_rate == DESC92S_RATE5_5M ||
+ ptcb_desc->hw_rate == DESC92S_RATE11M) {
+ ptcb_desc->hw_rate = DESC92S_RATE12M;
+ }
+ }
+
+ SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
+
+ if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
+ SET_TX_DESC_TX_SHORT(pdesc, 0);
+
+ /* Aggregation related */
+ if (info->flags & IEEE80211_TX_CTL_AMPDU)
+ SET_TX_DESC_AGG_ENABLE(pdesc, 1);
+
+ /* For AMPDU, we must insert SSN into TX_DESC */
+ SET_TX_DESC_SEQ(pdesc, seq_number);
+
+ /* Protection mode related */
+ /* For 92S, if RTS/CTS are set, HW will execute RTS. */
+ /* We choose only one protection mode to execute */
+ SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcb_desc->rts_enable &&
+ !ptcb_desc->cts_enable) ? 1 : 0));
+ SET_TX_DESC_CTS_ENABLE(pdesc, ((ptcb_desc->cts_enable) ?
+ 1 : 0));
+ SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
+
+ SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
+ SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc);
+ SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
+ DESC92S_RATE54M) ?
+ (ptcb_desc->rts_use_shortpreamble ? 1 : 0)
+ : (ptcb_desc->rts_use_shortgi ? 1 : 0)));
+
+
+ /* Set Bandwidth and sub-channel settings. */
+ if (bw_40) {
+ if (ptcb_desc->packet_bw) {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 1);
+ /* use duplicated mode */
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ } else {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+ mac->cur_40_prime_sc);
+ }
+ } else {
+ SET_TX_DESC_TX_BANDWIDTH(pdesc, 0);
+ SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+ }
+
+ /* 3 Fill necessary field in First Descriptor */
+ /*DWORD 0*/
+ SET_TX_DESC_LINIP(pdesc, 0);
+ SET_TX_DESC_OFFSET(pdesc, 32);
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
+
+ /*DWORD 1*/
+ SET_TX_DESC_RA_BRSR_ID(pdesc, ptcb_desc->ratr_index);
+
+ /* Fill security related */
+ if (info->control.hw_key) {
+ struct ieee80211_key_conf *keyconf;
+
+ keyconf = info->control.hw_key;
+ switch (keyconf->cipher) {
+ case WLAN_CIPHER_SUITE_WEP40:
+ case WLAN_CIPHER_SUITE_WEP104:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+ break;
+ case WLAN_CIPHER_SUITE_TKIP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x2);
+ break;
+ case WLAN_CIPHER_SUITE_CCMP:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+ break;
+ default:
+ SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+ break;
+
+ }
+ }
+
+ /* Set Packet ID */
+ SET_TX_DESC_PACKET_ID(pdesc, 0);
+
+ /* We will assign magement queue to BK. */
+ SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+
+ /* Alwasy enable all rate fallback range */
+ SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+
+ /* Fix: I don't kown why hw use 6.5M to tx when set it */
+ SET_TX_DESC_USER_RATE(pdesc,
+ ptcb_desc->use_driver_rate ? 1 : 0);
+
+ /* Set NON_QOS bit. */
+ if (!ieee80211_is_data_qos(fc))
+ SET_TX_DESC_NON_QOS(pdesc, 1);
+
+ }
+
+ /* Fill fields that are required to be initialized
+ * in all of the descriptors */
+ /*DWORD 0 */
+ SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+ SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+
+ /* DWORD 7 */
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
+
+ /* DOWRD 8 */
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, ("\n"));
+}
+
+void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+ bool firstseg, bool lastseg, struct sk_buff *skb)
+{
+ struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_tcb_desc *tcb_desc = (struct rtl_tcb_desc *)(skb->cb);
+
+ dma_addr_t mapping = pci_map_single(rtlpci->pdev, skb->data, skb->len,
+ PCI_DMA_TODEVICE);
+
+ /* Clear all status */
+ CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_CMDDESC_SIZE_RTL8192S);
+
+ /* This bit indicate this packet is used for FW download. */
+ if (tcb_desc->cmd_or_init == DESC_PACKET_TYPE_INIT) {
+ /* For firmware downlaod we only need to set LINIP */
+ SET_TX_DESC_LINIP(pdesc, tcb_desc->last_inipkt);
+
+ /* 92SE must set as 1 for firmware download HW DMA error */
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ /* 92SE need not to set TX packet size when firmware download */
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ SET_TX_DESC_OWN(pdesc, 1);
+ } else { /* H2C Command Desc format (Host TXCMD) */
+ /* 92SE must set as 1 for firmware download HW DMA error */
+ SET_TX_DESC_FIRST_SEG(pdesc, 1);
+ SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+ SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+ /* Buffer size + command header */
+ SET_TX_DESC_PKT_SIZE(pdesc, (u16)(skb->len));
+ /* Fixed queue of H2C command */
+ SET_TX_DESC_QUEUE_SEL(pdesc, 0x13);
+
+ SET_BITS_TO_LE_4BYTE(skb->data, 24, 7, rtlhal->h2c_txcmd_seq);
+
+ SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
+ SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
+
+ SET_TX_DESC_OWN(pdesc, 1);
+
+ }
+}
+
+void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ SET_TX_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_TX_NEXTDESC_ADDR:
+ SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_RXOWN:
+ SET_RX_STATUS_DESC_OWN(pdesc, 1);
+ break;
+ case HW_DESC_RXBUFF_ADDR:
+ SET_RX_STATUS__DESC_BUFF_ADDR(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ SET_RX_STATUS_DESC_PKT_LEN(pdesc, *(u32 *) val);
+ break;
+ case HW_DESC_RXERO:
+ SET_RX_STATUS_DESC_EOR(pdesc, 1);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ }
+}
+
+u32 rtl92se_get_desc(u8 *desc, bool istx, u8 desc_name)
+{
+ u32 ret = 0;
+
+ if (istx == true) {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_TX_DESC_OWN(desc);
+ break;
+ case HW_DESC_TXBUFF_ADDR:
+ ret = GET_TX_DESC_TX_BUFFER_ADDRESS(desc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR txdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ } else {
+ switch (desc_name) {
+ case HW_DESC_OWN:
+ ret = GET_RX_STATUS_DESC_OWN(desc);
+ break;
+ case HW_DESC_RXPKT_LEN:
+ ret = GET_RX_STATUS_DESC_PKT_LEN(desc);
+ break;
+ default:
+ RT_ASSERT(false, ("ERR rxdesc :%d not process\n",
+ desc_name));
+ break;
+ }
+ }
+ return ret;
+}
+
+void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ rtl_write_word(rtlpriv, TP_POLL, BIT(0) << (hw_queue));
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.h b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
new file mode 100644
index 0000000..05862c5
--- /dev/null
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.h
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2010 Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#ifndef __REALTEK_PCI92SE_TRX_H__
+#define __REALTEK_PCI92SE_TRX_H__
+
+void rtl92se_tx_fill_desc(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
+ u8 *pdesc, struct ieee80211_tx_info *info,
+ struct sk_buff *skb, u8 hw_queue,
+ struct rtl_tcb_desc *ptcb_desc);
+void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc, bool firstseg,
+ bool lastseg, struct sk_buff *skb);
+bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
+ struct ieee80211_rx_status *rx_status, u8 *pdesc,
+ struct sk_buff *skb);
+void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl92se_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl92se_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+
+#endif
diff --git a/drivers/net/wireless/wl12xx/acx.c b/drivers/net/wireless/wl12xx/acx.c
index a5c9c0a..c6ee530 100644
--- a/drivers/net/wireless/wl12xx/acx.c
+++ b/drivers/net/wireless/wl12xx/acx.c
@@ -325,12 +325,19 @@
return ret;
}
-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold)
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold)
{
struct acx_rts_threshold *rts;
int ret;
- wl1271_debug(DEBUG_ACX, "acx rts threshold");
+ /*
+ * If the RTS threshold is not configured or out of range, use the
+ * default value.
+ */
+ if (rts_threshold > IEEE80211_MAX_RTS_THRESHOLD)
+ rts_threshold = wl->conf.rx.rts_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx rts threshold: %d", rts_threshold);
rts = kzalloc(sizeof(*rts), GFP_KERNEL);
if (!rts) {
@@ -338,7 +345,7 @@
goto out;
}
- rts->threshold = cpu_to_le16(rts_threshold);
+ rts->threshold = cpu_to_le16((u16)rts_threshold);
ret = wl1271_cmd_configure(wl, DOT11_RTS_THRESHOLD, rts, sizeof(*rts));
if (ret < 0) {
@@ -540,13 +547,13 @@
return ret;
}
-int wl1271_acx_sg_cfg(struct wl1271 *wl)
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl)
{
- struct acx_bt_wlan_coex_param *param;
+ struct acx_sta_bt_wlan_coex_param *param;
struct conf_sg_settings *c = &wl->conf.sg;
int i, ret;
- wl1271_debug(DEBUG_ACX, "acx sg cfg");
+ wl1271_debug(DEBUG_ACX, "acx sg sta cfg");
param = kzalloc(sizeof(*param), GFP_KERNEL);
if (!param) {
@@ -555,8 +562,38 @@
}
/* BT-WLAN coext parameters */
- for (i = 0; i < CONF_SG_PARAMS_MAX; i++)
- param->params[i] = cpu_to_le32(c->params[i]);
+ for (i = 0; i < CONF_SG_STA_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->sta_params[i]);
+ param->param_idx = CONF_SG_PARAMS_ALL;
+
+ ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
+ if (ret < 0) {
+ wl1271_warning("failed to set sg config: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(param);
+ return ret;
+}
+
+int wl1271_acx_ap_sg_cfg(struct wl1271 *wl)
+{
+ struct acx_ap_bt_wlan_coex_param *param;
+ struct conf_sg_settings *c = &wl->conf.sg;
+ int i, ret;
+
+ wl1271_debug(DEBUG_ACX, "acx sg ap cfg");
+
+ param = kzalloc(sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* BT-WLAN coext parameters */
+ for (i = 0; i < CONF_SG_AP_PARAMS_MAX; i++)
+ param->params[i] = cpu_to_le32(c->ap_params[i]);
param->param_idx = CONF_SG_PARAMS_ALL;
ret = wl1271_cmd_configure(wl, ACX_SG_CFG, param, sizeof(*param));
@@ -804,7 +841,8 @@
struct acx_ap_rate_policy *acx;
int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx ap rate policy");
+ wl1271_debug(DEBUG_ACX, "acx ap rate policy %d rates 0x%x",
+ idx, c->enabled_rates);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx) {
@@ -898,12 +936,19 @@
return ret;
}
-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold)
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold)
{
struct acx_frag_threshold *acx;
int ret = 0;
- wl1271_debug(DEBUG_ACX, "acx frag threshold");
+ /*
+ * If the fragmentation is not configured or out of range, use the
+ * default value.
+ */
+ if (frag_threshold > IEEE80211_MAX_FRAG_THRESHOLD)
+ frag_threshold = wl->conf.tx.frag_threshold;
+
+ wl1271_debug(DEBUG_ACX, "acx frag threshold: %d", frag_threshold);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
@@ -912,7 +957,7 @@
goto out;
}
- acx->frag_threshold = cpu_to_le16(frag_threshold);
+ acx->frag_threshold = cpu_to_le16((u16)frag_threshold);
ret = wl1271_cmd_configure(wl, ACX_FRAG_CFG, acx, sizeof(*acx));
if (ret < 0) {
wl1271_warning("Setting of frag threshold failed: %d", ret);
@@ -954,6 +999,7 @@
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl)
{
struct wl1271_acx_ap_config_memory *mem_conf;
+ struct conf_memory_settings *mem;
int ret;
wl1271_debug(DEBUG_ACX, "wl1271 mem cfg");
@@ -964,14 +1010,21 @@
goto out;
}
+ if (wl->chip.id == CHIP_ID_1283_PG20)
+ /*
+ * FIXME: The 128x AP FW does not yet support dynamic memory.
+ * Use the base memory configuration for 128x for now. This
+ * should be fine tuned in the future.
+ */
+ mem = &wl->conf.mem_wl128x;
+ else
+ mem = &wl->conf.mem_wl127x;
+
/* memory config */
- /* FIXME: for now we always use mem_wl127x for AP, because it
- * doesn't support dynamic memory and we don't have the
- * optimal values for wl128x without dynamic memory yet */
- mem_conf->num_stations = wl->conf.mem_wl127x.num_stations;
- mem_conf->rx_mem_block_num = wl->conf.mem_wl127x.rx_block_num;
- mem_conf->tx_min_mem_block_num = wl->conf.mem_wl127x.tx_min_block_num;
- mem_conf->num_ssid_profiles = wl->conf.mem_wl127x.ssid_profiles;
+ mem_conf->num_stations = mem->num_stations;
+ mem_conf->rx_mem_block_num = mem->rx_block_num;
+ mem_conf->tx_min_mem_block_num = mem->tx_min_block_num;
+ mem_conf->num_ssid_profiles = mem->ssid_profiles;
mem_conf->total_tx_descriptors = cpu_to_le32(ACX_TX_DESCRIPTORS);
ret = wl1271_cmd_configure(wl, ACX_MEM_CFG, mem_conf,
@@ -1524,46 +1577,22 @@
return ret;
}
-int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl)
+int wl1271_acx_max_tx_retry(struct wl1271 *wl)
{
- struct wl1271_acx_ap_max_tx_retry *acx = NULL;
+ struct wl1271_acx_max_tx_retry *acx = NULL;
int ret;
- wl1271_debug(DEBUG_ACX, "acx ap max tx retry");
+ wl1271_debug(DEBUG_ACX, "acx max tx retry");
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
- acx->max_tx_retry = cpu_to_le16(wl->conf.tx.max_tx_retries);
+ acx->max_tx_retry = cpu_to_le16(wl->conf.tx.ap_max_tx_retries);
ret = wl1271_cmd_configure(wl, ACX_MAX_TX_FAILURE, acx, sizeof(*acx));
if (ret < 0) {
- wl1271_warning("acx ap max tx retry failed: %d", ret);
- goto out;
- }
-
-out:
- kfree(acx);
- return ret;
-}
-
-int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl)
-{
- struct wl1271_acx_sta_max_tx_retry *acx = NULL;
- int ret;
-
- wl1271_debug(DEBUG_ACX, "acx sta max tx retry");
-
- acx = kzalloc(sizeof(*acx), GFP_KERNEL);
- if (!acx)
- return -ENOMEM;
-
- acx->max_tx_retry = wl->conf.tx.max_tx_retries;
-
- ret = wl1271_cmd_configure(wl, ACX_CONS_TX_FAILURE, acx, sizeof(*acx));
- if (ret < 0) {
- wl1271_warning("acx sta max tx retry failed: %d", ret);
+ wl1271_warning("acx max tx retry failed: %d", ret);
goto out;
}
@@ -1626,3 +1655,68 @@
kfree(acx);
return ret;
}
+
+int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable)
+{
+ struct acx_ap_beacon_filter *acx = NULL;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx set ap beacon filter: %d", enable);
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx)
+ return -ENOMEM;
+
+ acx->enable = enable ? 1 : 0;
+
+ ret = wl1271_cmd_configure(wl, ACX_AP_BEACON_FILTER_OPT,
+ acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx set ap beacon filter failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl1271_acx_fm_coex(struct wl1271 *wl)
+{
+ struct wl1271_acx_fm_coex *acx;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx fm coex setting");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = wl->conf.fm_coex.enable;
+ acx->swallow_period = wl->conf.fm_coex.swallow_period;
+ acx->n_divider_fref_set_1 = wl->conf.fm_coex.n_divider_fref_set_1;
+ acx->n_divider_fref_set_2 = wl->conf.fm_coex.n_divider_fref_set_2;
+ acx->m_divider_fref_set_1 =
+ cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_1);
+ acx->m_divider_fref_set_2 =
+ cpu_to_le16(wl->conf.fm_coex.m_divider_fref_set_2);
+ acx->coex_pll_stabilization_time =
+ cpu_to_le32(wl->conf.fm_coex.coex_pll_stabilization_time);
+ acx->ldo_stabilization_time =
+ cpu_to_le16(wl->conf.fm_coex.ldo_stabilization_time);
+ acx->fm_disturbed_band_margin =
+ wl->conf.fm_coex.fm_disturbed_band_margin;
+ acx->swallow_clk_diff = wl->conf.fm_coex.swallow_clk_diff;
+
+ ret = wl1271_cmd_configure(wl, ACX_FM_COEX_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx fm coex setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/wl12xx/acx.h b/drivers/net/wireless/wl12xx/acx.h
index 942908c..9a895e3 100644
--- a/drivers/net/wireless/wl12xx/acx.h
+++ b/drivers/net/wireless/wl12xx/acx.h
@@ -303,7 +303,6 @@
struct acx_header header;
u8 enable;
-
/*
* The number of beacons without the unicast TIM
* bit set that the firmware buffers before
@@ -370,14 +369,23 @@
u8 pad[3];
} __packed;
-struct acx_bt_wlan_coex_param {
+struct acx_sta_bt_wlan_coex_param {
struct acx_header header;
- __le32 params[CONF_SG_PARAMS_MAX];
+ __le32 params[CONF_SG_STA_PARAMS_MAX];
u8 param_idx;
u8 padding[3];
} __packed;
+struct acx_ap_bt_wlan_coex_param {
+ struct acx_header header;
+
+ __le32 params[CONF_SG_AP_PARAMS_MAX];
+ u8 param_idx;
+ u8 padding[3];
+} __packed;
+
+
struct acx_dco_itrim_params {
struct acx_header header;
@@ -1145,7 +1153,7 @@
u8 padding[3];
} __packed;
-struct wl1271_acx_ap_max_tx_retry {
+struct wl1271_acx_max_tx_retry {
struct acx_header header;
/*
@@ -1156,13 +1164,6 @@
u8 padding_1[2];
} __packed;
-struct wl1271_acx_sta_max_tx_retry {
- struct acx_header header;
-
- u8 max_tx_retry;
- u8 padding_1[3];
-} __packed;
-
struct wl1271_acx_config_ps {
struct acx_header header;
@@ -1179,6 +1180,72 @@
u8 padding1[2];
} __packed;
+struct acx_ap_beacon_filter {
+ struct acx_header header;
+
+ u8 enable;
+ u8 pad[3];
+} __packed;
+
+/*
+ * ACX_FM_COEX_CFG
+ * set the FM co-existence parameters.
+ */
+struct wl1271_acx_fm_coex {
+ struct acx_header header;
+ /* enable(1) / disable(0) the FM Coex feature */
+ u8 enable;
+ /*
+ * Swallow period used in COEX PLL swallowing mechanism.
+ * 0xFF = use FW default
+ */
+ u8 swallow_period;
+ /*
+ * The N divider used in COEX PLL swallowing mechanism for Fref of
+ * 38.4/19.2 Mhz. 0xFF = use FW default
+ */
+ u8 n_divider_fref_set_1;
+ /*
+ * The N divider used in COEX PLL swallowing mechanism for Fref of
+ * 26/52 Mhz. 0xFF = use FW default
+ */
+ u8 n_divider_fref_set_2;
+ /*
+ * The M divider used in COEX PLL swallowing mechanism for Fref of
+ * 38.4/19.2 Mhz. 0xFFFF = use FW default
+ */
+ __le16 m_divider_fref_set_1;
+ /*
+ * The M divider used in COEX PLL swallowing mechanism for Fref of
+ * 26/52 Mhz. 0xFFFF = use FW default
+ */
+ __le16 m_divider_fref_set_2;
+ /*
+ * The time duration in uSec required for COEX PLL to stabilize.
+ * 0xFFFFFFFF = use FW default
+ */
+ __le32 coex_pll_stabilization_time;
+ /*
+ * The time duration in uSec required for LDO to stabilize.
+ * 0xFFFFFFFF = use FW default
+ */
+ __le16 ldo_stabilization_time;
+ /*
+ * The disturbed frequency band margin around the disturbed frequency
+ * center (single sided).
+ * For example, if 2 is configured, the following channels will be
+ * considered disturbed channel:
+ * 80 +- 0.1 MHz, 91 +- 0.1 MHz, 98 +- 0.1 MHz, 102 +- 0.1 MH
+ * 0xFF = use FW default
+ */
+ u8 fm_disturbed_band_margin;
+ /*
+ * The swallow clock difference of the swallowing mechanism.
+ * 0xFF = use FW default
+ */
+ u8 swallow_clk_diff;
+} __packed;
+
enum {
ACX_WAKE_UP_CONDITIONS = 0x0002,
ACX_MEM_CFG = 0x0003,
@@ -1197,6 +1264,7 @@
ACX_TID_CFG = 0x001A,
ACX_PS_RX_STREAMING = 0x001B,
ACX_BEACON_FILTER_OPT = 0x001F,
+ ACX_AP_BEACON_FILTER_OPT = 0x0020,
ACX_NOISE_HIST = 0x0021,
ACX_HDK_VERSION = 0x0022, /* ??? */
ACX_PD_THRESHOLD = 0x0023,
@@ -1208,6 +1276,7 @@
ACX_BCN_DTIM_OPTIONS = 0x0031,
ACX_SG_ENABLE = 0x0032,
ACX_SG_CFG = 0x0033,
+ ACX_FM_COEX_CFG = 0x0034,
ACX_BEACON_FILTER_TABLE = 0x0038,
ACX_ARP_IP_FILTER = 0x0039,
ACX_ROAMING_STATISTICS_TBL = 0x003B,
@@ -1264,13 +1333,14 @@
int wl1271_acx_group_address_tbl(struct wl1271 *wl, bool enable,
void *mc_list, u32 mc_list_len);
int wl1271_acx_service_period_timeout(struct wl1271 *wl);
-int wl1271_acx_rts_threshold(struct wl1271 *wl, u16 rts_threshold);
+int wl1271_acx_rts_threshold(struct wl1271 *wl, u32 rts_threshold);
int wl1271_acx_dco_itrim_params(struct wl1271 *wl);
int wl1271_acx_beacon_filter_opt(struct wl1271 *wl, bool enable_filter);
int wl1271_acx_beacon_filter_table(struct wl1271 *wl);
int wl1271_acx_conn_monit_params(struct wl1271 *wl, bool enable);
int wl1271_acx_sg_enable(struct wl1271 *wl, bool enable);
-int wl1271_acx_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_sta_sg_cfg(struct wl1271 *wl);
+int wl1271_acx_ap_sg_cfg(struct wl1271 *wl);
int wl1271_acx_cca_threshold(struct wl1271 *wl);
int wl1271_acx_bcn_dtim_options(struct wl1271 *wl);
int wl1271_acx_aid(struct wl1271 *wl, u16 aid);
@@ -1287,7 +1357,7 @@
int wl1271_acx_tid_cfg(struct wl1271 *wl, u8 queue_id, u8 channel_type,
u8 tsid, u8 ps_scheme, u8 ack_policy,
u32 apsd_conf0, u32 apsd_conf1);
-int wl1271_acx_frag_threshold(struct wl1271 *wl, u16 frag_threshold);
+int wl1271_acx_frag_threshold(struct wl1271 *wl, u32 frag_threshold);
int wl1271_acx_tx_config_options(struct wl1271 *wl);
int wl1271_acx_ap_mem_cfg(struct wl1271 *wl);
int wl1271_acx_sta_mem_cfg(struct wl1271 *wl);
@@ -1314,9 +1384,10 @@
int wl1271_acx_set_ba_receiver_session(struct wl1271 *wl, u8 tid_index, u16 ssn,
bool enable);
int wl1271_acx_tsf_info(struct wl1271 *wl, u64 *mactime);
-int wl1271_acx_ap_max_tx_retry(struct wl1271 *wl);
-int wl1271_acx_sta_max_tx_retry(struct wl1271 *wl);
+int wl1271_acx_max_tx_retry(struct wl1271 *wl);
int wl1271_acx_config_ps(struct wl1271 *wl);
int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
+int wl1271_acx_set_ap_beacon_filter(struct wl1271 *wl, bool enable);
+int wl1271_acx_fm_coex(struct wl1271 *wl);
#endif /* __WL1271_ACX_H__ */
diff --git a/drivers/net/wireless/wl12xx/boot.c b/drivers/net/wireless/wl12xx/boot.c
index d263ebb..b07f8b7 100644
--- a/drivers/net/wireless/wl12xx/boot.c
+++ b/drivers/net/wireless/wl12xx/boot.c
@@ -479,11 +479,11 @@
RSSI_SNR_TRIGGER_0_EVENT_ID |
PSPOLL_DELIVERY_FAILURE_EVENT_ID |
SOFT_GEMINI_SENSE_EVENT_ID |
- MAX_TX_RETRY_EVENT_ID;
+ PERIODIC_SCAN_REPORT_EVENT_ID |
+ PERIODIC_SCAN_COMPLETE_EVENT_ID;
if (wl->bss_type == BSS_TYPE_AP_BSS)
- wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID |
- INACTIVE_STA_EVENT_ID;
+ wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
else
wl->event_mask |= DUMMY_PACKET_EVENT_ID;
diff --git a/drivers/net/wireless/wl12xx/cmd.c b/drivers/net/wireless/wl12xx/cmd.c
index 69d24f3..42935ac 100644
--- a/drivers/net/wireless/wl12xx/cmd.c
+++ b/drivers/net/wireless/wl12xx/cmd.c
@@ -76,7 +76,7 @@
if (time_after(jiffies, timeout)) {
wl1271_error("command complete timeout");
ret = -ETIMEDOUT;
- goto out;
+ goto fail;
}
poll_count++;
@@ -96,14 +96,17 @@
status = le16_to_cpu(cmd->status);
if (status != CMD_STATUS_SUCCESS) {
wl1271_error("command execute failure %d", status);
- ieee80211_queue_work(wl->hw, &wl->recovery_work);
ret = -EIO;
+ goto fail;
}
wl1271_write32(wl, ACX_REG_INTERRUPT_ACK,
WL1271_ACX_INTR_CMD_COMPLETE);
+ return 0;
-out:
+fail:
+ WARN_ON(1);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
return ret;
}
@@ -129,6 +132,9 @@
if (gp->tx_bip_fem_auto_detect)
answer = true;
+ /* Override the REF CLK from the NVS with the one from platform data */
+ gen_parms->general_params.ref_clock = wl->ref_clock;
+
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -168,6 +174,10 @@
if (gp->tx_bip_fem_auto_detect)
answer = true;
+ /* Replace REF and TCXO CLKs with the ones from platform data */
+ gen_parms->general_params.ref_clock = wl->ref_clock;
+ gen_parms->general_params.tcxo_ref_clock = wl->tcxo_clock;
+
ret = wl1271_cmd_test(wl, gen_parms, sizeof(*gen_parms), answer);
if (ret < 0) {
wl1271_warning("CMD_INI_FILE_GENERAL_PARAM failed");
@@ -1070,7 +1080,7 @@
memcpy(cmd->bssid, bss_conf->bssid, ETH_ALEN);
- cmd->aging_period = cpu_to_le16(wl->conf.tx.ap_aging_period);
+ cmd->aging_period = cpu_to_le16(WL1271_AP_DEF_INACTIV_SEC);
cmd->bss_index = WL1271_AP_BSS_INDEX;
cmd->global_hlid = WL1271_AP_GLOBAL_HLID;
cmd->broadcast_hlid = WL1271_AP_BROADCAST_HLID;
diff --git a/drivers/net/wireless/wl12xx/conf.h b/drivers/net/wireless/wl12xx/conf.h
index e3de915..1ab6c86 100644
--- a/drivers/net/wireless/wl12xx/conf.h
+++ b/drivers/net/wireless/wl12xx/conf.h
@@ -396,12 +396,43 @@
CONF_SG_TEMP_PARAM_3,
CONF_SG_TEMP_PARAM_4,
CONF_SG_TEMP_PARAM_5,
- CONF_SG_PARAMS_MAX,
+
+ /*
+ * AP beacon miss
+ *
+ * Range: 0 - 255
+ */
+ CONF_SG_AP_BEACON_MISS_TX,
+
+ /*
+ * AP RX window length
+ *
+ * Range: 0 - 50
+ */
+ CONF_SG_RX_WINDOW_LENGTH,
+
+ /*
+ * AP connection protection time
+ *
+ * Range: 0 - 5000
+ */
+ CONF_SG_AP_CONNECTION_PROTECTION_TIME,
+
+ CONF_SG_TEMP_PARAM_6,
+ CONF_SG_TEMP_PARAM_7,
+ CONF_SG_TEMP_PARAM_8,
+ CONF_SG_TEMP_PARAM_9,
+ CONF_SG_TEMP_PARAM_10,
+
+ CONF_SG_STA_PARAMS_MAX = CONF_SG_TEMP_PARAM_5 + 1,
+ CONF_SG_AP_PARAMS_MAX = CONF_SG_TEMP_PARAM_10 + 1,
+
CONF_SG_PARAMS_ALL = 0xff
};
struct conf_sg_settings {
- u32 params[CONF_SG_PARAMS_MAX];
+ u32 sta_params[CONF_SG_STA_PARAMS_MAX];
+ u32 ap_params[CONF_SG_AP_PARAMS_MAX];
u8 state;
};
@@ -509,6 +540,12 @@
CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
CONF_HW_BIT_RATE_54MBPS)
+#define CONF_TX_OFDM_RATES (CONF_HW_BIT_RATE_6MBPS | \
+ CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \
+ CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \
+ CONF_HW_BIT_RATE_54MBPS)
+
+
/*
* Default rates for management traffic when operating in AP mode. This
* should be configured according to the basic rate set of the AP
@@ -516,6 +553,13 @@
#define CONF_TX_AP_DEFAULT_MGMT_RATES (CONF_HW_BIT_RATE_1MBPS | \
CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
+/*
+ * Default rates for working as IBSS. use 11b rates
+ */
+#define CONF_TX_IBSS_DEFAULT_RATES (CONF_HW_BIT_RATE_1MBPS | \
+ CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
+ CONF_HW_BIT_RATE_11MBPS);
+
struct conf_tx_rate_class {
/*
@@ -667,34 +711,10 @@
struct conf_tx_ac_category ac_conf[CONF_TX_MAX_AC_COUNT];
/*
- * Configuration for rate classes in AP-mode. These rate classes
- * are for the AC TX queues
- */
- struct conf_tx_rate_class ap_rc_conf[CONF_TX_MAX_AC_COUNT];
-
- /*
- * Management TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_mgmt_conf;
-
- /*
- * Broadcast TX rate class for AP-mode.
- */
- struct conf_tx_rate_class ap_bcst_conf;
-
- /*
- * Allow this number of TX retries to a connected station/AP before an
+ * AP-mode - allow this number of TX retries to a station before an
* event is triggered from FW.
- * In AP-mode the hlids of unreachable stations are given in the
- * "sta_tx_retry_exceeded" member in the event mailbox.
*/
- u8 max_tx_retries;
-
- /*
- * AP-mode - after this number of seconds a connected station is
- * considered inactive.
- */
- u16 ap_aging_period;
+ u16 ap_max_tx_retries;
/*
* Configuration for TID parameters.
@@ -1127,6 +1147,26 @@
};
+struct conf_sched_scan_settings {
+ /* minimum time to wait on the channel for active scans (in TUs) */
+ u16 min_dwell_time_active;
+
+ /* maximum time to wait on the channel for active scans (in TUs) */
+ u16 max_dwell_time_active;
+
+ /* time to wait on the channel for passive scans (in TUs) */
+ u32 dwell_time_passive;
+
+ /* number of probe requests to send on each channel in active scans */
+ u8 num_probe_reqs;
+
+ /* RSSI threshold to be used for filtering */
+ s8 rssi_threshold;
+
+ /* SNR threshold to be used for filtering */
+ s8 snr_threshold;
+};
+
/* these are number of channels on the band divided by two, rounded up */
#define CONF_TX_PWR_COMPENSATION_LEN_2 7
#define CONF_TX_PWR_COMPENSATION_LEN_5 18
@@ -1192,6 +1232,19 @@
u8 tx_min;
};
+struct conf_fm_coex {
+ u8 enable;
+ u8 swallow_period;
+ u8 n_divider_fref_set_1;
+ u8 n_divider_fref_set_2;
+ u16 m_divider_fref_set_1;
+ u16 m_divider_fref_set_2;
+ u32 coex_pll_stabilization_time;
+ u16 ldo_stabilization_time;
+ u8 fm_disturbed_band_margin;
+ u8 swallow_clk_diff;
+};
+
struct conf_drv_settings {
struct conf_sg_settings sg;
struct conf_rx_settings rx;
@@ -1201,10 +1254,12 @@
struct conf_pm_config_settings pm_config;
struct conf_roam_trigger_settings roam_trigger;
struct conf_scan_settings scan;
+ struct conf_sched_scan_settings sched_scan;
struct conf_rf_settings rf;
struct conf_ht_setting ht;
struct conf_memory_settings mem_wl127x;
struct conf_memory_settings mem_wl128x;
+ struct conf_fm_coex fm_coex;
u8 hci_io_ds;
};
diff --git a/drivers/net/wireless/wl12xx/debugfs.c b/drivers/net/wireless/wl12xx/debugfs.c
index 70ab198..f1f8df9 100644
--- a/drivers/net/wireless/wl12xx/debugfs.c
+++ b/drivers/net/wireless/wl12xx/debugfs.c
@@ -291,6 +291,242 @@
.llseek = default_llseek,
};
+static ssize_t start_recovery_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+
+ mutex_lock(&wl->mutex);
+ ieee80211_queue_work(wl->hw, &wl->recovery_work);
+ mutex_unlock(&wl->mutex);
+
+ return count;
+}
+
+static const struct file_operations start_recovery_ops = {
+ .write = start_recovery_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t driver_state_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ int res = 0;
+ char buf[1024];
+
+ mutex_lock(&wl->mutex);
+
+#define DRIVER_STATE_PRINT(x, fmt) \
+ (res += scnprintf(buf + res, sizeof(buf) - res,\
+ #x " = " fmt "\n", wl->x))
+
+#define DRIVER_STATE_PRINT_LONG(x) DRIVER_STATE_PRINT(x, "%ld")
+#define DRIVER_STATE_PRINT_INT(x) DRIVER_STATE_PRINT(x, "%d")
+#define DRIVER_STATE_PRINT_STR(x) DRIVER_STATE_PRINT(x, "%s")
+#define DRIVER_STATE_PRINT_LHEX(x) DRIVER_STATE_PRINT(x, "0x%lx")
+#define DRIVER_STATE_PRINT_HEX(x) DRIVER_STATE_PRINT(x, "0x%x")
+
+ DRIVER_STATE_PRINT_INT(tx_blocks_available);
+ DRIVER_STATE_PRINT_INT(tx_allocated_blocks);
+ DRIVER_STATE_PRINT_INT(tx_frames_cnt);
+ DRIVER_STATE_PRINT_LHEX(tx_frames_map[0]);
+ DRIVER_STATE_PRINT_INT(tx_queue_count);
+ DRIVER_STATE_PRINT_INT(tx_packets_count);
+ DRIVER_STATE_PRINT_INT(tx_results_count);
+ DRIVER_STATE_PRINT_LHEX(flags);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[0]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[1]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[2]);
+ DRIVER_STATE_PRINT_INT(tx_blocks_freed[3]);
+ DRIVER_STATE_PRINT_INT(tx_security_last_seq);
+ DRIVER_STATE_PRINT_INT(rx_counter);
+ DRIVER_STATE_PRINT_INT(session_counter);
+ DRIVER_STATE_PRINT_INT(state);
+ DRIVER_STATE_PRINT_INT(bss_type);
+ DRIVER_STATE_PRINT_INT(channel);
+ DRIVER_STATE_PRINT_HEX(rate_set);
+ DRIVER_STATE_PRINT_HEX(basic_rate_set);
+ DRIVER_STATE_PRINT_HEX(basic_rate);
+ DRIVER_STATE_PRINT_INT(band);
+ DRIVER_STATE_PRINT_INT(beacon_int);
+ DRIVER_STATE_PRINT_INT(psm_entry_retry);
+ DRIVER_STATE_PRINT_INT(ps_poll_failures);
+ DRIVER_STATE_PRINT_HEX(filters);
+ DRIVER_STATE_PRINT_HEX(rx_config);
+ DRIVER_STATE_PRINT_HEX(rx_filter);
+ DRIVER_STATE_PRINT_INT(power_level);
+ DRIVER_STATE_PRINT_INT(rssi_thold);
+ DRIVER_STATE_PRINT_INT(last_rssi_event);
+ DRIVER_STATE_PRINT_INT(sg_enabled);
+ DRIVER_STATE_PRINT_INT(enable_11a);
+ DRIVER_STATE_PRINT_INT(noise);
+ DRIVER_STATE_PRINT_LHEX(ap_hlid_map[0]);
+ DRIVER_STATE_PRINT_INT(last_tx_hlid);
+ DRIVER_STATE_PRINT_INT(ba_support);
+ DRIVER_STATE_PRINT_HEX(ba_rx_bitmap);
+ DRIVER_STATE_PRINT_HEX(ap_fw_ps_map);
+ DRIVER_STATE_PRINT_LHEX(ap_ps_map);
+ DRIVER_STATE_PRINT_HEX(quirks);
+ DRIVER_STATE_PRINT_HEX(irq);
+ DRIVER_STATE_PRINT_HEX(ref_clock);
+ DRIVER_STATE_PRINT_HEX(tcxo_clock);
+ DRIVER_STATE_PRINT_HEX(hw_pg_ver);
+ DRIVER_STATE_PRINT_HEX(platform_quirks);
+ DRIVER_STATE_PRINT_HEX(chip.id);
+ DRIVER_STATE_PRINT_STR(chip.fw_ver_str);
+ DRIVER_STATE_PRINT_INT(sched_scanning);
+
+#undef DRIVER_STATE_PRINT_INT
+#undef DRIVER_STATE_PRINT_LONG
+#undef DRIVER_STATE_PRINT_HEX
+#undef DRIVER_STATE_PRINT_LHEX
+#undef DRIVER_STATE_PRINT_STR
+#undef DRIVER_STATE_PRINT
+
+ mutex_unlock(&wl->mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, res);
+}
+
+static const struct file_operations driver_state_ops = {
+ .read = driver_state_read,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t dtim_interval_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u8 value;
+
+ if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_DTIM ||
+ wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_DTIM)
+ value = wl->conf.conn.listen_interval;
+ else
+ value = 0;
+
+ return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t dtim_interval_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for dtim_interval");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 10) {
+ wl1271_warning("dtim value is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.listen_interval = value;
+ /* for some reason there are different event types for 1 and >1 */
+ if (value == 1)
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_DTIM;
+ else
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_DTIM;
+
+ /*
+ * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
+ * take effect on the next time we enter psm.
+ */
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations dtim_interval_ops = {
+ .read = dtim_interval_read,
+ .write = dtim_interval_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
+static ssize_t beacon_interval_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ u8 value;
+
+ if (wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_BEACON ||
+ wl->conf.conn.wake_up_event == CONF_WAKE_UP_EVENT_N_BEACONS)
+ value = wl->conf.conn.listen_interval;
+ else
+ value = 0;
+
+ return wl1271_format_buffer(user_buf, count, ppos, "%d\n", value);
+}
+
+static ssize_t beacon_interval_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ char buf[10];
+ size_t len;
+ unsigned long value;
+ int ret;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+ buf[len] = '\0';
+
+ ret = kstrtoul(buf, 0, &value);
+ if (ret < 0) {
+ wl1271_warning("illegal value for beacon_interval");
+ return -EINVAL;
+ }
+
+ if (value < 1 || value > 255) {
+ wl1271_warning("beacon interval value is not in valid range");
+ return -ERANGE;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ wl->conf.conn.listen_interval = value;
+ /* for some reason there are different event types for 1 and >1 */
+ if (value == 1)
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_BEACON;
+ else
+ wl->conf.conn.wake_up_event = CONF_WAKE_UP_EVENT_N_BEACONS;
+
+ /*
+ * we don't reconfigure ACX_WAKE_UP_CONDITIONS now, so it will only
+ * take effect on the next time we enter psm.
+ */
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations beacon_interval_ops = {
+ .read = beacon_interval_read,
+ .write = beacon_interval_write,
+ .open = wl1271_open_file_generic,
+ .llseek = default_llseek,
+};
+
static int wl1271_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -399,6 +635,10 @@
DEBUGFS_ADD(excessive_retries, rootdir);
DEBUGFS_ADD(gpio_power, rootdir);
+ DEBUGFS_ADD(start_recovery, rootdir);
+ DEBUGFS_ADD(driver_state, rootdir);
+ DEBUGFS_ADD(dtim_interval, rootdir);
+ DEBUGFS_ADD(beacon_interval, rootdir);
return 0;
diff --git a/drivers/net/wireless/wl12xx/event.c b/drivers/net/wireless/wl12xx/event.c
index d7be3ae..c3c554c 100644
--- a/drivers/net/wireless/wl12xx/event.c
+++ b/drivers/net/wireless/wl12xx/event.c
@@ -135,6 +135,13 @@
/* enable beacon early termination */
ret = wl1271_acx_bet_enable(wl, true);
+ if (ret < 0)
+ break;
+
+ if (wl->ps_compl) {
+ complete(wl->ps_compl);
+ wl->ps_compl = NULL;
+ }
break;
default:
break;
@@ -174,8 +181,6 @@
u32 vector;
bool beacon_loss = false;
bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS);
- bool disconnect_sta = false;
- unsigned long sta_bitmap = 0;
wl1271_event_mbox_dump(mbox);
@@ -190,6 +195,22 @@
wl1271_scan_stm(wl);
}
+ if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_REPORT_EVENT "
+ "(status 0x%0x)", mbox->scheduled_scan_status);
+
+ wl1271_scan_sched_scan_results(wl);
+ }
+
+ if (vector & PERIODIC_SCAN_COMPLETE_EVENT_ID) {
+ wl1271_debug(DEBUG_EVENT, "PERIODIC_SCAN_COMPLETE_EVENT "
+ "(status 0x%0x)", mbox->scheduled_scan_status);
+ if (wl->sched_scanning) {
+ wl1271_scan_sched_scan_stop(wl);
+ ieee80211_sched_scan_stopped(wl->hw);
+ }
+ }
+
/* disable dynamic PS when requested by the firmware */
if (vector & SOFT_GEMINI_SENSE_EVENT_ID &&
wl->bss_type == BSS_TYPE_STA_BSS) {
@@ -237,54 +258,9 @@
wl1271_tx_dummy_packet(wl);
}
- /*
- * "TX retries exceeded" has a different meaning according to mode.
- * In AP mode the offending station is disconnected. In STA mode we
- * report connection loss.
- */
- if (vector & MAX_TX_RETRY_EVENT_ID) {
- wl1271_debug(DEBUG_EVENT, "MAX_TX_RETRY_EVENT_ID");
- if (is_ap) {
- sta_bitmap |= le16_to_cpu(mbox->sta_tx_retry_exceeded);
- disconnect_sta = true;
- } else {
- beacon_loss = true;
- }
- }
-
- if ((vector & INACTIVE_STA_EVENT_ID) && is_ap) {
- wl1271_debug(DEBUG_EVENT, "INACTIVE_STA_EVENT_ID");
- sta_bitmap |= le16_to_cpu(mbox->sta_aging_status);
- disconnect_sta = true;
- }
-
if (wl->vif && beacon_loss)
ieee80211_connection_loss(wl->vif);
- if (is_ap && disconnect_sta) {
- u32 num_packets = wl->conf.tx.max_tx_retries;
- struct ieee80211_sta *sta;
- const u8 *addr;
- int h;
-
- for (h = find_first_bit(&sta_bitmap, AP_MAX_LINKS);
- h < AP_MAX_LINKS;
- h = find_next_bit(&sta_bitmap, AP_MAX_LINKS, h+1)) {
- if (!wl1271_is_active_sta(wl, h))
- continue;
-
- addr = wl->links[h].addr;
-
- rcu_read_lock();
- sta = ieee80211_find_sta(wl->vif, addr);
- if (sta) {
- wl1271_debug(DEBUG_EVENT, "remove sta %d", h);
- ieee80211_report_low_ack(sta, num_packets);
- }
- rcu_read_unlock();
- }
- }
-
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/event.h b/drivers/net/wireless/wl12xx/event.h
index 7ae5a08..b6cf06e 100644
--- a/drivers/net/wireless/wl12xx/event.h
+++ b/drivers/net/wireless/wl12xx/event.h
@@ -58,16 +58,13 @@
CHANNEL_SWITCH_COMPLETE_EVENT_ID = BIT(17),
BSS_LOSE_EVENT_ID = BIT(18),
REGAINED_BSS_EVENT_ID = BIT(19),
- MAX_TX_RETRY_EVENT_ID = BIT(20),
+ ROAMING_TRIGGER_MAX_TX_RETRY_EVENT_ID = BIT(20),
/* STA: dummy paket for dynamic mem blocks */
DUMMY_PACKET_EVENT_ID = BIT(21),
/* AP: STA remove complete */
STA_REMOVE_COMPLETE_EVENT_ID = BIT(21),
SOFT_GEMINI_SENSE_EVENT_ID = BIT(22),
- /* STA: SG prediction */
SOFT_GEMINI_PREDICTION_EVENT_ID = BIT(23),
- /* AP: Inactive STA */
- INACTIVE_STA_EVENT_ID = BIT(23),
SOFT_GEMINI_AVALANCHE_EVENT_ID = BIT(24),
PLT_RX_CALIBRATION_COMPLETE_EVENT_ID = BIT(25),
DBG_EVENT_ID = BIT(26),
@@ -122,11 +119,7 @@
/* AP FW only */
u8 hlid_removed;
-
- /* a bitmap of hlids for stations that have been inactive too long */
__le16 sta_aging_status;
-
- /* a bitmap of hlids for stations which didn't respond to TX */
__le16 sta_tx_retry_exceeded;
u8 reserved_5[24];
@@ -137,7 +130,4 @@
int wl1271_event_handle(struct wl1271 *wl, u8 mbox);
void wl1271_pspoll_work(struct work_struct *work);
-/* Functions from main.c */
-bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid);
-
#endif
diff --git a/drivers/net/wireless/wl12xx/init.c b/drivers/net/wireless/wl12xx/init.c
index ab3b1e2..a8f4f15 100644
--- a/drivers/net/wireless/wl12xx/init.c
+++ b/drivers/net/wireless/wl12xx/init.c
@@ -258,7 +258,7 @@
if (ret < 0)
return ret;
- ret = wl1271_acx_rts_threshold(wl, wl->conf.rx.rts_threshold);
+ ret = wl1271_acx_rts_threshold(wl, wl->hw->wiphy->rts_threshold);
if (ret < 0)
return ret;
@@ -285,7 +285,10 @@
{
int ret;
- ret = wl1271_acx_sg_cfg(wl);
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ ret = wl1271_acx_ap_sg_cfg(wl);
+ else
+ ret = wl1271_acx_sta_sg_cfg(wl);
if (ret < 0)
return ret;
@@ -351,8 +354,8 @@
if (ret < 0)
return ret;
- /* Bluetooth WLAN coexistence */
- ret = wl1271_init_pta(wl);
+ /* FM WLAN coexistence */
+ ret = wl1271_acx_fm_coex(wl);
if (ret < 0)
return ret;
@@ -375,10 +378,6 @@
if (ret < 0)
return ret;
- ret = wl1271_acx_sta_max_tx_retry(wl);
- if (ret < 0)
- return ret;
-
ret = wl1271_acx_sta_mem_cfg(wl);
if (ret < 0)
return ret;
@@ -414,7 +413,7 @@
static int wl1271_ap_hw_init(struct wl1271 *wl)
{
- int ret, i;
+ int ret;
ret = wl1271_ap_init_templates_config(wl);
if (ret < 0)
@@ -425,27 +424,11 @@
if (ret < 0)
return ret;
- /* Configure initial TX rate classes */
- for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_rc_conf[i], i);
- if (ret < 0)
- return ret;
- }
-
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_mgmt_conf,
- ACX_TX_AP_MODE_MGMT_RATE);
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0)
return ret;
- ret = wl1271_acx_ap_rate_policy(wl,
- &wl->conf.tx.ap_bcst_conf,
- ACX_TX_AP_MODE_BCST_RATE);
- if (ret < 0)
- return ret;
-
- ret = wl1271_acx_ap_max_tx_retry(wl);
+ ret = wl1271_acx_max_tx_retry(wl);
if (ret < 0)
return ret;
@@ -456,7 +439,7 @@
return 0;
}
-static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+int wl1271_ap_init_templates(struct wl1271 *wl)
{
int ret;
@@ -472,6 +455,70 @@
if (ret < 0)
return ret;
+ /*
+ * when operating as AP we want to receive external beacons for
+ * configuring ERP protection.
+ */
+ ret = wl1271_acx_set_ap_beacon_filter(wl, false);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int wl1271_ap_hw_init_post_mem(struct wl1271 *wl)
+{
+ return wl1271_ap_init_templates(wl);
+}
+
+int wl1271_init_ap_rates(struct wl1271 *wl)
+{
+ int i, ret;
+ struct conf_tx_rate_class rc;
+ u32 supported_rates;
+
+ wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wl->basic_rate_set);
+
+ if (wl->basic_rate_set == 0)
+ return -EINVAL;
+
+ rc.enabled_rates = wl->basic_rate_set;
+ rc.long_retry_limit = 10;
+ rc.short_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_MGMT_RATE);
+ if (ret < 0)
+ return ret;
+
+ /* use the min basic rate for AP broadcast/multicast */
+ rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+ rc.short_retry_limit = 10;
+ rc.long_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, ACX_TX_AP_MODE_BCST_RATE);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * If the basic rates contain OFDM rates, use OFDM only
+ * rates for unicast TX as well. Else use all supported rates.
+ */
+ if ((wl->basic_rate_set & CONF_TX_OFDM_RATES))
+ supported_rates = CONF_TX_OFDM_RATES;
+ else
+ supported_rates = CONF_TX_AP_ENABLED_RATES;
+
+ /* configure unicast TX rate classes */
+ for (i = 0; i < wl->conf.tx.ac_conf_count; i++) {
+ rc.enabled_rates = supported_rates;
+ rc.short_retry_limit = 10;
+ rc.long_retry_limit = 10;
+ rc.aflags = 0;
+ ret = wl1271_acx_ap_rate_policy(wl, &rc, i);
+ if (ret < 0)
+ return ret;
+ }
+
return 0;
}
@@ -567,6 +614,11 @@
if (ret < 0)
return ret;
+ /* Bluetooth WLAN coexistence */
+ ret = wl1271_init_pta(wl);
+ if (ret < 0)
+ return ret;
+
/* Default memory configuration */
ret = wl1271_acx_init_mem_config(wl);
if (ret < 0)
@@ -606,7 +658,7 @@
goto out_free_memmap;
/* Default fragmentation threshold */
- ret = wl1271_acx_frag_threshold(wl, wl->conf.tx.frag_threshold);
+ ret = wl1271_acx_frag_threshold(wl, wl->hw->wiphy->frag_threshold);
if (ret < 0)
goto out_free_memmap;
diff --git a/drivers/net/wireless/wl12xx/init.h b/drivers/net/wireless/wl12xx/init.h
index 4975270..3a3c230 100644
--- a/drivers/net/wireless/wl12xx/init.h
+++ b/drivers/net/wireless/wl12xx/init.h
@@ -33,5 +33,7 @@
int wl1271_init_energy_detection(struct wl1271 *wl);
int wl1271_chip_specific_init(struct wl1271 *wl);
int wl1271_hw_init(struct wl1271 *wl);
+int wl1271_init_ap_rates(struct wl1271 *wl);
+int wl1271_ap_init_templates(struct wl1271 *wl);
#endif
diff --git a/drivers/net/wireless/wl12xx/main.c b/drivers/net/wireless/wl12xx/main.c
index 0c69e95..610be03 100644
--- a/drivers/net/wireless/wl12xx/main.c
+++ b/drivers/net/wireless/wl12xx/main.c
@@ -51,7 +51,7 @@
static struct conf_drv_settings default_conf = {
.sg = {
- .params = {
+ .sta_params = {
[CONF_SG_BT_PER_THRESHOLD] = 7500,
[CONF_SG_HV3_MAX_OVERRIDE] = 0,
[CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
@@ -101,6 +101,61 @@
[CONF_SG_DHCP_TIME] = 5000,
[CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
},
+ .ap_params = {
+ [CONF_SG_BT_PER_THRESHOLD] = 7500,
+ [CONF_SG_HV3_MAX_OVERRIDE] = 0,
+ [CONF_SG_BT_NFS_SAMPLE_INTERVAL] = 400,
+ [CONF_SG_BT_LOAD_RATIO] = 50,
+ [CONF_SG_AUTO_PS_MODE] = 1,
+ [CONF_SG_AUTO_SCAN_PROBE_REQ] = 170,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_HV3] = 50,
+ [CONF_SG_ANTENNA_CONFIGURATION] = 0,
+ [CONF_SG_BEACON_MISS_PERCENT] = 60,
+ [CONF_SG_RATE_ADAPT_THRESH] = 64,
+ [CONF_SG_RATE_ADAPT_SNR] = 1,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_BR] = 10,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_BR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_BR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_BR] = 20,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_BR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_BR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MIN_EDR] = 7,
+ [CONF_SG_WLAN_PS_BT_ACL_MASTER_MAX_EDR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_MASTER_EDR] = 25,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MIN_EDR] = 8,
+ [CONF_SG_WLAN_PS_BT_ACL_SLAVE_MAX_EDR] = 25,
+ [CONF_SG_WLAN_PS_MAX_BT_ACL_SLAVE_EDR] = 25,
+ [CONF_SG_RXT] = 1200,
+ [CONF_SG_TXT] = 1000,
+ [CONF_SG_ADAPTIVE_RXT_TXT] = 1,
+ [CONF_SG_PS_POLL_TIMEOUT] = 10,
+ [CONF_SG_UPSD_TIMEOUT] = 10,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MIN_EDR] = 7,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MASTER_MAX_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_MASTER_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MIN_EDR] = 8,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_SLAVE_MAX_EDR] = 20,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_SLAVE_EDR] = 15,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MIN_BR] = 20,
+ [CONF_SG_WLAN_ACTIVE_BT_ACL_MAX_BR] = 50,
+ [CONF_SG_WLAN_ACTIVE_MAX_BT_ACL_BR] = 10,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_HV3] = 200,
+ [CONF_SG_PASSIVE_SCAN_DURATION_FACTOR_A2DP] = 800,
+ [CONF_SG_PASSIVE_SCAN_A2DP_BT_TIME] = 75,
+ [CONF_SG_PASSIVE_SCAN_A2DP_WLAN_TIME] = 15,
+ [CONF_SG_HV3_MAX_SERVED] = 6,
+ [CONF_SG_DHCP_TIME] = 5000,
+ [CONF_SG_ACTIVE_SCAN_DURATION_FACTOR_A2DP] = 100,
+ [CONF_SG_TEMP_PARAM_1] = 0,
+ [CONF_SG_TEMP_PARAM_2] = 0,
+ [CONF_SG_TEMP_PARAM_3] = 0,
+ [CONF_SG_TEMP_PARAM_4] = 0,
+ [CONF_SG_TEMP_PARAM_5] = 0,
+ [CONF_SG_AP_BEACON_MISS_TX] = 3,
+ [CONF_SG_RX_WINDOW_LENGTH] = 6,
+ [CONF_SG_AP_CONNECTION_PROTECTION_TIME] = 50,
+ [CONF_SG_TEMP_PARAM_6] = 1,
+ },
.state = CONF_SG_PROTECTIVE,
},
.rx = {
@@ -108,7 +163,7 @@
.packet_detection_threshold = 0,
.ps_poll_timeout = 15,
.upsd_timeout = 15,
- .rts_threshold = 2347,
+ .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD,
.rx_cca_threshold = 0,
.irq_blk_threshold = 0xFFFF,
.irq_pkt_threshold = 0,
@@ -154,46 +209,7 @@
.tx_op_limit = 1504,
},
},
- .ap_rc_conf = {
- [0] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [1] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [2] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- [3] = {
- .enabled_rates = CONF_TX_AP_ENABLED_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- },
- .ap_mgmt_conf = {
- .enabled_rates = CONF_TX_AP_DEFAULT_MGMT_RATES,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- .ap_bcst_conf = {
- .enabled_rates = CONF_HW_BIT_RATE_1MBPS,
- .short_retry_limit = 10,
- .long_retry_limit = 10,
- .aflags = 0,
- },
- .max_tx_retries = 100,
- .ap_aging_period = 300,
+ .ap_max_tx_retries = 100,
.tid_conf_count = 4,
.tid_conf = {
[CONF_TX_AC_BE] = {
@@ -241,12 +257,16 @@
.wake_up_event = CONF_WAKE_UP_EVENT_DTIM,
.listen_interval = 1,
.bcn_filt_mode = CONF_BCN_FILT_MODE_ENABLED,
- .bcn_filt_ie_count = 1,
+ .bcn_filt_ie_count = 2,
.bcn_filt_ie = {
[0] = {
.ie = WLAN_EID_CHANNEL_SWITCH,
.rule = CONF_BCN_RULE_PASS_ON_APPEARANCE,
- }
+ },
+ [1] = {
+ .ie = WLAN_EID_HT_INFORMATION,
+ .rule = CONF_BCN_RULE_PASS_ON_CHANGE,
+ },
},
.synch_fail_thold = 10,
.bss_lose_timeout = 100,
@@ -258,7 +278,7 @@
.bet_enable = CONF_BET_MODE_ENABLE,
.bet_max_consecutive = 50,
.psm_entry_retries = 5,
- .psm_exit_retries = 255,
+ .psm_exit_retries = 16,
.psm_entry_nullfunc_retries = 3,
.psm_entry_hangover_period = 1,
.keep_alive_interval = 55000,
@@ -286,6 +306,15 @@
.max_dwell_time_passive = 100000,
.num_probe_reqs = 2,
},
+ .sched_scan = {
+ /* sched_scan requires dwell times in TU instead of TU/1000 */
+ .min_dwell_time_active = 8,
+ .max_dwell_time_active = 30,
+ .dwell_time_passive = 100,
+ .num_probe_reqs = 2,
+ .rssi_threshold = -90,
+ .snr_threshold = 0,
+ },
.rf = {
.tx_per_channel_power_compensation_2 = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -305,7 +334,7 @@
.ssid_profiles = 1,
.rx_block_num = 70,
.tx_min_block_num = 40,
- .dynamic_memory = 0,
+ .dynamic_memory = 1,
.min_req_tx_blocks = 100,
.min_req_rx_blocks = 22,
.tx_min = 27,
@@ -320,10 +349,23 @@
.min_req_rx_blocks = 22,
.tx_min = 27,
},
+ .fm_coex = {
+ .enable = true,
+ .swallow_period = 5,
+ .n_divider_fref_set_1 = 0xff, /* default */
+ .n_divider_fref_set_2 = 12,
+ .m_divider_fref_set_1 = 148,
+ .m_divider_fref_set_2 = 0xffff, /* default */
+ .coex_pll_stabilization_time = 0xffffffff, /* default */
+ .ldo_stabilization_time = 0xffff, /* default */
+ .fm_disturbed_band_margin = 0xff, /* default */
+ .swallow_clk_diff = 0xff, /* default */
+ },
.hci_io_ds = HCI_IO_DS_6MA,
};
-static void __wl1271_op_remove_interface(struct wl1271 *wl);
+static void __wl1271_op_remove_interface(struct wl1271 *wl,
+ bool reset_tx_queues);
static void wl1271_free_ap_keys(struct wl1271 *wl);
@@ -508,6 +550,11 @@
if (ret < 0)
goto out_free_memmap;
+ /* FM WLAN coexistence */
+ ret = wl1271_acx_fm_coex(wl);
+ if (ret < 0)
+ goto out_free_memmap;
+
/* Energy detection */
ret = wl1271_init_energy_detection(wl);
if (ret < 0)
@@ -932,15 +979,30 @@
if (wl->state != WL1271_STATE_ON)
goto out;
- wl1271_info("Hardware recovery in progress.");
+ wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
+ wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
ieee80211_connection_loss(wl->vif);
+ /* Prevent spurious TX during FW restart */
+ ieee80211_stop_queues(wl->hw);
+
+ if (wl->sched_scanning) {
+ ieee80211_sched_scan_stopped(wl->hw);
+ wl->sched_scanning = false;
+ }
+
/* reboot the chipset */
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, false);
ieee80211_restart_hw(wl->hw);
+ /*
+ * Its safe to enable TX now - the queues are stopped after a request
+ * to restart the HW.
+ */
+ ieee80211_wake_queues(wl->hw);
+
out:
mutex_unlock(&wl->mutex);
}
@@ -1011,6 +1073,10 @@
wl1271_debug(DEBUG_BOOT, "chip id 0x%x (1271 PG20)",
wl->chip.id);
+ /* end-of-transaction flag should be set in wl127x AP mode */
+ if (wl->bss_type == BSS_TYPE_AP_BSS)
+ wl->quirks |= WL12XX_QUIRK_END_OF_TRANSACTION;
+
ret = wl1271_setup(wl);
if (ret < 0)
goto out;
@@ -1273,7 +1339,7 @@
skb->priority = WL1271_TID_MGMT;
/* Initialize all fields that might be used */
- skb->queue_mapping = 0;
+ skb_set_queue_mapping(skb, 0);
memset(IEEE80211_SKB_CB(skb), 0, sizeof(struct ieee80211_tx_info));
return skb;
@@ -1284,6 +1350,150 @@
.notifier_call = wl1271_dev_notify,
};
+static int wl1271_configure_suspend(struct wl1271 *wl)
+{
+ int ret;
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return 0;
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+
+ /* enter psm if needed*/
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags)) {
+ DECLARE_COMPLETION_ONSTACK(compl);
+
+ wl->ps_compl = &compl;
+ ret = wl1271_ps_set_mode(wl, STATION_POWER_SAVE_MODE,
+ wl->basic_rate, true);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* we must unlock here so we will be able to get events */
+ wl1271_ps_elp_sleep(wl);
+ mutex_unlock(&wl->mutex);
+
+ ret = wait_for_completion_timeout(
+ &compl, msecs_to_jiffies(WL1271_PS_COMPLETE_TIMEOUT));
+ if (ret <= 0) {
+ wl1271_warning("couldn't enter ps mode!");
+ ret = -EBUSY;
+ goto out;
+ }
+
+ /* take mutex again, and wakeup */
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out_unlock;
+ }
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out_unlock:
+ mutex_unlock(&wl->mutex);
+out:
+ return ret;
+
+}
+
+static void wl1271_configure_resume(struct wl1271 *wl)
+{
+ int ret;
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return;
+
+ mutex_lock(&wl->mutex);
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ /* exit psm if it wasn't configured */
+ if (!test_bit(WL1271_FLAG_PSM_REQUESTED, &wl->flags))
+ wl1271_ps_set_mode(wl, STATION_ACTIVE_MODE,
+ wl->basic_rate, true);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int wl1271_op_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wow)
+{
+ struct wl1271 *wl = hw->priv;
+ wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow);
+ wl->wow_enabled = !!wow;
+ if (wl->wow_enabled) {
+ int ret;
+ ret = wl1271_configure_suspend(wl);
+ if (ret < 0) {
+ wl1271_warning("couldn't prepare device to suspend");
+ return ret;
+ }
+ /* flush any remaining work */
+ wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
+ flush_delayed_work(&wl->scan_complete_work);
+
+ /*
+ * disable and re-enable interrupts in order to flush
+ * the threaded_irq
+ */
+ wl1271_disable_interrupts(wl);
+
+ /*
+ * set suspended flag to avoid triggering a new threaded_irq
+ * work. no need for spinlock as interrupts are disabled.
+ */
+ set_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+
+ wl1271_enable_interrupts(wl);
+ flush_work(&wl->tx_work);
+ flush_delayed_work(&wl->pspoll_work);
+ flush_delayed_work(&wl->elp_work);
+ }
+ return 0;
+}
+
+static int wl1271_op_resume(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d",
+ wl->wow_enabled);
+
+ /*
+ * re-enable irq_work enqueuing, and call irq_work directly if
+ * there is a pending work.
+ */
+ if (wl->wow_enabled) {
+ struct wl1271 *wl = hw->priv;
+ unsigned long flags;
+ bool run_irq_work = false;
+
+ spin_lock_irqsave(&wl->wl_lock, flags);
+ clear_bit(WL1271_FLAG_SUSPENDED, &wl->flags);
+ if (test_and_clear_bit(WL1271_FLAG_PENDING_WORK, &wl->flags))
+ run_irq_work = true;
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+
+ if (run_irq_work) {
+ wl1271_debug(DEBUG_MAC80211,
+ "run postponed irq_work directly");
+ wl1271_irq(0, wl);
+ wl1271_enable_interrupts(wl);
+ }
+
+ wl1271_configure_resume(wl);
+ }
+
+ return 0;
+}
+
static int wl1271_op_start(struct ieee80211_hw *hw)
{
wl1271_debug(DEBUG_MAC80211, "mac80211 start");
@@ -1440,7 +1650,8 @@
return ret;
}
-static void __wl1271_op_remove_interface(struct wl1271 *wl)
+static void __wl1271_op_remove_interface(struct wl1271 *wl,
+ bool reset_tx_queues)
{
int i;
@@ -1486,7 +1697,7 @@
mutex_lock(&wl->mutex);
/* let's notify MAC80211 about the remaining pending TX frames */
- wl1271_tx_reset(wl);
+ wl1271_tx_reset(wl, reset_tx_queues);
wl1271_power_off(wl);
memset(wl->bssid, 0, ETH_ALEN);
@@ -1514,6 +1725,7 @@
memset(wl->ap_hlid_map, 0, sizeof(wl->ap_hlid_map));
wl->ap_fw_ps_map = 0;
wl->ap_ps_map = 0;
+ wl->sched_scanning = false;
/*
* this is performed after the cancel_work calls and the associated
@@ -1547,7 +1759,7 @@
*/
if (wl->vif) {
WARN_ON(wl->vif != vif);
- __wl1271_op_remove_interface(wl);
+ __wl1271_op_remove_interface(wl, true);
}
mutex_unlock(&wl->mutex);
@@ -1716,6 +1928,13 @@
wl->session_counter++;
if (wl->session_counter >= SESSION_COUNTER_MAX)
wl->session_counter = 0;
+
+ /* The current firmware only supports sched_scan in idle */
+ if (wl->sched_scanning) {
+ wl1271_scan_sched_scan_stop(wl);
+ ieee80211_sched_scan_stopped(wl->hw);
+ }
+
ret = wl1271_dummy_join(wl);
if (ret < 0)
goto out;
@@ -2268,6 +2487,60 @@
return ret;
}
+static int wl1271_op_sched_scan_start(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_start");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl1271_scan_sched_scan_config(wl, req, ies);
+ if (ret < 0)
+ goto out_sleep;
+
+ ret = wl1271_scan_sched_scan_start(wl);
+ if (ret < 0)
+ goto out_sleep;
+
+ wl->sched_scanning = true;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return ret;
+}
+
+static void wl1271_op_sched_scan_stop(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct wl1271 *wl = hw->priv;
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271_op_sched_scan_stop");
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl1271_scan_sched_scan_stop(wl);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static int wl1271_op_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
{
struct wl1271 *wl = hw->priv;
@@ -2284,7 +2557,7 @@
if (ret < 0)
goto out;
- ret = wl1271_acx_frag_threshold(wl, (u16)value);
+ ret = wl1271_acx_frag_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_frag_threshold failed: %d", ret);
@@ -2312,7 +2585,7 @@
if (ret < 0)
goto out;
- ret = wl1271_acx_rts_threshold(wl, (u16) value);
+ ret = wl1271_acx_rts_threshold(wl, value);
if (ret < 0)
wl1271_warning("wl1271_op_set_rts_threshold failed: %d", ret);
@@ -2327,20 +2600,24 @@
static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
int offset)
{
- u8 *ptr = skb->data + offset;
+ u8 ssid_len;
+ const u8 *ptr = cfg80211_find_ie(WLAN_EID_SSID, skb->data + offset,
+ skb->len - offset);
- /* find the location of the ssid in the beacon */
- while (ptr < skb->data + skb->len) {
- if (ptr[0] == WLAN_EID_SSID) {
- wl->ssid_len = ptr[1];
- memcpy(wl->ssid, ptr+2, wl->ssid_len);
- return 0;
- }
- ptr += (ptr[1] + 2);
+ if (!ptr) {
+ wl1271_error("No SSID in IEs!");
+ return -ENOENT;
}
- wl1271_error("No SSID in IEs!\n");
- return -ENOENT;
+ ssid_len = ptr[1];
+ if (ssid_len > IEEE80211_MAX_SSID_LEN) {
+ wl1271_error("SSID is too long!");
+ return -EINVAL;
+ }
+
+ wl->ssid_len = ssid_len;
+ memcpy(wl->ssid, ptr+2, ssid_len);
+ return 0;
}
static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
@@ -2455,24 +2732,19 @@
if ((changed & BSS_CHANGED_BASIC_RATES)) {
u32 rates = bss_conf->basic_rates;
- struct conf_tx_rate_class mgmt_rc;
wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
wl->basic_rate = wl1271_tx_min_rate_get(wl);
- wl1271_debug(DEBUG_AP, "basic rates: 0x%x",
- wl->basic_rate_set);
- /* update the AP management rate policy with the new rates */
- mgmt_rc.enabled_rates = wl->basic_rate_set;
- mgmt_rc.long_retry_limit = 10;
- mgmt_rc.short_retry_limit = 10;
- mgmt_rc.aflags = 0;
- ret = wl1271_acx_ap_rate_policy(wl, &mgmt_rc,
- ACX_TX_AP_MODE_MGMT_RATE);
+ ret = wl1271_init_ap_rates(wl);
if (ret < 0) {
- wl1271_error("AP mgmt policy change failed %d", ret);
+ wl1271_error("AP rate policy change failed %d", ret);
goto out;
}
+
+ ret = wl1271_ap_init_templates(wl);
+ if (ret < 0)
+ goto out;
}
ret = wl1271_bss_beacon_info_changed(wl, vif, bss_conf, changed);
@@ -2505,6 +2777,24 @@
}
}
+ if (changed & BSS_CHANGED_IBSS) {
+ wl1271_debug(DEBUG_ADHOC, "ibss_joined: %d",
+ bss_conf->ibss_joined);
+
+ if (bss_conf->ibss_joined) {
+ u32 rates = bss_conf->basic_rates;
+ wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
+ rates);
+ wl->basic_rate = wl1271_tx_min_rate_get(wl);
+
+ /* by default, use 11b rates */
+ wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
+ ret = wl1271_acx_sta_rate_policies(wl);
+ if (ret < 0)
+ goto out;
+ }
+ }
+
ret = wl1271_bss_erp_info_changed(wl, bss_conf, changed);
if (ret < 0)
goto out;
@@ -2694,8 +2984,10 @@
}
} else {
/* use defaults when not associated */
+ bool was_assoc =
+ !!test_and_clear_bit(WL1271_FLAG_STA_ASSOCIATED,
+ &wl->flags);
clear_bit(WL1271_FLAG_STA_STATE_SENT, &wl->flags);
- clear_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags);
wl->aid = 0;
/* free probe-request template */
@@ -2721,8 +3013,10 @@
goto out;
/* restore the bssid filter and go to dummy bssid */
- wl1271_unjoin(wl);
- wl1271_dummy_join(wl);
+ if (was_assoc) {
+ wl1271_unjoin(wl);
+ wl1271_dummy_join(wl);
+ }
}
}
@@ -2954,12 +3248,6 @@
__clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
}
-bool wl1271_is_active_sta(struct wl1271 *wl, u8 hlid)
-{
- int id = hlid - WL1271_AP_STA_HLID_START;
- return test_bit(id, wl->ap_hlid_map);
-}
-
static int wl1271_op_sta_add(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
@@ -3104,6 +3392,28 @@
return ret;
}
+static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
+{
+ struct wl1271 *wl = hw->priv;
+ bool ret = false;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state == WL1271_STATE_OFF))
+ goto out;
+
+ /* packets are considered pending if in the TX queue or the FW */
+ ret = (wl->tx_queue_count > 0) || (wl->tx_frames_cnt > 0);
+
+ /* the above is appropriate for STA mode for PS purposes */
+ WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+out:
+ mutex_unlock(&wl->mutex);
+
+ return ret;
+}
+
/* can't be const, mac80211 writes to this */
static struct ieee80211_rate wl1271_rates[] = {
{ .bitrate = 10,
@@ -3340,12 +3650,16 @@
.stop = wl1271_op_stop,
.add_interface = wl1271_op_add_interface,
.remove_interface = wl1271_op_remove_interface,
+ .suspend = wl1271_op_suspend,
+ .resume = wl1271_op_resume,
.config = wl1271_op_config,
.prepare_multicast = wl1271_op_prepare_multicast,
.configure_filter = wl1271_op_configure_filter,
.tx = wl1271_op_tx,
.set_key = wl1271_op_set_key,
.hw_scan = wl1271_op_hw_scan,
+ .sched_scan_start = wl1271_op_sched_scan_start,
+ .sched_scan_stop = wl1271_op_sched_scan_stop,
.bss_info_changed = wl1271_op_bss_info_changed,
.set_frag_threshold = wl1271_op_set_frag_threshold,
.set_rts_threshold = wl1271_op_set_rts_threshold,
@@ -3355,6 +3669,7 @@
.sta_add = wl1271_op_sta_add,
.sta_remove = wl1271_op_sta_remove,
.ampdu_action = wl1271_op_ampdu_action,
+ .tx_frames_pending = wl1271_tx_frames_pending,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -3542,6 +3857,8 @@
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_SUPPORTS_CQM_RSSI |
+ IEEE80211_HW_REPORTS_TX_ACK_STATUS |
+ IEEE80211_HW_SPECTRUM_MGMT |
IEEE80211_HW_AP_LINK_PS;
wl->hw->wiphy->cipher_suites = cipher_suites;
@@ -3663,6 +3980,7 @@
wl->ap_fw_ps_map = 0;
wl->quirks = 0;
wl->platform_quirks = 0;
+ wl->sched_scanning = false;
memset(wl->tx_frames_map, 0, sizeof(wl->tx_frames_map));
for (i = 0; i < ACX_TX_DESCRIPTORS; i++)
diff --git a/drivers/net/wireless/wl12xx/ps.c b/drivers/net/wireless/wl12xx/ps.c
index b8deada..b59b6771 100644
--- a/drivers/net/wireless/wl12xx/ps.c
+++ b/drivers/net/wireless/wl12xx/ps.c
@@ -43,6 +43,10 @@
if (unlikely(wl->state == WL1271_STATE_OFF))
goto out;
+ /* our work might have been already cancelled */
+ if (unlikely(!test_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ goto out;
+
if (test_bit(WL1271_FLAG_IN_ELP, &wl->flags) ||
(!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
!test_bit(WL1271_FLAG_IDLE, &wl->flags)))
@@ -61,12 +65,16 @@
/* Routines to toggle sleep mode while in ELP */
void wl1271_ps_elp_sleep(struct wl1271 *wl)
{
- if (test_bit(WL1271_FLAG_PSM, &wl->flags) ||
- test_bit(WL1271_FLAG_IDLE, &wl->flags)) {
- cancel_delayed_work(&wl->elp_work);
- ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
- msecs_to_jiffies(ELP_ENTRY_DELAY));
- }
+ /* we shouldn't get consecutive sleep requests */
+ if (WARN_ON(test_and_set_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags)))
+ return;
+
+ if (!test_bit(WL1271_FLAG_PSM, &wl->flags) &&
+ !test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return;
+
+ ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
+ msecs_to_jiffies(ELP_ENTRY_DELAY));
}
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
@@ -77,6 +85,16 @@
u32 start_time = jiffies;
bool pending = false;
+ /*
+ * we might try to wake up even if we didn't go to sleep
+ * before (e.g. on boot)
+ */
+ if (!test_and_clear_bit(WL1271_FLAG_ELP_REQUESTED, &wl->flags))
+ return 0;
+
+ /* don't cancel_sync as it might contend for a mutex and deadlock */
+ cancel_delayed_work(&wl->elp_work);
+
if (!test_bit(WL1271_FLAG_IN_ELP, &wl->flags))
return 0;
diff --git a/drivers/net/wireless/wl12xx/ps.h b/drivers/net/wireless/wl12xx/ps.h
index c41bd0a..25eb9bc 100644
--- a/drivers/net/wireless/wl12xx/ps.h
+++ b/drivers/net/wireless/wl12xx/ps.h
@@ -35,4 +35,6 @@
void wl1271_ps_link_start(struct wl1271 *wl, u8 hlid, bool clean_queues);
void wl1271_ps_link_end(struct wl1271 *wl, u8 hlid);
+#define WL1271_PS_COMPLETE_TIMEOUT 500
+
#endif /* __WL1271_PS_H__ */
diff --git a/drivers/net/wireless/wl12xx/rx.c b/drivers/net/wireless/wl12xx/rx.c
index 2a58149..7009103 100644
--- a/drivers/net/wireless/wl12xx/rx.c
+++ b/drivers/net/wireless/wl12xx/rx.c
@@ -76,12 +76,15 @@
status->band);
if (desc->flags & WL1271_RX_DESC_ENCRYPT_MASK) {
- status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
+ u8 desc_err_code = desc->status & WL1271_RX_DESC_STATUS_MASK;
- if (likely(!(desc->status & WL1271_RX_DESC_DECRYPT_FAIL)))
- status->flag |= RX_FLAG_DECRYPTED;
- if (unlikely(desc->status & WL1271_RX_DESC_MIC_FAIL))
+ status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED |
+ RX_FLAG_DECRYPTED;
+
+ if (unlikely(desc_err_code == WL1271_RX_DESC_MIC_FAIL)) {
status->flag |= RX_FLAG_MMIC_ERROR;
+ wl1271_warning("Michael MIC error");
+ }
}
}
@@ -100,6 +103,25 @@
if (unlikely(wl->state == WL1271_STATE_PLT))
return -EINVAL;
+ /* the data read starts with the descriptor */
+ desc = (struct wl1271_rx_descriptor *) data;
+
+ switch (desc->status & WL1271_RX_DESC_STATUS_MASK) {
+ /* discard corrupted packets */
+ case WL1271_RX_DESC_DRIVER_RX_Q_FAIL:
+ case WL1271_RX_DESC_DECRYPT_FAIL:
+ wl1271_warning("corrupted packet in RX with status: 0x%x",
+ desc->status & WL1271_RX_DESC_STATUS_MASK);
+ return -EINVAL;
+ case WL1271_RX_DESC_SUCCESS:
+ case WL1271_RX_DESC_MIC_FAIL:
+ break;
+ default:
+ wl1271_error("invalid RX descriptor status: 0x%x",
+ desc->status & WL1271_RX_DESC_STATUS_MASK);
+ return -EINVAL;
+ }
+
skb = __dev_alloc_skb(length, GFP_KERNEL);
if (!skb) {
wl1271_error("Couldn't allocate RX frame");
@@ -109,9 +131,6 @@
buf = skb_put(skb, length);
memcpy(buf, data, length);
- /* the data read starts with the descriptor */
- desc = (struct wl1271_rx_descriptor *) buf;
-
/* now we pull the descriptor out of the buffer */
skb_pull(skb, sizeof(*desc));
@@ -121,7 +140,8 @@
wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
- wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb, skb->len,
+ wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
+ skb->len - desc->pad_len,
beacon ? "beacon" : "");
skb_trim(skb, skb->len - desc->pad_len);
diff --git a/drivers/net/wireless/wl12xx/scan.c b/drivers/net/wireless/wl12xx/scan.c
index 5d0544c..f37e5a3 100644
--- a/drivers/net/wireless/wl12xx/scan.c
+++ b/drivers/net/wireless/wl12xx/scan.c
@@ -320,3 +320,246 @@
return 0;
}
+
+static int
+wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct conn_scan_ch_params *channels,
+ u32 band, bool radar, bool passive,
+ int start)
+{
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int i, j;
+ u32 flags;
+
+ for (i = 0, j = start;
+ i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
+ i++) {
+ flags = req->channels[i]->flags;
+
+ if (!(flags & IEEE80211_CHAN_DISABLED) &&
+ ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) &&
+ ((flags & IEEE80211_CHAN_RADAR) == radar) &&
+ (req->channels[i]->band == band)) {
+ wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
+ req->channels[i]->band,
+ req->channels[i]->center_freq);
+ wl1271_debug(DEBUG_SCAN, "hw_value %d, flags %X",
+ req->channels[i]->hw_value,
+ req->channels[i]->flags);
+ wl1271_debug(DEBUG_SCAN, "max_power %d",
+ req->channels[i]->max_power);
+
+ if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+ channels[j].passive_duration =
+ cpu_to_le16(c->dwell_time_passive);
+ } else {
+ channels[j].min_duration =
+ cpu_to_le16(c->min_dwell_time_active);
+ channels[j].max_duration =
+ cpu_to_le16(c->max_dwell_time_active);
+ }
+ channels[j].tx_power_att = req->channels[j]->max_power;
+ channels[j].channel = req->channels[i]->hw_value;
+
+ j++;
+ }
+ }
+
+ return j - start;
+}
+
+static int
+wl1271_scan_sched_scan_channels(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct wl1271_cmd_sched_scan_config *cfg)
+{
+ int idx = 0;
+
+ cfg->passive[0] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_2GHZ,
+ false, true, idx);
+ idx += cfg->passive[0];
+
+ cfg->active[0] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_2GHZ,
+ false, false, idx);
+ idx += cfg->active[0];
+
+ cfg->passive[1] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ false, true, idx);
+ idx += cfg->passive[1];
+
+ cfg->active[1] =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ false, false, 14);
+ idx += cfg->active[1];
+
+ cfg->dfs =
+ wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
+ IEEE80211_BAND_5GHZ,
+ true, false, idx);
+ idx += cfg->dfs;
+
+ wl1271_debug(DEBUG_SCAN, " 2.4GHz: active %d passive %d",
+ cfg->active[0], cfg->passive[0]);
+ wl1271_debug(DEBUG_SCAN, " 5GHz: active %d passive %d",
+ cfg->active[1], cfg->passive[1]);
+
+ return idx;
+}
+
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ struct wl1271_cmd_sched_scan_config *cfg = NULL;
+ struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
+ int i, total_channels, ret;
+
+ wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
+
+ cfg = kzalloc(sizeof(*cfg), GFP_KERNEL);
+ if (!cfg)
+ return -ENOMEM;
+
+ cfg->rssi_threshold = c->rssi_threshold;
+ cfg->snr_threshold = c->snr_threshold;
+ cfg->n_probe_reqs = c->num_probe_reqs;
+ /* cycles set to 0 it means infinite (until manually stopped) */
+ cfg->cycles = 0;
+ /* report APs when at least 1 is found */
+ cfg->report_after = 1;
+ /* don't stop scanning automatically when something is found */
+ cfg->terminate = 0;
+ cfg->tag = WL1271_SCAN_DEFAULT_TAG;
+ /* don't filter on BSS type */
+ cfg->bss_type = SCAN_BSS_TYPE_ANY;
+ /* currently NL80211 supports only a single interval */
+ for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
+ cfg->intervals[i] = cpu_to_le32(req->interval);
+
+ if (req->ssids[0].ssid_len && req->ssids[0].ssid) {
+ cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
+ cfg->ssid_len = req->ssids[0].ssid_len;
+ memcpy(cfg->ssid, req->ssids[0].ssid,
+ req->ssids[0].ssid_len);
+ } else {
+ cfg->filter_type = SCAN_SSID_FILTER_ANY;
+ cfg->ssid_len = 0;
+ }
+
+ total_channels = wl1271_scan_sched_scan_channels(wl, req, cfg);
+ if (total_channels == 0) {
+ wl1271_error("scan channel list is empty");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (cfg->active[0]) {
+ ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[IEEE80211_BAND_2GHZ],
+ ies->len[IEEE80211_BAND_2GHZ],
+ IEEE80211_BAND_2GHZ);
+ if (ret < 0) {
+ wl1271_error("2.4GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ if (cfg->active[1]) {
+ ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
+ req->ssids[0].ssid_len,
+ ies->ie[IEEE80211_BAND_5GHZ],
+ ies->len[IEEE80211_BAND_5GHZ],
+ IEEE80211_BAND_5GHZ);
+ if (ret < 0) {
+ wl1271_error("5GHz PROBE request template failed");
+ goto out;
+ }
+ }
+
+ wl1271_dump(DEBUG_SCAN, "SCAN_CFG: ", cfg, sizeof(*cfg));
+
+ ret = wl1271_cmd_send(wl, CMD_CONNECTION_SCAN_CFG, cfg,
+ sizeof(*cfg), 0);
+ if (ret < 0) {
+ wl1271_error("SCAN configuration failed");
+ goto out;
+ }
+out:
+ kfree(cfg);
+ return ret;
+}
+
+int wl1271_scan_sched_scan_start(struct wl1271 *wl)
+{
+ struct wl1271_cmd_sched_scan_start *start;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan start");
+
+ if (wl->bss_type != BSS_TYPE_STA_BSS)
+ return -EOPNOTSUPP;
+
+ if (!test_bit(WL1271_FLAG_IDLE, &wl->flags))
+ return -EBUSY;
+
+ start = kzalloc(sizeof(*start), GFP_KERNEL);
+ if (!start)
+ return -ENOMEM;
+
+ start->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ ret = wl1271_cmd_send(wl, CMD_START_PERIODIC_SCAN, start,
+ sizeof(*start), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send scan start command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(start);
+ return ret;
+}
+
+void wl1271_scan_sched_scan_results(struct wl1271 *wl)
+{
+ wl1271_debug(DEBUG_SCAN, "got periodic scan results");
+
+ ieee80211_sched_scan_results(wl->hw);
+}
+
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl)
+{
+ struct wl1271_cmd_sched_scan_stop *stop;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd periodic scan stop");
+
+ /* FIXME: what to do if alloc'ing to stop fails? */
+ stop = kzalloc(sizeof(*stop), GFP_KERNEL);
+ if (!stop) {
+ wl1271_error("failed to alloc memory to send sched scan stop");
+ return;
+ }
+
+ stop->tag = WL1271_SCAN_DEFAULT_TAG;
+
+ ret = wl1271_cmd_send(wl, CMD_STOP_PERIODIC_SCAN, stop,
+ sizeof(*stop), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send sched scan stop command");
+ goto out_free;
+ }
+ wl->sched_scanning = false;
+
+out_free:
+ kfree(stop);
+}
diff --git a/drivers/net/wireless/wl12xx/scan.h b/drivers/net/wireless/wl12xx/scan.h
index 421a750..c833195 100644
--- a/drivers/net/wireless/wl12xx/scan.h
+++ b/drivers/net/wireless/wl12xx/scan.h
@@ -33,6 +33,12 @@
const u8 *ie, size_t ie_len, u8 band);
void wl1271_scan_stm(struct wl1271 *wl);
void wl1271_scan_complete_work(struct work_struct *work);
+int wl1271_scan_sched_scan_config(struct wl1271 *wl,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+int wl1271_scan_sched_scan_start(struct wl1271 *wl);
+void wl1271_scan_sched_scan_stop(struct wl1271 *wl);
+void wl1271_scan_sched_scan_results(struct wl1271 *wl);
#define WL1271_SCAN_MAX_CHANNELS 24
#define WL1271_SCAN_DEFAULT_TAG 1
@@ -106,4 +112,112 @@
__le32 timeout;
} __packed;
+#define MAX_CHANNELS_ALL_BANDS 41
+#define SCAN_MAX_CYCLE_INTERVALS 16
+#define SCAN_MAX_BANDS 3
+
+enum {
+ SCAN_CHANNEL_TYPE_2GHZ_PASSIVE,
+ SCAN_CHANNEL_TYPE_2GHZ_ACTIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_PASSIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_ACTIVE,
+ SCAN_CHANNEL_TYPE_5GHZ_DFS,
+};
+
+enum {
+ SCAN_SSID_FILTER_ANY = 0,
+ SCAN_SSID_FILTER_SPECIFIC = 1,
+ SCAN_SSID_FILTER_LIST = 2,
+ SCAN_SSID_FILTER_DISABLED = 3
+};
+
+enum {
+ SCAN_BSS_TYPE_INDEPENDENT,
+ SCAN_BSS_TYPE_INFRASTRUCTURE,
+ SCAN_BSS_TYPE_ANY,
+};
+
+struct conn_scan_ch_params {
+ __le16 min_duration;
+ __le16 max_duration;
+ __le16 passive_duration;
+
+ u8 channel;
+ u8 tx_power_att;
+
+ /* bit 0: DFS channel; bit 1: DFS enabled */
+ u8 flags;
+
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_config {
+ struct wl1271_cmd_header header;
+
+ __le32 intervals[SCAN_MAX_CYCLE_INTERVALS];
+
+ s8 rssi_threshold; /* for filtering (in dBm) */
+ s8 snr_threshold; /* for filtering (in dB) */
+
+ u8 cycles; /* maximum number of scan cycles */
+ u8 report_after; /* report when this number of results are received */
+ u8 terminate; /* stop scanning after reporting */
+
+ u8 tag;
+ u8 bss_type; /* for filtering */
+ u8 filter_type;
+
+ u8 ssid_len; /* For SCAN_SSID_FILTER_SPECIFIC */
+ u8 ssid[IW_ESSID_MAX_SIZE];
+
+ u8 n_probe_reqs; /* Number of probes requests per channel */
+
+ u8 passive[SCAN_MAX_BANDS];
+ u8 active[SCAN_MAX_BANDS];
+
+ u8 dfs;
+
+ u8 padding[3];
+
+ struct conn_scan_ch_params channels[MAX_CHANNELS_ALL_BANDS];
+} __packed;
+
+
+#define SCHED_SCAN_MAX_SSIDS 8
+
+enum {
+ SCAN_SSID_TYPE_PUBLIC = 0,
+ SCAN_SSID_TYPE_HIDDEN = 1,
+};
+
+struct wl1271_ssid {
+ u8 type;
+ u8 len;
+ u8 ssid[IW_ESSID_MAX_SIZE];
+ /* u8 padding[2]; */
+} __packed;
+
+struct wl1271_cmd_sched_scan_ssid_list {
+ struct wl1271_cmd_header header;
+
+ u8 n_ssids;
+ struct wl1271_ssid ssids[SCHED_SCAN_MAX_SSIDS];
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_start {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 padding[3];
+} __packed;
+
+struct wl1271_cmd_sched_scan_stop {
+ struct wl1271_cmd_header header;
+
+ u8 tag;
+ u8 padding[3];
+} __packed;
+
+
#endif /* __WL1271_SCAN_H__ */
diff --git a/drivers/net/wireless/wl12xx/sdio.c b/drivers/net/wireless/wl12xx/sdio.c
index bcd4ad7..92d29a8 100644
--- a/drivers/net/wireless/wl12xx/sdio.c
+++ b/drivers/net/wireless/wl12xx/sdio.c
@@ -82,6 +82,16 @@
complete(wl->elp_compl);
wl->elp_compl = NULL;
}
+
+ if (test_bit(WL1271_FLAG_SUSPENDED, &wl->flags)) {
+ /* don't enqueue a work right now. mark it as pending */
+ set_bit(WL1271_FLAG_PENDING_WORK, &wl->flags);
+ wl1271_debug(DEBUG_IRQ, "should not enqueue work");
+ disable_irq_nosync(wl->irq);
+ pm_wakeup_event(wl1271_sdio_wl_to_dev(wl), 0);
+ spin_unlock_irqrestore(&wl->wl_lock, flags);
+ return IRQ_HANDLED;
+ }
spin_unlock_irqrestore(&wl->wl_lock, flags);
return IRQ_WAKE_THREAD;
@@ -221,6 +231,7 @@
const struct wl12xx_platform_data *wlan_data;
struct wl1271 *wl;
unsigned long irqflags;
+ mmc_pm_flag_t mmcflags;
int ret;
/* We are only able to handle the wlan function */
@@ -267,8 +278,18 @@
goto out_free;
}
+ enable_irq_wake(wl->irq);
+ device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 1);
+
disable_irq(wl->irq);
+ /* if sdio can keep power while host is suspended, enable wow */
+ mmcflags = sdio_get_host_pm_caps(func);
+ wl1271_debug(DEBUG_SDIO, "sdio PM caps = 0x%x", mmcflags);
+
+ if (mmcflags & MMC_PM_KEEP_POWER)
+ hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY;
+
ret = wl1271_init_ieee80211(wl);
if (ret)
goto out_irq;
@@ -303,6 +324,8 @@
pm_runtime_get_noresume(&func->dev);
wl1271_unregister_hw(wl);
+ device_init_wakeup(wl1271_sdio_wl_to_dev(wl), 0);
+ disable_irq_wake(wl->irq);
free_irq(wl->irq, wl);
wl1271_free_hw(wl);
}
@@ -311,11 +334,50 @@
{
/* Tell MMC/SDIO core it's OK to power down the card
* (if it isn't already), but not to remove it completely */
- return 0;
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wl1271 *wl = sdio_get_drvdata(func);
+ mmc_pm_flag_t sdio_flags;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271 suspend. wow_enabled: %d",
+ wl->wow_enabled);
+
+ /* check whether sdio should keep power */
+ if (wl->wow_enabled) {
+ sdio_flags = sdio_get_host_pm_caps(func);
+
+ if (!(sdio_flags & MMC_PM_KEEP_POWER)) {
+ wl1271_error("can't keep power while host "
+ "is suspended");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* keep power while host suspended */
+ ret = sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
+ if (ret) {
+ wl1271_error("error while trying to keep power");
+ goto out;
+ }
+
+ /* release host */
+ sdio_release_host(func);
+ }
+out:
+ return ret;
}
static int wl1271_resume(struct device *dev)
{
+ struct sdio_func *func = dev_to_sdio_func(dev);
+ struct wl1271 *wl = sdio_get_drvdata(func);
+
+ wl1271_debug(DEBUG_MAC80211, "wl1271 resume");
+ if (wl->wow_enabled) {
+ /* claim back host */
+ sdio_claim_host(func);
+ }
+
return 0;
}
diff --git a/drivers/net/wireless/wl12xx/tx.c b/drivers/net/wireless/wl12xx/tx.c
index 7a3339f..ca3ab1c 100644
--- a/drivers/net/wireless/wl12xx/tx.c
+++ b/drivers/net/wireless/wl12xx/tx.c
@@ -65,6 +65,9 @@
static void wl1271_free_tx_id(struct wl1271 *wl, int id)
{
if (__test_and_clear_bit(id, wl->tx_frames_map)) {
+ if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS))
+ clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
+
wl->tx_frames[id] = NULL;
wl->tx_frames_cnt--;
}
@@ -630,7 +633,7 @@
wl1271_tx_work_locked(wl);
- wl1271_ps_elp_wakeup(wl);
+ wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
}
@@ -766,8 +769,8 @@
wl1271_handle_tx_low_watermark(wl);
}
-/* caller must hold wl->mutex */
-void wl1271_tx_reset(struct wl1271 *wl)
+/* caller must hold wl->mutex and TX must be stopped */
+void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
{
int i;
struct sk_buff *skb;
@@ -803,8 +806,10 @@
/*
* Make sure the driver is at a consistent state, in case this
* function is called from a context other than interface removal.
+ * This call will always wake the TX queues.
*/
- wl1271_handle_tx_low_watermark(wl);
+ if (reset_tx_queues)
+ wl1271_handle_tx_low_watermark(wl);
for (i = 0; i < ACX_TX_DESCRIPTORS; i++) {
if (wl->tx_frames[i] == NULL)
diff --git a/drivers/net/wireless/wl12xx/tx.h b/drivers/net/wireless/wl12xx/tx.h
index fc7835c..832f925 100644
--- a/drivers/net/wireless/wl12xx/tx.h
+++ b/drivers/net/wireless/wl12xx/tx.h
@@ -185,7 +185,7 @@
void wl1271_tx_work(struct work_struct *work);
void wl1271_tx_work_locked(struct wl1271 *wl);
void wl1271_tx_complete(struct wl1271 *wl);
-void wl1271_tx_reset(struct wl1271 *wl);
+void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
void wl1271_tx_flush(struct wl1271 *wl);
u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
diff --git a/drivers/net/wireless/wl12xx/wl12xx.h b/drivers/net/wireless/wl12xx/wl12xx.h
index 7c521af..fbe8f46 100644
--- a/drivers/net/wireless/wl12xx/wl12xx.h
+++ b/drivers/net/wireless/wl12xx/wl12xx.h
@@ -172,6 +172,7 @@
#define WL1271_PS_STA_MAX_BLOCKS (2 * 9)
#define WL1271_AP_BSS_INDEX 0
+#define WL1271_AP_DEF_INACTIV_SEC 300
#define WL1271_AP_DEF_BEACON_EXP 20
#define ACX_TX_DESCRIPTORS 32
@@ -345,17 +346,19 @@
WL1271_FLAG_TX_QUEUE_STOPPED,
WL1271_FLAG_TX_PENDING,
WL1271_FLAG_IN_ELP,
+ WL1271_FLAG_ELP_REQUESTED,
WL1271_FLAG_PSM,
WL1271_FLAG_PSM_REQUESTED,
WL1271_FLAG_IRQ_RUNNING,
WL1271_FLAG_IDLE,
- WL1271_FLAG_IDLE_REQUESTED,
WL1271_FLAG_PSPOLL_FAILURE,
WL1271_FLAG_STA_STATE_SENT,
WL1271_FLAG_FW_TX_BUSY,
WL1271_FLAG_AP_STARTED,
WL1271_FLAG_IF_INITIALIZED,
WL1271_FLAG_DUMMY_PACKET_PENDING,
+ WL1271_FLAG_SUSPENDED,
+ WL1271_FLAG_PENDING_WORK,
};
struct wl1271_link {
@@ -478,6 +481,8 @@
struct wl1271_scan scan;
struct delayed_work scan_complete_work;
+ bool sched_scanning;
+
/* probe-req template for the current AP */
struct sk_buff *probereq;
@@ -508,6 +513,7 @@
unsigned int rx_filter;
struct completion *elp_compl;
+ struct completion *ps_compl;
struct delayed_work elp_work;
struct delayed_work pspoll_work;
@@ -562,6 +568,12 @@
int tcxo_clock;
/*
+ * wowlan trigger was configured during suspend.
+ * (currently, only "ANY" trigger is supported)
+ */
+ bool wow_enabled;
+
+ /*
* AP-mode - links indexed by HLID. The global and broadcast links
* are always active.
*/
diff --git a/drivers/ssb/driver_pcicore.c b/drivers/ssb/driver_pcicore.c
index 8fde122..82feb34 100644
--- a/drivers/ssb/driver_pcicore.c
+++ b/drivers/ssb/driver_pcicore.c
@@ -21,8 +21,6 @@
static void ssb_pcie_mdio_write(struct ssb_pcicore *pc, u8 device,
u8 address, u16 data);
-static void ssb_commit_settings(struct ssb_bus *bus);
-
static inline
u32 pcicore_read32(struct ssb_pcicore *pc, u16 offset)
{
@@ -659,30 +657,6 @@
pcicore_write32(pc, mdio_control, 0);
}
-static void ssb_broadcast_value(struct ssb_device *dev,
- u32 address, u32 data)
-{
- /* This is used for both, PCI and ChipCommon core, so be careful. */
- BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
- BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
-
- ssb_write32(dev, SSB_PCICORE_BCAST_ADDR, address);
- ssb_read32(dev, SSB_PCICORE_BCAST_ADDR); /* flush */
- ssb_write32(dev, SSB_PCICORE_BCAST_DATA, data);
- ssb_read32(dev, SSB_PCICORE_BCAST_DATA); /* flush */
-}
-
-static void ssb_commit_settings(struct ssb_bus *bus)
-{
- struct ssb_device *dev;
-
- dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
- if (WARN_ON(!dev))
- return;
- /* This forces an update of the cached registers. */
- ssb_broadcast_value(dev, 0xFD8, 0);
-}
-
int ssb_pcicore_dev_irqvecs_enable(struct ssb_pcicore *pc,
struct ssb_device *dev)
{
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index ad3da93..f8a13f8 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -1329,6 +1329,37 @@
}
EXPORT_SYMBOL(ssb_bus_powerup);
+static void ssb_broadcast_value(struct ssb_device *dev,
+ u32 address, u32 data)
+{
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ /* This is used for both, PCI and ChipCommon core, so be careful. */
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_ADDR != SSB_CHIPCO_BCAST_ADDR);
+ BUILD_BUG_ON(SSB_PCICORE_BCAST_DATA != SSB_CHIPCO_BCAST_DATA);
+#endif
+
+ ssb_write32(dev, SSB_CHIPCO_BCAST_ADDR, address);
+ ssb_read32(dev, SSB_CHIPCO_BCAST_ADDR); /* flush */
+ ssb_write32(dev, SSB_CHIPCO_BCAST_DATA, data);
+ ssb_read32(dev, SSB_CHIPCO_BCAST_DATA); /* flush */
+}
+
+void ssb_commit_settings(struct ssb_bus *bus)
+{
+ struct ssb_device *dev;
+
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+ dev = bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev;
+#else
+ dev = bus->chipco.dev;
+#endif
+ if (WARN_ON(!dev))
+ return;
+ /* This forces an update of the cached registers. */
+ ssb_broadcast_value(dev, 0xFD8, 0);
+}
+EXPORT_SYMBOL(ssb_commit_settings);
+
u32 ssb_admatch_base(u32 adm)
{
u32 base = 0;
diff --git a/drivers/ssb/scan.c b/drivers/ssb/scan.c
index 7dca719..45e5bab 100644
--- a/drivers/ssb/scan.c
+++ b/drivers/ssb/scan.c
@@ -258,7 +258,10 @@
#ifdef CONFIG_SSB_PCIHOST
if (bus->bustype == SSB_BUSTYPE_PCI) {
if (bus->host_pci->vendor == PCI_VENDOR_ID_BROADCOM &&
- bus->host_pci->device == 0x4324)
+ ((bus->host_pci->device == 0x4313) ||
+ (bus->host_pci->device == 0x431A) ||
+ (bus->host_pci->device == 0x4321) ||
+ (bus->host_pci->device == 0x4324)))
return 1;
}
#endif /* CONFIG_SSB_PCIHOST */
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
new file mode 100644
index 0000000..08763e4
--- /dev/null
+++ b/include/linux/bcma/bcma.h
@@ -0,0 +1,224 @@
+#ifndef LINUX_BCMA_H_
+#define LINUX_BCMA_H_
+
+#include <linux/pci.h>
+#include <linux/mod_devicetable.h>
+
+#include <linux/bcma/bcma_driver_chipcommon.h>
+#include <linux/bcma/bcma_driver_pci.h>
+
+#include "bcma_regs.h"
+
+struct bcma_device;
+struct bcma_bus;
+
+enum bcma_hosttype {
+ BCMA_HOSTTYPE_NONE,
+ BCMA_HOSTTYPE_PCI,
+ BCMA_HOSTTYPE_SDIO,
+};
+
+struct bcma_chipinfo {
+ u16 id;
+ u8 rev;
+ u8 pkg;
+};
+
+struct bcma_host_ops {
+ u8 (*read8)(struct bcma_device *core, u16 offset);
+ u16 (*read16)(struct bcma_device *core, u16 offset);
+ u32 (*read32)(struct bcma_device *core, u16 offset);
+ void (*write8)(struct bcma_device *core, u16 offset, u8 value);
+ void (*write16)(struct bcma_device *core, u16 offset, u16 value);
+ void (*write32)(struct bcma_device *core, u16 offset, u32 value);
+ /* Agent ops */
+ u32 (*aread32)(struct bcma_device *core, u16 offset);
+ void (*awrite32)(struct bcma_device *core, u16 offset, u32 value);
+};
+
+/* Core manufacturers */
+#define BCMA_MANUF_ARM 0x43B
+#define BCMA_MANUF_MIPS 0x4A7
+#define BCMA_MANUF_BCM 0x4BF
+
+/* Core class values. */
+#define BCMA_CL_SIM 0x0
+#define BCMA_CL_EROM 0x1
+#define BCMA_CL_CORESIGHT 0x9
+#define BCMA_CL_VERIF 0xB
+#define BCMA_CL_OPTIMO 0xD
+#define BCMA_CL_GEN 0xE
+#define BCMA_CL_PRIMECELL 0xF
+
+/* Core-ID values. */
+#define BCMA_CORE_OOB_ROUTER 0x367 /* Out of band */
+#define BCMA_CORE_INVALID 0x700
+#define BCMA_CORE_CHIPCOMMON 0x800
+#define BCMA_CORE_ILINE20 0x801
+#define BCMA_CORE_SRAM 0x802
+#define BCMA_CORE_SDRAM 0x803
+#define BCMA_CORE_PCI 0x804
+#define BCMA_CORE_MIPS 0x805
+#define BCMA_CORE_ETHERNET 0x806
+#define BCMA_CORE_V90 0x807
+#define BCMA_CORE_USB11_HOSTDEV 0x808
+#define BCMA_CORE_ADSL 0x809
+#define BCMA_CORE_ILINE100 0x80A
+#define BCMA_CORE_IPSEC 0x80B
+#define BCMA_CORE_UTOPIA 0x80C
+#define BCMA_CORE_PCMCIA 0x80D
+#define BCMA_CORE_INTERNAL_MEM 0x80E
+#define BCMA_CORE_MEMC_SDRAM 0x80F
+#define BCMA_CORE_OFDM 0x810
+#define BCMA_CORE_EXTIF 0x811
+#define BCMA_CORE_80211 0x812
+#define BCMA_CORE_PHY_A 0x813
+#define BCMA_CORE_PHY_B 0x814
+#define BCMA_CORE_PHY_G 0x815
+#define BCMA_CORE_MIPS_3302 0x816
+#define BCMA_CORE_USB11_HOST 0x817
+#define BCMA_CORE_USB11_DEV 0x818
+#define BCMA_CORE_USB20_HOST 0x819
+#define BCMA_CORE_USB20_DEV 0x81A
+#define BCMA_CORE_SDIO_HOST 0x81B
+#define BCMA_CORE_ROBOSWITCH 0x81C
+#define BCMA_CORE_PARA_ATA 0x81D
+#define BCMA_CORE_SATA_XORDMA 0x81E
+#define BCMA_CORE_ETHERNET_GBIT 0x81F
+#define BCMA_CORE_PCIE 0x820
+#define BCMA_CORE_PHY_N 0x821
+#define BCMA_CORE_SRAM_CTL 0x822
+#define BCMA_CORE_MINI_MACPHY 0x823
+#define BCMA_CORE_ARM_1176 0x824
+#define BCMA_CORE_ARM_7TDMI 0x825
+#define BCMA_CORE_PHY_LP 0x826
+#define BCMA_CORE_PMU 0x827
+#define BCMA_CORE_PHY_SSN 0x828
+#define BCMA_CORE_SDIO_DEV 0x829
+#define BCMA_CORE_ARM_CM3 0x82A
+#define BCMA_CORE_PHY_HT 0x82B
+#define BCMA_CORE_MIPS_74K 0x82C
+#define BCMA_CORE_MAC_GBIT 0x82D
+#define BCMA_CORE_DDR12_MEM_CTL 0x82E
+#define BCMA_CORE_PCIE_RC 0x82F /* PCIe Root Complex */
+#define BCMA_CORE_OCP_OCP_BRIDGE 0x830
+#define BCMA_CORE_SHARED_COMMON 0x831
+#define BCMA_CORE_OCP_AHB_BRIDGE 0x832
+#define BCMA_CORE_SPI_HOST 0x833
+#define BCMA_CORE_I2S 0x834
+#define BCMA_CORE_SDR_DDR1_MEM_CTL 0x835 /* SDR/DDR1 memory controller core */
+#define BCMA_CORE_SHIM 0x837 /* SHIM component in ubus/6362 */
+#define BCMA_CORE_DEFAULT 0xFFF
+
+#define BCMA_MAX_NR_CORES 16
+
+struct bcma_device {
+ struct bcma_bus *bus;
+ struct bcma_device_id id;
+
+ struct device dev;
+ bool dev_registered;
+
+ u8 core_index;
+
+ u32 addr;
+ u32 wrap;
+
+ void *drvdata;
+ struct list_head list;
+};
+
+static inline void *bcma_get_drvdata(struct bcma_device *core)
+{
+ return core->drvdata;
+}
+static inline void bcma_set_drvdata(struct bcma_device *core, void *drvdata)
+{
+ core->drvdata = drvdata;
+}
+
+struct bcma_driver {
+ const char *name;
+ const struct bcma_device_id *id_table;
+
+ int (*probe)(struct bcma_device *dev);
+ void (*remove)(struct bcma_device *dev);
+ int (*suspend)(struct bcma_device *dev, pm_message_t state);
+ int (*resume)(struct bcma_device *dev);
+ void (*shutdown)(struct bcma_device *dev);
+
+ struct device_driver drv;
+};
+extern
+int __bcma_driver_register(struct bcma_driver *drv, struct module *owner);
+static inline int bcma_driver_register(struct bcma_driver *drv)
+{
+ return __bcma_driver_register(drv, THIS_MODULE);
+}
+extern void bcma_driver_unregister(struct bcma_driver *drv);
+
+struct bcma_bus {
+ /* The MMIO area. */
+ void __iomem *mmio;
+
+ const struct bcma_host_ops *ops;
+
+ enum bcma_hosttype hosttype;
+ union {
+ /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
+ struct pci_dev *host_pci;
+ /* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
+ struct sdio_func *host_sdio;
+ };
+
+ struct bcma_chipinfo chipinfo;
+
+ struct bcma_device *mapped_core;
+ struct list_head cores;
+ u8 nr_cores;
+
+ struct bcma_drv_cc drv_cc;
+ struct bcma_drv_pci drv_pci;
+};
+
+extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
+{
+ return core->bus->ops->read8(core, offset);
+}
+extern inline u32 bcma_read16(struct bcma_device *core, u16 offset)
+{
+ return core->bus->ops->read16(core, offset);
+}
+extern inline u32 bcma_read32(struct bcma_device *core, u16 offset)
+{
+ return core->bus->ops->read32(core, offset);
+}
+extern inline
+void bcma_write8(struct bcma_device *core, u16 offset, u32 value)
+{
+ core->bus->ops->write8(core, offset, value);
+}
+extern inline
+void bcma_write16(struct bcma_device *core, u16 offset, u32 value)
+{
+ core->bus->ops->write16(core, offset, value);
+}
+extern inline
+void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
+{
+ core->bus->ops->write32(core, offset, value);
+}
+extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
+{
+ return core->bus->ops->aread32(core, offset);
+}
+extern inline
+void bcma_awrite32(struct bcma_device *core, u16 offset, u32 value)
+{
+ core->bus->ops->awrite32(core, offset, value);
+}
+
+extern bool bcma_core_is_enabled(struct bcma_device *core);
+extern int bcma_core_enable(struct bcma_device *core, u32 flags);
+
+#endif /* LINUX_BCMA_H_ */
diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h
new file mode 100644
index 0000000..083c3b6
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
@@ -0,0 +1,302 @@
+#ifndef LINUX_BCMA_DRIVER_CC_H_
+#define LINUX_BCMA_DRIVER_CC_H_
+
+/** ChipCommon core registers. **/
+#define BCMA_CC_ID 0x0000
+#define BCMA_CC_ID_ID 0x0000FFFF
+#define BCMA_CC_ID_ID_SHIFT 0
+#define BCMA_CC_ID_REV 0x000F0000
+#define BCMA_CC_ID_REV_SHIFT 16
+#define BCMA_CC_ID_PKG 0x00F00000
+#define BCMA_CC_ID_PKG_SHIFT 20
+#define BCMA_CC_ID_NRCORES 0x0F000000
+#define BCMA_CC_ID_NRCORES_SHIFT 24
+#define BCMA_CC_ID_TYPE 0xF0000000
+#define BCMA_CC_ID_TYPE_SHIFT 28
+#define BCMA_CC_CAP 0x0004 /* Capabilities */
+#define BCMA_CC_CAP_NRUART 0x00000003 /* # of UARTs */
+#define BCMA_CC_CAP_MIPSEB 0x00000004 /* MIPS in BigEndian Mode */
+#define BCMA_CC_CAP_UARTCLK 0x00000018 /* UART clock select */
+#define BCMA_CC_CAP_UARTCLK_INT 0x00000008 /* UARTs are driven by internal divided clock */
+#define BCMA_CC_CAP_UARTGPIO 0x00000020 /* UARTs on GPIO 15-12 */
+#define BCMA_CC_CAP_EXTBUS 0x000000C0 /* External buses present */
+#define BCMA_CC_CAP_FLASHT 0x00000700 /* Flash Type */
+#define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */
+#define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */
+#define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */
+#define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */
+#define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */
+#define BCMA_PLLTYPE_NONE 0x00000000
+#define BCMA_PLLTYPE_1 0x00010000 /* 48Mhz base, 3 dividers */
+#define BCMA_PLLTYPE_2 0x00020000 /* 48Mhz, 4 dividers */
+#define BCMA_PLLTYPE_3 0x00030000 /* 25Mhz, 2 dividers */
+#define BCMA_PLLTYPE_4 0x00008000 /* 48Mhz, 4 dividers */
+#define BCMA_PLLTYPE_5 0x00018000 /* 25Mhz, 4 dividers */
+#define BCMA_PLLTYPE_6 0x00028000 /* 100/200 or 120/240 only */
+#define BCMA_PLLTYPE_7 0x00038000 /* 25Mhz, 4 dividers */
+#define BCMA_CC_CAP_PCTL 0x00040000 /* Power Control */
+#define BCMA_CC_CAP_OTPS 0x00380000 /* OTP size */
+#define BCMA_CC_CAP_OTPS_SHIFT 19
+#define BCMA_CC_CAP_OTPS_BASE 5
+#define BCMA_CC_CAP_JTAGM 0x00400000 /* JTAG master present */
+#define BCMA_CC_CAP_BROM 0x00800000 /* Internal boot ROM active */
+#define BCMA_CC_CAP_64BIT 0x08000000 /* 64-bit Backplane */
+#define BCMA_CC_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */
+#define BCMA_CC_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */
+#define BCMA_CC_CAP_SPROM 0x40000000 /* SPROM present */
+#define BCMA_CC_CORECTL 0x0008
+#define BCMA_CC_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */
+#define BCMA_CC_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */
+#define BCMA_CC_CORECTL_UARTCLKEN 0x00000008 /* UART clock enable (rev >= 21) */
+#define BCMA_CC_BIST 0x000C
+#define BCMA_CC_OTPS 0x0010 /* OTP status */
+#define BCMA_CC_OTPS_PROGFAIL 0x80000000
+#define BCMA_CC_OTPS_PROTECT 0x00000007
+#define BCMA_CC_OTPS_HW_PROTECT 0x00000001
+#define BCMA_CC_OTPS_SW_PROTECT 0x00000002
+#define BCMA_CC_OTPS_CID_PROTECT 0x00000004
+#define BCMA_CC_OTPC 0x0014 /* OTP control */
+#define BCMA_CC_OTPC_RECWAIT 0xFF000000
+#define BCMA_CC_OTPC_PROGWAIT 0x00FFFF00
+#define BCMA_CC_OTPC_PRW_SHIFT 8
+#define BCMA_CC_OTPC_MAXFAIL 0x00000038
+#define BCMA_CC_OTPC_VSEL 0x00000006
+#define BCMA_CC_OTPC_SELVL 0x00000001
+#define BCMA_CC_OTPP 0x0018 /* OTP prog */
+#define BCMA_CC_OTPP_COL 0x000000FF
+#define BCMA_CC_OTPP_ROW 0x0000FF00
+#define BCMA_CC_OTPP_ROW_SHIFT 8
+#define BCMA_CC_OTPP_READERR 0x10000000
+#define BCMA_CC_OTPP_VALUE 0x20000000
+#define BCMA_CC_OTPP_READ 0x40000000
+#define BCMA_CC_OTPP_START 0x80000000
+#define BCMA_CC_OTPP_BUSY 0x80000000
+#define BCMA_CC_IRQSTAT 0x0020
+#define BCMA_CC_IRQMASK 0x0024
+#define BCMA_CC_IRQ_GPIO 0x00000001 /* gpio intr */
+#define BCMA_CC_IRQ_EXT 0x00000002 /* ro: ext intr pin (corerev >= 3) */
+#define BCMA_CC_IRQ_WDRESET 0x80000000 /* watchdog reset occurred */
+#define BCMA_CC_CHIPCTL 0x0028 /* Rev >= 11 only */
+#define BCMA_CC_CHIPSTAT 0x002C /* Rev >= 11 only */
+#define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */
+#define BCMA_CC_JCMD_START 0x80000000
+#define BCMA_CC_JCMD_BUSY 0x80000000
+#define BCMA_CC_JCMD_PAUSE 0x40000000
+#define BCMA_CC_JCMD0_ACC_MASK 0x0000F000
+#define BCMA_CC_JCMD0_ACC_IRDR 0x00000000
+#define BCMA_CC_JCMD0_ACC_DR 0x00001000
+#define BCMA_CC_JCMD0_ACC_IR 0x00002000
+#define BCMA_CC_JCMD0_ACC_RESET 0x00003000
+#define BCMA_CC_JCMD0_ACC_IRPDR 0x00004000
+#define BCMA_CC_JCMD0_ACC_PDR 0x00005000
+#define BCMA_CC_JCMD0_IRW_MASK 0x00000F00
+#define BCMA_CC_JCMD_ACC_MASK 0x000F0000 /* Changes for corerev 11 */
+#define BCMA_CC_JCMD_ACC_IRDR 0x00000000
+#define BCMA_CC_JCMD_ACC_DR 0x00010000
+#define BCMA_CC_JCMD_ACC_IR 0x00020000
+#define BCMA_CC_JCMD_ACC_RESET 0x00030000
+#define BCMA_CC_JCMD_ACC_IRPDR 0x00040000
+#define BCMA_CC_JCMD_ACC_PDR 0x00050000
+#define BCMA_CC_JCMD_IRW_MASK 0x00001F00
+#define BCMA_CC_JCMD_IRW_SHIFT 8
+#define BCMA_CC_JCMD_DRW_MASK 0x0000003F
+#define BCMA_CC_JIR 0x0034 /* Rev >= 10 only */
+#define BCMA_CC_JDR 0x0038 /* Rev >= 10 only */
+#define BCMA_CC_JCTL 0x003C /* Rev >= 10 only */
+#define BCMA_CC_JCTL_FORCE_CLK 4 /* Force clock */
+#define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */
+#define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */
+#define BCMA_CC_FLASHCTL 0x0040
+#define BCMA_CC_FLASHCTL_START 0x80000000
+#define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START
+#define BCMA_CC_FLASHADDR 0x0044
+#define BCMA_CC_FLASHDATA 0x0048
+#define BCMA_CC_BCAST_ADDR 0x0050
+#define BCMA_CC_BCAST_DATA 0x0054
+#define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */
+#define BCMA_CC_GPIOPULLDOWN 0x005C /* Rev >= 20 only */
+#define BCMA_CC_GPIOIN 0x0060
+#define BCMA_CC_GPIOOUT 0x0064
+#define BCMA_CC_GPIOOUTEN 0x0068
+#define BCMA_CC_GPIOCTL 0x006C
+#define BCMA_CC_GPIOPOL 0x0070
+#define BCMA_CC_GPIOIRQ 0x0074
+#define BCMA_CC_WATCHDOG 0x0080
+#define BCMA_CC_GPIOTIMER 0x0088 /* LED powersave (corerev >= 16) */
+#define BCMA_CC_GPIOTIMER_OFFTIME 0x0000FFFF
+#define BCMA_CC_GPIOTIMER_OFFTIME_SHIFT 0
+#define BCMA_CC_GPIOTIMER_ONTIME 0xFFFF0000
+#define BCMA_CC_GPIOTIMER_ONTIME_SHIFT 16
+#define BCMA_CC_GPIOTOUTM 0x008C /* LED powersave (corerev >= 16) */
+#define BCMA_CC_CLOCK_N 0x0090
+#define BCMA_CC_CLOCK_SB 0x0094
+#define BCMA_CC_CLOCK_PCI 0x0098
+#define BCMA_CC_CLOCK_M2 0x009C
+#define BCMA_CC_CLOCK_MIPS 0x00A0
+#define BCMA_CC_CLKDIV 0x00A4 /* Rev >= 3 only */
+#define BCMA_CC_CLKDIV_SFLASH 0x0F000000
+#define BCMA_CC_CLKDIV_SFLASH_SHIFT 24
+#define BCMA_CC_CLKDIV_OTP 0x000F0000
+#define BCMA_CC_CLKDIV_OTP_SHIFT 16
+#define BCMA_CC_CLKDIV_JTAG 0x00000F00
+#define BCMA_CC_CLKDIV_JTAG_SHIFT 8
+#define BCMA_CC_CLKDIV_UART 0x000000FF
+#define BCMA_CC_CAP_EXT 0x00AC /* Capabilities */
+#define BCMA_CC_PLLONDELAY 0x00B0 /* Rev >= 4 only */
+#define BCMA_CC_FREFSELDELAY 0x00B4 /* Rev >= 4 only */
+#define BCMA_CC_SLOWCLKCTL 0x00B8 /* 6 <= Rev <= 9 only */
+#define BCMA_CC_SLOWCLKCTL_SRC 0x00000007 /* slow clock source mask */
+#define BCMA_CC_SLOWCLKCTL_SRC_LPO 0x00000000 /* source of slow clock is LPO */
+#define BCMA_CC_SLOWCLKCTL_SRC_XTAL 0x00000001 /* source of slow clock is crystal */
+#define BCMA_CC_SLOECLKCTL_SRC_PCI 0x00000002 /* source of slow clock is PCI */
+#define BCMA_CC_SLOWCLKCTL_LPOFREQ 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */
+#define BCMA_CC_SLOWCLKCTL_LPOPD 0x00000400 /* LPOPowerDown, 1: LPO is disabled, 0: LPO is enabled */
+#define BCMA_CC_SLOWCLKCTL_FSLOW 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, 0: power logic control */
+#define BCMA_CC_SLOWCLKCTL_IPLL 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors PLL clock disable requests from core */
+#define BCMA_CC_SLOWCLKCTL_ENXTAL 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't disable crystal when appropriate */
+#define BCMA_CC_SLOWCLKCTL_XTALPU 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */
+#define BCMA_CC_SLOWCLKCTL_CLKDIV 0xFFFF0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */
+#define BCMA_CC_SLOWCLKCTL_CLKDIV_SHIFT 16
+#define BCMA_CC_SYSCLKCTL 0x00C0 /* Rev >= 3 only */
+#define BCMA_CC_SYSCLKCTL_IDLPEN 0x00000001 /* ILPen: Enable Idle Low Power */
+#define BCMA_CC_SYSCLKCTL_ALPEN 0x00000002 /* ALPen: Enable Active Low Power */
+#define BCMA_CC_SYSCLKCTL_PLLEN 0x00000004 /* ForcePLLOn */
+#define BCMA_CC_SYSCLKCTL_FORCEALP 0x00000008 /* Force ALP (or HT if ALPen is not set */
+#define BCMA_CC_SYSCLKCTL_FORCEHT 0x00000010 /* Force HT */
+#define BCMA_CC_SYSCLKCTL_CLKDIV 0xFFFF0000 /* ClkDiv (ILP = 1/(4+divisor)) */
+#define BCMA_CC_SYSCLKCTL_CLKDIV_SHIFT 16
+#define BCMA_CC_CLKSTSTR 0x00C4 /* Rev >= 3 only */
+#define BCMA_CC_EROM 0x00FC
+#define BCMA_CC_PCMCIA_CFG 0x0100
+#define BCMA_CC_PCMCIA_MEMWAIT 0x0104
+#define BCMA_CC_PCMCIA_ATTRWAIT 0x0108
+#define BCMA_CC_PCMCIA_IOWAIT 0x010C
+#define BCMA_CC_IDE_CFG 0x0110
+#define BCMA_CC_IDE_MEMWAIT 0x0114
+#define BCMA_CC_IDE_ATTRWAIT 0x0118
+#define BCMA_CC_IDE_IOWAIT 0x011C
+#define BCMA_CC_PROG_CFG 0x0120
+#define BCMA_CC_PROG_WAITCNT 0x0124
+#define BCMA_CC_FLASH_CFG 0x0128
+#define BCMA_CC_FLASH_WAITCNT 0x012C
+#define BCMA_CC_CLKCTLST 0x01E0 /* Clock control and status (rev >= 20) */
+#define BCMA_CC_CLKCTLST_FORCEALP 0x00000001 /* Force ALP request */
+#define BCMA_CC_CLKCTLST_FORCEHT 0x00000002 /* Force HT request */
+#define BCMA_CC_CLKCTLST_FORCEILP 0x00000004 /* Force ILP request */
+#define BCMA_CC_CLKCTLST_HAVEALPREQ 0x00000008 /* ALP available request */
+#define BCMA_CC_CLKCTLST_HAVEHTREQ 0x00000010 /* HT available request */
+#define BCMA_CC_CLKCTLST_HWCROFF 0x00000020 /* Force HW clock request off */
+#define BCMA_CC_CLKCTLST_HAVEHT 0x00010000 /* HT available */
+#define BCMA_CC_CLKCTLST_HAVEALP 0x00020000 /* APL available */
+#define BCMA_CC_HW_WORKAROUND 0x01E4 /* Hardware workaround (rev >= 20) */
+#define BCMA_CC_UART0_DATA 0x0300
+#define BCMA_CC_UART0_IMR 0x0304
+#define BCMA_CC_UART0_FCR 0x0308
+#define BCMA_CC_UART0_LCR 0x030C
+#define BCMA_CC_UART0_MCR 0x0310
+#define BCMA_CC_UART0_LSR 0x0314
+#define BCMA_CC_UART0_MSR 0x0318
+#define BCMA_CC_UART0_SCRATCH 0x031C
+#define BCMA_CC_UART1_DATA 0x0400
+#define BCMA_CC_UART1_IMR 0x0404
+#define BCMA_CC_UART1_FCR 0x0408
+#define BCMA_CC_UART1_LCR 0x040C
+#define BCMA_CC_UART1_MCR 0x0410
+#define BCMA_CC_UART1_LSR 0x0414
+#define BCMA_CC_UART1_MSR 0x0418
+#define BCMA_CC_UART1_SCRATCH 0x041C
+/* PMU registers (rev >= 20) */
+#define BCMA_CC_PMU_CTL 0x0600 /* PMU control */
+#define BCMA_CC_PMU_CTL_ILP_DIV 0xFFFF0000 /* ILP div mask */
+#define BCMA_CC_PMU_CTL_ILP_DIV_SHIFT 16
+#define BCMA_CC_PMU_CTL_NOILPONW 0x00000200 /* No ILP on wait */
+#define BCMA_CC_PMU_CTL_HTREQEN 0x00000100 /* HT req enable */
+#define BCMA_CC_PMU_CTL_ALPREQEN 0x00000080 /* ALP req enable */
+#define BCMA_CC_PMU_CTL_XTALFREQ 0x0000007C /* Crystal freq */
+#define BCMA_CC_PMU_CTL_XTALFREQ_SHIFT 2
+#define BCMA_CC_PMU_CTL_ILPDIVEN 0x00000002 /* ILP div enable */
+#define BCMA_CC_PMU_CTL_LPOSEL 0x00000001 /* LPO sel */
+#define BCMA_CC_PMU_CAP 0x0604 /* PMU capabilities */
+#define BCMA_CC_PMU_CAP_REVISION 0x000000FF /* Revision mask */
+#define BCMA_CC_PMU_STAT 0x0608 /* PMU status */
+#define BCMA_CC_PMU_STAT_INTPEND 0x00000040 /* Interrupt pending */
+#define BCMA_CC_PMU_STAT_SBCLKST 0x00000030 /* Backplane clock status? */
+#define BCMA_CC_PMU_STAT_HAVEALP 0x00000008 /* ALP available */
+#define BCMA_CC_PMU_STAT_HAVEHT 0x00000004 /* HT available */
+#define BCMA_CC_PMU_STAT_RESINIT 0x00000003 /* Res init */
+#define BCMA_CC_PMU_RES_STAT 0x060C /* PMU res status */
+#define BCMA_CC_PMU_RES_PEND 0x0610 /* PMU res pending */
+#define BCMA_CC_PMU_TIMER 0x0614 /* PMU timer */
+#define BCMA_CC_PMU_MINRES_MSK 0x0618 /* PMU min res mask */
+#define BCMA_CC_PMU_MAXRES_MSK 0x061C /* PMU max res mask */
+#define BCMA_CC_PMU_RES_TABSEL 0x0620 /* PMU res table sel */
+#define BCMA_CC_PMU_RES_DEPMSK 0x0624 /* PMU res dep mask */
+#define BCMA_CC_PMU_RES_UPDNTM 0x0628 /* PMU res updown timer */
+#define BCMA_CC_PMU_RES_TIMER 0x062C /* PMU res timer */
+#define BCMA_CC_PMU_CLKSTRETCH 0x0630 /* PMU clockstretch */
+#define BCMA_CC_PMU_WATCHDOG 0x0634 /* PMU watchdog */
+#define BCMA_CC_PMU_RES_REQTS 0x0640 /* PMU res req timer sel */
+#define BCMA_CC_PMU_RES_REQT 0x0644 /* PMU res req timer */
+#define BCMA_CC_PMU_RES_REQM 0x0648 /* PMU res req mask */
+#define BCMA_CC_CHIPCTL_ADDR 0x0650
+#define BCMA_CC_CHIPCTL_DATA 0x0654
+#define BCMA_CC_REGCTL_ADDR 0x0658
+#define BCMA_CC_REGCTL_DATA 0x065C
+#define BCMA_CC_PLLCTL_ADDR 0x0660
+#define BCMA_CC_PLLCTL_DATA 0x0664
+
+/* Data for the PMU, if available.
+ * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
+ */
+struct bcma_chipcommon_pmu {
+ u8 rev; /* PMU revision */
+ u32 crystalfreq; /* The active crystal frequency (in kHz) */
+};
+
+struct bcma_drv_cc {
+ struct bcma_device *core;
+ u32 status;
+ u32 capabilities;
+ u32 capabilities_ext;
+ /* Fast Powerup Delay constant */
+ u16 fast_pwrup_delay;
+ struct bcma_chipcommon_pmu pmu;
+};
+
+/* Register access */
+#define bcma_cc_read32(cc, offset) \
+ bcma_read32((cc)->core, offset)
+#define bcma_cc_write32(cc, offset, val) \
+ bcma_write32((cc)->core, offset, val)
+
+#define bcma_cc_mask32(cc, offset, mask) \
+ bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) & (mask))
+#define bcma_cc_set32(cc, offset, set) \
+ bcma_cc_write32(cc, offset, bcma_cc_read32(cc, offset) | (set))
+#define bcma_cc_maskset32(cc, offset, mask, set) \
+ bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
+
+extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
+
+extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
+extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
+
+extern void bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc,
+ u32 ticks);
+
+void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value);
+
+u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask);
+
+/* Chipcommon GPIO pin access. */
+u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask);
+u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value);
+u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
+
+/* PMU support */
+extern void bcma_pmu_init(struct bcma_drv_cc *cc);
+
+#endif /* LINUX_BCMA_DRIVER_CC_H_ */
diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h
new file mode 100644
index 0000000..b7e191c
--- /dev/null
+++ b/include/linux/bcma/bcma_driver_pci.h
@@ -0,0 +1,89 @@
+#ifndef LINUX_BCMA_DRIVER_PCI_H_
+#define LINUX_BCMA_DRIVER_PCI_H_
+
+#include <linux/types.h>
+
+struct pci_dev;
+
+/** PCI core registers. **/
+#define BCMA_CORE_PCI_CTL 0x0000 /* PCI Control */
+#define BCMA_CORE_PCI_CTL_RST_OE 0x00000001 /* PCI_RESET Output Enable */
+#define BCMA_CORE_PCI_CTL_RST 0x00000002 /* PCI_RESET driven out to pin */
+#define BCMA_CORE_PCI_CTL_CLK_OE 0x00000004 /* Clock gate Output Enable */
+#define BCMA_CORE_PCI_CTL_CLK 0x00000008 /* Gate for clock driven out to pin */
+#define BCMA_CORE_PCI_ARBCTL 0x0010 /* PCI Arbiter Control */
+#define BCMA_CORE_PCI_ARBCTL_INTERN 0x00000001 /* Use internal arbiter */
+#define BCMA_CORE_PCI_ARBCTL_EXTERN 0x00000002 /* Use external arbiter */
+#define BCMA_CORE_PCI_ARBCTL_PARKID 0x00000006 /* Mask, selects which agent is parked on an idle bus */
+#define BCMA_CORE_PCI_ARBCTL_PARKID_LAST 0x00000000 /* Last requestor */
+#define BCMA_CORE_PCI_ARBCTL_PARKID_4710 0x00000002 /* 4710 */
+#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT0 0x00000004 /* External requestor 0 */
+#define BCMA_CORE_PCI_ARBCTL_PARKID_EXT1 0x00000006 /* External requestor 1 */
+#define BCMA_CORE_PCI_ISTAT 0x0020 /* Interrupt status */
+#define BCMA_CORE_PCI_ISTAT_INTA 0x00000001 /* PCI INTA# */
+#define BCMA_CORE_PCI_ISTAT_INTB 0x00000002 /* PCI INTB# */
+#define BCMA_CORE_PCI_ISTAT_SERR 0x00000004 /* PCI SERR# (write to clear) */
+#define BCMA_CORE_PCI_ISTAT_PERR 0x00000008 /* PCI PERR# (write to clear) */
+#define BCMA_CORE_PCI_ISTAT_PME 0x00000010 /* PCI PME# */
+#define BCMA_CORE_PCI_IMASK 0x0024 /* Interrupt mask */
+#define BCMA_CORE_PCI_IMASK_INTA 0x00000001 /* PCI INTA# */
+#define BCMA_CORE_PCI_IMASK_INTB 0x00000002 /* PCI INTB# */
+#define BCMA_CORE_PCI_IMASK_SERR 0x00000004 /* PCI SERR# */
+#define BCMA_CORE_PCI_IMASK_PERR 0x00000008 /* PCI PERR# */
+#define BCMA_CORE_PCI_IMASK_PME 0x00000010 /* PCI PME# */
+#define BCMA_CORE_PCI_MBOX 0x0028 /* Backplane to PCI Mailbox */
+#define BCMA_CORE_PCI_MBOX_F0_0 0x00000100 /* PCI function 0, INT 0 */
+#define BCMA_CORE_PCI_MBOX_F0_1 0x00000200 /* PCI function 0, INT 1 */
+#define BCMA_CORE_PCI_MBOX_F1_0 0x00000400 /* PCI function 1, INT 0 */
+#define BCMA_CORE_PCI_MBOX_F1_1 0x00000800 /* PCI function 1, INT 1 */
+#define BCMA_CORE_PCI_MBOX_F2_0 0x00001000 /* PCI function 2, INT 0 */
+#define BCMA_CORE_PCI_MBOX_F2_1 0x00002000 /* PCI function 2, INT 1 */
+#define BCMA_CORE_PCI_MBOX_F3_0 0x00004000 /* PCI function 3, INT 0 */
+#define BCMA_CORE_PCI_MBOX_F3_1 0x00008000 /* PCI function 3, INT 1 */
+#define BCMA_CORE_PCI_BCAST_ADDR 0x0050 /* Backplane Broadcast Address */
+#define BCMA_CORE_PCI_BCAST_ADDR_MASK 0x000000FF
+#define BCMA_CORE_PCI_BCAST_DATA 0x0054 /* Backplane Broadcast Data */
+#define BCMA_CORE_PCI_GPIO_IN 0x0060 /* rev >= 2 only */
+#define BCMA_CORE_PCI_GPIO_OUT 0x0064 /* rev >= 2 only */
+#define BCMA_CORE_PCI_GPIO_ENABLE 0x0068 /* rev >= 2 only */
+#define BCMA_CORE_PCI_GPIO_CTL 0x006C /* rev >= 2 only */
+#define BCMA_CORE_PCI_SBTOPCI0 0x0100 /* Backplane to PCI translation 0 (sbtopci0) */
+#define BCMA_CORE_PCI_SBTOPCI0_MASK 0xFC000000
+#define BCMA_CORE_PCI_SBTOPCI1 0x0104 /* Backplane to PCI translation 1 (sbtopci1) */
+#define BCMA_CORE_PCI_SBTOPCI1_MASK 0xFC000000
+#define BCMA_CORE_PCI_SBTOPCI2 0x0108 /* Backplane to PCI translation 2 (sbtopci2) */
+#define BCMA_CORE_PCI_SBTOPCI2_MASK 0xC0000000
+#define BCMA_CORE_PCI_PCICFG0 0x0400 /* PCI config space 0 (rev >= 8) */
+#define BCMA_CORE_PCI_PCICFG1 0x0500 /* PCI config space 1 (rev >= 8) */
+#define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */
+#define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */
+#define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */
+
+/* SBtoPCIx */
+#define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000
+#define BCMA_CORE_PCI_SBTOPCI_IO 0x00000001
+#define BCMA_CORE_PCI_SBTOPCI_CFG0 0x00000002
+#define BCMA_CORE_PCI_SBTOPCI_CFG1 0x00000003
+#define BCMA_CORE_PCI_SBTOPCI_PREF 0x00000004 /* Prefetch enable */
+#define BCMA_CORE_PCI_SBTOPCI_BURST 0x00000008 /* Burst enable */
+#define BCMA_CORE_PCI_SBTOPCI_MRM 0x00000020 /* Memory Read Multiple */
+#define BCMA_CORE_PCI_SBTOPCI_RC 0x00000030 /* Read Command mask (rev >= 11) */
+#define BCMA_CORE_PCI_SBTOPCI_RC_READ 0x00000000 /* Memory read */
+#define BCMA_CORE_PCI_SBTOPCI_RC_READL 0x00000010 /* Memory read line */
+#define BCMA_CORE_PCI_SBTOPCI_RC_READM 0x00000020 /* Memory read multiple */
+
+/* PCIcore specific boardflags */
+#define BCMA_CORE_PCI_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
+
+struct bcma_drv_pci {
+ struct bcma_device *core;
+ u8 setup_done:1;
+};
+
+/* Register access */
+#define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset)
+#define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val)
+
+extern void bcma_core_pci_init(struct bcma_drv_pci *pc);
+
+#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
diff --git a/include/linux/bcma/bcma_regs.h b/include/linux/bcma/bcma_regs.h
new file mode 100644
index 0000000..f82d88a
--- /dev/null
+++ b/include/linux/bcma/bcma_regs.h
@@ -0,0 +1,34 @@
+#ifndef LINUX_BCMA_REGS_H_
+#define LINUX_BCMA_REGS_H_
+
+/* Agent registers (common for every core) */
+#define BCMA_IOCTL 0x0408
+#define BCMA_IOCTL_CLK 0x0001
+#define BCMA_IOCTL_FGC 0x0002
+#define BCMA_IOCTL_CORE_BITS 0x3FFC
+#define BCMA_IOCTL_PME_EN 0x4000
+#define BCMA_IOCTL_BIST_EN 0x8000
+#define BCMA_RESET_CTL 0x0800
+#define BCMA_RESET_CTL_RESET 0x0001
+
+/* BCMA PCI config space registers. */
+#define BCMA_PCI_PMCSR 0x44
+#define BCMA_PCI_PE 0x100
+#define BCMA_PCI_BAR0_WIN 0x80 /* Backplane address space 0 */
+#define BCMA_PCI_BAR1_WIN 0x84 /* Backplane address space 1 */
+#define BCMA_PCI_SPROMCTL 0x88 /* SPROM control */
+#define BCMA_PCI_SPROMCTL_WE 0x10 /* SPROM write enable */
+#define BCMA_PCI_BAR1_CONTROL 0x8c /* Address space 1 burst control */
+#define BCMA_PCI_IRQS 0x90 /* PCI interrupts */
+#define BCMA_PCI_IRQMASK 0x94 /* PCI IRQ control and mask (pcirev >= 6 only) */
+#define BCMA_PCI_BACKPLANE_IRQS 0x98 /* Backplane Interrupts */
+#define BCMA_PCI_BAR0_WIN2 0xAC
+#define BCMA_PCI_GPIO_IN 0xB0 /* GPIO Input (pcirev >= 3 only) */
+#define BCMA_PCI_GPIO_OUT 0xB4 /* GPIO Output (pcirev >= 3 only) */
+#define BCMA_PCI_GPIO_OUT_ENABLE 0xB8 /* GPIO Output Enable/Disable (pcirev >= 3 only) */
+#define BCMA_PCI_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
+#define BCMA_PCI_GPIO_HWRAD 0x20 /* PCI config space GPIO 13 for hw radio disable */
+#define BCMA_PCI_GPIO_XTAL 0x40 /* PCI config space GPIO 14 for Xtal powerup */
+#define BCMA_PCI_GPIO_PLL 0x80 /* PCI config space GPIO 15 for PLL powerdown */
+
+#endif /* LINUX_BCMA_REGS_H_ */
diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h
index 79690b7..b2eee58 100644
--- a/include/linux/ieee80211.h
+++ b/include/linux/ieee80211.h
@@ -1002,6 +1002,11 @@
#define WLAN_CAPABILITY_ESS (1<<0)
#define WLAN_CAPABILITY_IBSS (1<<1)
+
+/* A mesh STA sets the ESS and IBSS capability bits to zero */
+#define WLAN_CAPABILITY_IS_MBSS(cap) \
+ (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)))
+
#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
#define WLAN_CAPABILITY_PRIVACY (1<<4)
@@ -1261,9 +1266,8 @@
WLAN_CATEGORY_MULTIHOP_ACTION = 14,
WLAN_CATEGORY_SELF_PROTECTED = 15,
WLAN_CATEGORY_WMM = 17,
- /* TODO: remove MESH_PLINK and MESH_PATH_SEL after */
- /* mesh is updated to current 802.11s draft */
- WLAN_CATEGORY_MESH_PLINK = 30,
+ /* TODO: remove MESH_PATH_SEL after mesh is updated
+ * to current 802.11s draft */
WLAN_CATEGORY_MESH_PATH_SEL = 32,
WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126,
WLAN_CATEGORY_VENDOR_SPECIFIC = 127,
@@ -1516,6 +1520,7 @@
category = ((u8 *) hdr) + 24;
return *category != WLAN_CATEGORY_PUBLIC &&
*category != WLAN_CATEGORY_HT &&
+ *category != WLAN_CATEGORY_SELF_PROTECTED &&
*category != WLAN_CATEGORY_VENDOR_SPECIFIC;
}
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 48c007d..ae28e93 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -382,6 +382,23 @@
#define SSB_ANY_ID 0xFFFF
#define SSB_ANY_REV 0xFF
+/* Broadcom's specific AMBA core, see drivers/bcma/ */
+struct bcma_device_id {
+ __u16 manuf;
+ __u16 id;
+ __u8 rev;
+ __u8 class;
+};
+#define BCMA_CORE(_manuf, _id, _rev, _class) \
+ { .manuf = _manuf, .id = _id, .rev = _rev, .class = _class, }
+#define BCMA_CORETABLE_END \
+ { 0, },
+
+#define BCMA_ANY_MANUF 0xFFFF
+#define BCMA_ANY_ID 0xFFFF
+#define BCMA_ANY_REV 0xFF
+#define BCMA_ANY_CLASS 0xFF
+
struct virtio_device_id {
__u32 device;
__u32 vendor;
diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h
index 216b1d8..c7ccaae 100644
--- a/include/linux/nl80211.h
+++ b/include/linux/nl80211.h
@@ -77,6 +77,39 @@
*/
/**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
* enum nl80211_commands - supported nl80211 commands
*
* @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -203,6 +236,28 @@
* @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
* partial scan results may be available
*
+ * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
+ * intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ * Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
+ * are passed, they are used in the probe requests. For
+ * broadcast, a broadcast SSID must be passed (ie. an empty
+ * string). If no SSID is passed, no probe requests are sent and
+ * a passive scan is performed. %NL80211_ATTR_SCAN_FREQUENCIES,
+ * if passed, define which channels should be scanned; if not
+ * passed, all channels allowed for the current regulatory domain
+ * are used. Extra IEs can also be passed from the userspace by
+ * using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ * results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ * stopped. The driver may issue this event at any time during a
+ * scheduled scan. One reason for stopping the scan is if the hardware
+ * does not support starting an association or a normal scan while running
+ * a scheduled scan. This event is also sent when the
+ * %NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ * is brought down while a scheduled scan was running.
+ *
* @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
* or noise level
* @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
@@ -420,6 +475,14 @@
* new station with the AUTHENTICATED flag unset and maybe change it later
* depending on the authentication result.
*
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ * Since wireless is more complex than wired ethernet, it supports
+ * various triggers. These triggers can be configured through this
+ * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ * more background information, see
+ * http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
* @NL80211_CMD_MAX: highest used command number
* @__NL80211_CMD_AFTER_LAST: internal use
*/
@@ -534,6 +597,14 @@
NL80211_CMD_NEW_PEER_CANDIDATE,
+ NL80211_CMD_GET_WOWLAN,
+ NL80211_CMD_SET_WOWLAN,
+
+ NL80211_CMD_START_SCHED_SCAN,
+ NL80211_CMD_STOP_SCHED_SCAN,
+ NL80211_CMD_SCHED_SCAN_RESULTS,
+ NL80211_CMD_SCHED_SCAN_STOPPED,
+
/* add new commands above here */
/* used to define NL80211_CMD_MAX below */
@@ -902,6 +973,28 @@
* @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
* allows auth frames in a mesh to be passed to userspace for processing via
* the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ * defined in &enum nl80211_plink_state. Used when userspace is
+ * driving the peer link management state machine.
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_SUPPORTED: indicates, as part of the wiphy capabilities,
+ * the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ * indicate which WoW triggers should be enabled. This is also
+ * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ * triggers.
+
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ * cycles, in msecs.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ * interface combinations. In each nested item, it contains attributes
+ * defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ * %NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ * are managed in software: interfaces of these types aren't subject to
+ * any restrictions in their number or combinations.
*
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1091,6 +1184,15 @@
NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
NL80211_ATTR_SUPPORT_MESH_AUTH,
+ NL80211_ATTR_STA_PLINK_STATE,
+
+ NL80211_ATTR_WOWLAN_TRIGGERS,
+ NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+ NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+ NL80211_ATTR_INTERFACE_COMBINATIONS,
+ NL80211_ATTR_SOFTWARE_IFTYPES,
/* add attributes here, update the policy in nl80211.c */
@@ -1144,7 +1246,9 @@
* @NL80211_IFTYPE_ADHOC: independent BSS member
* @NL80211_IFTYPE_STATION: managed BSS member
* @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ * are a bit special in that they must always be tied to a pre-existing
+ * AP type interface.
* @NL80211_IFTYPE_WDS: wireless distribution interface
* @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
* @NL80211_IFTYPE_MESH_POINT: mesh point
@@ -1293,6 +1397,7 @@
* @NL80211_STA_INFO_LLID: the station's mesh LLID
* @NL80211_STA_INFO_PLID: the station's mesh PLID
* @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ * (see %enum nl80211_plink_state)
* @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
* attribute, like NL80211_STA_INFO_TX_BITRATE.
* @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
@@ -1748,6 +1853,15 @@
* @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
* daemon will be authenticating mesh candidates.
*
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ * daemon will be securing peer link frames. AMPE is a secured version of Mesh
+ * Peering Management (MPM) and is implemented with the assistance of a
+ * userspace daemon. When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and key
+ * management). When the flag is unset (default), the kernel can autonomously
+ * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *
* @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
* @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
*/
@@ -1757,6 +1871,7 @@
NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
NL80211_MESH_SETUP_IE,
NL80211_MESH_SETUP_USERSPACE_AUTH,
+ NL80211_MESH_SETUP_USERSPACE_AMPE,
/* keep last */
__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
@@ -2061,4 +2176,189 @@
NL80211_TX_POWER_FIXED,
};
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ * a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ * a bit for each byte in the pattern. The lowest-order bit corresponds
+ * to the first byte of the pattern, but the bytes of the pattern are
+ * in a little-endian-like format, i.e. the 9th byte of the pattern
+ * corresponds to the lowest-order bit in the second byte of the mask.
+ * For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ * xx indicates "don't care") would be represented by a pattern of
+ * twelve zero bytes, and a mask of "0xed,0x07".
+ * Note that the pattern matching is done as though frames were not
+ * 802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ * first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+ __NL80211_WOWLAN_PKTPAT_INVALID,
+ NL80211_WOWLAN_PKTPAT_MASK,
+ NL80211_WOWLAN_PKTPAT_PATTERN,
+
+ NUM_NL80211_WOWLAN_PKTPAT,
+ MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+ __u32 max_patterns;
+ __u32 min_pattern_len;
+ __u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ * the chip into a special state -- works best with chips that have
+ * support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ * is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ * by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ * which are passed in an array of nested attributes, each nested attribute
+ * defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ * Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ * i.e. as though the packet was an 802.3 packet, so the pattern matching
+ * is done after the packet is converted to the MSDU.
+ *
+ * In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ * carrying a &struct nl80211_wowlan_pattern_support.
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+ __NL80211_WOWLAN_TRIG_INVALID,
+ NL80211_WOWLAN_TRIG_ANY,
+ NL80211_WOWLAN_TRIG_DISCONNECT,
+ NL80211_WOWLAN_TRIG_MAGIC_PKT,
+ NL80211_WOWLAN_TRIG_PKT_PATTERN,
+
+ /* keep last */
+ NUM_NL80211_WOWLAN_TRIG,
+ MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ * can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ * flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+ NL80211_IFACE_LIMIT_UNSPEC,
+ NL80211_IFACE_LIMIT_MAX,
+ NL80211_IFACE_LIMIT_TYPES,
+
+ /* keep last */
+ NUM_NL80211_IFACE_LIMIT,
+ MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ * for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ * interfaces that can be created in this group. This number doesn't
+ * apply to interfaces purely managed in software, which are listed
+ * in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ * beacon intervals within this group must be all the same even for
+ * infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ * the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ * different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ * limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ * => allows an AP and a STA that must match BIs
+ *
+ * numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ * => allows 8 of AP/GO
+ *
+ * numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ * => allows two STAs on different channels
+ *
+ * numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ * => allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ * numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+ NL80211_IFACE_COMB_UNSPEC,
+ NL80211_IFACE_COMB_LIMITS,
+ NL80211_IFACE_COMB_MAXNUM,
+ NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+ NL80211_IFACE_COMB_NUM_CHANNELS,
+
+ /* keep last */
+ NUM_NL80211_IFACE_COMB,
+ MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ * state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ * this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ * from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ * received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ * plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+ NL80211_PLINK_LISTEN,
+ NL80211_PLINK_OPN_SNT,
+ NL80211_PLINK_OPN_RCVD,
+ NL80211_PLINK_CNF_RCVD,
+ NL80211_PLINK_ESTAB,
+ NL80211_PLINK_HOLDING,
+ NL80211_PLINK_BLOCKED,
+
+ /* keep last */
+ NUM_NL80211_PLINK_STATES,
+ MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
#endif /* __LINUX_NL80211_H */
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h
index 7e99b34..f017b89 100644
--- a/include/linux/ssb/ssb.h
+++ b/include/linux/ssb/ssb.h
@@ -518,6 +518,7 @@
* Otherwise static always-on powercontrol will be used. */
extern int ssb_bus_powerup(struct ssb_bus *bus, bool dynamic_pctl);
+extern void ssb_commit_settings(struct ssb_bus *bus);
/* Various helper functions */
extern u32 ssb_admatch_base(u32 adm);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 14cc324..6c994c0 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -422,6 +422,7 @@
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
+int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level);
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
int hci_conn_change_link_key(struct hci_conn *conn);
int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c34b1c1..d09c9b1 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -350,6 +350,7 @@
struct list_head srej_l;
struct list_head list;
+ struct list_head global_l;
};
struct l2cap_conn {
@@ -441,7 +442,6 @@
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
extern int disable_ertm;
-extern struct bt_sock_list l2cap_sk_list;
int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);
@@ -458,6 +458,9 @@
void l2cap_streaming_send(struct l2cap_chan *chan);
int l2cap_ertm_send(struct l2cap_chan *chan);
+int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
+int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
+
void l2cap_sock_set_timer(struct sock *sk, long timeout);
void l2cap_sock_clear_timer(struct sock *sk);
void __l2cap_sock_close(struct sock *sk, int reason);
@@ -466,9 +469,9 @@
struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
int proto, gfp_t prio);
void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err);
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk);
+struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_del(struct l2cap_chan *chan, int err);
-void l2cap_chan_free(struct l2cap_chan *chan);
+void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);
#endif /* __L2CAP_H */
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index d30eada..bfd6557 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -387,6 +387,7 @@
* @listen_interval: listen interval or -1 for no change
* @aid: AID or zero for no change
* @plink_action: plink action to take
+ * @plink_state: set the peer link state for a station
* @ht_capa: HT capabilities of station
*/
struct station_parameters {
@@ -397,6 +398,7 @@
u16 aid;
u8 supported_rates_len;
u8 plink_action;
+ u8 plink_state;
struct ieee80211_ht_cap *ht_capa;
};
@@ -695,7 +697,8 @@
* @path_metric: which metric to use
* @ie: vendor information elements (optional)
* @ie_len: length of vendor information elements
- * @is_secure: or not
+ * @is_authenticated: this mesh requires authentication
+ * @is_secure: this mesh uses security
*
* These parameters are fixed when the mesh is created.
*/
@@ -706,6 +709,7 @@
u8 path_metric;
const u8 *ie;
u8 ie_len;
+ bool is_authenticated;
bool is_secure;
};
@@ -793,6 +797,35 @@
};
/**
+ * struct cfg80211_sched_scan_request - scheduled scan request description
+ *
+ * @ssids: SSIDs to scan for (passed in the probe_reqs in active scans)
+ * @n_ssids: number of SSIDs
+ * @n_channels: total number of channels to scan
+ * @interval: interval between each scheduled scan cycle
+ * @ie: optional information element(s) to add into Probe Request or %NULL
+ * @ie_len: length of ie in octets
+ * @wiphy: the wiphy this was for
+ * @dev: the interface
+ * @channels: channels to scan
+ */
+struct cfg80211_sched_scan_request {
+ struct cfg80211_ssid *ssids;
+ int n_ssids;
+ u32 n_channels;
+ u32 interval;
+ const u8 *ie;
+ size_t ie_len;
+
+ /* internal */
+ struct wiphy *wiphy;
+ struct net_device *dev;
+
+ /* keep last */
+ struct ieee80211_channel *channels[0];
+};
+
+/**
* enum cfg80211_signal_type - signal type
*
* @CFG80211_SIGNAL_TYPE_NONE: no signal strength information available
@@ -1088,6 +1121,38 @@
};
/**
+ * struct cfg80211_wowlan_trig_pkt_pattern - packet pattern
+ * @mask: bitmask where to match pattern and where to ignore bytes,
+ * one bit per byte, in same format as nl80211
+ * @pattern: bytes to match where bitmask is 1
+ * @pattern_len: length of pattern (in bytes)
+ *
+ * Internal note: @mask and @pattern are allocated in one chunk of
+ * memory, free @mask only!
+ */
+struct cfg80211_wowlan_trig_pkt_pattern {
+ u8 *mask, *pattern;
+ int pattern_len;
+};
+
+/**
+ * struct cfg80211_wowlan - Wake on Wireless-LAN support info
+ *
+ * This structure defines the enabled WoWLAN triggers for the device.
+ * @any: wake up on any activity -- special trigger if device continues
+ * operating as normal during suspend
+ * @disconnect: wake up if getting disconnected
+ * @magic_pkt: wake up on receiving magic packet
+ * @patterns: wake up on receiving packet matching a pattern
+ * @n_patterns: number of patterns
+ */
+struct cfg80211_wowlan {
+ bool any, disconnect, magic_pkt;
+ struct cfg80211_wowlan_trig_pkt_pattern *patterns;
+ int n_patterns;
+};
+
+/**
* struct cfg80211_ops - backend description for wireless configuration
*
* This struct is registered by fullmac card drivers and/or wireless stacks
@@ -1100,7 +1165,9 @@
* wireless extensions but this is subject to reevaluation as soon as this
* code is used more widely and we have a first user without wext.
*
- * @suspend: wiphy device needs to be suspended
+ * @suspend: wiphy device needs to be suspended. The variable @wow will
+ * be %NULL or contain the enabled Wake-on-Wireless triggers that are
+ * configured for the device.
* @resume: wiphy device needs to be resumed
*
* @add_virtual_intf: create a new virtual interface with the given name,
@@ -1227,6 +1294,10 @@
* @set_power_mgmt: Configure WLAN power management. A timeout value of -1
* allows the driver to adjust the dynamic ps timeout value.
* @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold.
+ * @sched_scan_start: Tell the driver to start a scheduled scan.
+ * @sched_scan_stop: Tell the driver to stop an ongoing scheduled
+ * scan. The driver_initiated flag specifies whether the driver
+ * itself has informed that the scan has stopped.
*
* @mgmt_frame_register: Notify driver that a management frame type was
* registered. Note that this callback may not sleep, and cannot run
@@ -1244,7 +1315,7 @@
* @get_ringparam: Get tx and rx ring current and maximum sizes.
*/
struct cfg80211_ops {
- int (*suspend)(struct wiphy *wiphy);
+ int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
int (*resume)(struct wiphy *wiphy);
struct net_device * (*add_virtual_intf)(struct wiphy *wiphy,
@@ -1413,6 +1484,11 @@
int (*set_ringparam)(struct wiphy *wiphy, u32 tx, u32 rx);
void (*get_ringparam)(struct wiphy *wiphy,
u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max);
+
+ int (*sched_scan_start)(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *request);
+ int (*sched_scan_stop)(struct wiphy *wiphy, struct net_device *dev);
};
/*
@@ -1444,6 +1520,10 @@
* hints read the documenation for regulatory_hint_found_beacon()
* @WIPHY_FLAG_NETNS_OK: if not set, do not allow changing the netns of this
* wiphy at all
+ * @WIPHY_FLAG_ENFORCE_COMBINATIONS: Set this flag to enforce interface
+ * combinations for this device. This flag is used for backward
+ * compatibility only until all drivers advertise combinations and
+ * they will always be enforced.
* @WIPHY_FLAG_PS_ON_BY_DEFAULT: if set to true, powersave will be enabled
* by default -- this flag will be set depending on the kernel's default
* on wiphy_new(), but can be changed by the driver if it has a good
@@ -1455,10 +1535,9 @@
* control port protocol ethertype. The device also honours the
* control_port_no_encrypt flag.
* @WIPHY_FLAG_IBSS_RSN: The device supports IBSS RSN.
- * @WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS: The device supports separate
- * unicast and multicast TX keys.
* @WIPHY_FLAG_MESH_AUTH: The device supports mesh authentication by routing
* auth frames to userspace. See @NL80211_MESH_SETUP_USERSPACE_AUTH.
+ * @WIPHY_FLAG_SCHED_SCAN: The device supports scheduled scans.
*/
enum wiphy_flags {
WIPHY_FLAG_CUSTOM_REGULATORY = BIT(0),
@@ -1470,8 +1549,83 @@
WIPHY_FLAG_4ADDR_STATION = BIT(6),
WIPHY_FLAG_CONTROL_PORT_PROTOCOL = BIT(7),
WIPHY_FLAG_IBSS_RSN = BIT(8),
- WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS= BIT(9),
WIPHY_FLAG_MESH_AUTH = BIT(10),
+ WIPHY_FLAG_SUPPORTS_SCHED_SCAN = BIT(11),
+ WIPHY_FLAG_ENFORCE_COMBINATIONS = BIT(12),
+};
+
+/**
+ * struct ieee80211_iface_limit - limit on certain interface types
+ * @max: maximum number of interfaces of these types
+ * @types: interface types (bits)
+ */
+struct ieee80211_iface_limit {
+ u16 max;
+ u16 types;
+};
+
+/**
+ * struct ieee80211_iface_combination - possible interface combination
+ * @limits: limits for the given interface types
+ * @n_limits: number of limitations
+ * @num_different_channels: can use up to this many different channels
+ * @max_interfaces: maximum number of interfaces in total allowed in this
+ * group
+ * @beacon_int_infra_match: In this combination, the beacon intervals
+ * between infrastructure and AP types must match. This is required
+ * only in special cases.
+ *
+ * These examples can be expressed as follows:
+ *
+ * Allow #STA <= 1, #AP <= 1, matching BI, channels = 1, 2 total:
+ *
+ * struct ieee80211_iface_limit limits1[] = {
+ * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), },
+ * { .max = 1, .types = BIT(NL80211_IFTYPE_AP}, },
+ * };
+ * struct ieee80211_iface_combination combination1 = {
+ * .limits = limits1,
+ * .n_limits = ARRAY_SIZE(limits1),
+ * .max_interfaces = 2,
+ * .beacon_int_infra_match = true,
+ * };
+ *
+ *
+ * Allow #{AP, P2P-GO} <= 8, channels = 1, 8 total:
+ *
+ * struct ieee80211_iface_limit limits2[] = {
+ * { .max = 8, .types = BIT(NL80211_IFTYPE_AP) |
+ * BIT(NL80211_IFTYPE_P2P_GO), },
+ * };
+ * struct ieee80211_iface_combination combination2 = {
+ * .limits = limits2,
+ * .n_limits = ARRAY_SIZE(limits2),
+ * .max_interfaces = 8,
+ * .num_different_channels = 1,
+ * };
+ *
+ *
+ * Allow #STA <= 1, #{P2P-client,P2P-GO} <= 3 on two channels, 4 total.
+ * This allows for an infrastructure connection and three P2P connections.
+ *
+ * struct ieee80211_iface_limit limits3[] = {
+ * { .max = 1, .types = BIT(NL80211_IFTYPE_STATION), },
+ * { .max = 3, .types = BIT(NL80211_IFTYPE_P2P_GO) |
+ * BIT(NL80211_IFTYPE_P2P_CLIENT), },
+ * };
+ * struct ieee80211_iface_combination combination3 = {
+ * .limits = limits3,
+ * .n_limits = ARRAY_SIZE(limits3),
+ * .max_interfaces = 4,
+ * .num_different_channels = 2,
+ * };
+ */
+struct ieee80211_iface_combination {
+ const struct ieee80211_iface_limit *limits;
+ u32 num_different_channels;
+ u16 max_interfaces;
+ u8 n_limits;
+ bool beacon_int_infra_match;
};
struct mac_address {
@@ -1483,6 +1637,38 @@
};
/**
+ * enum wiphy_wowlan_support_flags - WoWLAN support flags
+ * @WIPHY_WOWLAN_ANY: supports wakeup for the special "any"
+ * trigger that keeps the device operating as-is and
+ * wakes up the host on any activity, for example a
+ * received packet that passed filtering; note that the
+ * packet should be preserved in that case
+ * @WIPHY_WOWLAN_MAGIC_PKT: supports wakeup on magic packet
+ * (see nl80211.h)
+ * @WIPHY_WOWLAN_DISCONNECT: supports wakeup on disconnect
+ */
+enum wiphy_wowlan_support_flags {
+ WIPHY_WOWLAN_ANY = BIT(0),
+ WIPHY_WOWLAN_MAGIC_PKT = BIT(1),
+ WIPHY_WOWLAN_DISCONNECT = BIT(2),
+};
+
+/**
+ * struct wiphy_wowlan_support - WoWLAN support data
+ * @flags: see &enum wiphy_wowlan_support_flags
+ * @n_patterns: number of supported wakeup patterns
+ * (see nl80211.h for the pattern definition)
+ * @pattern_max_len: maximum length of each pattern
+ * @pattern_min_len: minimum length of each pattern
+ */
+struct wiphy_wowlan_support {
+ u32 flags;
+ int n_patterns;
+ int pattern_max_len;
+ int pattern_min_len;
+};
+
+/**
* struct wiphy - wireless hardware description
* @reg_notifier: the driver's regulatory notification callback,
* note that if your driver uses wiphy_apply_custom_regulatory()
@@ -1519,6 +1705,11 @@
* @priv: driver private data (sized according to wiphy_new() parameter)
* @interface_modes: bitmask of interfaces types valid for this wiphy,
* must be set by driver
+ * @iface_combinations: Valid interface combinations array, should not
+ * list single interface types.
+ * @n_iface_combinations: number of entries in @iface_combinations array.
+ * @software_iftypes: bitmask of software interface types, these are not
+ * subject to any restrictions since they are purely managed in SW.
* @flags: wiphy flags, see &enum wiphy_flags
* @bss_priv_size: each BSS struct has private data allocated with it,
* this variable determines its size
@@ -1549,6 +1740,8 @@
*
* @max_remain_on_channel_duration: Maximum time a remain-on-channel operation
* may request, if implemented.
+ *
+ * @wowlan: WoWLAN support information
*/
struct wiphy {
/* assign these fields before you register the wiphy */
@@ -1561,6 +1754,10 @@
const struct ieee80211_txrx_stypes *mgmt_stypes;
+ const struct ieee80211_iface_combination *iface_combinations;
+ int n_iface_combinations;
+ u16 software_iftypes;
+
u16 n_addresses;
/* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
@@ -1586,6 +1783,8 @@
char fw_version[ETHTOOL_BUSINFO_LEN];
u32 hw_version;
+ struct wiphy_wowlan_support wowlan;
+
u16 max_remain_on_channel_duration;
u8 max_num_pmkids;
@@ -1769,6 +1968,8 @@
* @mgmt_registrations_lock: lock for the list
* @mtx: mutex used to lock data in this struct
* @cleanup_work: work struct used for cleanup that can't be done directly
+ * @beacon_interval: beacon interval used on this device for transmitting
+ * beacons, 0 when not valid
*/
struct wireless_dev {
struct wiphy *wiphy;
@@ -1809,6 +2010,8 @@
bool ps;
int ps_timeout;
+ int beacon_interval;
+
#ifdef CONFIG_CFG80211_WEXT
/* wext data */
struct {
@@ -2034,10 +2237,12 @@
* @addr: The device MAC address.
* @iftype: The device interface type.
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
+ * @has_80211_header: Set it true if SKB is with IEEE 802.11 header.
*/
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom);
+ const unsigned int extra_headroom,
+ bool has_80211_header);
/**
* cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
@@ -2257,6 +2462,24 @@
void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
/**
+ * cfg80211_sched_scan_results - notify that new scan results are available
+ *
+ * @wiphy: the wiphy which got scheduled scan results
+ */
+void cfg80211_sched_scan_results(struct wiphy *wiphy);
+
+/**
+ * cfg80211_sched_scan_stopped - notify that the scheduled scan has stopped
+ *
+ * @wiphy: the wiphy on which the scheduled scan stopped
+ *
+ * The driver can call this function to inform cfg80211 that the
+ * scheduled scan had to be stopped, for whatever reason. The driver
+ * is then called back via the sched_scan_stop operation when done.
+ */
+void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
+
+/**
* cfg80211_inform_bss_frame - inform cfg80211 of a received BSS frame
*
* @wiphy: the wiphy reporting the BSS
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index db4b6b9..8c7189c 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -537,6 +537,21 @@
};
};
+/**
+ * ieee80211_sched_scan_ies - scheduled scan IEs
+ *
+ * This structure is used to pass the appropriate IEs to be used in scheduled
+ * scans for all bands. It contains both the IEs passed from the userspace
+ * and the ones generated by mac80211.
+ *
+ * @ie: array with the IEs for each supported band
+ * @len: array with the total length of the IEs for each band
+ */
+struct ieee80211_sched_scan_ies {
+ u8 *ie[IEEE80211_NUM_BANDS];
+ size_t len[IEEE80211_NUM_BANDS];
+};
+
static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb)
{
return (struct ieee80211_tx_info *)skb->cb;
@@ -1606,6 +1621,18 @@
* you should ensure to cancel it on this callback.
* Must be implemented and can sleep.
*
+ * @suspend: Suspend the device; mac80211 itself will quiesce before and
+ * stop transmitting and doing any other configuration, and then
+ * ask the device to suspend. This is only invoked when WoWLAN is
+ * configured, otherwise the device is deconfigured completely and
+ * reconfigured at resume time.
+ *
+ * @resume: If WoWLAN was configured, this indicates that mac80211 is
+ * now resuming its operation, after this the device must be fully
+ * functional again. If this returns an error, the only way out is
+ * to also unregister the device. If it returns 1, then mac80211
+ * will also go through the regular complete restart on resume.
+ *
* @add_interface: Called when a netdevice attached to the hardware is
* enabled. Because it is not called for monitor mode devices, @start
* and @stop must be implemented.
@@ -1681,6 +1708,13 @@
* any error unless this callback returned a negative error code.
* The callback can sleep.
*
+ * @sched_scan_start: Ask the hardware to start scanning repeatedly at
+ * specific intervals. The driver must call the
+ * ieee80211_sched_scan_results() function whenever it finds results.
+ * This process will continue until sched_scan_stop is called.
+ *
+ * @sched_scan_stop: Tell the hardware to stop an ongoing scheduled scan.
+ *
* @sw_scan_start: Notifier function that is called just before a software scan
* is started. Can be NULL, if the driver doesn't need this notification.
* The callback can sleep.
@@ -1831,6 +1865,10 @@
void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw);
+#ifdef CONFIG_PM
+ int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+ int (*resume)(struct ieee80211_hw *hw);
+#endif
int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif);
int (*change_interface)(struct ieee80211_hw *hw,
@@ -1861,6 +1899,12 @@
u32 iv32, u16 *phase1key);
int (*hw_scan)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
struct cfg80211_scan_request *req);
+ int (*sched_scan_start)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies);
+ void (*sched_scan_stop)(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif);
void (*sw_scan_start)(struct ieee80211_hw *hw);
void (*sw_scan_complete)(struct ieee80211_hw *hw);
int (*get_stats)(struct ieee80211_hw *hw,
@@ -2578,6 +2622,28 @@
void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted);
/**
+ * ieee80211_sched_scan_results - got results from scheduled scan
+ *
+ * When a scheduled scan is running, this function needs to be called by the
+ * driver whenever there are new scan results available.
+ *
+ * @hw: the hardware that is performing scheduled scans
+ */
+void ieee80211_sched_scan_results(struct ieee80211_hw *hw);
+
+/**
+ * ieee80211_sched_scan_stopped - inform that the scheduled scan has stopped
+ *
+ * When a scheduled scan is running, this function can be called by
+ * the driver if it needs to stop the scan to perform another task.
+ * Usual scenarios are drivers that cannot continue the scheduled scan
+ * while associating, for instance.
+ *
+ * @hw: the hardware that is performing scheduled scans
+ */
+void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
+
+/**
* ieee80211_iterate_active_interfaces - iterate active interfaces
*
* This function iterates over the interfaces associated with a given
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 7f5ad8a..3163330 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -623,6 +623,23 @@
}
EXPORT_SYMBOL(hci_conn_security);
+/* Check secure link requirement */
+int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level)
+{
+ BT_DBG("conn %p", conn);
+
+ if (sec_level != BT_SECURITY_HIGH)
+ return 1; /* Accept if non-secure is required */
+
+ if (conn->key_type == HCI_LK_AUTH_COMBINATION ||
+ (conn->key_type == HCI_LK_COMBINATION &&
+ conn->pin_length == 16))
+ return 1;
+
+ return 0; /* Reject not secure link */
+}
+EXPORT_SYMBOL(hci_conn_check_secure);
+
/* Change link key */
int hci_conn_change_link_key(struct hci_conn *conn)
{
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d5aa97e..f13ddbf 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1440,7 +1440,7 @@
conn->state = BT_CLOSED;
- if (conn->type == ACL_LINK)
+ if (conn->type == ACL_LINK || conn->type == LE_LINK)
mgmt_disconnected(hdev->id, &conn->dst);
hci_proto_disconn_cfm(conn, ev->reason);
@@ -2659,12 +2659,15 @@
}
if (ev->status) {
+ mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
hci_proto_connect_cfm(conn, ev->status);
conn->state = BT_CLOSED;
hci_conn_del(conn);
goto unlock;
}
+ mgmt_connected(hdev->id, &ev->bdaddr);
+
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index a378acc..4f3bc74 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -62,9 +62,8 @@
static struct workqueue_struct *_busy_wq;
-struct bt_sock_list l2cap_sk_list = {
- .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock)
-};
+LIST_HEAD(chan_list);
+DEFINE_RWLOCK(chan_list_lock);
static void l2cap_busy_work(struct work_struct *work);
@@ -135,6 +134,64 @@
return c;
}
+static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
+{
+ struct l2cap_chan *c;
+
+ list_for_each_entry(c, &chan_list, global_l) {
+ if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src))
+ goto found;
+ }
+
+ c = NULL;
+found:
+ return c;
+}
+
+int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm)
+{
+ int err;
+
+ write_lock_bh(&chan_list_lock);
+
+ if (psm && __l2cap_global_chan_by_addr(psm, src)) {
+ err = -EADDRINUSE;
+ goto done;
+ }
+
+ if (psm) {
+ chan->psm = psm;
+ chan->sport = psm;
+ err = 0;
+ } else {
+ u16 p;
+
+ err = -EINVAL;
+ for (p = 0x1001; p < 0x1100; p += 2)
+ if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) {
+ chan->psm = cpu_to_le16(p);
+ chan->sport = cpu_to_le16(p);
+ err = 0;
+ break;
+ }
+ }
+
+done:
+ write_unlock_bh(&chan_list_lock);
+ return err;
+}
+
+int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid)
+{
+ write_lock_bh(&chan_list_lock);
+
+ chan->scid = scid;
+
+ write_unlock_bh(&chan_list_lock);
+
+ return 0;
+}
+
static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
{
u16 cid = L2CAP_CID_DYN_START;
@@ -147,7 +204,7 @@
return 0;
}
-struct l2cap_chan *l2cap_chan_alloc(struct sock *sk)
+struct l2cap_chan *l2cap_chan_create(struct sock *sk)
{
struct l2cap_chan *chan;
@@ -157,11 +214,19 @@
chan->sk = sk;
+ write_lock_bh(&chan_list_lock);
+ list_add(&chan->global_l, &chan_list);
+ write_unlock_bh(&chan_list_lock);
+
return chan;
}
-void l2cap_chan_free(struct l2cap_chan *chan)
+void l2cap_chan_destroy(struct l2cap_chan *chan)
{
+ write_lock_bh(&chan_list_lock);
+ list_del(&chan->global_l);
+ write_unlock_bh(&chan_list_lock);
+
kfree(chan);
}
@@ -591,48 +656,51 @@
/* Find socket with cid and source bdaddr.
* Returns closest match, locked.
*/
-static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src)
{
- struct sock *sk = NULL, *sk1 = NULL;
- struct hlist_node *node;
+ struct l2cap_chan *c, *c1 = NULL;
- read_lock(&l2cap_sk_list.lock);
+ read_lock(&chan_list_lock);
- sk_for_each(sk, node, &l2cap_sk_list.head) {
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ list_for_each_entry(c, &chan_list, global_l) {
+ struct sock *sk = c->sk;
if (state && sk->sk_state != state)
continue;
- if (chan->scid == cid) {
+ if (c->scid == cid) {
/* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src))
- break;
+ if (!bacmp(&bt_sk(sk)->src, src)) {
+ read_unlock(&chan_list_lock);
+ return c;
+ }
/* Closest match */
if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- sk1 = sk;
+ c1 = c;
}
}
- read_unlock(&l2cap_sk_list.lock);
+ read_unlock(&chan_list_lock);
- return node ? sk : sk1;
+ return c1;
}
static void l2cap_le_conn_ready(struct l2cap_conn *conn)
{
struct sock *parent, *sk;
- struct l2cap_chan *chan;
+ struct l2cap_chan *chan, *pchan;
BT_DBG("");
/* Check if we have socket listening on cid */
- parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
+ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA,
conn->src);
- if (!parent)
+ if (!pchan)
return;
+ parent = pchan->sk;
+
bh_lock_sock(parent);
/* Check for backlog size */
@@ -645,7 +713,7 @@
if (!sk)
goto clean;
- chan = l2cap_chan_alloc(sk);
+ chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
goto clean;
@@ -823,33 +891,34 @@
/* Find socket with psm and source bdaddr.
* Returns closest match.
*/
-static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
+static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src)
{
- struct sock *sk = NULL, *sk1 = NULL;
- struct hlist_node *node;
+ struct l2cap_chan *c, *c1 = NULL;
- read_lock(&l2cap_sk_list.lock);
+ read_lock(&chan_list_lock);
- sk_for_each(sk, node, &l2cap_sk_list.head) {
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ list_for_each_entry(c, &chan_list, global_l) {
+ struct sock *sk = c->sk;
if (state && sk->sk_state != state)
continue;
- if (chan->psm == psm) {
+ if (c->psm == psm) {
/* Exact match. */
- if (!bacmp(&bt_sk(sk)->src, src))
- break;
+ if (!bacmp(&bt_sk(sk)->src, src)) {
+ read_unlock_bh(&chan_list_lock);
+ return c;
+ }
/* Closest match */
if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
- sk1 = sk;
+ c1 = c;
}
}
- read_unlock(&l2cap_sk_list.lock);
+ read_unlock(&chan_list_lock);
- return node ? sk : sk1;
+ return c1;
}
int l2cap_chan_connect(struct l2cap_chan *chan)
@@ -2019,7 +2088,7 @@
{
struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
struct l2cap_conn_rsp rsp;
- struct l2cap_chan *chan = NULL;
+ struct l2cap_chan *chan = NULL, *pchan;
struct sock *parent, *sk = NULL;
int result, status = L2CAP_CS_NO_INFO;
@@ -2029,12 +2098,14 @@
BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid);
/* Check if we have socket listening on psm */
- parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src);
- if (!parent) {
+ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src);
+ if (!pchan) {
result = L2CAP_CR_BAD_PSM;
goto sendresp;
}
+ parent = pchan->sk;
+
bh_lock_sock(parent);
/* Check if the ACL is secure enough (if not SDP) */
@@ -2057,7 +2128,7 @@
if (!sk)
goto response;
- chan = l2cap_chan_alloc(sk);
+ chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
goto response;
@@ -3685,11 +3756,14 @@
static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb)
{
struct sock *sk;
+ struct l2cap_chan *chan;
- sk = l2cap_get_sock_by_psm(0, psm, conn->src);
- if (!sk)
+ chan = l2cap_global_chan_by_psm(0, psm, conn->src);
+ if (!chan)
goto drop;
+ sk = chan->sk;
+
bh_lock_sock(sk);
BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3715,11 +3789,14 @@
static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb)
{
struct sock *sk;
+ struct l2cap_chan *chan;
- sk = l2cap_get_sock_by_scid(0, cid, conn->src);
- if (!sk)
+ chan = l2cap_global_chan_by_scid(0, cid, conn->src);
+ if (!chan)
goto drop;
+ sk = chan->sk;
+
bh_lock_sock(sk);
BT_DBG("sk %p, len %d", sk, skb->len);
@@ -3786,8 +3863,7 @@
static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
{
int exact = 0, lm1 = 0, lm2 = 0;
- register struct sock *sk;
- struct hlist_node *node;
+ struct l2cap_chan *c;
if (type != ACL_LINK)
return -EINVAL;
@@ -3795,25 +3871,25 @@
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Find listening sockets and check their link_mode */
- read_lock(&l2cap_sk_list.lock);
- sk_for_each(sk, node, &l2cap_sk_list.head) {
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
+ read_lock(&chan_list_lock);
+ list_for_each_entry(c, &chan_list, global_l) {
+ struct sock *sk = c->sk;
if (sk->sk_state != BT_LISTEN)
continue;
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
lm1 |= HCI_LM_ACCEPT;
- if (chan->role_switch)
+ if (c->role_switch)
lm1 |= HCI_LM_MASTER;
exact++;
} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
lm2 |= HCI_LM_ACCEPT;
- if (chan->role_switch)
+ if (c->role_switch)
lm2 |= HCI_LM_MASTER;
}
}
- read_unlock(&l2cap_sk_list.lock);
+ read_unlock(&chan_list_lock);
return exact ? lm1 : lm2;
}
@@ -4066,25 +4142,22 @@
static int l2cap_debugfs_show(struct seq_file *f, void *p)
{
- struct sock *sk;
- struct hlist_node *node;
+ struct l2cap_chan *c;
- read_lock_bh(&l2cap_sk_list.lock);
+ read_lock_bh(&chan_list_lock);
- sk_for_each(sk, node, &l2cap_sk_list.head) {
- struct l2cap_pinfo *pi = l2cap_pi(sk);
- struct l2cap_chan *chan = pi->chan;
+ list_for_each_entry(c, &chan_list, global_l) {
+ struct sock *sk = c->sk;
seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
batostr(&bt_sk(sk)->src),
batostr(&bt_sk(sk)->dst),
- sk->sk_state, __le16_to_cpu(chan->psm),
- chan->scid, chan->dcid,
- chan->imtu, chan->omtu, chan->sec_level,
- chan->mode);
+ sk->sk_state, __le16_to_cpu(c->psm),
+ c->scid, c->dcid, c->imtu, c->omtu,
+ c->sec_level, c->mode);
}
- read_unlock_bh(&l2cap_sk_list.lock);
+ read_unlock_bh(&chan_list_lock);
return 0;
}
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 7c4a9ae..18dc988 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -78,22 +78,6 @@
sk_stop_timer(sk, &sk->sk_timer);
}
-static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src)
-{
- struct sock *sk;
- struct hlist_node *node;
- sk_for_each(sk, node, &l2cap_sk_list.head) {
- struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-
- if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src))
- goto found;
- }
-
- sk = NULL;
-found:
- return sk;
-}
-
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sock *sk = sock->sk;
@@ -136,26 +120,20 @@
}
}
- write_lock_bh(&l2cap_sk_list.lock);
-
- if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
- err = -EADDRINUSE;
- } else {
- /* Save source address */
- bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
- chan->psm = la.l2_psm;
- chan->sport = la.l2_psm;
- sk->sk_state = BT_BOUND;
-
- if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
- __le16_to_cpu(la.l2_psm) == 0x0003)
- chan->sec_level = BT_SECURITY_SDP;
- }
-
if (la.l2_cid)
- chan->scid = la.l2_cid;
+ err = l2cap_add_scid(chan, la.l2_cid);
+ else
+ err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm);
- write_unlock_bh(&l2cap_sk_list.lock);
+ if (err < 0)
+ goto done;
+
+ if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
+ __le16_to_cpu(la.l2_psm) == 0x0003)
+ chan->sec_level = BT_SECURITY_SDP;
+
+ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+ sk->sk_state = BT_BOUND;
done:
release_sock(sk);
@@ -278,28 +256,6 @@
goto done;
}
- if (!chan->psm && !chan->scid) {
- bdaddr_t *src = &bt_sk(sk)->src;
- u16 psm;
-
- err = -EINVAL;
-
- write_lock_bh(&l2cap_sk_list.lock);
-
- for (psm = 0x1001; psm < 0x1100; psm += 2)
- if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) {
- chan->psm = cpu_to_le16(psm);
- chan->sport = cpu_to_le16(psm);
- err = 0;
- break;
- }
-
- write_unlock_bh(&l2cap_sk_list.lock);
-
- if (err < 0)
- goto done;
- }
-
sk->sk_max_ack_backlog = backlog;
sk->sk_ack_backlog = 0;
sk->sk_state = BT_LISTEN;
@@ -852,8 +808,7 @@
/* Kill poor orphan */
- l2cap_chan_free(l2cap_pi(sk)->chan);
- bt_sock_unlink(&l2cap_sk_list, sk);
+ l2cap_chan_destroy(l2cap_pi(sk)->chan);
sock_set_flag(sk, SOCK_DEAD);
sock_put(sk);
}
@@ -1069,7 +1024,6 @@
setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
- bt_sock_link(&l2cap_sk_list, sk);
return sk;
}
@@ -1096,7 +1050,7 @@
if (!sk)
return -ENOMEM;
- chan = l2cap_chan_alloc(sk);
+ chan = l2cap_chan_create(sk);
if (!chan) {
l2cap_sock_kill(sk);
return -ENOMEM;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2481d25..dae382c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1033,6 +1033,9 @@
}
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+ if (!conn)
+ conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
+
if (!conn) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN);
goto failed;
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 121a5c1..5759bb7 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -2096,7 +2096,7 @@
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue;
- if (!status)
+ if (!status && hci_conn_check_secure(conn, d->sec_level))
set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c
index 0c9d0c0..9c0d76c 100644
--- a/net/mac80211/agg-rx.c
+++ b/net/mac80211/agg-rx.c
@@ -63,7 +63,8 @@
lockdep_assert_held(&sta->ampdu_mlme.mtx);
- tid_rx = sta->ampdu_mlme.tid_rx[tid];
+ tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
+ lockdep_is_held(&sta->ampdu_mlme.mtx));
if (!tid_rx)
return;
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 63d852c..cd5125f 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -136,6 +136,14 @@
ieee80211_tx_skb(sdata, skb);
}
+void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+ struct tid_ampdu_tx *tid_tx)
+{
+ lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ lockdep_assert_held(&sta->lock);
+ rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+}
+
static void kfree_tid_tx(struct rcu_head *rcu_head)
{
struct tid_ampdu_tx *tid_tx =
@@ -149,19 +157,22 @@
bool tx)
{
struct ieee80211_local *local = sta->local;
- struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ struct tid_ampdu_tx *tid_tx;
int ret;
lockdep_assert_held(&sta->ampdu_mlme.mtx);
- if (!tid_tx)
- return -ENOENT;
-
spin_lock_bh(&sta->lock);
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+ if (!tid_tx) {
+ spin_unlock_bh(&sta->lock);
+ return -ENOENT;
+ }
+
if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
/* not even started yet! */
- rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ ieee80211_assign_tid_tx(sta, tid, NULL);
spin_unlock_bh(&sta->lock);
call_rcu(&tid_tx->rcu_head, kfree_tid_tx);
return 0;
@@ -283,13 +294,13 @@
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
{
- struct tid_ampdu_tx *tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ struct tid_ampdu_tx *tid_tx;
struct ieee80211_local *local = sta->local;
struct ieee80211_sub_if_data *sdata = sta->sdata;
u16 start_seq_num;
int ret;
- lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
/*
* While we're asking the driver about the aggregation,
@@ -318,7 +329,7 @@
" tid %d\n", tid);
#endif
spin_lock_bh(&sta->lock);
- rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ ieee80211_assign_tid_tx(sta, tid, NULL);
spin_unlock_bh(&sta->lock);
ieee80211_wake_queue_agg(local, tid);
@@ -396,9 +407,9 @@
goto err_unlock_sta;
}
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
/* check if the TID is not in aggregation flow already */
- if (tid_tx) {
+ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) {
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "BA request denied - session is not "
"idle on tid %u\n", tid);
@@ -433,8 +444,11 @@
sta->ampdu_mlme.dialog_token_allocator++;
tid_tx->dialog_token = sta->ampdu_mlme.dialog_token_allocator;
- /* finally, assign it to the array */
- rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
+ /*
+ * Finally, assign it to the start array; the work item will
+ * collect it and move it to the normal array.
+ */
+ sta->ampdu_mlme.tid_start_tx[tid] = tid_tx;
ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
@@ -480,16 +494,19 @@
static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
struct sta_info *sta, u16 tid)
{
+ struct tid_ampdu_tx *tid_tx;
+
lockdep_assert_held(&sta->ampdu_mlme.mtx);
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+
#ifdef CONFIG_MAC80211_HT_DEBUG
printk(KERN_DEBUG "Aggregation is on for tid %d\n", tid);
#endif
drv_ampdu_action(local, sta->sdata,
IEEE80211_AMPDU_TX_OPERATIONAL,
- &sta->sta, tid, NULL,
- sta->ampdu_mlme.tid_tx[tid]->buf_size);
+ &sta->sta, tid, NULL, tid_tx->buf_size);
/*
* synchronize with TX path, while splicing the TX path
@@ -497,13 +514,13 @@
*/
spin_lock_bh(&sta->lock);
- ieee80211_agg_splice_packets(local, sta->ampdu_mlme.tid_tx[tid], tid);
+ ieee80211_agg_splice_packets(local, tid_tx, tid);
/*
* Now mark as operational. This will be visible
* in the TX path, and lets it go lock-free in
* the common case.
*/
- set_bit(HT_AGG_STATE_OPERATIONAL, &sta->ampdu_mlme.tid_tx[tid]->state);
+ set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
ieee80211_agg_splice_finish(local, tid);
spin_unlock_bh(&sta->lock);
@@ -537,7 +554,7 @@
}
mutex_lock(&sta->ampdu_mlme.mtx);
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (WARN_ON(!tid_tx)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -615,7 +632,7 @@
return -EINVAL;
spin_lock_bh(&sta->lock);
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx) {
ret = -ENOENT;
@@ -671,7 +688,7 @@
mutex_lock(&sta->ampdu_mlme.mtx);
spin_lock_bh(&sta->lock);
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
#ifdef CONFIG_MAC80211_HT_DEBUG
@@ -697,7 +714,7 @@
ieee80211_agg_splice_packets(local, tid_tx, tid);
/* future packets must not find the tid_tx struct any more */
- rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], NULL);
+ ieee80211_assign_tid_tx(sta, tid, NULL);
ieee80211_agg_splice_finish(local, tid);
@@ -752,7 +769,7 @@
mutex_lock(&sta->ampdu_mlme.mtx);
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx)
goto out;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 12d52ce..be70c70 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -136,7 +136,10 @@
mutex_lock(&sdata->local->sta_mtx);
if (mac_addr) {
- sta = sta_info_get_bss(sdata, mac_addr);
+ if (ieee80211_vif_is_mesh(&sdata->vif))
+ sta = sta_info_get(sdata, mac_addr);
+ else
+ sta = sta_info_get_bss(sdata, mac_addr);
if (!sta) {
ieee80211_key_free(sdata->local, key);
err = -ENOENT;
@@ -157,13 +160,14 @@
static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev,
u8 key_idx, bool pairwise, const u8 *mac_addr)
{
- struct ieee80211_sub_if_data *sdata;
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+ struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
+ struct ieee80211_key *key = NULL;
int ret;
- sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-
- mutex_lock(&sdata->local->sta_mtx);
+ mutex_lock(&local->sta_mtx);
+ mutex_lock(&local->key_mtx);
if (mac_addr) {
ret = -ENOENT;
@@ -172,33 +176,24 @@
if (!sta)
goto out_unlock;
- if (pairwise) {
- if (sta->ptk) {
- ieee80211_key_free(sdata->local, sta->ptk);
- ret = 0;
- }
- } else {
- if (sta->gtk[key_idx]) {
- ieee80211_key_free(sdata->local,
- sta->gtk[key_idx]);
- ret = 0;
- }
- }
+ if (pairwise)
+ key = key_mtx_dereference(local, sta->ptk);
+ else
+ key = key_mtx_dereference(local, sta->gtk[key_idx]);
+ } else
+ key = key_mtx_dereference(local, sdata->keys[key_idx]);
- goto out_unlock;
- }
-
- if (!sdata->keys[key_idx]) {
+ if (!key) {
ret = -ENOENT;
goto out_unlock;
}
- ieee80211_key_free(sdata->local, sdata->keys[key_idx]);
- WARN_ON(sdata->keys[key_idx]);
+ __ieee80211_key_free(key);
ret = 0;
out_unlock:
- mutex_unlock(&sdata->local->sta_mtx);
+ mutex_unlock(&local->key_mtx);
+ mutex_unlock(&local->sta_mtx);
return ret;
}
@@ -228,11 +223,11 @@
goto out;
if (pairwise)
- key = sta->ptk;
+ key = rcu_dereference(sta->ptk);
else if (key_idx < NUM_DEFAULT_KEYS)
- key = sta->gtk[key_idx];
+ key = rcu_dereference(sta->gtk[key_idx]);
} else
- key = sdata->keys[key_idx];
+ key = rcu_dereference(sdata->keys[key_idx]);
if (!key)
goto out;
@@ -468,7 +463,7 @@
int size;
int err = -EINVAL;
- old = sdata->u.ap.beacon;
+ old = rtnl_dereference(sdata->u.ap.beacon);
/* head must not be zero-length */
if (params->head && !params->head_len)
@@ -563,8 +558,7 @@
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
-
+ old = rtnl_dereference(sdata->u.ap.beacon);
if (old)
return -EALREADY;
@@ -579,8 +573,7 @@
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
-
+ old = rtnl_dereference(sdata->u.ap.beacon);
if (!old)
return -ENOENT;
@@ -594,8 +587,7 @@
sdata = IEEE80211_DEV_TO_SUB_IF(dev);
- old = sdata->u.ap.beacon;
-
+ old = rtnl_dereference(sdata->u.ap.beacon);
if (!old)
return -ENOENT;
@@ -734,15 +726,29 @@
params->ht_capa,
&sta->sta.ht_cap);
- if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) {
- switch (params->plink_action) {
- case PLINK_ACTION_OPEN:
- mesh_plink_open(sta);
- break;
- case PLINK_ACTION_BLOCK:
- mesh_plink_block(sta);
- break;
- }
+ if (ieee80211_vif_is_mesh(&sdata->vif)) {
+#ifdef CONFIG_MAC80211_MESH
+ if (sdata->u.mesh.security & IEEE80211_MESH_SEC_SECURED)
+ switch (params->plink_state) {
+ case NL80211_PLINK_LISTEN:
+ case NL80211_PLINK_ESTAB:
+ case NL80211_PLINK_BLOCKED:
+ sta->plink_state = params->plink_state;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ else
+ switch (params->plink_action) {
+ case PLINK_ACTION_OPEN:
+ mesh_plink_open(sta);
+ break;
+ case PLINK_ACTION_BLOCK:
+ mesh_plink_block(sta);
+ break;
+ }
+#endif
}
}
@@ -943,8 +949,10 @@
static void mpath_set_pinfo(struct mesh_path *mpath, u8 *next_hop,
struct mpath_info *pinfo)
{
- if (mpath->next_hop)
- memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
+ struct sta_info *next_hop_sta = rcu_dereference(mpath->next_hop);
+
+ if (next_hop_sta)
+ memcpy(next_hop, next_hop_sta->sta.addr, ETH_ALEN);
else
memset(next_hop, 0, ETH_ALEN);
@@ -1064,7 +1072,11 @@
memcpy(ifmsh->mesh_id, setup->mesh_id, ifmsh->mesh_id_len);
ifmsh->mesh_pp_id = setup->path_sel_proto;
ifmsh->mesh_pm_id = setup->path_metric;
- ifmsh->is_secure = setup->is_secure;
+ ifmsh->security = IEEE80211_MESH_SEC_NONE;
+ if (setup->is_authenticated)
+ ifmsh->security |= IEEE80211_MESH_SEC_AUTHED;
+ if (setup->is_secure)
+ ifmsh->security |= IEEE80211_MESH_SEC_SECURED;
return 0;
}
@@ -1297,9 +1309,10 @@
}
#ifdef CONFIG_PM
-static int ieee80211_suspend(struct wiphy *wiphy)
+static int ieee80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wowlan)
{
- return __ieee80211_suspend(wiphy_priv(wiphy));
+ return __ieee80211_suspend(wiphy_priv(wiphy), wowlan);
}
static int ieee80211_resume(struct wiphy *wiphy)
@@ -1342,6 +1355,30 @@
return ieee80211_request_scan(sdata, req);
}
+static int
+ieee80211_sched_scan_start(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_sched_scan_request *req)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (!sdata->local->ops->sched_scan_start)
+ return -EOPNOTSUPP;
+
+ return ieee80211_request_sched_scan_start(sdata, req);
+}
+
+static int
+ieee80211_sched_scan_stop(struct wiphy *wiphy, struct net_device *dev)
+{
+ struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+ if (!sdata->local->ops->sched_scan_stop)
+ return -EOPNOTSUPP;
+
+ return ieee80211_request_sched_scan_stop(sdata);
+}
+
static int ieee80211_auth(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_auth_request *req)
{
@@ -2083,6 +2120,8 @@
.suspend = ieee80211_suspend,
.resume = ieee80211_resume,
.scan = ieee80211_scan,
+ .sched_scan_start = ieee80211_sched_scan_start,
+ .sched_scan_stop = ieee80211_sched_scan_stop,
.auth = ieee80211_auth,
.assoc = ieee80211_assoc,
.deauth = ieee80211_deauth,
diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c
index 0a602db..186e02f 100644
--- a/net/mac80211/debugfs.c
+++ b/net/mac80211/debugfs.c
@@ -135,7 +135,7 @@
struct ieee80211_local *local = file->private_data;
rtnl_lock();
- __ieee80211_suspend(&local->hw);
+ __ieee80211_suspend(&local->hw, NULL);
__ieee80211_resume(&local->hw);
rtnl_unlock();
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c
index f7ef347..33c58b8 100644
--- a/net/mac80211/debugfs_key.c
+++ b/net/mac80211/debugfs_key.c
@@ -241,16 +241,12 @@
if (!key->debugfs.dir)
return;
- rcu_read_lock();
- sta = rcu_dereference(key->sta);
- if (sta)
+ sta = key->sta;
+ if (sta) {
sprintf(buf, "../../stations/%pM", sta->sta.addr);
- rcu_read_unlock();
-
- /* using sta as a boolean is fine outside RCU lock */
- if (sta)
key->debugfs.stalink =
debugfs_create_symlink("station", key->debugfs.dir, buf);
+ }
DEBUGFS_ADD(keylen);
DEBUGFS_ADD(flags);
@@ -286,7 +282,8 @@
lockdep_assert_held(&sdata->local->key_mtx);
if (sdata->default_unicast_key) {
- key = sdata->default_unicast_key;
+ key = key_mtx_dereference(sdata->local,
+ sdata->default_unicast_key);
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_unicast_key =
debugfs_create_symlink("default_unicast_key",
@@ -297,7 +294,8 @@
}
if (sdata->default_multicast_key) {
- key = sdata->default_multicast_key;
+ key = key_mtx_dereference(sdata->local,
+ sdata->default_multicast_key);
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_multicast_key =
debugfs_create_symlink("default_multicast_key",
@@ -316,9 +314,8 @@
if (!sdata->debugfs.dir)
return;
- /* this is running under the key lock */
-
- key = sdata->default_mgmt_key;
+ key = key_mtx_dereference(sdata->local,
+ sdata->default_mgmt_key);
if (key) {
sprintf(buf, "../keys/%d", key->debugfs.cnt);
sdata->debugfs.default_mgmt_key =
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 2ddb56e..eebf7a6 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -41,6 +41,33 @@
local->started = false;
}
+#ifdef CONFIG_PM
+static inline int drv_suspend(struct ieee80211_local *local,
+ struct cfg80211_wowlan *wowlan)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_suspend(local);
+ ret = local->ops->suspend(&local->hw, wowlan);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+static inline int drv_resume(struct ieee80211_local *local)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_resume(local);
+ ret = local->ops->resume(&local->hw);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+#endif
+
static inline int drv_add_interface(struct ieee80211_local *local,
struct ieee80211_vif *vif)
{
@@ -185,12 +212,39 @@
might_sleep();
- trace_drv_hw_scan(local, sdata, req);
+ trace_drv_hw_scan(local, sdata);
ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
trace_drv_return_int(local, ret);
return ret;
}
+static inline int
+drv_sched_scan_start(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_sched_scan_request *req,
+ struct ieee80211_sched_scan_ies *ies)
+{
+ int ret;
+
+ might_sleep();
+
+ trace_drv_sched_scan_start(local, sdata);
+ ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
+ req, ies);
+ trace_drv_return_int(local, ret);
+ return ret;
+}
+
+static inline void drv_sched_scan_stop(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata)
+{
+ might_sleep();
+
+ trace_drv_sched_scan_stop(local, sdata);
+ local->ops->sched_scan_stop(&local->hw, &sdata->vif);
+ trace_drv_return_void(local);
+}
+
static inline void drv_sw_scan_start(struct ieee80211_local *local)
{
might_sleep();
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index 191e834..ed9edcb 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -55,6 +55,70 @@
TP_printk(LOCAL_PR_FMT, LOCAL_PR_ARG)
);
+DECLARE_EVENT_CLASS(local_sdata_addr_evt,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __array(char, addr, 6)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ memcpy(__entry->addr, sdata->vif.addr, 6);
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
+ )
+);
+
+DECLARE_EVENT_CLASS(local_u32_evt,
+ TP_PROTO(struct ieee80211_local *local, u32 value),
+ TP_ARGS(local, value),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ __field(u32, value)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ __entry->value = value;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT " value:%d",
+ LOCAL_PR_ARG, __entry->value
+ )
+);
+
+DECLARE_EVENT_CLASS(local_sdata_evt,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT,
+ LOCAL_PR_ARG, VIF_PR_ARG
+ )
+);
+
DEFINE_EVENT(local_only_evt, drv_return_void,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
@@ -108,33 +172,25 @@
TP_ARGS(local)
);
+DEFINE_EVENT(local_only_evt, drv_suspend,
+ TP_PROTO(struct ieee80211_local *local),
+ TP_ARGS(local)
+);
+
+DEFINE_EVENT(local_only_evt, drv_resume,
+ TP_PROTO(struct ieee80211_local *local),
+ TP_ARGS(local)
+);
+
DEFINE_EVENT(local_only_evt, drv_stop,
TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local)
);
-TRACE_EVENT(drv_add_interface,
+DEFINE_EVENT(local_sdata_addr_evt, drv_add_interface,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata),
-
- TP_ARGS(local, sdata),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __array(char, addr, 6)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- memcpy(__entry->addr, sdata->vif.addr, 6);
- ),
-
- TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
- )
+ TP_ARGS(local, sdata)
);
TRACE_EVENT(drv_change_interface,
@@ -165,27 +221,10 @@
)
);
-TRACE_EVENT(drv_remove_interface,
- TP_PROTO(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata),
-
- TP_ARGS(local, sdata),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- __array(char, addr, 6)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- memcpy(__entry->addr, sdata->vif.addr, 6);
- ),
-
- TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT " addr:%pM",
- LOCAL_PR_ARG, VIF_PR_ARG, __entry->addr
- )
+DEFINE_EVENT(local_sdata_addr_evt, drv_remove_interface,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
);
TRACE_EVENT(drv_config,
@@ -415,27 +454,22 @@
)
);
-TRACE_EVENT(drv_hw_scan,
+DEFINE_EVENT(local_sdata_evt, drv_hw_scan,
TP_PROTO(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct cfg80211_scan_request *req),
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
+);
- TP_ARGS(local, sdata, req),
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_start,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
+);
- TP_STRUCT__entry(
- LOCAL_ENTRY
- VIF_ENTRY
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- VIF_ASSIGN;
- ),
-
- TP_printk(
- LOCAL_PR_FMT VIF_PR_FMT,
- LOCAL_PR_ARG,VIF_PR_ARG
- )
+DEFINE_EVENT(local_sdata_evt, drv_sched_scan_stop,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata),
+ TP_ARGS(local, sdata)
);
DEFINE_EVENT(local_only_evt, drv_sw_scan_start,
@@ -504,46 +538,14 @@
)
);
-TRACE_EVENT(drv_set_frag_threshold,
+DEFINE_EVENT(local_u32_evt, drv_set_frag_threshold,
TP_PROTO(struct ieee80211_local *local, u32 value),
-
- TP_ARGS(local, value),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- __field(u32, value)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- __entry->value = value;
- ),
-
- TP_printk(
- LOCAL_PR_FMT " value:%d",
- LOCAL_PR_ARG, __entry->value
- )
+ TP_ARGS(local, value)
);
-TRACE_EVENT(drv_set_rts_threshold,
+DEFINE_EVENT(local_u32_evt, drv_set_rts_threshold,
TP_PROTO(struct ieee80211_local *local, u32 value),
-
- TP_ARGS(local, value),
-
- TP_STRUCT__entry(
- LOCAL_ENTRY
- __field(u32, value)
- ),
-
- TP_fast_assign(
- LOCAL_ASSIGN;
- __entry->value = value;
- ),
-
- TP_printk(
- LOCAL_PR_FMT " value:%d",
- LOCAL_PR_ARG, __entry->value
- )
+ TP_ARGS(local, value)
);
TRACE_EVENT(drv_set_coverage_class,
@@ -1194,6 +1196,42 @@
)
);
+TRACE_EVENT(api_sched_scan_results,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
+TRACE_EVENT(api_sched_scan_stopped,
+ TP_PROTO(struct ieee80211_local *local),
+
+ TP_ARGS(local),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT, LOCAL_PR_ARG
+ )
+);
+
TRACE_EVENT(api_sta_block_awake,
TP_PROTO(struct ieee80211_local *local,
struct ieee80211_sta *sta, bool block),
diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c
index b9e4b9b..591add2 100644
--- a/net/mac80211/ht.c
+++ b/net/mac80211/ht.c
@@ -140,14 +140,29 @@
sta, tid, WLAN_BACK_RECIPIENT,
WLAN_REASON_QSTA_TIMEOUT, true);
- tid_tx = sta->ampdu_mlme.tid_tx[tid];
- if (!tid_tx)
- continue;
+ tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
+ if (tid_tx) {
+ /*
+ * Assign it over to the normal tid_tx array
+ * where it "goes live".
+ */
+ spin_lock_bh(&sta->lock);
- if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state))
+ sta->ampdu_mlme.tid_start_tx[tid] = NULL;
+ /* could there be a race? */
+ if (sta->ampdu_mlme.tid_tx[tid])
+ kfree(tid_tx);
+ else
+ ieee80211_assign_tid_tx(sta, tid, tid_tx);
+ spin_unlock_bh(&sta->lock);
+
ieee80211_tx_ba_session_handle_start(sta, tid);
- else if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
- &tid_tx->state))
+ continue;
+ }
+
+ tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
+ if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP,
+ &tid_tx->state))
___ieee80211_stop_tx_ba_session(sta, tid,
WLAN_BACK_INITIATOR,
true);
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index b81860c..421eaa6 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -662,12 +662,16 @@
int tx_last_beacon, len = req->len;
struct sk_buff *skb;
struct ieee80211_mgmt *resp;
+ struct sk_buff *presp;
u8 *pos, *end;
lockdep_assert_held(&ifibss->mtx);
+ presp = rcu_dereference_protected(ifibss->presp,
+ lockdep_is_held(&ifibss->mtx));
+
if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
- len < 24 + 2 || !ifibss->presp)
+ len < 24 + 2 || !presp)
return;
tx_last_beacon = drv_tx_last_beacon(local);
@@ -705,7 +709,7 @@
}
/* Reply with ProbeResp */
- skb = skb_copy(ifibss->presp, GFP_KERNEL);
+ skb = skb_copy(presp, GFP_KERNEL);
if (!skb)
return;
@@ -985,7 +989,8 @@
/* remove beacon */
kfree(sdata->u.ibss.ie);
- skb = sdata->u.ibss.presp;
+ skb = rcu_dereference_protected(sdata->u.ibss.presp,
+ lockdep_is_held(&sdata->u.ibss.mtx));
rcu_assign_pointer(sdata->u.ibss.presp, NULL);
sdata->vif.bss_conf.ibss_joined = false;
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 027c046..2025af5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -214,7 +214,7 @@
};
struct ieee80211_if_ap {
- struct beacon_data *beacon;
+ struct beacon_data __rcu *beacon;
struct list_head vlans;
@@ -237,7 +237,7 @@
struct list_head list;
/* used for all tx if the VLAN is configured to 4-addr mode */
- struct sta_info *sta;
+ struct sta_info __rcu *sta;
};
struct mesh_stats {
@@ -442,7 +442,8 @@
unsigned long ibss_join_req;
/* probe response/beacon for IBSS */
- struct sk_buff *presp, *skb;
+ struct sk_buff __rcu *presp;
+ struct sk_buff *skb;
enum {
IEEE80211_IBSS_MLME_SEARCH,
@@ -490,7 +491,11 @@
bool accepting_plinks;
const u8 *ie;
u8 ie_len;
- bool is_secure;
+ enum {
+ IEEE80211_MESH_SEC_NONE = 0x0,
+ IEEE80211_MESH_SEC_AUTHED = 0x1,
+ IEEE80211_MESH_SEC_SECURED = 0x2,
+ } security;
};
#ifdef CONFIG_MAC80211_MESH
@@ -563,9 +568,10 @@
struct ieee80211_fragment_entry fragments[IEEE80211_FRAGMENT_MAX];
unsigned int fragment_next;
- struct ieee80211_key *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
- struct ieee80211_key *default_unicast_key, *default_multicast_key;
- struct ieee80211_key *default_mgmt_key;
+ struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+ struct ieee80211_key __rcu *default_unicast_key;
+ struct ieee80211_key __rcu *default_multicast_key;
+ struct ieee80211_key __rcu *default_mgmt_key;
u16 sequence_number;
__be16 control_port_protocol;
@@ -764,6 +770,9 @@
/* device is started */
bool started;
+ /* wowlan is enabled -- don't reconfig on resume */
+ bool wowlan;
+
int tx_headroom; /* required headroom for hardware/radiotap */
/* count for keys needing tailroom space allocation */
@@ -798,7 +807,7 @@
spinlock_t sta_lock;
unsigned long num_sta;
struct list_head sta_list, sta_pending_list;
- struct sta_info *sta_hash[STA_HASH_SIZE];
+ struct sta_info __rcu *sta_hash[STA_HASH_SIZE];
struct timer_list sta_cleanup;
struct work_struct sta_finish_work;
int sta_generation;
@@ -840,6 +849,10 @@
int scan_channel_idx;
int scan_ies_len;
+ bool sched_scanning;
+ struct ieee80211_sched_scan_ies sched_scan_ies;
+ struct work_struct sched_scan_stopped_work;
+
unsigned long leave_oper_channel_time;
enum mac80211_scan_state next_scan_state;
struct delayed_work scan_work;
@@ -1147,6 +1160,12 @@
void ieee80211_rx_bss_put(struct ieee80211_local *local,
struct ieee80211_bss *bss);
+/* scheduled scan handling */
+int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_sched_scan_request *req);
+int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata);
+void ieee80211_sched_scan_stopped_work(struct work_struct *work);
+
/* off-channel helpers */
bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local);
void ieee80211_offchannel_enable_all_ps(struct ieee80211_local *local,
@@ -1250,7 +1269,8 @@
void ieee80211_stop_device(struct ieee80211_local *local);
#ifdef CONFIG_PM
-int __ieee80211_suspend(struct ieee80211_hw *hw);
+int __ieee80211_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan);
static inline int __ieee80211_resume(struct ieee80211_hw *hw)
{
@@ -1263,7 +1283,8 @@
return ieee80211_reconfig(hw_to_local(hw));
}
#else
-static inline int __ieee80211_suspend(struct ieee80211_hw *hw)
+static inline int __ieee80211_suspend(struct ieee80211_hw *hw,
+ struct cfg80211_wowlan *wowlan)
{
return 0;
}
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 80c29d6..7dfbe71 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -449,7 +449,8 @@
/* APs need special treatment */
if (sdata->vif.type == NL80211_IFTYPE_AP) {
struct ieee80211_sub_if_data *vlan, *tmpsdata;
- struct beacon_data *old_beacon = sdata->u.ap.beacon;
+ struct beacon_data *old_beacon =
+ rtnl_dereference(sdata->u.ap.beacon);
/* sdata_running will return false, so this will disable */
ieee80211_bss_info_change_notify(sdata,
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index b510721..31afd712 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -195,7 +195,7 @@
assert_key_lock(sdata->local);
if (idx >= 0 && idx < NUM_DEFAULT_KEYS)
- key = sdata->keys[idx];
+ key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
if (uni)
rcu_assign_pointer(sdata->default_unicast_key, key);
@@ -222,7 +222,7 @@
if (idx >= NUM_DEFAULT_KEYS &&
idx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS)
- key = sdata->keys[idx];
+ key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
rcu_assign_pointer(sdata->default_mgmt_key, key);
@@ -266,9 +266,15 @@
else
idx = new->conf.keyidx;
- defunikey = old && sdata->default_unicast_key == old;
- defmultikey = old && sdata->default_multicast_key == old;
- defmgmtkey = old && sdata->default_mgmt_key == old;
+ defunikey = old &&
+ old == key_mtx_dereference(sdata->local,
+ sdata->default_unicast_key);
+ defmultikey = old &&
+ old == key_mtx_dereference(sdata->local,
+ sdata->default_multicast_key);
+ defmgmtkey = old &&
+ old == key_mtx_dereference(sdata->local,
+ sdata->default_mgmt_key);
if (defunikey && !new)
__ieee80211_set_default_key(sdata, -1, true, false);
@@ -451,11 +457,11 @@
mutex_lock(&sdata->local->key_mtx);
if (sta && pairwise)
- old_key = sta->ptk;
+ old_key = key_mtx_dereference(sdata->local, sta->ptk);
else if (sta)
- old_key = sta->gtk[idx];
+ old_key = key_mtx_dereference(sdata->local, sta->gtk[idx]);
else
- old_key = sdata->keys[idx];
+ old_key = key_mtx_dereference(sdata->local, sdata->keys[idx]);
__ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
__ieee80211_key_destroy(old_key);
@@ -471,8 +477,11 @@
return ret;
}
-static void __ieee80211_key_free(struct ieee80211_key *key)
+void __ieee80211_key_free(struct ieee80211_key *key)
{
+ if (!key)
+ return;
+
/*
* Replace key with nothingness if it was ever used.
*/
@@ -486,9 +495,6 @@
void ieee80211_key_free(struct ieee80211_local *local,
struct ieee80211_key *key)
{
- if (!key)
- return;
-
mutex_lock(&local->key_mtx);
__ieee80211_key_free(key);
mutex_unlock(&local->key_mtx);
diff --git a/net/mac80211/key.h b/net/mac80211/key.h
index 4ddbe27..d801d53 100644
--- a/net/mac80211/key.h
+++ b/net/mac80211/key.h
@@ -135,6 +135,7 @@
int __must_check ieee80211_key_link(struct ieee80211_key *key,
struct ieee80211_sub_if_data *sdata,
struct sta_info *sta);
+void __ieee80211_key_free(struct ieee80211_key *key);
void ieee80211_key_free(struct ieee80211_local *local,
struct ieee80211_key *key);
void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx,
@@ -145,4 +146,7 @@
void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
+#define key_mtx_dereference(local, ref) \
+ rcu_dereference_protected(ref, lockdep_is_held(&((local)->key_mtx)))
+
#endif /* IEEE80211_KEY_H */
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 6187766..0d7b08d 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -358,7 +358,8 @@
flush_workqueue(local->workqueue);
mutex_lock(&local->mtx);
- WARN(test_bit(SCAN_HW_SCANNING, &local->scanning),
+ WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) ||
+ local->sched_scanning,
"%s called with hardware scan in progress\n", __func__);
mutex_unlock(&local->mtx);
@@ -580,8 +581,7 @@
wiphy->flags |= WIPHY_FLAG_NETNS_OK |
WIPHY_FLAG_4ADDR_AP |
- WIPHY_FLAG_4ADDR_STATION |
- WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS;
+ WIPHY_FLAG_4ADDR_STATION;
if (!ops->set_key)
wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -652,6 +652,9 @@
setup_timer(&local->dynamic_ps_timer,
ieee80211_dynamic_ps_timer, (unsigned long) local);
+ INIT_WORK(&local->sched_scan_stopped_work,
+ ieee80211_sched_scan_stopped_work);
+
sta_info_init(local);
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -682,7 +685,7 @@
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
- int result;
+ int result, i;
enum ieee80211_band band;
int channels, max_bitrates;
bool supp_ht;
@@ -697,6 +700,13 @@
WLAN_CIPHER_SUITE_AES_CMAC
};
+ if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns)
+#ifdef CONFIG_PM
+ && (!local->ops->suspend || !local->ops->resume)
+#endif
+ )
+ return -EINVAL;
+
if (hw->max_report_rates == 0)
hw->max_report_rates = hw->max_rates;
@@ -733,11 +743,19 @@
return -ENOMEM;
/* if low-level driver supports AP, we also support VLAN */
- if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP))
- local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+ if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP_VLAN);
+ hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_AP_VLAN);
+ }
/* mac80211 always supports monitor */
- local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
+ hw->wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
+
+ /* mac80211 doesn't support more than 1 channel */
+ for (i = 0; i < hw->wiphy->n_iface_combinations; i++)
+ if (hw->wiphy->iface_combinations[i].num_different_channels > 1)
+ return -EINVAL;
#ifndef CONFIG_MAC80211_MESH
/* mesh depends on Kconfig, but drivers should set it if they want */
@@ -827,6 +845,9 @@
if (!local->ops->remain_on_channel)
local->hw.wiphy->max_remain_on_channel_duration = 5000;
+ if (local->ops->sched_scan_start)
+ local->hw.wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+
result = wiphy_register(local->hw.wiphy);
if (result < 0)
goto fail_wiphy_register;
@@ -850,8 +871,10 @@
* and we need some headroom for passing the frame to monitor
* interfaces, but never both at the same time.
*/
+#ifndef __CHECKER__
BUILD_BUG_ON(IEEE80211_TX_STATUS_HEADROOM !=
sizeof(struct ieee80211_tx_status_rtap_hdr));
+#endif
local->tx_headroom = max_t(unsigned int , local->hw.extra_tx_headroom,
sizeof(struct ieee80211_tx_status_rtap_hdr));
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index c1299e2..29e9980 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -287,49 +287,6 @@
}
}
-u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata, struct mesh_table *tbl)
-{
- /* Use last four bytes of hw addr and interface index as hash index */
- return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
- & tbl->hash_mask;
-}
-
-struct mesh_table *mesh_table_alloc(int size_order)
-{
- int i;
- struct mesh_table *newtbl;
-
- newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
- if (!newtbl)
- return NULL;
-
- newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
- (1 << size_order), GFP_KERNEL);
-
- if (!newtbl->hash_buckets) {
- kfree(newtbl);
- return NULL;
- }
-
- newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
- (1 << size_order), GFP_KERNEL);
- if (!newtbl->hashwlock) {
- kfree(newtbl->hash_buckets);
- kfree(newtbl);
- return NULL;
- }
-
- newtbl->size_order = size_order;
- newtbl->hash_mask = (1 << size_order) - 1;
- atomic_set(&newtbl->entries, 0);
- get_random_bytes(&newtbl->hash_rnd,
- sizeof(newtbl->hash_rnd));
- for (i = 0; i <= newtbl->hash_mask; i++)
- spin_lock_init(&newtbl->hashwlock[i]);
-
- return newtbl;
-}
-
static void ieee80211_mesh_path_timer(unsigned long data)
{
@@ -574,7 +531,7 @@
&elems);
/* ignore beacons from secure mesh peers if our security is off */
- if (elems.rsn_len && !sdata->u.mesh.is_secure)
+ if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE)
return;
if (elems.ds_params && elems.ds_params_len == 1)
@@ -600,7 +557,7 @@
struct ieee80211_rx_status *rx_status)
{
switch (mgmt->u.action.category) {
- case WLAN_CATEGORY_MESH_PLINK:
+ case WLAN_CATEGORY_MESH_ACTION:
mesh_rx_plink_frame(sdata, mgmt, len, rx_status);
break;
case WLAN_CATEGORY_MESH_PATH_SEL:
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h
index 10acf1c..e7c5fdd 100644
--- a/net/mac80211/mesh.h
+++ b/net/mac80211/mesh.h
@@ -92,7 +92,7 @@
u8 dst[ETH_ALEN];
u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
struct ieee80211_sub_if_data *sdata;
- struct sta_info *next_hop;
+ struct sta_info __rcu *next_hop;
struct timer_list timer;
struct sk_buff_head frame_queue;
struct rcu_head rcu;
@@ -240,12 +240,8 @@
/* Private interfaces */
/* Mesh tables */
-struct mesh_table *mesh_table_alloc(int size_order);
-void mesh_table_free(struct mesh_table *tbl, bool free_leafs);
void mesh_mpath_table_grow(void);
void mesh_mpp_table_grow(void);
-u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
- struct mesh_table *tbl);
/* Mesh paths */
int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, __le16 target_rcode,
const u8 *ra, struct ieee80211_sub_if_data *sdata);
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index e57f2e7..2b18053 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -391,7 +391,6 @@
(mpath->flags & MESH_PATH_SN_VALID)) {
if (SN_GT(mpath->sn, orig_sn) ||
(mpath->sn == orig_sn &&
- action == MPATH_PREQ &&
new_metric >= mpath->metric)) {
process = false;
fresh_info = false;
@@ -561,6 +560,14 @@
}
+static inline struct sta_info *
+next_hop_deref_protected(struct mesh_path *mpath)
+{
+ return rcu_dereference_protected(mpath->next_hop,
+ lockdep_is_held(&mpath->state_lock));
+}
+
+
static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
u8 *prep_elem, u32 metric)
@@ -600,7 +607,7 @@
spin_unlock_bh(&mpath->state_lock);
goto fail;
}
- memcpy(next_hop, mpath->next_hop->sta.addr, ETH_ALEN);
+ memcpy(next_hop, next_hop_deref_protected(mpath)->sta.addr, ETH_ALEN);
spin_unlock_bh(&mpath->state_lock);
--ttl;
flags = PREP_IE_FLAGS(prep_elem);
@@ -652,7 +659,8 @@
if (mpath) {
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_ACTIVE &&
- memcmp(ta, mpath->next_hop->sta.addr, ETH_ALEN) == 0 &&
+ memcmp(ta, next_hop_deref_protected(mpath)->sta.addr,
+ ETH_ALEN) == 0 &&
(!(mpath->flags & MESH_PATH_SN_VALID) ||
SN_GT(target_sn, mpath->sn))) {
mpath->flags &= ~MESH_PATH_ACTIVE;
@@ -914,6 +922,7 @@
{
struct sk_buff *skb_to_free = NULL;
struct mesh_path *mpath;
+ struct sta_info *next_hop;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
u8 *target_addr = hdr->addr3;
int err = 0;
@@ -941,7 +950,11 @@
mesh_queue_preq(mpath,
PREQ_Q_F_START | PREQ_Q_F_REFRESH);
}
- memcpy(hdr->addr1, mpath->next_hop->sta.addr, ETH_ALEN);
+ next_hop = rcu_dereference(mpath->next_hop);
+ if (next_hop)
+ memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
+ else
+ err = -ENOENT;
} else {
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
if (!(mpath->flags & MESH_PATH_RESOLVING)) {
@@ -967,20 +980,11 @@
void mesh_path_timer(unsigned long data)
{
- struct ieee80211_sub_if_data *sdata;
- struct mesh_path *mpath;
+ struct mesh_path *mpath = (void *) data;
+ struct ieee80211_sub_if_data *sdata = mpath->sdata;
- rcu_read_lock();
- mpath = (struct mesh_path *) data;
- mpath = rcu_dereference(mpath);
- if (!mpath)
- goto endmpathtimer;
- sdata = mpath->sdata;
-
- if (sdata->local->quiescing) {
- rcu_read_unlock();
+ if (sdata->local->quiescing)
return;
- }
spin_lock_bh(&mpath->state_lock);
if (mpath->flags & MESH_PATH_RESOLVED ||
@@ -997,8 +1001,6 @@
}
spin_unlock_bh(&mpath->state_lock);
-endmpathtimer:
- rcu_read_unlock();
}
void
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c
index 35c715a..83ce48e 100644
--- a/net/mac80211/mesh_pathtbl.c
+++ b/net/mac80211/mesh_pathtbl.c
@@ -40,6 +40,50 @@
static struct mesh_table *mpp_paths; /* Store paths for MPP&MAP */
int mesh_paths_generation;
+
+/* This lock will have the grow table function as writer and add / delete nodes
+ * as readers. When reading the table (i.e. doing lookups) we are well protected
+ * by RCU
+ */
+static DEFINE_RWLOCK(pathtbl_resize_lock);
+
+
+static struct mesh_table *mesh_table_alloc(int size_order)
+{
+ int i;
+ struct mesh_table *newtbl;
+
+ newtbl = kmalloc(sizeof(struct mesh_table), GFP_KERNEL);
+ if (!newtbl)
+ return NULL;
+
+ newtbl->hash_buckets = kzalloc(sizeof(struct hlist_head) *
+ (1 << size_order), GFP_KERNEL);
+
+ if (!newtbl->hash_buckets) {
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->hashwlock = kmalloc(sizeof(spinlock_t) *
+ (1 << size_order), GFP_KERNEL);
+ if (!newtbl->hashwlock) {
+ kfree(newtbl->hash_buckets);
+ kfree(newtbl);
+ return NULL;
+ }
+
+ newtbl->size_order = size_order;
+ newtbl->hash_mask = (1 << size_order) - 1;
+ atomic_set(&newtbl->entries, 0);
+ get_random_bytes(&newtbl->hash_rnd,
+ sizeof(newtbl->hash_rnd));
+ for (i = 0; i <= newtbl->hash_mask; i++)
+ spin_lock_init(&newtbl->hashwlock[i]);
+
+ return newtbl;
+}
+
static void __mesh_table_free(struct mesh_table *tbl)
{
kfree(tbl->hash_buckets);
@@ -47,7 +91,7 @@
kfree(tbl);
}
-void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
+static void mesh_table_free(struct mesh_table *tbl, bool free_leafs)
{
struct hlist_head *mesh_hash;
struct hlist_node *p, *q;
@@ -55,18 +99,18 @@
mesh_hash = tbl->hash_buckets;
for (i = 0; i <= tbl->hash_mask; i++) {
- spin_lock(&tbl->hashwlock[i]);
+ spin_lock_bh(&tbl->hashwlock[i]);
hlist_for_each_safe(p, q, &mesh_hash[i]) {
tbl->free_node(p, free_leafs);
atomic_dec(&tbl->entries);
}
- spin_unlock(&tbl->hashwlock[i]);
+ spin_unlock_bh(&tbl->hashwlock[i]);
}
__mesh_table_free(tbl);
}
static int mesh_table_grow(struct mesh_table *oldtbl,
- struct mesh_table *newtbl)
+ struct mesh_table *newtbl)
{
struct hlist_head *oldhash;
struct hlist_node *p, *q;
@@ -76,7 +120,6 @@
< oldtbl->mean_chain_len * (oldtbl->hash_mask + 1))
return -EAGAIN;
-
newtbl->free_node = oldtbl->free_node;
newtbl->mean_chain_len = oldtbl->mean_chain_len;
newtbl->copy_node = oldtbl->copy_node;
@@ -98,12 +141,14 @@
return -ENOMEM;
}
+static u32 mesh_table_hash(u8 *addr, struct ieee80211_sub_if_data *sdata,
+ struct mesh_table *tbl)
+{
+ /* Use last four bytes of hw addr and interface index as hash index */
+ return jhash_2words(*(u32 *)(addr+2), sdata->dev->ifindex, tbl->hash_rnd)
+ & tbl->hash_mask;
+}
-/* This lock will have the grow table function as writer and add / delete nodes
- * as readers. When reading the table (i.e. doing lookups) we are well protected
- * by RCU
- */
-static DEFINE_RWLOCK(pathtbl_resize_lock);
/**
*
@@ -275,7 +320,7 @@
if (!new_node)
goto err_node_alloc;
- read_lock(&pathtbl_resize_lock);
+ read_lock_bh(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
new_mpath->sdata = sdata;
new_mpath->flags = 0;
@@ -290,7 +335,7 @@
hash_idx = mesh_table_hash(dst, sdata, mesh_paths);
bucket = &mesh_paths->hash_buckets[hash_idx];
- spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
err = -EEXIST;
hlist_for_each_entry(node, n, bucket, list) {
@@ -306,8 +351,8 @@
mesh_paths_generation++;
- spin_unlock(&mesh_paths->hashwlock[hash_idx]);
- read_unlock(&pathtbl_resize_lock);
+ spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
if (grow) {
set_bit(MESH_WORK_GROW_MPATH_TABLE, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
@@ -315,8 +360,8 @@
return 0;
err_exists:
- spin_unlock(&mesh_paths->hashwlock[hash_idx]);
- read_unlock(&pathtbl_resize_lock);
+ spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
kfree(new_node);
err_node_alloc:
kfree(new_mpath);
@@ -329,18 +374,21 @@
{
struct mesh_table *oldtbl, *newtbl;
- newtbl = mesh_table_alloc(mesh_paths->size_order + 1);
+ rcu_read_lock();
+ newtbl = mesh_table_alloc(rcu_dereference(mesh_paths)->size_order + 1);
if (!newtbl)
return;
- write_lock(&pathtbl_resize_lock);
+ write_lock_bh(&pathtbl_resize_lock);
oldtbl = mesh_paths;
if (mesh_table_grow(mesh_paths, newtbl) < 0) {
+ rcu_read_unlock();
__mesh_table_free(newtbl);
- write_unlock(&pathtbl_resize_lock);
+ write_unlock_bh(&pathtbl_resize_lock);
return;
}
+ rcu_read_unlock();
rcu_assign_pointer(mesh_paths, newtbl);
- write_unlock(&pathtbl_resize_lock);
+ write_unlock_bh(&pathtbl_resize_lock);
synchronize_rcu();
mesh_table_free(oldtbl, false);
@@ -350,18 +398,21 @@
{
struct mesh_table *oldtbl, *newtbl;
- newtbl = mesh_table_alloc(mpp_paths->size_order + 1);
+ rcu_read_lock();
+ newtbl = mesh_table_alloc(rcu_dereference(mpp_paths)->size_order + 1);
if (!newtbl)
return;
- write_lock(&pathtbl_resize_lock);
+ write_lock_bh(&pathtbl_resize_lock);
oldtbl = mpp_paths;
if (mesh_table_grow(mpp_paths, newtbl) < 0) {
+ rcu_read_unlock();
__mesh_table_free(newtbl);
- write_unlock(&pathtbl_resize_lock);
+ write_unlock_bh(&pathtbl_resize_lock);
return;
}
+ rcu_read_unlock();
rcu_assign_pointer(mpp_paths, newtbl);
- write_unlock(&pathtbl_resize_lock);
+ write_unlock_bh(&pathtbl_resize_lock);
synchronize_rcu();
mesh_table_free(oldtbl, false);
@@ -395,7 +446,7 @@
if (!new_node)
goto err_node_alloc;
- read_lock(&pathtbl_resize_lock);
+ read_lock_bh(&pathtbl_resize_lock);
memcpy(new_mpath->dst, dst, ETH_ALEN);
memcpy(new_mpath->mpp, mpp, ETH_ALEN);
new_mpath->sdata = sdata;
@@ -408,7 +459,7 @@
hash_idx = mesh_table_hash(dst, sdata, mpp_paths);
bucket = &mpp_paths->hash_buckets[hash_idx];
- spin_lock(&mpp_paths->hashwlock[hash_idx]);
+ spin_lock_bh(&mpp_paths->hashwlock[hash_idx]);
err = -EEXIST;
hlist_for_each_entry(node, n, bucket, list) {
@@ -422,8 +473,8 @@
mpp_paths->mean_chain_len * (mpp_paths->hash_mask + 1))
grow = 1;
- spin_unlock(&mpp_paths->hashwlock[hash_idx]);
- read_unlock(&pathtbl_resize_lock);
+ spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
if (grow) {
set_bit(MESH_WORK_GROW_MPP_TABLE, &ifmsh->wrkq_flags);
ieee80211_queue_work(&local->hw, &sdata->work);
@@ -431,8 +482,8 @@
return 0;
err_exists:
- spin_unlock(&mpp_paths->hashwlock[hash_idx]);
- read_unlock(&pathtbl_resize_lock);
+ spin_unlock_bh(&mpp_paths->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
kfree(new_node);
err_node_alloc:
kfree(new_mpath);
@@ -545,11 +596,11 @@
int hash_idx;
int err = 0;
- read_lock(&pathtbl_resize_lock);
+ read_lock_bh(&pathtbl_resize_lock);
hash_idx = mesh_table_hash(addr, sdata, mesh_paths);
bucket = &mesh_paths->hash_buckets[hash_idx];
- spin_lock(&mesh_paths->hashwlock[hash_idx]);
+ spin_lock_bh(&mesh_paths->hashwlock[hash_idx]);
hlist_for_each_entry(node, n, bucket, list) {
mpath = node->mpath;
if (mpath->sdata == sdata &&
@@ -567,8 +618,8 @@
err = -ENXIO;
enddel:
mesh_paths_generation++;
- spin_unlock(&mesh_paths->hashwlock[hash_idx]);
- read_unlock(&pathtbl_resize_lock);
+ spin_unlock_bh(&mesh_paths->hashwlock[hash_idx]);
+ read_unlock_bh(&pathtbl_resize_lock);
return err;
}
@@ -720,7 +771,7 @@
struct hlist_node *p;
int i;
- read_lock(&pathtbl_resize_lock);
+ read_lock_bh(&pathtbl_resize_lock);
for_each_mesh_entry(mesh_paths, p, node, i) {
if (node->mpath->sdata != sdata)
continue;
@@ -735,7 +786,7 @@
} else
spin_unlock_bh(&mpath->state_lock);
}
- read_unlock(&pathtbl_resize_lock);
+ read_unlock_bh(&pathtbl_resize_lock);
}
void mesh_pathtbl_unregister(void)
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c
index 84e5b05..f4adc09 100644
--- a/net/mac80211/mesh_plink.c
+++ b/net/mac80211/mesh_plink.c
@@ -43,7 +43,7 @@
#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
enum plink_frame_type {
- PLINK_OPEN = 0,
+ PLINK_OPEN = 1,
PLINK_CONFIRM,
PLINK_CLOSE
};
@@ -83,7 +83,7 @@
*/
static inline void mesh_plink_fsm_restart(struct sta_info *sta)
{
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = NL80211_PLINK_LISTEN;
sta->llid = sta->plid = sta->reason = 0;
sta->plink_retries = 0;
}
@@ -126,11 +126,11 @@
struct ieee80211_sub_if_data *sdata = sta->sdata;
bool deactivated = false;
- if (sta->plink_state == PLINK_ESTAB) {
+ if (sta->plink_state == NL80211_PLINK_ESTAB) {
mesh_plink_dec_estab_count(sdata);
deactivated = true;
}
- sta->plink_state = PLINK_BLOCKED;
+ sta->plink_state = NL80211_PLINK_BLOCKED;
mesh_path_flush_by_nexthop(sta);
return deactivated;
@@ -181,8 +181,8 @@
IEEE80211_STYPE_ACTION);
memcpy(mgmt->da, da, ETH_ALEN);
memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
- /* BSSID is left zeroed, wildcard value */
- mgmt->u.action.category = WLAN_CATEGORY_MESH_PLINK;
+ memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
+ mgmt->u.action.category = WLAN_CATEGORY_MESH_ACTION;
mgmt->u.action.u.plink_action.action_code = action;
if (action == PLINK_CLOSE)
@@ -251,7 +251,7 @@
rcu_read_unlock();
/* Userspace handles peer allocation when security is enabled
* */
- if (sdata->u.mesh.is_secure)
+ if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED)
cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr,
elems->ie_start, elems->total_len,
GFP_KERNEL);
@@ -268,7 +268,7 @@
sta->last_rx = jiffies;
sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
if (mesh_peer_accepts_plinks(elems) &&
- sta->plink_state == PLINK_LISTEN &&
+ sta->plink_state == NL80211_PLINK_LISTEN &&
sdata->u.mesh.accepting_plinks &&
sdata->u.mesh.mshcfg.auto_open_plinks)
mesh_plink_open(sta);
@@ -308,8 +308,8 @@
sdata = sta->sdata;
switch (sta->plink_state) {
- case PLINK_OPN_RCVD:
- case PLINK_OPN_SNT:
+ case NL80211_PLINK_OPN_RCVD:
+ case NL80211_PLINK_OPN_SNT:
/* retry timer */
if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
u32 rand;
@@ -328,17 +328,17 @@
}
reason = cpu_to_le16(MESH_MAX_RETRIES);
/* fall through on else */
- case PLINK_CNF_RCVD:
+ case NL80211_PLINK_CNF_RCVD:
/* confirm timer */
if (!reason)
reason = cpu_to_le16(MESH_CONFIRM_TIMEOUT);
- sta->plink_state = PLINK_HOLDING;
+ sta->plink_state = NL80211_PLINK_HOLDING;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, plid,
reason);
break;
- case PLINK_HOLDING:
+ case NL80211_PLINK_HOLDING:
/* holding timer */
del_timer(&sta->plink_timer);
mesh_plink_fsm_restart(sta);
@@ -386,11 +386,11 @@
spin_lock_bh(&sta->lock);
get_random_bytes(&llid, 2);
sta->llid = llid;
- if (sta->plink_state != PLINK_LISTEN) {
+ if (sta->plink_state != NL80211_PLINK_LISTEN) {
spin_unlock_bh(&sta->lock);
return -EBUSY;
}
- sta->plink_state = PLINK_OPN_SNT;
+ sta->plink_state = NL80211_PLINK_OPN_SNT;
mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
spin_unlock_bh(&sta->lock);
mpl_dbg("Mesh plink: starting establishment with %pM\n",
@@ -407,7 +407,7 @@
spin_lock_bh(&sta->lock);
deactivated = __mesh_plink_deactivate(sta);
- sta->plink_state = PLINK_BLOCKED;
+ sta->plink_state = NL80211_PLINK_BLOCKED;
spin_unlock_bh(&sta->lock);
if (deactivated)
@@ -430,13 +430,13 @@
__le16 plid, llid, reason;
#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG
static const char *mplstates[] = {
- [PLINK_LISTEN] = "LISTEN",
- [PLINK_OPN_SNT] = "OPN-SNT",
- [PLINK_OPN_RCVD] = "OPN-RCVD",
- [PLINK_CNF_RCVD] = "CNF_RCVD",
- [PLINK_ESTAB] = "ESTAB",
- [PLINK_HOLDING] = "HOLDING",
- [PLINK_BLOCKED] = "BLOCKED"
+ [NL80211_PLINK_LISTEN] = "LISTEN",
+ [NL80211_PLINK_OPN_SNT] = "OPN-SNT",
+ [NL80211_PLINK_OPN_RCVD] = "OPN-RCVD",
+ [NL80211_PLINK_CNF_RCVD] = "CNF_RCVD",
+ [NL80211_PLINK_ESTAB] = "ESTAB",
+ [NL80211_PLINK_HOLDING] = "HOLDING",
+ [NL80211_PLINK_BLOCKED] = "BLOCKED"
};
#endif
@@ -460,7 +460,8 @@
mpl_dbg("Mesh plink: missing necessary peer link ie\n");
return;
}
- if (elems.rsn_len && !sdata->u.mesh.is_secure) {
+ if (elems.rsn_len &&
+ sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) {
mpl_dbg("Mesh plink: can't establish link with secure peer\n");
return;
}
@@ -501,7 +502,7 @@
return;
}
- if (sta && sta->plink_state == PLINK_BLOCKED) {
+ if (sta && sta->plink_state == NL80211_PLINK_BLOCKED) {
rcu_read_unlock();
return;
}
@@ -571,7 +572,7 @@
event = CNF_ACPT;
break;
case PLINK_CLOSE:
- if (sta->plink_state == PLINK_ESTAB)
+ if (sta->plink_state == NL80211_PLINK_ESTAB)
/* Do not check for llid or plid. This does not
* follow the standard but since multiple plinks
* per sta are not supported, it is necessary in
@@ -606,14 +607,14 @@
reason = 0;
switch (sta->plink_state) {
/* spin_unlock as soon as state is updated at each case */
- case PLINK_LISTEN:
+ case NL80211_PLINK_LISTEN:
switch (event) {
case CLS_ACPT:
mesh_plink_fsm_restart(sta);
spin_unlock_bh(&sta->lock);
break;
case OPN_ACPT:
- sta->plink_state = PLINK_OPN_RCVD;
+ sta->plink_state = NL80211_PLINK_OPN_RCVD;
sta->plid = plid;
get_random_bytes(&llid, 2);
sta->llid = llid;
@@ -630,7 +631,7 @@
}
break;
- case PLINK_OPN_SNT:
+ case NL80211_PLINK_OPN_SNT:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
@@ -639,7 +640,7 @@
if (!reason)
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
- sta->plink_state = PLINK_HOLDING;
+ sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
dot11MeshHoldingTimeout(sdata)))
sta->ignore_plink_timer = true;
@@ -651,7 +652,7 @@
break;
case OPN_ACPT:
/* retry timer is left untouched */
- sta->plink_state = PLINK_OPN_RCVD;
+ sta->plink_state = NL80211_PLINK_OPN_RCVD;
sta->plid = plid;
llid = sta->llid;
spin_unlock_bh(&sta->lock);
@@ -659,7 +660,7 @@
plid, 0);
break;
case CNF_ACPT:
- sta->plink_state = PLINK_CNF_RCVD;
+ sta->plink_state = NL80211_PLINK_CNF_RCVD;
if (!mod_plink_timer(sta,
dot11MeshConfirmTimeout(sdata)))
sta->ignore_plink_timer = true;
@@ -672,7 +673,7 @@
}
break;
- case PLINK_OPN_RCVD:
+ case NL80211_PLINK_OPN_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
@@ -681,7 +682,7 @@
if (!reason)
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
- sta->plink_state = PLINK_HOLDING;
+ sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
dot11MeshHoldingTimeout(sdata)))
sta->ignore_plink_timer = true;
@@ -699,7 +700,7 @@
break;
case CNF_ACPT:
del_timer(&sta->plink_timer);
- sta->plink_state = PLINK_ESTAB;
+ sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
@@ -712,7 +713,7 @@
}
break;
- case PLINK_CNF_RCVD:
+ case NL80211_PLINK_CNF_RCVD:
switch (event) {
case OPN_RJCT:
case CNF_RJCT:
@@ -721,7 +722,7 @@
if (!reason)
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
- sta->plink_state = PLINK_HOLDING;
+ sta->plink_state = NL80211_PLINK_HOLDING;
if (!mod_plink_timer(sta,
dot11MeshHoldingTimeout(sdata)))
sta->ignore_plink_timer = true;
@@ -733,7 +734,7 @@
break;
case OPN_ACPT:
del_timer(&sta->plink_timer);
- sta->plink_state = PLINK_ESTAB;
+ sta->plink_state = NL80211_PLINK_ESTAB;
spin_unlock_bh(&sta->lock);
mesh_plink_inc_estab_count(sdata);
ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON);
@@ -748,13 +749,13 @@
}
break;
- case PLINK_ESTAB:
+ case NL80211_PLINK_ESTAB:
switch (event) {
case CLS_ACPT:
reason = cpu_to_le16(MESH_CLOSE_RCVD);
sta->reason = reason;
deactivated = __mesh_plink_deactivate(sta);
- sta->plink_state = PLINK_HOLDING;
+ sta->plink_state = NL80211_PLINK_HOLDING;
llid = sta->llid;
mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
spin_unlock_bh(&sta->lock);
@@ -774,7 +775,7 @@
break;
}
break;
- case PLINK_HOLDING:
+ case NL80211_PLINK_HOLDING:
switch (event) {
case CLS_ACPT:
if (del_timer(&sta->plink_timer))
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index a41f234..4f6b267 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -750,6 +750,8 @@
dynamic_ps_enable_work);
struct ieee80211_sub_if_data *sdata = local->ps_sdata;
struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ unsigned long flags;
+ int q;
/* can only happen when PS was just disabled anyway */
if (!sdata)
@@ -758,6 +760,24 @@
if (local->hw.conf.flags & IEEE80211_CONF_PS)
return;
+ /*
+ * transmission can be stopped by others which leads to
+ * dynamic_ps_timer expiry. Postpond the ps timer if it
+ * is not the actual idle state.
+ */
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+ for (q = 0; q < local->hw.queues; q++) {
+ if (local->queue_stop_reasons[q]) {
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock,
+ flags);
+ mod_timer(&local->dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(
+ local->hw.conf.dynamic_ps_timeout));
+ return;
+ }
+ }
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
(!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED))) {
netif_tx_stop_all_queues(sdata->dev);
@@ -781,7 +801,7 @@
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
}
- netif_tx_start_all_queues(sdata->dev);
+ netif_tx_wake_all_queues(sdata->dev);
}
void ieee80211_dynamic_ps_timer(unsigned long data)
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 0424617..730778a 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -6,7 +6,7 @@
#include "driver-ops.h"
#include "led.h"
-int __ieee80211_suspend(struct ieee80211_hw *hw)
+int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{
struct ieee80211_local *local = hw_to_local(hw);
struct ieee80211_sub_if_data *sdata;
@@ -47,6 +47,16 @@
cancel_work_sync(&local->dynamic_ps_enable_work);
del_timer_sync(&local->dynamic_ps_timer);
+ local->wowlan = wowlan && local->open_count;
+ if (local->wowlan) {
+ int err = drv_suspend(local, wowlan);
+ if (err) {
+ local->quiescing = false;
+ return err;
+ }
+ goto suspend;
+ }
+
/* disable keys */
list_for_each_entry(sdata, &local->interfaces, list)
ieee80211_disable_keys(sdata);
@@ -104,6 +114,7 @@
if (local->open_count)
ieee80211_stop_device(local);
+ suspend:
local->suspended = true;
/* need suspended to be visible before quiescing is false */
barrier();
diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c
index 778c604..8adac67 100644
--- a/net/mac80211/rc80211_minstrel.c
+++ b/net/mac80211/rc80211_minstrel.c
@@ -417,8 +417,8 @@
tx_time_single = mr->ack_time + mr->perfect_tx_time;
/* contention window */
- tx_time_single += t_slot + min(cw, mp->cw_max);
- cw = (cw << 1) | 1;
+ tx_time_single += (t_slot * cw) >> 1;
+ cw = min((cw << 1) | 1, mp->cw_max);
tx_time += tx_time_single;
tx_time_cts += tx_time_single + mi->sp_ack_dur;
diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c
index c06aa3a..333b511 100644
--- a/net/mac80211/rc80211_minstrel_ht.c
+++ b/net/mac80211/rc80211_minstrel_ht.c
@@ -464,6 +464,7 @@
const struct mcs_group *group;
unsigned int tx_time, tx_time_rtscts, tx_time_data;
unsigned int cw = mp->cw_min;
+ unsigned int ctime = 0;
unsigned int t_slot = 9; /* FIXME */
unsigned int ampdu_len = MINSTREL_TRUNC(mi->avg_ampdu_len);
@@ -480,13 +481,27 @@
group = &minstrel_mcs_groups[index / MCS_GROUP_RATES];
tx_time_data = group->duration[index % MCS_GROUP_RATES] * ampdu_len;
- tx_time = 2 * (t_slot + mi->overhead + tx_time_data);
- tx_time_rtscts = 2 * (t_slot + mi->overhead_rtscts + tx_time_data);
+
+ /* Contention time for first 2 tries */
+ ctime = (t_slot * cw) >> 1;
+ cw = min((cw << 1) | 1, mp->cw_max);
+ ctime += (t_slot * cw) >> 1;
+ cw = min((cw << 1) | 1, mp->cw_max);
+
+ /* Total TX time for data and Contention after first 2 tries */
+ tx_time = ctime + 2 * (mi->overhead + tx_time_data);
+ tx_time_rtscts = ctime + 2 * (mi->overhead_rtscts + tx_time_data);
+
+ /* See how many more tries we can fit inside segment size */
do {
- cw = (cw << 1) | 1;
- cw = min(cw, mp->cw_max);
- tx_time += cw + t_slot + mi->overhead;
- tx_time_rtscts += cw + t_slot + mi->overhead_rtscts;
+ /* Contention time for this try */
+ ctime = (t_slot * cw) >> 1;
+ cw = min((cw << 1) | 1, mp->cw_max);
+
+ /* Total TX time after this try */
+ tx_time += ctime + mi->overhead + tx_time_data;
+ tx_time_rtscts += ctime + mi->overhead_rtscts + tx_time_data;
+
if (tx_time_rtscts < mp->segment_size)
mr->retry_count_rtscts++;
} while ((tx_time < mp->segment_size) &&
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 13a6697..7fa8c6b 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -404,11 +404,13 @@
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
struct sk_buff *skb = rx->skb;
- if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN)))
+ if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) &&
+ !local->sched_scanning))
return RX_CONTINUE;
if (test_bit(SCAN_HW_SCANNING, &local->scanning) ||
- test_bit(SCAN_SW_SCANNING, &local->scanning))
+ test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+ local->sched_scanning)
return ieee80211_scan_rx(rx->sdata, skb);
/* scanning finished during invoking of handlers */
@@ -488,15 +490,18 @@
* establisment frame, beacon or probe, drop the frame.
*/
- if (!rx->sta || sta_plink_state(rx->sta) != PLINK_ESTAB) {
+ if (!rx->sta || sta_plink_state(rx->sta) != NL80211_PLINK_ESTAB) {
struct ieee80211_mgmt *mgmt;
if (!ieee80211_is_mgmt(hdr->frame_control))
return RX_DROP_MONITOR;
if (ieee80211_is_action(hdr->frame_control)) {
+ u8 category;
mgmt = (struct ieee80211_mgmt *)hdr;
- if (mgmt->u.action.category != WLAN_CATEGORY_MESH_PLINK)
+ category = mgmt->u.action.category;
+ if (category != WLAN_CATEGORY_MESH_ACTION &&
+ category != WLAN_CATEGORY_SELF_PROTECTED)
return RX_DROP_MONITOR;
return RX_CONTINUE;
}
@@ -1778,7 +1783,7 @@
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
rx->sdata->vif.type,
- rx->local->hw.extra_tx_headroom);
+ rx->local->hw.extra_tx_headroom, true);
while (!skb_queue_empty(&frame_list)) {
rx->skb = __skb_dequeue(&frame_list);
@@ -2205,7 +2210,7 @@
goto handled;
}
break;
- case WLAN_CATEGORY_MESH_PLINK:
+ case WLAN_CATEGORY_MESH_ACTION:
if (!ieee80211_vif_is_mesh(&sdata->vif))
break;
goto queue;
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 489b6ad..d20046b 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -15,6 +15,7 @@
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
#include <linux/pm_qos_params.h>
+#include <linux/slab.h>
#include <net/sch_generic.h>
#include <linux/slab.h>
#include <net/mac80211.h>
@@ -170,7 +171,7 @@
return RX_CONTINUE;
if (skb->len < 24)
- return RX_DROP_MONITOR;
+ return RX_CONTINUE;
presp = ieee80211_is_probe_resp(fc);
if (presp) {
@@ -850,3 +851,122 @@
}
mutex_unlock(&local->mtx);
}
+
+int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata,
+ struct cfg80211_sched_scan_request *req)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret, i;
+
+ mutex_lock(&sdata->local->mtx);
+
+ if (local->sched_scanning) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ if (!local->ops->sched_scan_start) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++) {
+ local->sched_scan_ies.ie[i] = kzalloc(2 +
+ IEEE80211_MAX_SSID_LEN +
+ local->scan_ies_len,
+ GFP_KERNEL);
+ if (!local->sched_scan_ies.ie[i]) {
+ ret = -ENOMEM;
+ goto out_free;
+ }
+
+ local->sched_scan_ies.len[i] =
+ ieee80211_build_preq_ies(local,
+ local->sched_scan_ies.ie[i],
+ req->ie, req->ie_len, i,
+ (u32) -1, 0);
+ }
+
+ ret = drv_sched_scan_start(local, sdata, req,
+ &local->sched_scan_ies);
+ if (ret == 0) {
+ local->sched_scanning = true;
+ goto out;
+ }
+
+out_free:
+ while (i > 0)
+ kfree(local->sched_scan_ies.ie[--i]);
+out:
+ mutex_unlock(&sdata->local->mtx);
+ return ret;
+}
+
+int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata)
+{
+ struct ieee80211_local *local = sdata->local;
+ int ret = 0, i;
+
+ mutex_lock(&sdata->local->mtx);
+
+ if (!local->ops->sched_scan_stop) {
+ ret = -ENOTSUPP;
+ goto out;
+ }
+
+ if (local->sched_scanning) {
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(local->sched_scan_ies.ie[i]);
+
+ drv_sched_scan_stop(local, sdata);
+ local->sched_scanning = false;
+ }
+out:
+ mutex_unlock(&sdata->local->mtx);
+
+ return ret;
+}
+
+void ieee80211_sched_scan_results(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ trace_api_sched_scan_results(local);
+
+ cfg80211_sched_scan_results(hw->wiphy);
+}
+EXPORT_SYMBOL(ieee80211_sched_scan_results);
+
+void ieee80211_sched_scan_stopped_work(struct work_struct *work)
+{
+ struct ieee80211_local *local =
+ container_of(work, struct ieee80211_local,
+ sched_scan_stopped_work);
+ int i;
+
+ mutex_lock(&local->mtx);
+
+ if (!local->sched_scanning) {
+ mutex_unlock(&local->mtx);
+ return;
+ }
+
+ for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+ kfree(local->sched_scan_ies.ie[i]);
+
+ local->sched_scanning = false;
+
+ mutex_unlock(&local->mtx);
+
+ cfg80211_sched_scan_stopped(local->hw.wiphy);
+}
+
+void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw)
+{
+ struct ieee80211_local *local = hw_to_local(hw);
+
+ trace_api_sched_scan_stopped(local);
+
+ ieee80211_queue_work(&local->hw, &local->sched_scan_stopped_work);
+}
+EXPORT_SYMBOL(ieee80211_sched_scan_stopped);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index d9e6e81..b83870b 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -67,7 +67,8 @@
{
struct sta_info *s;
- s = local->sta_hash[STA_HASH(sta->sta.addr)];
+ s = rcu_dereference_protected(local->sta_hash[STA_HASH(sta->sta.addr)],
+ lockdep_is_held(&local->sta_lock));
if (!s)
return -ENOENT;
if (s == sta) {
@@ -76,9 +77,11 @@
return 0;
}
- while (s->hnext && s->hnext != sta)
- s = s->hnext;
- if (s->hnext) {
+ while (rcu_access_pointer(s->hnext) &&
+ rcu_access_pointer(s->hnext) != sta)
+ s = rcu_dereference_protected(s->hnext,
+ lockdep_is_held(&local->sta_lock));
+ if (rcu_access_pointer(s->hnext)) {
rcu_assign_pointer(s->hnext, sta->hnext);
return 0;
}
@@ -274,7 +277,7 @@
#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
#ifdef CONFIG_MAC80211_MESH
- sta->plink_state = PLINK_LISTEN;
+ sta->plink_state = NL80211_PLINK_LISTEN;
init_timer(&sta->plink_timer);
#endif
@@ -652,10 +655,12 @@
if (ret)
return ret;
+ mutex_lock(&local->key_mtx);
for (i = 0; i < NUM_DEFAULT_KEYS; i++)
- ieee80211_key_free(local, sta->gtk[i]);
+ __ieee80211_key_free(key_mtx_dereference(local, sta->gtk[i]));
if (sta->ptk)
- ieee80211_key_free(local, sta->ptk);
+ __ieee80211_key_free(key_mtx_dereference(local, sta->ptk));
+ mutex_unlock(&local->key_mtx);
sta->dead = true;
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index aa0adcb..c6ae8718 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -152,6 +152,7 @@
*
* @tid_rx: aggregation info for Rx per TID -- RCU protected
* @tid_tx: aggregation info for Tx per TID
+ * @tid_start_tx: sessions where start was requested
* @addba_req_num: number of times addBA request has been sent.
* @dialog_token_allocator: dialog token enumerator for each new session;
* @work: work struct for starting/stopping aggregation
@@ -163,40 +164,18 @@
struct sta_ampdu_mlme {
struct mutex mtx;
/* rx */
- struct tid_ampdu_rx *tid_rx[STA_TID_NUM];
+ struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM];
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
/* tx */
struct work_struct work;
- struct tid_ampdu_tx *tid_tx[STA_TID_NUM];
+ struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM];
+ struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM];
u8 addba_req_num[STA_TID_NUM];
u8 dialog_token_allocator;
};
/**
- * enum plink_state - state of a mesh peer link finite state machine
- *
- * @PLINK_LISTEN: initial state, considered the implicit state of non existent
- * mesh peer links
- * @PLINK_OPN_SNT: mesh plink open frame has been sent to this mesh peer
- * @PLINK_OPN_RCVD: mesh plink open frame has been received from this mesh peer
- * @PLINK_CNF_RCVD: mesh plink confirm frame has been received from this mesh
- * peer
- * @PLINK_ESTAB: mesh peer link is established
- * @PLINK_HOLDING: mesh peer link is being closed or cancelled
- * @PLINK_BLOCKED: all frames transmitted from this mesh plink are discarded
- */
-enum plink_state {
- PLINK_LISTEN,
- PLINK_OPN_SNT,
- PLINK_OPN_RCVD,
- PLINK_CNF_RCVD,
- PLINK_ESTAB,
- PLINK_HOLDING,
- PLINK_BLOCKED
-};
-
-/**
* struct sta_info - STA information
*
* This structure collects information about a station that
@@ -264,11 +243,11 @@
struct sta_info {
/* General information, mostly static */
struct list_head list;
- struct sta_info *hnext;
+ struct sta_info __rcu *hnext;
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
- struct ieee80211_key *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
- struct ieee80211_key *ptk;
+ struct ieee80211_key __rcu *gtk[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS];
+ struct ieee80211_key __rcu *ptk;
struct rate_control_ref *rate_ctrl;
void *rate_ctrl_priv;
spinlock_t lock;
@@ -339,7 +318,7 @@
u8 plink_retries;
bool ignore_plink_timer;
bool plink_timer_was_running;
- enum plink_state plink_state;
+ enum nl80211_plink_state plink_state;
u32 plink_timeout;
struct timer_list plink_timer;
#endif
@@ -357,12 +336,12 @@
struct ieee80211_sta sta;
};
-static inline enum plink_state sta_plink_state(struct sta_info *sta)
+static inline enum nl80211_plink_state sta_plink_state(struct sta_info *sta)
{
#ifdef CONFIG_MAC80211_MESH
return sta->plink_state;
#endif
- return PLINK_LISTEN;
+ return NL80211_PLINK_LISTEN;
}
static inline void set_sta_flags(struct sta_info *sta, const u32 flags)
@@ -421,7 +400,16 @@
return ret;
}
+void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
+ struct tid_ampdu_tx *tid_tx);
+static inline struct tid_ampdu_tx *
+rcu_dereference_protected_tid_tx(struct sta_info *sta, int tid)
+{
+ return rcu_dereference_protected(sta->ampdu_mlme.tid_tx[tid],
+ lockdep_is_held(&sta->lock) ||
+ lockdep_is_held(&sta->ampdu_mlme.mtx));
+}
#define STA_HASH_SIZE 256
#define STA_HASH(sta) (sta[5])
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e3e3aa1..6eeaaa2 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1147,7 +1147,7 @@
* packet pass through because splicing the frames
* back is already done.
*/
- tid_tx = tx->sta->ampdu_mlme.tid_tx[tid];
+ tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid);
if (!tid_tx) {
/* do nothing, let packet pass through */
@@ -1751,6 +1751,7 @@
ret = NETDEV_TX_OK;
goto fail;
}
+ rcu_read_lock();
if (!is_multicast_ether_addr(skb->data))
mppath = mpp_path_lookup(skb->data, sdata);
@@ -1765,13 +1766,13 @@
!(mppath && compare_ether_addr(mppath->mpp, skb->data))) {
hdrlen = ieee80211_fill_mesh_addresses(&hdr, &fc,
skb->data, skb->data + ETH_ALEN);
+ rcu_read_unlock();
meshhdrlen = ieee80211_new_mesh_header(&mesh_hdr,
sdata, NULL, NULL);
} else {
int is_mesh_mcast = 1;
const u8 *mesh_da;
- rcu_read_lock();
if (is_multicast_ether_addr(skb->data))
/* DA TA mSA AE:SA */
mesh_da = skb->data;
@@ -2534,8 +2535,9 @@
skb_set_network_header(skb, 0);
skb_set_transport_header(skb, 0);
- /* send all internal mgmt frames on VO */
- skb_set_queue_mapping(skb, 0);
+ /* Send all internal mgmt frames on VO. Accordingly set TID to 7. */
+ skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+ skb->priority = 7;
/*
* The other path calling ieee80211_xmit is from the tasklet,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ef0560a..d3fe2d2 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1125,9 +1125,27 @@
struct sta_info *sta;
int res;
+#ifdef CONFIG_PM
if (local->suspended)
local->resuming = true;
+ if (local->wowlan) {
+ local->wowlan = false;
+ res = drv_resume(local);
+ if (res < 0) {
+ local->resuming = false;
+ return res;
+ }
+ if (res == 0)
+ goto wake_up;
+ WARN_ON(res > 1);
+ /*
+ * res is 1, which means the driver requested
+ * to go through a regular reset on wakeup.
+ */
+ }
+#endif
+
/* restart hardware */
if (local->open_count) {
/*
@@ -1258,6 +1276,7 @@
if (ieee80211_sdata_running(sdata))
ieee80211_enable_keys(sdata);
+ wake_up:
ieee80211_wake_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
diff --git a/net/rfkill/core.c b/net/rfkill/core.c
index 0198191..be90640 100644
--- a/net/rfkill/core.c
+++ b/net/rfkill/core.c
@@ -1024,7 +1024,6 @@
* start getting events from elsewhere but hold mtx to get
* startup events added first
*/
- list_add(&data->list, &rfkill_fds);
list_for_each_entry(rfkill, &rfkill_list, node) {
ev = kzalloc(sizeof(*ev), GFP_KERNEL);
@@ -1033,6 +1032,7 @@
rfkill_fill_event(&ev->ev, rfkill, RFKILL_OP_ADD);
list_add_tail(&ev->list, &data->events);
}
+ list_add(&data->list, &rfkill_fds);
mutex_unlock(&data->mtx);
mutex_unlock(&rfkill_global_mutex);
diff --git a/net/wireless/core.c b/net/wireless/core.c
index bbf1fa1..c22ef34 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -370,7 +370,7 @@
spin_lock_init(&rdev->bss_lock);
INIT_LIST_HEAD(&rdev->bss_list);
INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
-
+ INIT_WORK(&rdev->sched_scan_results_wk, __cfg80211_sched_scan_results);
#ifdef CONFIG_CFG80211_WEXT
rdev->wiphy.wext = &cfg80211_wext_handler;
#endif
@@ -416,6 +416,67 @@
}
EXPORT_SYMBOL(wiphy_new);
+static int wiphy_verify_combinations(struct wiphy *wiphy)
+{
+ const struct ieee80211_iface_combination *c;
+ int i, j;
+
+ /* If we have combinations enforce them */
+ if (wiphy->n_iface_combinations)
+ wiphy->flags |= WIPHY_FLAG_ENFORCE_COMBINATIONS;
+
+ for (i = 0; i < wiphy->n_iface_combinations; i++) {
+ u32 cnt = 0;
+ u16 all_iftypes = 0;
+
+ c = &wiphy->iface_combinations[i];
+
+ /* Combinations with just one interface aren't real */
+ if (WARN_ON(c->max_interfaces < 2))
+ return -EINVAL;
+
+ /* Need at least one channel */
+ if (WARN_ON(!c->num_different_channels))
+ return -EINVAL;
+
+ if (WARN_ON(!c->n_limits))
+ return -EINVAL;
+
+ for (j = 0; j < c->n_limits; j++) {
+ u16 types = c->limits[j].types;
+
+ /*
+ * interface types shouldn't overlap, this is
+ * used in cfg80211_can_change_interface()
+ */
+ if (WARN_ON(types & all_iftypes))
+ return -EINVAL;
+ all_iftypes |= types;
+
+ if (WARN_ON(!c->limits[j].max))
+ return -EINVAL;
+
+ /* Shouldn't list software iftypes in combinations! */
+ if (WARN_ON(wiphy->software_iftypes & types))
+ return -EINVAL;
+
+ cnt += c->limits[j].max;
+ /*
+ * Don't advertise an unsupported type
+ * in a combination.
+ */
+ if (WARN_ON((wiphy->interface_modes & types) != types))
+ return -EINVAL;
+ }
+
+ /* You can't even choose that many! */
+ if (WARN_ON(cnt < c->max_interfaces))
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int wiphy_register(struct wiphy *wiphy)
{
struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
@@ -444,6 +505,10 @@
if (WARN_ON(ifmodes != wiphy->interface_modes))
wiphy->interface_modes = ifmodes;
+ res = wiphy_verify_combinations(wiphy);
+ if (res)
+ return res;
+
/* sanity check supported bands/channels */
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
sband = wiphy->bands[band];
@@ -493,6 +558,13 @@
return -EINVAL;
}
+ if (rdev->wiphy.wowlan.n_patterns) {
+ if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len ||
+ rdev->wiphy.wowlan.pattern_min_len >
+ rdev->wiphy.wowlan.pattern_max_len))
+ return -EINVAL;
+ }
+
/* check and set up bitrates */
ieee80211_set_bitrate_flags(wiphy);
@@ -631,6 +703,7 @@
mutex_destroy(&rdev->devlist_mtx);
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&scan->pub);
+ cfg80211_rdev_free_wowlan(rdev);
kfree(rdev);
}
@@ -664,6 +737,11 @@
___cfg80211_scan_done(rdev, true);
}
+ if (WARN_ON(rdev->sched_scan_req &&
+ rdev->sched_scan_req->dev == wdev->netdev)) {
+ __cfg80211_stop_sched_scan(rdev, false);
+ }
+
cfg80211_unlock_rdev(rdev);
mutex_lock(&rdev->devlist_mtx);
@@ -685,6 +763,7 @@
struct net_device *dev = ndev;
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct cfg80211_registered_device *rdev;
+ int ret;
if (!wdev)
return NOTIFY_DONE;
@@ -751,6 +830,10 @@
break;
case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_STATION:
+ cfg80211_lock_rdev(rdev);
+ __cfg80211_stop_sched_scan(rdev, false);
+ cfg80211_unlock_rdev(rdev);
+
wdev_lock(wdev);
#ifdef CONFIG_CFG80211_WEXT
kfree(wdev->wext.ie);
@@ -769,6 +852,7 @@
default:
break;
}
+ wdev->beacon_interval = 0;
break;
case NETDEV_DOWN:
dev_hold(dev);
@@ -875,6 +959,9 @@
return notifier_from_errno(-EOPNOTSUPP);
if (rfkill_blocked(rdev->rfkill))
return notifier_from_errno(-ERFKILL);
+ ret = cfg80211_can_add_interface(rdev, wdev->iftype);
+ if (ret)
+ return notifier_from_errno(ret);
break;
}
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 26a0a08..bf0fb40 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -60,8 +60,10 @@
struct rb_root bss_tree;
u32 bss_generation;
struct cfg80211_scan_request *scan_req; /* protected by RTNL */
+ struct cfg80211_sched_scan_request *sched_scan_req;
unsigned long suspend_at;
struct work_struct scan_done_wk;
+ struct work_struct sched_scan_results_wk;
#ifdef CONFIG_NL80211_TESTMODE
struct genl_info *testmode_info;
@@ -70,6 +72,8 @@
struct work_struct conn_work;
struct work_struct event_work;
+ struct cfg80211_wowlan *wowlan;
+
/* must be last because of the way we do wiphy_priv(),
* and it should at least be aligned to NETDEV_ALIGN */
struct wiphy wiphy __attribute__((__aligned__(NETDEV_ALIGN)));
@@ -89,6 +93,18 @@
return wiphy_idx >= 0;
}
+static inline void
+cfg80211_rdev_free_wowlan(struct cfg80211_registered_device *rdev)
+{
+ int i;
+
+ if (!rdev->wowlan)
+ return;
+ for (i = 0; i < rdev->wowlan->n_patterns; i++)
+ kfree(rdev->wowlan->patterns[i].mask);
+ kfree(rdev->wowlan->patterns);
+ kfree(rdev->wowlan);
+}
extern struct workqueue_struct *cfg80211_wq;
extern struct mutex cfg80211_mutex;
@@ -397,12 +413,26 @@
void cfg80211_sme_disassoc(struct net_device *dev, int idx);
void __cfg80211_scan_done(struct work_struct *wk);
void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak);
+void __cfg80211_sched_scan_results(struct work_struct *wk);
+int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
+ bool driver_initiated);
void cfg80211_upload_connect_keys(struct wireless_dev *wdev);
int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype,
u32 *flags, struct vif_params *params);
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
+int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ enum nl80211_iftype iftype);
+
+static inline int
+cfg80211_can_add_interface(struct cfg80211_registered_device *rdev,
+ enum nl80211_iftype iftype)
+{
+ return cfg80211_can_change_interface(rdev, NULL, iftype);
+}
+
struct ieee80211_channel *
rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
int freq, enum nl80211_channel_type channel_type);
@@ -412,6 +442,9 @@
u16 cfg80211_calculate_bitrate(struct rate_info *rate);
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+ u32 beacon_int);
+
#ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
#define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond)
#else
diff --git a/net/wireless/lib80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c
index e2e8887..2f265e0 100644
--- a/net/wireless/lib80211_crypt_wep.c
+++ b/net/wireless/lib80211_crypt_wep.c
@@ -96,13 +96,12 @@
u8 *key, int keylen, void *priv)
{
struct lib80211_wep_data *wep = priv;
- u32 klen, len;
+ u32 klen;
u8 *pos;
if (skb_headroom(skb) < 4 || skb->len < hdr_len)
return -1;
- len = skb->len - hdr_len;
pos = skb_push(skb, 4);
memmove(pos, pos + 4, hdr_len);
pos += hdr_len;
diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c
index 16881fe..493b939 100644
--- a/net/wireless/mlme.c
+++ b/net/wireless/mlme.c
@@ -963,6 +963,16 @@
if (memcmp(mgmt->bssid, dev->dev_addr, ETH_ALEN))
err = -EINVAL;
break;
+ case NL80211_IFTYPE_MESH_POINT:
+ if (memcmp(mgmt->sa, mgmt->bssid, ETH_ALEN)) {
+ err = -EINVAL;
+ break;
+ }
+ /*
+ * check for mesh DA must be done by driver as
+ * cfg80211 doesn't track the stations
+ */
+ break;
default:
err = -EOPNOTSUPP;
break;
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 0efa7fd..2222ce08 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -173,6 +173,9 @@
[NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
[NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
[NL80211_ATTR_KEY_DEFAULT_TYPES] = { .type = NLA_NESTED },
+ [NL80211_ATTR_WOWLAN_TRIGGERS] = { .type = NLA_NESTED },
+ [NL80211_ATTR_STA_PLINK_STATE] = { .type = NLA_U8 },
+ [NL80211_ATTR_SCHED_SCAN_INTERVAL] = { .type = NLA_U32 },
};
/* policy for the key attributes */
@@ -194,6 +197,15 @@
[NL80211_KEY_DEFAULT_TYPE_MULTICAST] = { .type = NLA_FLAG },
};
+/* policy for WoWLAN attributes */
+static const struct nla_policy
+nl80211_wowlan_policy[NUM_NL80211_WOWLAN_TRIG] = {
+ [NL80211_WOWLAN_TRIG_ANY] = { .type = NLA_FLAG },
+ [NL80211_WOWLAN_TRIG_DISCONNECT] = { .type = NLA_FLAG },
+ [NL80211_WOWLAN_TRIG_MAGIC_PKT] = { .type = NLA_FLAG },
+ [NL80211_WOWLAN_TRIG_PKT_PATTERN] = { .type = NLA_NESTED },
+};
+
/* ifidx get helper */
static int nl80211_get_ifidx(struct netlink_callback *cb)
{
@@ -534,6 +546,7 @@
case NL80211_IFTYPE_AP:
case NL80211_IFTYPE_AP_VLAN:
case NL80211_IFTYPE_P2P_GO:
+ case NL80211_IFTYPE_MESH_POINT:
break;
case NL80211_IFTYPE_ADHOC:
if (!wdev->current_bss)
@@ -551,6 +564,88 @@
return 0;
}
+static int nl80211_put_iftypes(struct sk_buff *msg, u32 attr, u16 ifmodes)
+{
+ struct nlattr *nl_modes = nla_nest_start(msg, attr);
+ int i;
+
+ if (!nl_modes)
+ goto nla_put_failure;
+
+ i = 0;
+ while (ifmodes) {
+ if (ifmodes & 1)
+ NLA_PUT_FLAG(msg, i);
+ ifmodes >>= 1;
+ i++;
+ }
+
+ nla_nest_end(msg, nl_modes);
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+static int nl80211_put_iface_combinations(struct wiphy *wiphy,
+ struct sk_buff *msg)
+{
+ struct nlattr *nl_combis;
+ int i, j;
+
+ nl_combis = nla_nest_start(msg,
+ NL80211_ATTR_INTERFACE_COMBINATIONS);
+ if (!nl_combis)
+ goto nla_put_failure;
+
+ for (i = 0; i < wiphy->n_iface_combinations; i++) {
+ const struct ieee80211_iface_combination *c;
+ struct nlattr *nl_combi, *nl_limits;
+
+ c = &wiphy->iface_combinations[i];
+
+ nl_combi = nla_nest_start(msg, i + 1);
+ if (!nl_combi)
+ goto nla_put_failure;
+
+ nl_limits = nla_nest_start(msg, NL80211_IFACE_COMB_LIMITS);
+ if (!nl_limits)
+ goto nla_put_failure;
+
+ for (j = 0; j < c->n_limits; j++) {
+ struct nlattr *nl_limit;
+
+ nl_limit = nla_nest_start(msg, j + 1);
+ if (!nl_limit)
+ goto nla_put_failure;
+ NLA_PUT_U32(msg, NL80211_IFACE_LIMIT_MAX,
+ c->limits[j].max);
+ if (nl80211_put_iftypes(msg, NL80211_IFACE_LIMIT_TYPES,
+ c->limits[j].types))
+ goto nla_put_failure;
+ nla_nest_end(msg, nl_limit);
+ }
+
+ nla_nest_end(msg, nl_limits);
+
+ if (c->beacon_int_infra_match)
+ NLA_PUT_FLAG(msg,
+ NL80211_IFACE_COMB_STA_AP_BI_MATCH);
+ NLA_PUT_U32(msg, NL80211_IFACE_COMB_NUM_CHANNELS,
+ c->num_different_channels);
+ NLA_PUT_U32(msg, NL80211_IFACE_COMB_MAXNUM,
+ c->max_interfaces);
+
+ nla_nest_end(msg, nl_combi);
+ }
+
+ nla_nest_end(msg, nl_combis);
+
+ return 0;
+nla_put_failure:
+ return -ENOBUFS;
+}
+
static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *dev)
{
@@ -558,13 +653,11 @@
struct nlattr *nl_bands, *nl_band;
struct nlattr *nl_freqs, *nl_freq;
struct nlattr *nl_rates, *nl_rate;
- struct nlattr *nl_modes;
struct nlattr *nl_cmds;
enum ieee80211_band band;
struct ieee80211_channel *chan;
struct ieee80211_rate *rate;
int i;
- u16 ifmodes = dev->wiphy.interface_modes;
const struct ieee80211_txrx_stypes *mgmt_stypes =
dev->wiphy.mgmt_stypes;
@@ -624,20 +717,10 @@
}
}
- nl_modes = nla_nest_start(msg, NL80211_ATTR_SUPPORTED_IFTYPES);
- if (!nl_modes)
+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SUPPORTED_IFTYPES,
+ dev->wiphy.interface_modes))
goto nla_put_failure;
- i = 0;
- while (ifmodes) {
- if (ifmodes & 1)
- NLA_PUT_FLAG(msg, i);
- ifmodes >>= 1;
- i++;
- }
-
- nla_nest_end(msg, nl_modes);
-
nl_bands = nla_nest_start(msg, NL80211_ATTR_WIPHY_BANDS);
if (!nl_bands)
goto nla_put_failure;
@@ -749,6 +832,8 @@
}
CMD(set_channel, SET_CHANNEL);
CMD(set_wds_peer, SET_WDS_PEER);
+ if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
+ CMD(sched_scan_start, START_SCHED_SCAN);
#undef CMD
@@ -821,6 +906,42 @@
nla_nest_end(msg, nl_ifs);
}
+ if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) {
+ struct nlattr *nl_wowlan;
+
+ nl_wowlan = nla_nest_start(msg,
+ NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED);
+ if (!nl_wowlan)
+ goto nla_put_failure;
+
+ if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_ANY)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
+ if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_DISCONNECT)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
+ if (dev->wiphy.wowlan.flags & WIPHY_WOWLAN_MAGIC_PKT)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
+ if (dev->wiphy.wowlan.n_patterns) {
+ struct nl80211_wowlan_pattern_support pat = {
+ .max_patterns = dev->wiphy.wowlan.n_patterns,
+ .min_pattern_len =
+ dev->wiphy.wowlan.pattern_min_len,
+ .max_pattern_len =
+ dev->wiphy.wowlan.pattern_max_len,
+ };
+ NLA_PUT(msg, NL80211_WOWLAN_TRIG_PKT_PATTERN,
+ sizeof(pat), &pat);
+ }
+
+ nla_nest_end(msg, nl_wowlan);
+ }
+
+ if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES,
+ dev->wiphy.software_iftypes))
+ goto nla_put_failure;
+
+ if (nl80211_put_iface_combinations(&dev->wiphy, msg))
+ goto nla_put_failure;
+
return genlmsg_end(msg, hdr);
nla_put_failure:
@@ -1682,14 +1803,6 @@
if (err)
goto out;
- if (!(rdev->wiphy.flags &
- WIPHY_FLAG_SUPPORTS_SEPARATE_DEFAULT_KEYS)) {
- if (!key.def_uni || !key.def_multi) {
- err = -EOPNOTSUPP;
- goto out;
- }
- }
-
err = rdev->ops->set_default_key(&rdev->wiphy, dev, key.idx,
key.def_uni, key.def_multi);
@@ -1840,8 +1953,9 @@
struct beacon_parameters *info);
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
struct beacon_parameters params;
- int haveinfo = 0;
+ int haveinfo = 0, err;
if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_BEACON_TAIL]))
return -EINVAL;
@@ -1850,6 +1964,8 @@
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
+ memset(¶ms, 0, sizeof(params));
+
switch (info->genlhdr->cmd) {
case NL80211_CMD_NEW_BEACON:
/* these are required for NEW_BEACON */
@@ -1858,6 +1974,15 @@
!info->attrs[NL80211_ATTR_BEACON_HEAD])
return -EINVAL;
+ params.interval =
+ nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
+ params.dtim_period =
+ nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
+
+ err = cfg80211_validate_beacon_int(rdev, params.interval);
+ if (err)
+ return err;
+
call = rdev->ops->add_beacon;
break;
case NL80211_CMD_SET_BEACON:
@@ -1871,20 +1996,6 @@
if (!call)
return -EOPNOTSUPP;
- memset(¶ms, 0, sizeof(params));
-
- if (info->attrs[NL80211_ATTR_BEACON_INTERVAL]) {
- params.interval =
- nla_get_u32(info->attrs[NL80211_ATTR_BEACON_INTERVAL]);
- haveinfo = 1;
- }
-
- if (info->attrs[NL80211_ATTR_DTIM_PERIOD]) {
- params.dtim_period =
- nla_get_u32(info->attrs[NL80211_ATTR_DTIM_PERIOD]);
- haveinfo = 1;
- }
-
if (info->attrs[NL80211_ATTR_BEACON_HEAD]) {
params.head = nla_data(info->attrs[NL80211_ATTR_BEACON_HEAD]);
params.head_len =
@@ -1902,13 +2013,18 @@
if (!haveinfo)
return -EINVAL;
- return call(&rdev->wiphy, dev, ¶ms);
+ err = call(&rdev->wiphy, dev, ¶ms);
+ if (!err && params.interval)
+ wdev->beacon_interval = params.interval;
+ return err;
}
static int nl80211_del_beacon(struct sk_buff *skb, struct genl_info *info)
{
struct cfg80211_registered_device *rdev = info->user_ptr[0];
struct net_device *dev = info->user_ptr[1];
+ struct wireless_dev *wdev = dev->ieee80211_ptr;
+ int err;
if (!rdev->ops->del_beacon)
return -EOPNOTSUPP;
@@ -1917,7 +2033,10 @@
dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
return -EOPNOTSUPP;
- return rdev->ops->del_beacon(&rdev->wiphy, dev);
+ err = rdev->ops->del_beacon(&rdev->wiphy, dev);
+ if (!err)
+ wdev->beacon_interval = 0;
+ return err;
}
static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = {
@@ -2216,6 +2335,7 @@
memset(¶ms, 0, sizeof(params));
params.listen_interval = -1;
+ params.plink_state = -1;
if (info->attrs[NL80211_ATTR_STA_AID])
return -EINVAL;
@@ -2247,6 +2367,10 @@
params.plink_action =
nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_ACTION]);
+ if (info->attrs[NL80211_ATTR_STA_PLINK_STATE])
+ params.plink_state =
+ nla_get_u8(info->attrs[NL80211_ATTR_STA_PLINK_STATE]);
+
err = get_vlan(info, rdev, ¶ms.vlan);
if (err)
goto out;
@@ -2286,10 +2410,9 @@
err = -EINVAL;
if (params.listen_interval >= 0)
err = -EINVAL;
- if (params.supported_rates)
- err = -EINVAL;
if (params.sta_flags_mask &
~(BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+ BIT(NL80211_STA_FLAG_MFP) |
BIT(NL80211_STA_FLAG_AUTHORIZED)))
err = -EINVAL;
break;
@@ -2840,6 +2963,7 @@
[NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG },
[NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY,
.len = IEEE80211_MAX_DATA_LEN },
+ [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG },
};
static int nl80211_parse_mesh_config(struct genl_info *info,
@@ -2949,7 +3073,8 @@
setup->ie = nla_data(ieattr);
setup->ie_len = nla_len(ieattr);
}
- setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
+ setup->is_authenticated = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AUTH]);
+ setup->is_secure = nla_get_flag(tb[NL80211_MESH_SETUP_USERSPACE_AMPE]);
return 0;
}
@@ -3318,6 +3443,188 @@
return err;
}
+static int nl80211_start_sched_scan(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_sched_scan_request *request;
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct net_device *dev = info->user_ptr[1];
+ struct cfg80211_ssid *ssid;
+ struct ieee80211_channel *channel;
+ struct nlattr *attr;
+ struct wiphy *wiphy;
+ int err, tmp, n_ssids = 0, n_channels, i;
+ u32 interval;
+ enum ieee80211_band band;
+ size_t ie_len;
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
+ !rdev->ops->sched_scan_start)
+ return -EOPNOTSUPP;
+
+ if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
+ return -EINVAL;
+
+ if (rdev->sched_scan_req)
+ return -EINPROGRESS;
+
+ if (!info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL])
+ return -EINVAL;
+
+ interval = nla_get_u32(info->attrs[NL80211_ATTR_SCHED_SCAN_INTERVAL]);
+ if (interval == 0)
+ return -EINVAL;
+
+ wiphy = &rdev->wiphy;
+
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ n_channels = validate_scan_freqs(
+ info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]);
+ if (!n_channels)
+ return -EINVAL;
+ } else {
+ n_channels = 0;
+
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++)
+ if (wiphy->bands[band])
+ n_channels += wiphy->bands[band]->n_channels;
+ }
+
+ if (info->attrs[NL80211_ATTR_SCAN_SSIDS])
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
+ tmp)
+ n_ssids++;
+
+ if (n_ssids > wiphy->max_scan_ssids)
+ return -EINVAL;
+
+ if (info->attrs[NL80211_ATTR_IE])
+ ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ else
+ ie_len = 0;
+
+ if (ie_len > wiphy->max_scan_ie_len)
+ return -EINVAL;
+
+ request = kzalloc(sizeof(*request)
+ + sizeof(*ssid) * n_ssids
+ + sizeof(channel) * n_channels
+ + ie_len, GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ if (n_ssids)
+ request->ssids = (void *)&request->channels[n_channels];
+ request->n_ssids = n_ssids;
+ if (ie_len) {
+ if (request->ssids)
+ request->ie = (void *)(request->ssids + n_ssids);
+ else
+ request->ie = (void *)(request->channels + n_channels);
+ }
+
+ i = 0;
+ if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
+ /* user specified, bail out if channel not found */
+ nla_for_each_nested(attr,
+ info->attrs[NL80211_ATTR_SCAN_FREQUENCIES],
+ tmp) {
+ struct ieee80211_channel *chan;
+
+ chan = ieee80211_get_channel(wiphy, nla_get_u32(attr));
+
+ if (!chan) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ /* ignore disabled channels */
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ request->channels[i] = chan;
+ i++;
+ }
+ } else {
+ /* all channels */
+ for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+ int j;
+ if (!wiphy->bands[band])
+ continue;
+ for (j = 0; j < wiphy->bands[band]->n_channels; j++) {
+ struct ieee80211_channel *chan;
+
+ chan = &wiphy->bands[band]->channels[j];
+
+ if (chan->flags & IEEE80211_CHAN_DISABLED)
+ continue;
+
+ request->channels[i] = chan;
+ i++;
+ }
+ }
+ }
+
+ if (!i) {
+ err = -EINVAL;
+ goto out_free;
+ }
+
+ request->n_channels = i;
+
+ i = 0;
+ if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
+ nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
+ tmp) {
+ if (request->ssids[i].ssid_len >
+ IEEE80211_MAX_SSID_LEN) {
+ err = -EINVAL;
+ goto out_free;
+ }
+ memcpy(request->ssids[i].ssid, nla_data(attr),
+ nla_len(attr));
+ request->ssids[i].ssid_len = nla_len(attr);
+ i++;
+ }
+ }
+
+ if (info->attrs[NL80211_ATTR_IE]) {
+ request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+ memcpy((void *)request->ie,
+ nla_data(info->attrs[NL80211_ATTR_IE]),
+ request->ie_len);
+ }
+
+ request->dev = dev;
+ request->wiphy = &rdev->wiphy;
+ request->interval = interval;
+
+ err = rdev->ops->sched_scan_start(&rdev->wiphy, dev, request);
+ if (!err) {
+ rdev->sched_scan_req = request;
+ nl80211_send_sched_scan(rdev, dev,
+ NL80211_CMD_START_SCHED_SCAN);
+ goto out;
+ }
+
+out_free:
+ kfree(request);
+out:
+ return err;
+}
+
+static int nl80211_stop_sched_scan(struct sk_buff *skb,
+ struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN) ||
+ !rdev->ops->sched_scan_stop)
+ return -EOPNOTSUPP;
+
+ return __cfg80211_stop_sched_scan(rdev, false);
+}
+
static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
struct cfg80211_registered_device *rdev,
struct wireless_dev *wdev,
@@ -4816,6 +5123,194 @@
return cfg80211_leave_mesh(rdev, dev);
}
+static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct sk_buff *msg;
+ void *hdr;
+
+ if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
+ return -EOPNOTSUPP;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return -ENOMEM;
+
+ hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+ NL80211_CMD_GET_WOWLAN);
+ if (!hdr)
+ goto nla_put_failure;
+
+ if (rdev->wowlan) {
+ struct nlattr *nl_wowlan;
+
+ nl_wowlan = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
+ if (!nl_wowlan)
+ goto nla_put_failure;
+
+ if (rdev->wowlan->any)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
+ if (rdev->wowlan->disconnect)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
+ if (rdev->wowlan->magic_pkt)
+ NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
+ if (rdev->wowlan->n_patterns) {
+ struct nlattr *nl_pats, *nl_pat;
+ int i, pat_len;
+
+ nl_pats = nla_nest_start(msg,
+ NL80211_WOWLAN_TRIG_PKT_PATTERN);
+ if (!nl_pats)
+ goto nla_put_failure;
+
+ for (i = 0; i < rdev->wowlan->n_patterns; i++) {
+ nl_pat = nla_nest_start(msg, i + 1);
+ if (!nl_pat)
+ goto nla_put_failure;
+ pat_len = rdev->wowlan->patterns[i].pattern_len;
+ NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_MASK,
+ DIV_ROUND_UP(pat_len, 8),
+ rdev->wowlan->patterns[i].mask);
+ NLA_PUT(msg, NL80211_WOWLAN_PKTPAT_PATTERN,
+ pat_len,
+ rdev->wowlan->patterns[i].pattern);
+ nla_nest_end(msg, nl_pat);
+ }
+ nla_nest_end(msg, nl_pats);
+ }
+
+ nla_nest_end(msg, nl_wowlan);
+ }
+
+ genlmsg_end(msg, hdr);
+ return genlmsg_reply(msg, info);
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return -ENOBUFS;
+}
+
+static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
+{
+ struct cfg80211_registered_device *rdev = info->user_ptr[0];
+ struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG];
+ struct cfg80211_wowlan no_triggers = {};
+ struct cfg80211_wowlan new_triggers = {};
+ struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
+ int err, i;
+
+ if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
+ return -EOPNOTSUPP;
+
+ if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS])
+ goto no_triggers;
+
+ err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG,
+ nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
+ nla_len(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]),
+ nl80211_wowlan_policy);
+ if (err)
+ return err;
+
+ if (tb[NL80211_WOWLAN_TRIG_ANY]) {
+ if (!(wowlan->flags & WIPHY_WOWLAN_ANY))
+ return -EINVAL;
+ new_triggers.any = true;
+ }
+
+ if (tb[NL80211_WOWLAN_TRIG_DISCONNECT]) {
+ if (!(wowlan->flags & WIPHY_WOWLAN_DISCONNECT))
+ return -EINVAL;
+ new_triggers.disconnect = true;
+ }
+
+ if (tb[NL80211_WOWLAN_TRIG_MAGIC_PKT]) {
+ if (!(wowlan->flags & WIPHY_WOWLAN_MAGIC_PKT))
+ return -EINVAL;
+ new_triggers.magic_pkt = true;
+ }
+
+ if (tb[NL80211_WOWLAN_TRIG_PKT_PATTERN]) {
+ struct nlattr *pat;
+ int n_patterns = 0;
+ int rem, pat_len, mask_len;
+ struct nlattr *pat_tb[NUM_NL80211_WOWLAN_PKTPAT];
+
+ nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
+ rem)
+ n_patterns++;
+ if (n_patterns > wowlan->n_patterns)
+ return -EINVAL;
+
+ new_triggers.patterns = kcalloc(n_patterns,
+ sizeof(new_triggers.patterns[0]),
+ GFP_KERNEL);
+ if (!new_triggers.patterns)
+ return -ENOMEM;
+
+ new_triggers.n_patterns = n_patterns;
+ i = 0;
+
+ nla_for_each_nested(pat, tb[NL80211_WOWLAN_TRIG_PKT_PATTERN],
+ rem) {
+ nla_parse(pat_tb, MAX_NL80211_WOWLAN_PKTPAT,
+ nla_data(pat), nla_len(pat), NULL);
+ err = -EINVAL;
+ if (!pat_tb[NL80211_WOWLAN_PKTPAT_MASK] ||
+ !pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN])
+ goto error;
+ pat_len = nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]);
+ mask_len = DIV_ROUND_UP(pat_len, 8);
+ if (nla_len(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]) !=
+ mask_len)
+ goto error;
+ if (pat_len > wowlan->pattern_max_len ||
+ pat_len < wowlan->pattern_min_len)
+ goto error;
+
+ new_triggers.patterns[i].mask =
+ kmalloc(mask_len + pat_len, GFP_KERNEL);
+ if (!new_triggers.patterns[i].mask) {
+ err = -ENOMEM;
+ goto error;
+ }
+ new_triggers.patterns[i].pattern =
+ new_triggers.patterns[i].mask + mask_len;
+ memcpy(new_triggers.patterns[i].mask,
+ nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_MASK]),
+ mask_len);
+ new_triggers.patterns[i].pattern_len = pat_len;
+ memcpy(new_triggers.patterns[i].pattern,
+ nla_data(pat_tb[NL80211_WOWLAN_PKTPAT_PATTERN]),
+ pat_len);
+ i++;
+ }
+ }
+
+ if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) {
+ struct cfg80211_wowlan *ntrig;
+ ntrig = kmemdup(&new_triggers, sizeof(new_triggers),
+ GFP_KERNEL);
+ if (!ntrig) {
+ err = -ENOMEM;
+ goto error;
+ }
+ cfg80211_rdev_free_wowlan(rdev);
+ rdev->wowlan = ntrig;
+ } else {
+ no_triggers:
+ cfg80211_rdev_free_wowlan(rdev);
+ rdev->wowlan = NULL;
+ }
+
+ return 0;
+ error:
+ for (i = 0; i < new_triggers.n_patterns; i++)
+ kfree(new_triggers.patterns[i].mask);
+ kfree(new_triggers.patterns);
+ return err;
+}
+
#define NL80211_FLAG_NEED_WIPHY 0x01
#define NL80211_FLAG_NEED_NETDEV 0x02
#define NL80211_FLAG_NEED_RTNL 0x04
@@ -5100,6 +5595,22 @@
.dumpit = nl80211_dump_scan,
},
{
+ .cmd = NL80211_CMD_START_SCHED_SCAN,
+ .doit = nl80211_start_sched_scan,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_STOP_SCHED_SCAN,
+ .doit = nl80211_stop_sched_scan,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
.cmd = NL80211_CMD_AUTHENTICATE,
.doit = nl80211_authenticate,
.policy = nl80211_policy,
@@ -5314,6 +5825,22 @@
.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
NL80211_FLAG_NEED_RTNL,
},
+ {
+ .cmd = NL80211_CMD_GET_WOWLAN,
+ .doit = nl80211_get_wowlan,
+ .policy = nl80211_policy,
+ /* can be retrieved by unprivileged users */
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
+ },
+ {
+ .cmd = NL80211_CMD_SET_WOWLAN,
+ .doit = nl80211_set_wowlan,
+ .policy = nl80211_policy,
+ .flags = GENL_ADMIN_PERM,
+ .internal_flags = NL80211_FLAG_NEED_WIPHY |
+ NL80211_FLAG_NEED_RTNL,
+ },
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -5409,6 +5936,28 @@
return -EMSGSIZE;
}
+static int
+nl80211_send_sched_scan_msg(struct sk_buff *msg,
+ struct cfg80211_registered_device *rdev,
+ struct net_device *netdev,
+ u32 pid, u32 seq, int flags, u32 cmd)
+{
+ void *hdr;
+
+ hdr = nl80211hdr_put(msg, pid, seq, flags, cmd);
+ if (!hdr)
+ return -1;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+ return genlmsg_end(msg, hdr);
+
+ nla_put_failure:
+ genlmsg_cancel(msg, hdr);
+ return -EMSGSIZE;
+}
+
void nl80211_send_scan_start(struct cfg80211_registered_device *rdev,
struct net_device *netdev)
{
@@ -5466,6 +6015,43 @@
nl80211_scan_mcgrp.id, GFP_KERNEL);
}
+void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev)
+{
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0,
+ NL80211_CMD_SCHED_SCAN_RESULTS) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
+void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u32 cmd)
+{
+ struct sk_buff *msg;
+
+ msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+ if (!msg)
+ return;
+
+ if (nl80211_send_sched_scan_msg(msg, rdev, netdev, 0, 0, 0, cmd) < 0) {
+ nlmsg_free(msg);
+ return;
+ }
+
+ genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+ nl80211_scan_mcgrp.id, GFP_KERNEL);
+}
+
/*
* This can happen on global regulatory changes or device specific settings
* based on custom world regulatory domains.
diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h
index f2af695..2f1bfb8 100644
--- a/net/wireless/nl80211.h
+++ b/net/wireless/nl80211.h
@@ -12,6 +12,10 @@
struct net_device *netdev);
void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
struct net_device *netdev);
+void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev, u32 cmd);
+void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev,
+ struct net_device *netdev);
void nl80211_send_reg_change_event(struct regulatory_request *request);
void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev,
struct net_device *netdev,
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 1613080..1ad0f39 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -672,11 +672,9 @@
for (i = 0; i < regd->n_reg_rules; i++) {
const struct ieee80211_reg_rule *rr;
const struct ieee80211_freq_range *fr = NULL;
- const struct ieee80211_power_rule *pr = NULL;
rr = ®d->reg_rules[i];
fr = &rr->freq_range;
- pr = &rr->power_rule;
/*
* We only need to know if one frequency rule was
diff --git a/net/wireless/scan.c b/net/wireless/scan.c
index fbf6f33..73a441d 100644
--- a/net/wireless/scan.c
+++ b/net/wireless/scan.c
@@ -93,6 +93,69 @@
}
EXPORT_SYMBOL(cfg80211_scan_done);
+void __cfg80211_sched_scan_results(struct work_struct *wk)
+{
+ struct cfg80211_registered_device *rdev;
+
+ rdev = container_of(wk, struct cfg80211_registered_device,
+ sched_scan_results_wk);
+
+ cfg80211_lock_rdev(rdev);
+
+ /* we don't have sched_scan_req anymore if the scan is stopping */
+ if (rdev->sched_scan_req)
+ nl80211_send_sched_scan_results(rdev,
+ rdev->sched_scan_req->dev);
+
+ cfg80211_unlock_rdev(rdev);
+}
+
+void cfg80211_sched_scan_results(struct wiphy *wiphy)
+{
+ /* ignore if we're not scanning */
+ if (wiphy_to_dev(wiphy)->sched_scan_req)
+ queue_work(cfg80211_wq,
+ &wiphy_to_dev(wiphy)->sched_scan_results_wk);
+}
+EXPORT_SYMBOL(cfg80211_sched_scan_results);
+
+void cfg80211_sched_scan_stopped(struct wiphy *wiphy)
+{
+ struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+ cfg80211_lock_rdev(rdev);
+ __cfg80211_stop_sched_scan(rdev, true);
+ cfg80211_unlock_rdev(rdev);
+}
+EXPORT_SYMBOL(cfg80211_sched_scan_stopped);
+
+int __cfg80211_stop_sched_scan(struct cfg80211_registered_device *rdev,
+ bool driver_initiated)
+{
+ int err;
+ struct net_device *dev;
+
+ ASSERT_RDEV_LOCK(rdev);
+
+ if (!rdev->sched_scan_req)
+ return 0;
+
+ dev = rdev->sched_scan_req->dev;
+
+ if (!driver_initiated) {
+ err = rdev->ops->sched_scan_stop(&rdev->wiphy, dev);
+ if (err)
+ return err;
+ }
+
+ nl80211_send_sched_scan(rdev, dev, NL80211_CMD_SCHED_SCAN_STOPPED);
+
+ kfree(rdev->sched_scan_req);
+ rdev->sched_scan_req = NULL;
+
+ return err;
+}
+
static void bss_release(struct kref *ref)
{
struct cfg80211_internal_bss *bss;
@@ -210,7 +273,7 @@
{
const u8 *ie;
- if (!is_zero_ether_addr(a->bssid))
+ if (!WLAN_CAPABILITY_IS_MBSS(a->capability))
return false;
ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
@@ -248,11 +311,7 @@
if (a->channel != b->channel)
return b->channel->center_freq - a->channel->center_freq;
- r = memcmp(a->bssid, b->bssid, ETH_ALEN);
- if (r)
- return r;
-
- if (is_zero_ether_addr(a->bssid)) {
+ if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) {
r = cmp_ies(WLAN_EID_MESH_ID,
a->information_elements,
a->len_information_elements,
@@ -267,6 +326,10 @@
b->len_information_elements);
}
+ r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+ if (r)
+ return r;
+
return cmp_ies(WLAN_EID_SSID,
a->information_elements,
a->len_information_elements,
@@ -407,7 +470,7 @@
res->ts = jiffies;
- if (is_zero_ether_addr(res->pub.bssid)) {
+ if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) {
/* must be mesh, verify */
meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
res->pub.information_elements,
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 4294fa2..c6e4ca6 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -93,7 +93,7 @@
if (rdev->ops->suspend) {
rtnl_lock();
- ret = rdev->ops->suspend(&rdev->wiphy);
+ ret = rdev->ops->suspend(&rdev->wiphy, rdev->wowlan);
rtnl_unlock();
}
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 6a750bc..f0536d4 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -544,7 +544,8 @@
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
- const unsigned int extra_headroom)
+ const unsigned int extra_headroom,
+ bool has_80211_header)
{
struct sk_buff *frame = NULL;
u16 ethertype;
@@ -553,14 +554,18 @@
int remaining, err;
u8 dst[ETH_ALEN], src[ETH_ALEN];
- err = ieee80211_data_to_8023(skb, addr, iftype);
- if (err)
- goto out;
+ if (has_80211_header) {
+ err = ieee80211_data_to_8023(skb, addr, iftype);
+ if (err)
+ goto out;
- /* skip the wrapping header */
- eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
- if (!eth)
- goto out;
+ /* skip the wrapping header */
+ eth = (struct ethhdr *) skb_pull(skb, sizeof(struct ethhdr));
+ if (!eth)
+ goto out;
+ } else {
+ eth = (struct ethhdr *) skb->data;
+ }
while (skb != frame) {
u8 padding;
@@ -803,6 +808,11 @@
return -EBUSY;
if (ntype != otype) {
+ err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr,
+ ntype);
+ if (err)
+ return err;
+
dev->ieee80211_ptr->use_4addr = false;
dev->ieee80211_ptr->mesh_id_up_len = 0;
@@ -896,3 +906,103 @@
/* do NOT round down here */
return (bitrate + 50000) / 100000;
}
+
+int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
+ u32 beacon_int)
+{
+ struct wireless_dev *wdev;
+ int res = 0;
+
+ if (!beacon_int)
+ return -EINVAL;
+
+ mutex_lock(&rdev->devlist_mtx);
+
+ list_for_each_entry(wdev, &rdev->netdev_list, list) {
+ if (!wdev->beacon_interval)
+ continue;
+ if (wdev->beacon_interval != beacon_int) {
+ res = -EINVAL;
+ break;
+ }
+ }
+
+ mutex_unlock(&rdev->devlist_mtx);
+
+ return res;
+}
+
+int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev,
+ struct wireless_dev *wdev,
+ enum nl80211_iftype iftype)
+{
+ struct wireless_dev *wdev_iter;
+ int num[NUM_NL80211_IFTYPES];
+ int total = 1;
+ int i, j;
+
+ ASSERT_RTNL();
+
+ /* Always allow software iftypes */
+ if (rdev->wiphy.software_iftypes & BIT(iftype))
+ return 0;
+
+ /*
+ * Drivers will gradually all set this flag, until all
+ * have it we only enforce for those that set it.
+ */
+ if (!(rdev->wiphy.flags & WIPHY_FLAG_ENFORCE_COMBINATIONS))
+ return 0;
+
+ memset(num, 0, sizeof(num));
+
+ num[iftype] = 1;
+
+ mutex_lock(&rdev->devlist_mtx);
+ list_for_each_entry(wdev_iter, &rdev->netdev_list, list) {
+ if (wdev_iter == wdev)
+ continue;
+ if (!netif_running(wdev_iter->netdev))
+ continue;
+
+ if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype))
+ continue;
+
+ num[wdev_iter->iftype]++;
+ total++;
+ }
+ mutex_unlock(&rdev->devlist_mtx);
+
+ for (i = 0; i < rdev->wiphy.n_iface_combinations; i++) {
+ const struct ieee80211_iface_combination *c;
+ struct ieee80211_iface_limit *limits;
+
+ c = &rdev->wiphy.iface_combinations[i];
+
+ limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits,
+ GFP_KERNEL);
+ if (!limits)
+ return -ENOMEM;
+ if (total > c->max_interfaces)
+ goto cont;
+
+ for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) {
+ if (rdev->wiphy.software_iftypes & BIT(iftype))
+ continue;
+ for (j = 0; j < c->n_limits; j++) {
+ if (!(limits[j].types & iftype))
+ continue;
+ if (limits[j].max < num[iftype])
+ goto cont;
+ limits[j].max -= num[iftype];
+ }
+ }
+ /* yay, it fits */
+ kfree(limits);
+ return 0;
+ cont:
+ kfree(limits);
+ }
+
+ return -EBUSY;
+}
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 88f3f07..e26e2fb 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -702,6 +702,24 @@
return 1;
}
+/* Looks like: bcma:mNidNrevNclN. */
+static int do_bcma_entry(const char *filename,
+ struct bcma_device_id *id, char *alias)
+{
+ id->manuf = TO_NATIVE(id->manuf);
+ id->id = TO_NATIVE(id->id);
+ id->rev = TO_NATIVE(id->rev);
+ id->class = TO_NATIVE(id->class);
+
+ strcpy(alias, "bcma:");
+ ADD(alias, "m", id->manuf != BCMA_ANY_MANUF, id->manuf);
+ ADD(alias, "id", id->id != BCMA_ANY_ID, id->id);
+ ADD(alias, "rev", id->rev != BCMA_ANY_REV, id->rev);
+ ADD(alias, "cl", id->class != BCMA_ANY_CLASS, id->class);
+ add_wildcard(alias);
+ return 1;
+}
+
/* Looks like: virtio:dNvN */
static int do_virtio_entry(const char *filename, struct virtio_device_id *id,
char *alias)
@@ -968,6 +986,10 @@
do_table(symval, sym->st_size,
sizeof(struct ssb_device_id), "ssb",
do_ssb_entry, mod);
+ else if (sym_is(symname, "__mod_bcma_device_table"))
+ do_table(symval, sym->st_size,
+ sizeof(struct bcma_device_id), "bcma",
+ do_bcma_entry, mod);
else if (sym_is(symname, "__mod_virtio_device_table"))
do_table(symval, sym->st_size,
sizeof(struct virtio_device_id), "virtio",