Merge tag 'wireless-drivers-next-for-davem-2016-02-12' of git://git.kernel.org/pub...
authorDavid S. Miller <davem@davemloft.net>
Wed, 17 Feb 2016 01:38:29 +0000 (20:38 -0500)
committerDavid S. Miller <davem@davemloft.net>
Wed, 17 Feb 2016 01:38:29 +0000 (20:38 -0500)
Kalle Valo says:

====================
Major changes:

wl12xx

* add device tree support for SPI

mwifiex

* add debugfs file to read chip information
* add MSIx support for newer pcie chipsets (8997 onwards)
* add schedule scan support
* add WoWLAN net-detect support
* firmware dump support for w8997 chipset

iwlwifi

* continue the work on multiple Rx queues
* add support for beacon storing used in low power states
* use the regular firmware image of WoWLAN
* fix 8000 devices for Big Endian machines
* more firmware debug hooks
* add support for P2P Client snoozing
* make the beacon filtering for AP mode configurable
* fix transmit queues overflow with LSO

libertas

* add support for setting power save via cfg80211
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
94 files changed:
Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt [new file with mode: 0644]
drivers/bcma/bcma_private.h
drivers/bcma/driver_chipcommon.c
drivers/bcma/driver_chipcommon_pmu.c
drivers/bcma/driver_chipcommon_sflash.c
drivers/bcma/driver_gpio.c
drivers/bcma/driver_mips.c
drivers/bcma/host_pci.c
drivers/bcma/scan.c
drivers/net/wireless/broadcom/b43/main.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/intel/iwlwifi/Kconfig
drivers/net/wireless/intel/iwlwifi/dvm/led.c
drivers/net/wireless/intel/iwlwifi/dvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/iwl-9000.c
drivers/net/wireless/intel/iwlwifi/iwl-config.h
drivers/net/wireless/intel/iwlwifi/iwl-fh.h
drivers/net/wireless/intel/iwlwifi/iwl-fw-error-dump.h
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intel/iwlwifi/iwl-modparams.h
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/intel/iwlwifi/iwl-trans.h
drivers/net/wireless/intel/iwlwifi/mvm/constants.h
drivers/net/wireless/intel/iwlwifi/mvm/d3.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/intel/iwlwifi/mvm/debugfs.c
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-rx.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h
drivers/net/wireless/intel/iwlwifi/mvm/fw-dbg.c
drivers/net/wireless/intel/iwlwifi/mvm/fw.c
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/nvm.c
drivers/net/wireless/intel/iwlwifi/mvm/ops.c
drivers/net/wireless/intel/iwlwifi/mvm/power.c
drivers/net/wireless/intel/iwlwifi/mvm/quota.c
drivers/net/wireless/intel/iwlwifi/mvm/rs.c
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c
drivers/net/wireless/intel/iwlwifi/mvm/scan.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.c
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/tt.c
drivers/net/wireless/intel/iwlwifi/mvm/tx.c
drivers/net/wireless/intel/iwlwifi/mvm/utils.c
drivers/net/wireless/intel/iwlwifi/pcie/drv.c
drivers/net/wireless/intel/iwlwifi/pcie/internal.h
drivers/net/wireless/intel/iwlwifi/pcie/rx.c
drivers/net/wireless/intel/iwlwifi/pcie/trans.c
drivers/net/wireless/intel/iwlwifi/pcie/tx.c
drivers/net/wireless/intersil/hostap/hostap_hw.c
drivers/net/wireless/marvell/libertas/cfg.c
drivers/net/wireless/marvell/libertas/cmd.c
drivers/net/wireless/marvell/libertas/cmdresp.c
drivers/net/wireless/marvell/libertas/dev.h
drivers/net/wireless/marvell/libertas/if_sdio.c
drivers/net/wireless/marvell/libertas/if_usb.c
drivers/net/wireless/marvell/libertas/main.c
drivers/net/wireless/marvell/mwifiex/README
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/marvell/mwifiex/cmdevt.c
drivers/net/wireless/marvell/mwifiex/debugfs.c
drivers/net/wireless/marvell/mwifiex/decl.h
drivers/net/wireless/marvell/mwifiex/fw.h
drivers/net/wireless/marvell/mwifiex/init.c
drivers/net/wireless/marvell/mwifiex/ioctl.h
drivers/net/wireless/marvell/mwifiex/join.c
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/pcie.c
drivers/net/wireless/marvell/mwifiex/pcie.h
drivers/net/wireless/marvell/mwifiex/scan.c
drivers/net/wireless/marvell/mwifiex/sdio.c
drivers/net/wireless/marvell/mwifiex/sta_cmd.c
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_event.c
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
drivers/net/wireless/marvell/mwifiex/wmm.c
drivers/net/wireless/ralink/rt2x00/rt2x00.h
drivers/net/wireless/ralink/rt2x00/rt2x00debug.c
drivers/net/wireless/ralink/rt2x00/rt61pci.h
drivers/net/wireless/ti/wlcore/Kconfig
drivers/net/wireless/ti/wlcore/event.c
drivers/net/wireless/ti/wlcore/spi.c
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h

diff --git a/Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt b/Documentation/devicetree/bindings/net/wireless/ti,wlcore,spi.txt
new file mode 100644 (file)
index 0000000..9180724
--- /dev/null
@@ -0,0 +1,36 @@
+* Texas Instruments wl1271 wireless lan controller
+
+The wl1271 chip can be connected via SPI or via SDIO. This
+document describes the binding for the SPI connected chip.
+
+Required properties:
+- compatible :          Should be "ti,wl1271"
+- reg :                 Chip select address of device
+- spi-max-frequency :   Maximum SPI clocking speed of device in Hz
+- ref-clock-frequency : Reference clock frequency
+- interrupt-parent, interrupts :
+                        Should contain parameters for 1 interrupt line.
+                        Interrupt parameters: parent, line number, type.
+- vwlan-supply :        Point the node of the regulator that powers/enable the wl1271 chip
+
+Optional properties:
+- clock-xtal :          boolean, clock is generated from XTAL
+
+- Please consult Documentation/devicetree/bindings/spi/spi-bus.txt
+  for optional SPI connection related properties,
+
+Examples:
+
+&spi1 {
+       wl1271@1 {
+               compatible = "ti,wl1271";
+
+               reg = <1>;
+               spi-max-frequency = <48000000>;
+               clock-xtal;
+               ref-clock-frequency = <38400000>;
+               interrupt-parent = <&gpio3>;
+               interrupts = <8 IRQ_TYPE_LEVEL_HIGH>;
+               vwlan-supply = <&vwlan_fixed>;
+       };
+};
index 38f1567..7e4ddfb 100644 (file)
@@ -48,7 +48,6 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
 void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
 void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
 #ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
 extern struct platform_device bcma_pflash_dev;
 #endif /* CONFIG_BCMA_DRIVER_MIPS */
 
index b7c8a8d..b0f44a2 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/platform_device.h>
 #include <linux/bcma/bcma.h>
 
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
+
 static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
                                         u32 mask, u32 value)
 {
@@ -115,6 +117,8 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
 
 void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
 {
+       struct bcma_bus *bus = cc->core->bus;
+
        if (cc->early_setup_done)
                return;
 
@@ -129,6 +133,9 @@ void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
        if (cc->capabilities & BCMA_CC_CAP_PMU)
                bcma_pmu_early_init(cc);
 
+       if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
+               bcma_chipco_serial_init(cc);
+
        cc->early_setup_done = true;
 }
 
@@ -185,11 +192,12 @@ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
                        ticks = 2;
                else if (ticks > maxt)
                        ticks = maxt;
-               bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
        } else {
                struct bcma_bus *bus = cc->core->bus;
 
                if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+                   bus->chipinfo.id != BCMA_CHIP_ID_BCM47094 &&
                    bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
                        bcma_core_set_clockmode(cc->core,
                                                ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
@@ -314,9 +322,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
        return res;
 }
 
-#ifdef CONFIG_BCMA_DRIVER_MIPS
-void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
+static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 {
+#if IS_BUILTIN(CONFIG_BCM47XX)
        unsigned int irq;
        u32 baud_base;
        u32 i;
@@ -358,5 +366,5 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
                ports[i].baud_base = baud_base;
                ports[i].reg_shift = 0;
        }
+#endif /* CONFIG_BCM47XX */
 }
-#endif /* CONFIG_BCMA_DRIVER_MIPS */
index fe0d48c..f1eb4d3 100644 (file)
 
 u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       return bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_read);
 
 void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
 
 void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
                             u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_PLLCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
 
 void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
                                 u32 offset, u32 mask, u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_CHIPCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_CHIPCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_CHIPCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
 
 void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
                                u32 set)
 {
-       bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
-       bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
-       bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_REGCTL_ADDR, offset);
+       bcma_pmu_read32(cc, BCMA_CC_PMU_REGCTL_ADDR);
+       bcma_pmu_maskset32(cc, BCMA_CC_PMU_REGCTL_DATA, mask, set);
 }
 EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 
@@ -60,18 +60,18 @@ static u32 bcma_pmu_xtalfreq(struct bcma_drv_cc *cc)
 {
        u32 ilp_ctl, alp_hz;
 
-       if (!(bcma_cc_read32(cc, BCMA_CC_PMU_STAT) &
+       if (!(bcma_pmu_read32(cc, BCMA_CC_PMU_STAT) &
              BCMA_CC_PMU_STAT_EXT_LPO_AVAIL))
                return 0;
 
-       bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
-                       BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
+       bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ,
+                        BIT(BCMA_CC_PMU_XTAL_FREQ_MEASURE_SHIFT));
        usleep_range(1000, 2000);
 
-       ilp_ctl = bcma_cc_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
+       ilp_ctl = bcma_pmu_read32(cc, BCMA_CC_PMU_XTAL_FREQ);
        ilp_ctl &= BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK;
 
-       bcma_cc_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_XTAL_FREQ, 0);
 
        alp_hz = ilp_ctl * 32768 / 4;
        return (alp_hz + 50000) / 100000 * 100;
@@ -127,8 +127,8 @@ static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
                mask = (u32)~(BCMA_RES_4314_HT_AVAIL |
                              BCMA_RES_4314_MACPHY_CLK_AVAIL);
 
-               bcma_cc_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
-               bcma_cc_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
+               bcma_pmu_mask32(cc, BCMA_CC_PMU_MINRES_MSK, mask);
+               bcma_pmu_mask32(cc, BCMA_CC_PMU_MAXRES_MSK, mask);
                bcma_wait_value(cc->core, BCMA_CLKCTLST,
                                BCMA_CLKCTLST_HAVEHT, 0, 20000);
                break;
@@ -140,7 +140,7 @@ static void bcma_pmu2_pll_init0(struct bcma_drv_cc *cc, u32 xtalfreq)
 
        /* Flush */
        if (cc->pmu.rev >= 2)
-               bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
+               bcma_pmu_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_PLL_UPD);
 
        /* TODO: Do we need to update OTP? */
 }
@@ -195,9 +195,9 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
 
        /* Set the resource masks. */
        if (min_msk)
-               bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
        if (max_msk)
-               bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
 
        /*
         * Add some delay; allow resources to come up and settle.
@@ -269,23 +269,33 @@ static void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 
 void bcma_pmu_early_init(struct bcma_drv_cc *cc)
 {
+       struct bcma_bus *bus = cc->core->bus;
        u32 pmucap;
 
-       pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
+       if (cc->core->id.rev >= 35 &&
+           cc->capabilities_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
+               cc->pmu.core = bcma_find_core(bus, BCMA_CORE_PMU);
+               if (!cc->pmu.core)
+                       bcma_warn(bus, "Couldn't find expected PMU core");
+       }
+       if (!cc->pmu.core)
+               cc->pmu.core = cc->core;
+
+       pmucap = bcma_pmu_read32(cc, BCMA_CC_PMU_CAP);
        cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
 
-       bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n",
-                  cc->pmu.rev, pmucap);
+       bcma_debug(bus, "Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
+                  pmucap);
 }
 
 void bcma_pmu_init(struct bcma_drv_cc *cc)
 {
        if (cc->pmu.rev == 1)
-               bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
-                             ~BCMA_CC_PMU_CTL_NOILPONW);
+               bcma_pmu_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);
+               bcma_pmu_set32(cc, BCMA_CC_PMU_CTL,
+                              BCMA_CC_PMU_CTL_NOILPONW);
 
        bcma_pmu_pll_init(cc);
        bcma_pmu_resources_init(cc);
@@ -472,8 +482,8 @@ u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc)
 static void bcma_pmu_spuravoid_pll_write(struct bcma_drv_cc *cc, u32 offset,
                                         u32 value)
 {
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
-       bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR, offset);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, value);
 }
 
 void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
@@ -497,20 +507,20 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
                       bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0;
 
                /* RMW only the P1 divider */
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
                                BCMA_CC_PMU_PLL_CTL0 + phypll_offset);
-               tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+               tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
                tmp &= (~(BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK));
                tmp |= (bcm5357_bcm43236_p1div[spuravoid] << BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT);
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
 
                /* RMW only the int feedback divider */
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR,
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_ADDR,
                                BCMA_CC_PMU_PLL_CTL2 + phypll_offset);
-               tmp = bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
+               tmp = bcma_pmu_read32(cc, BCMA_CC_PMU_PLLCTL_DATA);
                tmp &= ~(BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK);
                tmp |= (bcm5357_bcm43236_ndiv[spuravoid]) << BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT;
-               bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, tmp);
+               bcma_pmu_write32(cc, BCMA_CC_PMU_PLLCTL_DATA, tmp);
 
                tmp = BCMA_CC_PMU_CTL_PLL_UPD;
                break;
@@ -646,7 +656,7 @@ void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid)
                break;
        }
 
-       tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL);
-       bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp);
+       tmp |= bcma_pmu_read32(cc, BCMA_CC_PMU_CTL);
+       bcma_pmu_write32(cc, BCMA_CC_PMU_CTL, tmp);
 }
 EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate);
index 7e11ef4..04d706c 100644 (file)
@@ -38,6 +38,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
+       { "MX25L25635F", 0x18, 0x10000, 512, },
        { NULL },
 };
 
index 98067f7..771a2a2 100644 (file)
@@ -192,6 +192,7 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
        case BCMA_CHIP_ID_BCM4707:
        case BCMA_CHIP_ID_BCM5357:
        case BCMA_CHIP_ID_BCM53572:
+       case BCMA_CHIP_ID_BCM47094:
                chip->ngpio     = 32;
                break;
        default:
index 24424f3..a40a203 100644 (file)
@@ -337,12 +337,9 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 
 void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 {
-       struct bcma_bus *bus = mcore->core->bus;
-
        if (mcore->early_setup_done)
                return;
 
-       bcma_chipco_serial_init(&bus->drv_cc);
        bcma_core_mips_flash_detect(mcore);
 
        mcore->early_setup_done = true;
index 0856189..cae5385 100644 (file)
@@ -294,7 +294,7 @@ static const struct pci_device_id bcma_pci_bridge_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4358) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4359) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4360) },
-       { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4365) },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_BROADCOM, 0x4365, PCI_VENDOR_ID_DELL, 0x0016) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a0) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43a9) },
        { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x43aa) },
index df806b9..4a2d1b2 100644 (file)
@@ -98,6 +98,9 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = {
        { BCMA_CORE_SHIM, "SHIM" },
        { BCMA_CORE_PCIE2, "PCIe Gen2" },
        { BCMA_CORE_ARM_CR4, "ARM CR4" },
+       { BCMA_CORE_GCI, "GCI" },
+       { BCMA_CORE_CMEM, "CNDS DDR2/3 memory controller" },
+       { BCMA_CORE_ARM_CA7, "ARM CA7" },
        { BCMA_CORE_DEFAULT, "Default" },
 };
 
@@ -315,6 +318,8 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
                switch (core->id.id) {
                case BCMA_CORE_4706_MAC_GBIT_COMMON:
                case BCMA_CORE_NS_CHIPCOMMON_B:
+               case BCMA_CORE_PMU:
+               case BCMA_CORE_GCI:
                /* Not used yet: case BCMA_CORE_OOB_ROUTER: */
                        break;
                default:
index ec013fb..c279211 100644 (file)
@@ -1215,10 +1215,10 @@ void b43_wireless_core_phy_pll_reset(struct b43_wldev *dev)
        case B43_BUS_BCMA:
                bcma_cc = &dev->dev->bdev->bus->drv_cc;
 
-               bcma_cc_write32(bcma_cc, BCMA_CC_CHIPCTL_ADDR, 0);
-               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
-               bcma_cc_set32(bcma_cc, BCMA_CC_CHIPCTL_DATA, 0x4);
-               bcma_cc_mask32(bcma_cc, BCMA_CC_CHIPCTL_DATA, ~0x4);
+               bcma_cc_write32(bcma_cc, BCMA_CC_PMU_CHIPCTL_ADDR, 0);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
+               bcma_cc_set32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, 0x4);
+               bcma_cc_mask32(bcma_cc, BCMA_CC_PMU_CHIPCTL_DATA, ~0x4);
                break;
 #endif
 #ifdef CONFIG_B43_SSB
index 7b01e4d..d00c5c1 100644 (file)
@@ -247,7 +247,7 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
        brcmf_dbg(TRACE, "chandef: control %d center %d width %d\n",
                  ch->chan->center_freq, ch->center_freq1, ch->width);
        ch_inf.chnum = ieee80211_frequency_to_channel(ch->center_freq1);
-       primary_offset = ch->center_freq1 - ch->chan->center_freq;
+       primary_offset = ch->chan->center_freq - ch->center_freq1;
        switch (ch->width) {
        case NL80211_CHAN_WIDTH_20:
        case NL80211_CHAN_WIDTH_20_NOHT:
@@ -256,24 +256,21 @@ static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
                break;
        case NL80211_CHAN_WIDTH_40:
                ch_inf.bw = BRCMU_CHAN_BW_40;
-               if (primary_offset < 0)
+               if (primary_offset > 0)
                        ch_inf.sb = BRCMU_CHAN_SB_U;
                else
                        ch_inf.sb = BRCMU_CHAN_SB_L;
                break;
        case NL80211_CHAN_WIDTH_80:
                ch_inf.bw = BRCMU_CHAN_BW_80;
-               if (primary_offset < 0) {
-                       if (primary_offset < -CH_10MHZ_APART)
-                               ch_inf.sb = BRCMU_CHAN_SB_UU;
-                       else
-                               ch_inf.sb = BRCMU_CHAN_SB_UL;
-               } else {
-                       if (primary_offset > CH_10MHZ_APART)
-                               ch_inf.sb = BRCMU_CHAN_SB_LL;
-                       else
-                               ch_inf.sb = BRCMU_CHAN_SB_LU;
-               }
+               if (primary_offset == -30)
+                       ch_inf.sb = BRCMU_CHAN_SB_LL;
+               else if (primary_offset == -10)
+                       ch_inf.sb = BRCMU_CHAN_SB_LU;
+               else if (primary_offset == 10)
+                       ch_inf.sb = BRCMU_CHAN_SB_UL;
+               else
+                       ch_inf.sb = BRCMU_CHAN_SB_UU;
                break;
        case NL80211_CHAN_WIDTH_80P80:
        case NL80211_CHAN_WIDTH_160:
index 82e4382..0e8f2a0 100644 (file)
@@ -803,7 +803,14 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr,
                                *eromaddr -= 4;
                                return -EFAULT;
                        }
-               } while (desc != DMP_DESC_ADDRESS);
+               } while (desc != DMP_DESC_ADDRESS &&
+                        desc != DMP_DESC_COMPONENT);
+
+               /* stop if we crossed current component border */
+               if (desc == DMP_DESC_COMPONENT) {
+                       *eromaddr -= 4;
+                       return 0;
+               }
 
                /* skip upper 32-bit address descriptor */
                if (val & DMP_DESC_ADDRSIZE_GT32)
@@ -876,7 +883,8 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci)
                rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S;
 
                /* need core with ports */
-               if (nmw + nsw == 0)
+               if (nmw + nsw == 0 &&
+                   id != BCMA_CORE_PMU)
                        continue;
 
                /* try to obtain register address info */
@@ -1006,6 +1014,7 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
 {
        struct brcmf_chip *pub;
        struct brcmf_core_priv *cc;
+       struct brcmf_core *pmu;
        u32 base;
        u32 val;
        int ret = 0;
@@ -1017,11 +1026,15 @@ static int brcmf_chip_setup(struct brcmf_chip_priv *chip)
        /* get chipcommon capabilites */
        pub->cc_caps = chip->ops->read32(chip->ctx,
                                         CORE_CC_REG(base, capabilities));
+       pub->cc_caps_ext = chip->ops->read32(chip->ctx,
+                                            CORE_CC_REG(base,
+                                                        capabilities_ext));
 
        /* get pmu caps & rev */
+       pmu = brcmf_chip_get_pmu(pub); /* after reading cc_caps_ext */
        if (pub->cc_caps & CC_CAP_PMU) {
                val = chip->ops->read32(chip->ctx,
-                                       CORE_CC_REG(base, pmucapabilities));
+                                       CORE_CC_REG(pmu->base, pmucapabilities));
                pub->pmurev = val & PCAP_REV_MASK;
                pub->pmucaps = val;
        }
@@ -1120,6 +1133,23 @@ struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *pub)
        return &cc->pub;
 }
 
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub)
+{
+       struct brcmf_core *cc = brcmf_chip_get_chipcommon(pub);
+       struct brcmf_core *pmu;
+
+       /* See if there is separated PMU core available */
+       if (cc->rev >= 35 &&
+           pub->cc_caps_ext & BCMA_CC_CAP_EXT_AOB_PRESENT) {
+               pmu = brcmf_chip_get_core(pub, BCMA_CORE_PMU);
+               if (pmu)
+                       return pmu;
+       }
+
+       /* Fallback to ChipCommon core for older hardware */
+       return cc;
+}
+
 bool brcmf_chip_iscoreup(struct brcmf_core *pub)
 {
        struct brcmf_core_priv *core;
@@ -1290,6 +1320,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
 {
        u32 base, addr, reg, pmu_cc3_mask = ~0;
        struct brcmf_chip_priv *chip;
+       struct brcmf_core *pmu = brcmf_chip_get_pmu(pub);
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -1309,9 +1340,9 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
        case BRCM_CC_4335_CHIP_ID:
        case BRCM_CC_4339_CHIP_ID:
                /* read PMU chipcontrol register 3 */
-               addr = CORE_CC_REG(base, chipcontrol_addr);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
                chip->ops->write32(chip->ctx, addr, 3);
-               addr = CORE_CC_REG(base, chipcontrol_data);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_data);
                reg = chip->ops->read32(chip->ctx, addr);
                return (reg & pmu_cc3_mask) != 0;
        case BRCM_CC_43430_CHIP_ID:
@@ -1319,12 +1350,12 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub)
                reg = chip->ops->read32(chip->ctx, addr);
                return reg != 0;
        default:
-               addr = CORE_CC_REG(base, pmucapabilities_ext);
+               addr = CORE_CC_REG(pmu->base, pmucapabilities_ext);
                reg = chip->ops->read32(chip->ctx, addr);
                if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
                        return false;
 
-               addr = CORE_CC_REG(base, retention_ctl);
+               addr = CORE_CC_REG(pmu->base, retention_ctl);
                reg = chip->ops->read32(chip->ctx, addr);
                return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
                               PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
index f6b5fee..dd0ec3e 100644 (file)
@@ -27,6 +27,7 @@
  * @chip: chip identifier.
  * @chiprev: chip revision.
  * @cc_caps: chipcommon core capabilities.
+ * @cc_caps_ext: chipcommon core extended capabilities.
  * @pmucaps: PMU capabilities.
  * @pmurev: PMU revision.
  * @rambase: RAM base address (only applicable for ARM CR4 chips).
@@ -38,6 +39,7 @@ struct brcmf_chip {
        u32 chip;
        u32 chiprev;
        u32 cc_caps;
+       u32 cc_caps_ext;
        u32 pmucaps;
        u32 pmurev;
        u32 rambase;
@@ -83,6 +85,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx,
 void brcmf_chip_detach(struct brcmf_chip *chip);
 struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid);
 struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip);
+struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub);
 bool brcmf_chip_iscoreup(struct brcmf_core *core);
 void brcmf_chip_coredisable(struct brcmf_core *core, u32 prereset, u32 reset);
 void brcmf_chip_resetcore(struct brcmf_core *core, u32 prereset, u32 reset,
index 1365c12..7269056 100644 (file)
@@ -93,7 +93,7 @@ static enum nvram_parser_state brcmf_nvram_handle_idle(struct nvram_parser *nvp)
        c = nvp->data[nvp->pos];
        if (c == '\n')
                return COMMENT;
-       if (is_whitespace(c))
+       if (is_whitespace(c) || c == '\0')
                goto proceed;
        if (c == '#')
                return COMMENT;
index 0480b70..d5f9ef4 100644 (file)
@@ -1951,6 +1951,9 @@ static const struct dev_pm_ops brcmf_pciedrvr_pm = {
 
 #define BRCMF_PCIE_DEVICE(dev_id)      { BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
        PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
+#define BRCMF_PCIE_DEVICE_SUB(dev_id, subvend, subdev) { \
+       BRCM_PCIE_VENDOR_ID_BROADCOM, dev_id,\
+       subvend, subdev, PCI_CLASS_NETWORK_OTHER << 8, 0xffff00, 0 }
 
 static struct pci_device_id brcmf_pcie_devid_table[] = {
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4350_DEVICE_ID),
@@ -1966,6 +1969,7 @@ static struct pci_device_id brcmf_pcie_devid_table[] = {
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_2G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4365_5G_DEVICE_ID),
+       BRCMF_PCIE_DEVICE_SUB(0x4365, BRCM_PCIE_VENDOR_ID_BROADCOM, 0x4365),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_2G_DEVICE_ID),
        BRCMF_PCIE_DEVICE(BRCM_PCIE_4366_5G_DEVICE_ID),
index a14d9d9..c790fa8 100644 (file)
@@ -45,8 +45,8 @@
 #include "chip.h"
 #include "firmware.h"
 
-#define DCMD_RESP_TIMEOUT      msecs_to_jiffies(2000)
-#define CTL_DONE_TIMEOUT       msecs_to_jiffies(2000)
+#define DCMD_RESP_TIMEOUT      msecs_to_jiffies(2500)
+#define CTL_DONE_TIMEOUT       msecs_to_jiffies(2500)
 
 #ifdef DEBUG
 
@@ -3615,7 +3615,6 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
        const struct sdiod_drive_str *str_tab = NULL;
        u32 str_mask;
        u32 str_shift;
-       u32 base;
        u32 i;
        u32 drivestrength_sel = 0;
        u32 cc_data_temp;
@@ -3658,14 +3657,15 @@ brcmf_sdio_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
        }
 
        if (str_tab != NULL) {
+               struct brcmf_core *pmu = brcmf_chip_get_pmu(ci);
+
                for (i = 0; str_tab[i].strength != 0; i++) {
                        if (drivestrength >= str_tab[i].strength) {
                                drivestrength_sel = str_tab[i].sel;
                                break;
                        }
                }
-               base = brcmf_chip_get_chipcommon(ci)->base;
-               addr = CORE_CC_REG(base, chipcontrol_addr);
+               addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
                brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
                cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
                cc_data_temp &= ~str_mask;
@@ -3835,8 +3835,7 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
                goto fail;
 
        /* set PMUControl so a backplane reset does PMU state reload */
-       reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
-                              pmucontrol);
+       reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
        reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
        if (err)
                goto fail;
index 8660677..11932d5 100644 (file)
@@ -99,6 +99,18 @@ config IWLWIFI_UAPSD
 
          If unsure, say N.
 
+config IWLWIFI_PCIE_RTPM
+       bool "Enable runtime power management mode for PCIe devices"
+       depends on IWLMVM && PM
+       default false
+       help
+         Say Y here to enable runtime power management for PCIe
+         devices.  If enabled, the device will go into low power mode
+         when idle for a short period of time, allowing for improved
+         power saving during runtime.
+
+        If unsure, say N.
+
 menu "Debugging Options"
 
 config IWLWIFI_DEBUG
index 1aabb5e..1bbd17a 100644 (file)
@@ -152,11 +152,14 @@ static void iwl_led_brightness_set(struct led_classdev *led_cdev,
 {
        struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, led);
        unsigned long on = 0;
+       unsigned long off = 0;
 
        if (brightness > 0)
                on = IWL_LED_SOLID;
+       else
+               off = IWL_LED_SOLID;
 
-       iwl_led_cmd(priv, on, 0);
+       iwl_led_cmd(priv, on, off);
 }
 
 static int iwl_led_blink_set(struct led_classdev *led_cdev,
index 29ea1c6..4db4cb7 100644 (file)
@@ -396,7 +396,7 @@ static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
        iwl_write32(priv->trans, CSR_UCODE_DRV_GP1_SET,
                    CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
 
-       iwl_trans_d3_suspend(priv->trans, false);
+       iwl_trans_d3_suspend(priv->trans, false, true);
 
        goto out;
 
@@ -469,7 +469,7 @@ static int iwlagn_mac_resume(struct ieee80211_hw *hw)
        /* we'll clear ctx->vif during iwlagn_prepare_restart() */
        vif = ctx->vif;
 
-       ret = iwl_trans_d3_resume(priv->trans, &d3_status, false);
+       ret = iwl_trans_d3_resume(priv->trans, &d3_status, false, true);
        if (ret)
                goto out_unlock;
 
index ecbf482..4b93404 100644 (file)
@@ -138,7 +138,8 @@ static const struct iwl_tt_params iwl9000_tt_params = {
        .smem_offset = IWL9000_SMEM_OFFSET,                             \
        .smem_len = IWL9000_SMEM_LEN,                                   \
        .thermal_params = &iwl9000_tt_params,                           \
-       .apmg_not_supported = true
+       .apmg_not_supported = true,                                     \
+       .mq_rx_supported = true
 
 const struct iwl_cfg iwl9260_2ac_cfg = {
                .name = "Intel(R) Dual Band Wireless AC 9260",
index f990481..dad5570 100644 (file)
@@ -311,6 +311,7 @@ struct iwl_pwr_tx_backoff {
  * @dccm2_len: length of the second DCCM
  * @smem_offset: offset from which the SMEM begins
  * @smem_len: the length of SMEM
+ * @mq_rx_supported: multi-queue rx support
  *
  * We enable the driver to be backward compatible wrt. hardware features.
  * API differences in uCode shouldn't be handled here but through TLVs
@@ -362,6 +363,7 @@ struct iwl_cfg {
        const u32 smem_len;
        const struct iwl_tt_params *thermal_params;
        bool apmg_not_supported;
+       bool mq_rx_supported;
 };
 
 /*
index 5cc6be9..4ab6682 100644 (file)
@@ -6,6 +6,7 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -31,6 +32,7 @@
  * BSD LICENSE
  *
  * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2015 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -312,6 +314,77 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT        28
 #define FH_MEM_TB_MAX_LENGTH                   (0x00020000)
 
+/* 9000 rx series registers */
+
+#define RFH_Q0_FRBDCB_BA_LSB 0xA08000 /* 64 bit address */
+#define RFH_Q_FRBDCB_BA_LSB(q) (RFH_Q0_FRBDCB_BA_LSB + (q) * 8)
+/* Write index table */
+#define RFH_Q0_FRBDCB_WIDX 0xA08080
+#define RFH_Q_FRBDCB_WIDX(q) (RFH_Q0_FRBDCB_WIDX + (q) * 4)
+/* Read index table */
+#define RFH_Q0_FRBDCB_RIDX 0xA080C0
+#define RFH_Q_FRBDCB_RIDX(q) (RFH_Q0_FRBDCB_RIDX + (q) * 4)
+/* Used list table */
+#define RFH_Q0_URBDCB_BA_LSB 0xA08100 /* 64 bit address */
+#define RFH_Q_URBDCB_BA_LSB(q) (RFH_Q0_URBDCB_BA_LSB + (q) * 8)
+/* Write index table */
+#define RFH_Q0_URBDCB_WIDX 0xA08180
+#define RFH_Q_URBDCB_WIDX(q) (RFH_Q0_URBDCB_WIDX + (q) * 4)
+#define RFH_Q0_URBDCB_VAID 0xA081C0
+#define RFH_Q_URBDCB_VAID(q) (RFH_Q0_URBDCB_VAID + (q) * 4)
+/* stts */
+#define RFH_Q0_URBD_STTS_WPTR_LSB 0xA08200 /*64 bits address */
+#define RFH_Q_URBD_STTS_WPTR_LSB(q) (RFH_Q0_URBD_STTS_WPTR_LSB + (q) * 8)
+
+#define RFH_Q0_ORB_WPTR_LSB 0xA08280
+#define RFH_Q_ORB_WPTR_LSB(q) (RFH_Q0_ORB_WPTR_LSB + (q) * 8)
+#define RFH_RBDBUF_RBD0_LSB 0xA08300
+#define RFH_RBDBUF_RBD_LSB(q) (RFH_RBDBUF_RBD0_LSB + (q) * 8)
+
+/* DMA configuration */
+#define RFH_RXF_DMA_CFG 0xA09820
+/* RB size */
+#define RFH_RXF_DMA_RB_SIZE_MASK (0x000F0000) /* bits 16-19 */
+#define RFH_RXF_DMA_RB_SIZE_POS 16
+#define RFH_RXF_DMA_RB_SIZE_1K (0x1 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_2K (0x2 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_4K (0x4 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_8K (0x8 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_12K        (0x9 << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_16K        (0xA << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_20K        (0xB << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_24K        (0xC << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_28K        (0xD << RFH_RXF_DMA_RB_SIZE_POS)
+#define RFH_RXF_DMA_RB_SIZE_32K        (0xE << RFH_RXF_DMA_RB_SIZE_POS)
+/* RB Circular Buffer size:defines the table sizes in RBD units */
+#define RFH_RXF_DMA_RBDCB_SIZE_MASK (0x00F00000) /* bits 20-23 */
+#define RFH_RXF_DMA_RBDCB_SIZE_POS 20
+#define RFH_RXF_DMA_RBDCB_SIZE_8       (0x3 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_16      (0x4 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_32      (0x5 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_64      (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_128     (0x7 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_256     (0x8 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_512     (0x9 << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_1024    (0xA << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_RBDCB_SIZE_2048    (0xB << RFH_RXF_DMA_RBDCB_SIZE_POS)
+#define RFH_RXF_DMA_MIN_RB_SIZE_MASK (0x03000000) /* bit 24-25 */
+#define RFH_RXF_DMA_MIN_RB_SIZE_POS    24
+#define RFH_RXF_DMA_MIN_RB_4_8 (3 << RFH_RXF_DMA_MIN_RB_SIZE_POS)
+#define RFH_RXF_DMA_SINGLE_FRAME_MASK (0x20000000) /* bit 29 */
+#define RFH_DMA_EN_MASK (0xC0000000) /* bits 30-31*/
+#define RFH_DMA_EN_ENABLE_VAL BIT(31)
+
+#define RFH_RXF_RXQ_ACTIVE 0xA0980C
+
+#define RFH_GEN_CFG    0xA09800
+#define RFH_GEN_CFG_DEFAULT_RXQ_NUM_MASK 0xF00
+#define RFH_GEN_CFG_SERVICE_DMA_SNOOP BIT(0)
+#define RFH_GEN_CFG_RFH_DMA_SNOOP BIT(1)
+#define DEFAULT_RXQ_NUM 8
+
+/* end of 9000 rx series registers */
+
 /* TFDB  Area - TFDs buffer table */
 #define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK      (0xFFFFFFFF)
 #define FH_TFDIB_LOWER_BOUND       (FH_MEM_LOWER_BOUND + 0x900)
@@ -434,6 +507,10 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
  */
 #define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN   (0x00000002)
 
+#define MQ_RX_TABLE_SIZE               512
+#define MQ_RX_TABLE_MASK               (MQ_RX_TABLE_SIZE - 1)
+#define MQ_RX_POOL_SIZE                        MQ_RX_TABLE_MASK
+
 #define RX_QUEUE_SIZE                         256
 #define RX_QUEUE_MASK                         255
 #define RX_QUEUE_SIZE_LOG                     8
index a5aaf68..8425e1a 100644 (file)
@@ -293,6 +293,8 @@ iwl_fw_error_next_data(struct iwl_fw_error_dump_data *data)
  * @FW_DBG_TX_LATENCY: trigger log collection when the tx latency goes above a
  *     threshold.
  * @FW_DBG_TDLS: trigger log collection upon TDLS related events.
+ * @FW_DBG_TRIGGER_TX_STATUS: trigger log collection upon tx status when
+ *  the firmware sends a tx reply.
  */
 enum iwl_fw_dbg_trigger {
        FW_DBG_TRIGGER_INVALID = 0,
@@ -309,6 +311,7 @@ enum iwl_fw_dbg_trigger {
        FW_DBG_TRIGGER_BA,
        FW_DBG_TRIGGER_TX_LATENCY,
        FW_DBG_TRIGGER_TDLS,
+       FW_DBG_TRIGGER_TX_STATUS,
 
        /* must be last */
        FW_DBG_TRIGGER_MAX,
index 84f8aeb..e2dbc67 100644 (file)
@@ -297,10 +297,12 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_DQA_SUPPORT: supports dynamic queue allocation (DQA),
  *     which also implies support for the scheduler configuration command
  * @IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH: supports TDLS channel switching
+ * @IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG: Consolidated D3-D0 image
  * @IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT: supports Hot Spot Command
  * @IWL_UCODE_TLV_CAPA_DC2DC_SUPPORT: supports DC2DC Command
  * @IWL_UCODE_TLV_CAPA_CSUM_SUPPORT: supports TCP Checksum Offload
  * @IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS: support radio and beacon statistics
+ * @IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD: support p2p standalone U-APSD
  * @IWL_UCODE_TLV_CAPA_BT_COEX_PLCR: enabled BT Coex packet level co-running
  * @IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC: ucode supports LAR updates with different
  *     sources for the MCC. This TLV bit is a future replacement to
@@ -313,6 +315,8 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_capa_t;
  * @IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT: supports bt-coex Multi-priority LUT
  * @IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION: firmware will decide on what
  *     antenna the beacon should be transmitted
+ * @IWL_UCODE_TLV_CAPA_BEACON_STORING: firmware will store the latest beacon
+ *     from AP and will send it upon d0i3 exit.
  * @IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2: support LAR API V2
  *
  * @NUM_IWL_UCODE_TLV_CAPA: number of bits used
@@ -330,10 +334,12 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_QUIET_PERIOD_SUPPORT         = (__force iwl_ucode_tlv_capa_t)11,
        IWL_UCODE_TLV_CAPA_DQA_SUPPORT                  = (__force iwl_ucode_tlv_capa_t)12,
        IWL_UCODE_TLV_CAPA_TDLS_CHANNEL_SWITCH          = (__force iwl_ucode_tlv_capa_t)13,
+       IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG            = (__force iwl_ucode_tlv_capa_t)17,
        IWL_UCODE_TLV_CAPA_HOTSPOT_SUPPORT              = (__force iwl_ucode_tlv_capa_t)18,
        IWL_UCODE_TLV_CAPA_DC2DC_CONFIG_SUPPORT         = (__force iwl_ucode_tlv_capa_t)19,
        IWL_UCODE_TLV_CAPA_CSUM_SUPPORT                 = (__force iwl_ucode_tlv_capa_t)21,
        IWL_UCODE_TLV_CAPA_RADIO_BEACON_STATS           = (__force iwl_ucode_tlv_capa_t)22,
+       IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD         = (__force iwl_ucode_tlv_capa_t)26,
        IWL_UCODE_TLV_CAPA_BT_COEX_PLCR                 = (__force iwl_ucode_tlv_capa_t)28,
        IWL_UCODE_TLV_CAPA_LAR_MULTI_MCC                = (__force iwl_ucode_tlv_capa_t)29,
        IWL_UCODE_TLV_CAPA_BT_COEX_RRC                  = (__force iwl_ucode_tlv_capa_t)30,
@@ -341,7 +347,9 @@ enum iwl_ucode_tlv_capa {
        IWL_UCODE_TLV_CAPA_EXTENDED_DTS_MEASURE         = (__force iwl_ucode_tlv_capa_t)64,
        IWL_UCODE_TLV_CAPA_SHORT_PM_TIMEOUTS            = (__force iwl_ucode_tlv_capa_t)65,
        IWL_UCODE_TLV_CAPA_BT_MPLUT_SUPPORT             = (__force iwl_ucode_tlv_capa_t)67,
+       IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT       = (__force iwl_ucode_tlv_capa_t)68,
        IWL_UCODE_TLV_CAPA_BEACON_ANT_SELECTION         = (__force iwl_ucode_tlv_capa_t)71,
+       IWL_UCODE_TLV_CAPA_BEACON_STORING               = (__force iwl_ucode_tlv_capa_t)72,
        IWL_UCODE_TLV_CAPA_LAR_SUPPORT_V2               = (__force iwl_ucode_tlv_capa_t)73,
 
        NUM_IWL_UCODE_TLV_CAPA
@@ -748,6 +756,19 @@ struct iwl_fw_dbg_trigger_tdls {
 } __packed;
 
 /**
+ * struct iwl_fw_dbg_trigger_tx_status - configures trigger for tx response
+ *  status.
+ * @statuses: the list of statuses to trigger the collection on
+ */
+struct iwl_fw_dbg_trigger_tx_status {
+       struct tx_status {
+               u8 status;
+               u8 reserved[3];
+       } __packed statuses[16];
+       __le32 reserved[2];
+} __packed;
+
+/**
  * struct iwl_fw_dbg_conf_tlv - a TLV that describes a debug configuration.
  * @id: conf id
  * @usniffer: should the uSniffer image be used
index fd42f63..b88ecc7 100644 (file)
@@ -108,6 +108,8 @@ enum iwl_amsdu_size {
  * @power_level: power level, default = 1
  * @debug_level: levels are IWL_DL_*
  * @ant_coupling: antenna coupling in dB, default = 0
+ * @nvm_file: specifies a external NVM file
+ * @uapsd_disable: disable U-APSD, default = 1
  * @d0i3_disable: disable d0i3, default = 1,
  * @d0i3_entry_delay: time to wait after no refs are taken before
  *     entering D0i3 (in msecs)
index 7b89bfc..50f4cc6 100644 (file)
@@ -539,7 +539,7 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
                                           struct iwl_nvm_data *data,
                                           const __le16 *mac_override,
                                           const __le16 *nvm_hw,
-                                          u32 mac_addr0, u32 mac_addr1)
+                                          __le32 mac_addr0, __le32 mac_addr1)
 {
        const u8 *hw_addr;
 
@@ -583,7 +583,8 @@ static void iwl_set_hw_address_family_8000(struct device *dev,
 
                if (!is_valid_ether_addr(data->hw_addr))
                        IWL_ERR_DEV(dev,
-                                   "mac address from hw section is not valid\n");
+                                   "mac address (%pM) from hw section is not valid\n",
+                                   data->hw_addr);
 
                return;
        }
@@ -597,7 +598,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_calib, const __le16 *regulatory,
                   const __le16 *mac_override, const __le16 *phy_sku,
                   u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
-                  u32 mac_addr0, u32 mac_addr1)
+                  __le32 mac_addr0, __le32 mac_addr1)
 {
        struct iwl_nvm_data *data;
        u32 sku;
index 92466ee..4e8e0dc 100644 (file)
@@ -79,7 +79,7 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
                   const __le16 *nvm_calib, const __le16 *regulatory,
                   const __le16 *mac_override, const __le16 *phy_sku,
                   u8 tx_chains, u8 rx_chains, bool lar_fw_supported,
-                  u32 mac_addr0, u32 mac_addr1);
+                  __le32 mac_addr0, __le32 mac_addr1);
 
 /**
  * iwl_parse_mcc_info - parse MCC (mobile country code) info coming from FW
index 82fb3a9..0ca0f13 100644 (file)
@@ -506,7 +506,7 @@ struct iwl_trans_config {
        bool sw_csum_tx;
        const struct iwl_hcmd_arr *command_groups;
        int command_groups_size;
+
        u32 sdio_adma_addr;
 };
 
@@ -618,9 +618,9 @@ struct iwl_trans_ops {
        void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
        void (*stop_device)(struct iwl_trans *trans, bool low_power);
 
-       void (*d3_suspend)(struct iwl_trans *trans, bool test);
+       void (*d3_suspend)(struct iwl_trans *trans, bool test, bool reset);
        int (*d3_resume)(struct iwl_trans *trans, enum iwl_d3_status *status,
-                        bool test);
+                        bool test, bool reset);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -736,6 +736,11 @@ enum iwl_plat_pm_mode {
        IWL_PLAT_PM_MODE_D0I3,
 };
 
+/* Max time to wait for trans to become idle/non-idle on d0i3
+ * enter/exit (in msecs).
+ */
+#define IWL_TRANS_IDLE_TIMEOUT 2000
+
 /**
  * struct iwl_trans - transport common data
  *
@@ -920,22 +925,23 @@ static inline void iwl_trans_stop_device(struct iwl_trans *trans)
        _iwl_trans_stop_device(trans, true);
 }
 
-static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test)
+static inline void iwl_trans_d3_suspend(struct iwl_trans *trans, bool test,
+                                       bool reset)
 {
        might_sleep();
        if (trans->ops->d3_suspend)
-               trans->ops->d3_suspend(trans, test);
+               trans->ops->d3_suspend(trans, test, reset);
 }
 
 static inline int iwl_trans_d3_resume(struct iwl_trans *trans,
                                      enum iwl_d3_status *status,
-                                     bool test)
+                                     bool test, bool reset)
 {
        might_sleep();
        if (!trans->ops->d3_resume)
                return 0;
 
-       return trans->ops->d3_resume(trans, status, test);
+       return trans->ops->d3_resume(trans, status, test, reset);
 }
 
 static inline void iwl_trans_ref(struct iwl_trans *trans)
index b00c03f..4b560e4 100644 (file)
@@ -6,7 +6,8 @@
  * GPL LICENSE SUMMARY
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -32,7 +33,8 @@
  * BSD LICENSE
  *
  * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2015        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,6 +75,7 @@
 #define IWL_MVM_WOWLAN_PS_RX_DATA_TIMEOUT      (10 * USEC_PER_MSEC)
 #define IWL_MVM_SHORT_PS_TX_DATA_TIMEOUT       (2 * 1024) /* defined in TU */
 #define IWL_MVM_SHORT_PS_RX_DATA_TIMEOUT       (40 * 1024) /* defined in TU */
+#define IWL_MVM_P2P_UAPSD_STANDALONE           0
 #define IWL_MVM_P2P_LOWLATENCY_PS_ENABLE       0
 #define IWL_MVM_UAPSD_RX_DATA_TIMEOUT          (50 * USEC_PER_MSEC)
 #define IWL_MVM_UAPSD_TX_DATA_TIMEOUT          (50 * USEC_PER_MSEC)
 #define IWL_MVM_RS_80_20_FAR_RANGE_TWEAK       1
 #define IWL_MVM_TOF_IS_RESPONDER               0
 #define IWL_MVM_SW_TX_CSUM_OFFLOAD             0
+#define IWL_MVM_COLLECT_FW_ERR_DUMP            1
 #define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE    1
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE      2
 #define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW   1
index d3e21d9..3463761 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016   Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016   Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -851,7 +853,8 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
        wowlan_config_cmd->is_11n_connection =
                                        ap_sta->ht_cap.ht_supported;
        wowlan_config_cmd->flags = ENABLE_L3_FILTERING |
-               ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING;
+               ENABLE_NBNS_FILTERING | ENABLE_DHCP_FILTERING |
+               ENABLE_STORE_BEACON;
 
        /* Query the last used seqno and set it */
        ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
@@ -1023,14 +1026,18 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm,
                      struct ieee80211_sta *ap_sta)
 {
        int ret;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
-       ret = iwl_mvm_switch_to_d3(mvm);
-       if (ret)
-               return ret;
+       if (!unified_image) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       return ret;
 
-       ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
-       if (ret)
-               return ret;
+               ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta);
+               if (ret)
+                       return ret;
+       }
 
        if (!iwlwifi_mod_params.sw_crypto) {
                /*
@@ -1072,10 +1079,14 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm,
 {
        struct iwl_wowlan_config_cmd wowlan_config_cmd = {};
        int ret;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
-       ret = iwl_mvm_switch_to_d3(mvm);
-       if (ret)
-               return ret;
+       if (!unified_image) {
+               ret = iwl_mvm_switch_to_d3(mvm);
+               if (ret)
+                       return ret;
+       }
 
        /* rfkill release can be either for wowlan or netdetect */
        if (wowlan->rfkill_release)
@@ -1151,6 +1162,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        };
        int ret;
        int len __maybe_unused;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
 
        if (!wowlan) {
                /*
@@ -1236,7 +1249,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
        clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
 
-       iwl_trans_d3_suspend(mvm->trans, test);
+       iwl_trans_d3_suspend(mvm->trans, test, !unified_image);
  out:
        if (ret < 0) {
                iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
@@ -1299,7 +1312,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
                mutex_unlock(&mvm->d0i3_suspend_mutex);
 
-               iwl_trans_d3_suspend(trans, false);
+               iwl_trans_d3_suspend(trans, false, false);
 
                return 0;
        }
@@ -2041,9 +2054,14 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac,
 static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
 {
        struct ieee80211_vif *vif = NULL;
-       int ret;
+       int ret = 1;
        enum iwl_d3_status d3_status;
        bool keep = false;
+       bool unified_image = fw_has_capa(&mvm->fw->ucode_capa,
+                                        IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG);
+
+       u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE |
+                                   CMD_WAKE_UP_TRANS;
 
        mutex_lock(&mvm->mutex);
 
@@ -2052,7 +2070,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test)
        if (IS_ERR_OR_NULL(vif))
                goto err;
 
-       ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test);
+       ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image);
        if (ret)
                goto err;
 
@@ -2095,17 +2113,28 @@ out_iterate:
                        iwl_mvm_d3_disconnect_iter, keep ? vif : NULL);
 
 out:
-       /* return 1 to reconfigure the device */
+       if (unified_image && !ret) {
+               ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL);
+               if (!ret) /* D3 ended successfully - no need to reset device */
+                       return 0;
+       }
+
+       /*
+        * Reconfigure the device in one of the following cases:
+        * 1. We are not using a unified image
+        * 2. We are using a unified image but had an error while exiting D3
+        */
        set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status);
        set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status);
-
-       /* We always return 1, which causes mac80211 to do a reconfig
-        * with IEEE80211_RECONFIG_TYPE_RESTART.  This type of
-        * reconfig calls iwl_mvm_restart_complete(), where we unref
-        * the IWL_MVM_REF_UCODE_DOWN, so we need to take the
-        * reference here.
+       /*
+        * When switching images we return 1, which causes mac80211
+        * to do a reconfig with IEEE80211_RECONFIG_TYPE_RESTART.
+        * This type of reconfig calls iwl_mvm_restart_complete(),
+        * where we unref the IWL_MVM_REF_UCODE_DOWN, so we need
+        * to take the reference here.
         */
        iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
+
        return 1;
 }
 
@@ -2122,7 +2151,7 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm)
        enum iwl_d3_status d3_status;
        struct iwl_trans *trans = mvm->trans;
 
-       iwl_trans_d3_resume(trans, &d3_status, false);
+       iwl_trans_d3_resume(trans, &d3_status, false, false);
 
        /*
         * make sure to clear D0I3_DEFER_WAKEUP before
index 9e0d463..1400445 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -1255,6 +1257,7 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm *mvm = mvmvif->mvm;
+       bool prev;
        u8 value;
        int ret;
 
@@ -1265,7 +1268,9 @@ static ssize_t iwl_dbgfs_low_latency_write(struct ieee80211_vif *vif, char *buf,
                return -EINVAL;
 
        mutex_lock(&mvm->mutex);
-       iwl_mvm_update_low_latency(mvm, vif, value);
+       prev = iwl_mvm_vif_low_latency(mvmvif);
+       mvmvif->low_latency_dbgfs = value;
+       iwl_mvm_update_low_latency(mvm, vif, prev);
        mutex_unlock(&mvm->mutex);
 
        return count;
@@ -1277,11 +1282,15 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
 {
        struct ieee80211_vif *vif = file->private_data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       char buf[2];
+       char buf[30] = {};
+       int len;
 
-       buf[0] = mvmvif->low_latency ? '1' : '0';
-       buf[1] = '\n';
-       return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
+       len = snprintf(buf, sizeof(buf) - 1,
+                      "traffic=%d\ndbgfs=%d\nvcmd=%d\n",
+                      mvmvif->low_latency_traffic,
+                      mvmvif->low_latency_dbgfs,
+                      mvmvif->low_latency_vcmd);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
 }
 
 static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
@@ -1363,6 +1372,59 @@ static ssize_t iwl_dbgfs_rx_phyinfo_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
 }
 
+static void iwl_dbgfs_quota_check(void *data, u8 *mac,
+                                 struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       int *ret = data;
+
+       if (mvmvif->dbgfs_quota_min)
+               *ret = -EINVAL;
+}
+
+static ssize_t iwl_dbgfs_quota_min_write(struct ieee80211_vif *vif, char *buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm *mvm = mvmvif->mvm;
+       u16 value;
+       int ret;
+
+       ret = kstrtou16(buf, 0, &value);
+       if (ret)
+               return ret;
+
+       if (value > 95)
+               return -EINVAL;
+
+       mutex_lock(&mvm->mutex);
+
+       mvmvif->dbgfs_quota_min = 0;
+       ieee80211_iterate_interfaces(mvm->hw, IEEE80211_IFACE_ITER_NORMAL,
+                                    iwl_dbgfs_quota_check, &ret);
+       if (ret == 0) {
+               mvmvif->dbgfs_quota_min = value;
+               iwl_mvm_update_quotas(mvm, false, NULL);
+       }
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_quota_min_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct ieee80211_vif *vif = file->private_data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       char buf[10];
+       int len;
+
+       len = snprintf(buf, sizeof(buf), "%d\n", mvmvif->dbgfs_quota_min);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
 #define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
        _MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
 #define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -1386,6 +1448,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_req_ext, 32);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_range_abort, 32);
 MVM_DEBUGFS_READ_FILE_OPS(tof_range_response);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(tof_responder_params, 32);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(quota_min, 32);
 
 void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 {
@@ -1423,6 +1486,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                                 S_IRUSR | S_IWUSR);
        MVM_DEBUGFS_ADD_FILE_VIF(rx_phyinfo, mvmvif->dbgfs_dir,
                                 S_IRUSR | S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE_VIF(quota_min, mvmvif->dbgfs_dir,
+                                S_IRUSR | S_IWUSR);
 
        if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
            mvmvif == mvm->bf_allowed_vif)
index 90500e2..c529e53 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -261,17 +262,18 @@ static ssize_t iwl_dbgfs_nic_temp_read(struct file *file,
 {
        struct iwl_mvm *mvm = file->private_data;
        char buf[16];
-       int pos, temp;
+       int pos, ret;
+       s32 temp;
 
        if (!mvm->ucode_loaded)
                return -EIO;
 
        mutex_lock(&mvm->mutex);
-       temp = iwl_mvm_get_temp(mvm);
+       ret = iwl_mvm_get_temp(mvm, &temp);
        mutex_unlock(&mvm->mutex);
 
-       if (temp < 0)
-               return temp;
+       if (ret)
+               return -EIO;
 
        pos = scnprintf(buf , sizeof(buf), "%d\n", temp);
 
@@ -942,6 +944,47 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
        return count;
 }
 
+static ssize_t iwl_dbgfs_indirection_tbl_write(struct iwl_mvm *mvm,
+                                              char *buf, size_t count,
+                                              loff_t *ppos)
+{
+       struct iwl_rss_config_cmd cmd = {
+               .flags = cpu_to_le32(IWL_RSS_ENABLE),
+               .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
+                            IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
+                            IWL_RSS_HASH_TYPE_IPV6_TCP |
+                            IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+       };
+       int ret, i, num_repeats, nbytes = count / 2;
+
+       ret = hex2bin(cmd.indirection_table, buf, nbytes);
+       if (ret)
+               return ret;
+
+       /*
+        * The input is the redirection table, partial or full.
+        * Repeat the pattern if needed.
+        * For example, input of 01020F will be repeated 42 times,
+        * indirecting RSS hash results to queues 1, 2, 15 (skipping
+        * queues 3 - 14).
+        */
+       num_repeats = ARRAY_SIZE(cmd.indirection_table) / nbytes;
+       for (i = 1; i < num_repeats; i++)
+               memcpy(&cmd.indirection_table[i * nbytes],
+                      cmd.indirection_table, nbytes);
+       /* handle cut in the middle pattern for the last places */
+       memcpy(&cmd.indirection_table[i * nbytes], cmd.indirection_table,
+              ARRAY_SIZE(cmd.indirection_table) % nbytes);
+
+       memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key));
+
+       mutex_lock(&mvm->mutex);
+       ret = iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
+       mutex_unlock(&mvm->mutex);
+
+       return ret ?: count;
+}
+
 static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
                                          char __user *user_buf,
                                          size_t count, loff_t *ppos)
@@ -983,7 +1026,7 @@ static ssize_t iwl_dbgfs_cont_recording_write(struct iwl_mvm *mvm,
            trans->cfg->device_family != IWL_DEVICE_FAMILY_8000)
                return -EOPNOTSUPP;
 
-       ret = kstrtouint(buf, 0, &rec_mode);
+       ret = kstrtoint(buf, 0, &rec_mode);
        if (ret)
                return ret;
 
@@ -1454,6 +1497,7 @@ MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
 MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 64);
 MVM_DEBUGFS_WRITE_FILE_OPS(cont_recording, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(indirection_tbl, 16);
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
 MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1498,11 +1542,15 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
        MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(send_echo_cmd, mvm->debugfs_dir, S_IWUSR);
        MVM_DEBUGFS_ADD_FILE(cont_recording, mvm->debugfs_dir, S_IWUSR);
+       MVM_DEBUGFS_ADD_FILE(indirection_tbl, mvm->debugfs_dir, S_IWUSR);
        if (!debugfs_create_bool("enable_scan_iteration_notif",
                                 S_IRUSR | S_IWUSR,
                                 mvm->debugfs_dir,
                                 &mvm->scan_iter_notif_enabled))
                goto err;
+       if (!debugfs_create_bool("drop_bcn_ap_mode", S_IRUSR | S_IWUSR,
+                                mvm->debugfs_dir, &mvm->drop_bcn_ap_mode))
+               goto err;
 
 #ifdef CONFIG_IWLWIFI_BCAST_FILTERING
        if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
index 62b9a0a..eec52c5 100644 (file)
@@ -251,6 +251,7 @@ enum iwl_wowlan_flags {
        ENABLE_L3_FILTERING     = BIT(1),
        ENABLE_NBNS_FILTERING   = BIT(2),
        ENABLE_DHCP_FILTERING   = BIT(3),
+       ENABLE_STORE_BEACON     = BIT(4),
 };
 
 struct iwl_wowlan_config_cmd {
index fb6d341..df939f5 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -287,16 +287,13 @@ enum iwl_rx_mpdu_status {
        IWL_RX_MPDU_STATUS_KEY_ERROR            = BIT(4),
        IWL_RX_MPDU_STATUS_ICV_OK               = BIT(5),
        IWL_RX_MPDU_STATUS_MIC_OK               = BIT(6),
-       /* TODO - verify this is the correct value */
        IWL_RX_MPDU_RES_STATUS_TTAK_OK          = BIT(7),
        IWL_RX_MPDU_STATUS_SEC_MASK             = 0x7 << 8,
        IWL_RX_MPDU_STATUS_SEC_NONE             = 0x0 << 8,
        IWL_RX_MPDU_STATUS_SEC_WEP              = 0x1 << 8,
        IWL_RX_MPDU_STATUS_SEC_CCM              = 0x2 << 8,
        IWL_RX_MPDU_STATUS_SEC_TKIP             = 0x3 << 8,
-       /* TODO - define IWL_RX_MPDU_STATUS_SEC_EXT_ENC - this is a stub */
        IWL_RX_MPDU_STATUS_SEC_EXT_ENC          = 0x4 << 8,
-       /* TODO - define IWL_RX_MPDU_STATUS_SEC_GCM - this is a stub */
        IWL_RX_MPDU_STATUS_SEC_GCM              = 0x5 << 8,
        IWL_RX_MPDU_STATUS_DECRYPTED            = BIT(11),
        IWL_RX_MPDU_STATUS_WEP_MATCH            = BIT(12),
@@ -350,11 +347,11 @@ struct iwl_rx_mpdu_desc {
        /* DW8 */
        __le32 filter_match;
        /* DW9 */
-       __le32 gp2_on_air_rise;
-       /* DW10 */
        __le32 rate_n_flags;
+       /* DW10 */
+       u8 energy_a, energy_b, channel, reserved;
        /* DW11 */
-       u8 energy_a, energy_b, energy_c, channel;
+       __le32 gp2_on_air_rise;
        /* DW12 & DW13 */
        __le64 tsf_on_air_rise;
 } __packed;
@@ -365,4 +362,33 @@ struct iwl_frame_release {
        __le16 nssn;
 };
 
+enum iwl_rss_hash_func_en {
+       IWL_RSS_HASH_TYPE_IPV4_TCP,
+       IWL_RSS_HASH_TYPE_IPV4_UDP,
+       IWL_RSS_HASH_TYPE_IPV4_PAYLOAD,
+       IWL_RSS_HASH_TYPE_IPV6_TCP,
+       IWL_RSS_HASH_TYPE_IPV6_UDP,
+       IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+};
+
+#define IWL_RSS_HASH_KEY_CNT 10
+#define IWL_RSS_INDIRECTION_TABLE_SIZE 128
+#define IWL_RSS_ENABLE 1
+
+/**
+ * struct iwl_rss_config_cmd - RSS (Receive Side Scaling) configuration
+ *
+ * @flags: 1 - enable, 0 - disable
+ * @hash_mask: Type of RSS to use. Values are from %iwl_rss_hash_func_en
+ * @secret_key: 320 bit input of random key configuration from driver
+ * @indirection_table: indirection table
+ */
+struct iwl_rss_config_cmd {
+       __le32 flags;
+       u8 hash_mask;
+       u8 reserved[3];
+       __le32 secret_key[IWL_RSS_HASH_KEY_CNT];
+       u8 indirection_table[IWL_RSS_INDIRECTION_TABLE_SIZE];
+} __packed; /* RSS_CONFIG_CMD_API_S_VER_1 */
+
 #endif /* __fw_api_rx_h__ */
index 6fca4fb..90d9113 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -253,6 +255,68 @@ struct iwl_mvm_keyinfo {
        __le64 hw_tkip_mic_tx_key;
 } __packed;
 
+#define IWL_ADD_STA_STATUS_MASK        0xFF
+#define IWL_ADD_STA_BAID_MASK  0xFF00
+
+/**
+ * struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.
+ * ( REPLY_ADD_STA = 0x18 )
+ * @add_modify: 1: modify existing, 0: add new station
+ * @awake_acs:
+ * @tid_disable_tx: is tid BIT(tid) enabled for Tx. Clear BIT(x) to enable
+ *     AMPDU for tid x. Set %STA_MODIFY_TID_DISABLE_TX to change this field.
+ * @mac_id_n_color: the Mac context this station belongs to
+ * @addr[ETH_ALEN]: station's MAC address
+ * @sta_id: index of station in uCode's station table
+ * @modify_mask: STA_MODIFY_*, selects which parameters to modify vs. leave
+ *     alone. 1 - modify, 0 - don't change.
+ * @station_flags: look at %iwl_sta_flags
+ * @station_flags_msk: what of %station_flags have changed
+ * @add_immediate_ba_tid: tid for which to add block-ack support (Rx)
+ *     Set %STA_MODIFY_ADD_BA_TID to use this field, and also set
+ *     add_immediate_ba_ssn.
+ * @remove_immediate_ba_tid: tid for which to remove block-ack support (Rx)
+ *     Set %STA_MODIFY_REMOVE_BA_TID to use this field
+ * @add_immediate_ba_ssn: ssn for the Rx block-ack session. Used together with
+ *     add_immediate_ba_tid.
+ * @sleep_tx_count: number of packets to transmit to station even though it is
+ *     asleep. Used to synchronise PS-poll and u-APSD responses while ucode
+ *     keeps track of STA sleep state.
+ * @sleep_state_flags: Look at %iwl_sta_sleep_flag.
+ * @assoc_id: assoc_id to be sent in VHT PLCP (9-bit), for grp use 0, for AP
+ *     mac-addr.
+ * @beamform_flags: beam forming controls
+ * @tfd_queue_msk: tfd queues used by this station
+ *
+ * The device contains an internal table of per-station information, with info
+ * on security keys, aggregation parameters, and Tx rates for initial Tx
+ * attempt and any retries (set by REPLY_TX_LINK_QUALITY_CMD).
+ *
+ * ADD_STA sets up the table entry for one station, either creating a new
+ * entry, or modifying a pre-existing one.
+ */
+struct iwl_mvm_add_sta_cmd_v7 {
+       u8 add_modify;
+       u8 awake_acs;
+       __le16 tid_disable_tx;
+       __le32 mac_id_n_color;
+       u8 addr[ETH_ALEN];      /* _STA_ID_MODIFY_INFO_API_S_VER_1 */
+       __le16 reserved2;
+       u8 sta_id;
+       u8 modify_mask;
+       __le16 reserved3;
+       __le32 station_flags;
+       __le32 station_flags_msk;
+       u8 add_immediate_ba_tid;
+       u8 remove_immediate_ba_tid;
+       __le16 add_immediate_ba_ssn;
+       __le16 sleep_tx_count;
+       __le16 sleep_state_flags;
+       __le16 assoc_id;
+       __le16 beamform_flags;
+       __le32 tfd_queue_msk;
+} __packed; /* ADD_STA_CMD_API_S_VER_7 */
+
 /**
  * struct iwl_mvm_add_sta_cmd - Add/modify a station in the fw's sta table.
  * ( REPLY_ADD_STA = 0x18 )
@@ -282,6 +346,7 @@ struct iwl_mvm_keyinfo {
  *     mac-addr.
  * @beamform_flags: beam forming controls
  * @tfd_queue_msk: tfd queues used by this station
+ * @rx_ba_window: aggregation window size
  *
  * The device contains an internal table of per-station information, with info
  * on security keys, aggregation parameters, and Tx rates for initial Tx
@@ -310,7 +375,9 @@ struct iwl_mvm_add_sta_cmd {
        __le16 assoc_id;
        __le16 beamform_flags;
        __le32 tfd_queue_msk;
-} __packed; /* ADD_STA_CMD_API_S_VER_7 */
+       __le16 rx_ba_window;
+       __le16 reserved;
+} __packed; /* ADD_STA_CMD_API_S_VER_8 */
 
 /**
  * struct iwl_mvm_add_sta_key_cmd - add/modify sta key
index 82049bb..f332497 100644 (file)
@@ -213,6 +213,8 @@ enum {
 
        MFUART_LOAD_NOTIFICATION = 0xb1,
 
+       RSS_CONFIG_CMD = 0xb3,
+
        REPLY_RX_PHY_CMD = 0xc0,
        REPLY_RX_MPDU_CMD = 0xc1,
        FRAME_RELEASE = 0xc3,
@@ -280,11 +282,16 @@ enum iwl_phy_ops_subcmd_ids {
        DTS_MEASUREMENT_NOTIF_WIDE = 0xFF,
 };
 
+enum iwl_prot_offload_subcmd_ids {
+       STORED_BEACON_NTF = 0xFF,
+};
+
 /* command groups */
 enum {
        LEGACY_GROUP = 0x0,
        LONG_GROUP = 0x1,
        PHY_OPS_GROUP = 0x4,
+       PROT_OFFLOAD_GROUP = 0xb,
 };
 
 /**
@@ -1851,4 +1858,28 @@ struct iwl_shared_mem_cfg {
        __le32 page_buff_size;
 } __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */
 
+#define MAX_STORED_BEACON_SIZE 600
+
+/**
+ * Stored beacon notification
+ *
+ * @system_time: system time on air rise
+ * @tsf: TSF on air rise
+ * @beacon_timestamp: beacon on air rise
+ * @phy_flags: general phy flags: band, modulation, etc.
+ * @channel: channel this beacon was received on
+ * @rates: rate in ucode internal format
+ * @byte_count: frame's byte count
+ */
+struct iwl_stored_beacon_notif {
+       __le32 system_time;
+       __le64 tsf;
+       __le32 beacon_timestamp;
+       __le16 phy_flags;
+       __le16 channel;
+       __le32 rates;
+       __le32 byte_count;
+       u8 data[MAX_STORED_BEACON_SIZE];
+} __packed; /* WOWLAN_STROED_BEACON_INFO_S_VER_1 */
+
 #endif /* __fw_api_h__ */
index 0813f81..4856eac 100644 (file)
@@ -435,6 +435,10 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
        bool monitor_dump_only = false;
        int i;
 
+       if (!IWL_MVM_COLLECT_FW_ERR_DUMP &&
+           !mvm->trans->dbg_dest_tlv)
+               return;
+
        lockdep_assert_held(&mvm->mutex);
 
        /* there's no point in fw dump if the bus is dead */
@@ -640,8 +644,6 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
 
        /* Dump fw's virtual image */
        if (mvm->fw->img[mvm->cur_ucode].paging_mem_size) {
-               u32 i;
-
                for (i = 1; i < mvm->num_of_paging_blk + 1; i++) {
                        struct iwl_fw_error_dump_paging *paging;
                        struct page *pages =
index 4ed5180..070e2af 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -107,6 +108,24 @@ static int iwl_send_tx_ant_cfg(struct iwl_mvm *mvm, u8 valid_tx_ant)
                                    sizeof(tx_ant_cmd), &tx_ant_cmd);
 }
 
+static int iwl_send_rss_cfg_cmd(struct iwl_mvm *mvm)
+{
+       int i;
+       struct iwl_rss_config_cmd cmd = {
+               .flags = cpu_to_le32(IWL_RSS_ENABLE),
+               .hash_mask = IWL_RSS_HASH_TYPE_IPV4_TCP |
+                            IWL_RSS_HASH_TYPE_IPV4_PAYLOAD |
+                            IWL_RSS_HASH_TYPE_IPV6_TCP |
+                            IWL_RSS_HASH_TYPE_IPV6_PAYLOAD,
+       };
+
+       for (i = 0; i < ARRAY_SIZE(cmd.indirection_table); i++)
+               cmd.indirection_table[i] = i % mvm->trans->num_rx_queues;
+       memcpy(cmd.secret_key, mvm->secret_key, ARRAY_SIZE(cmd.secret_key));
+
+       return iwl_mvm_send_cmd_pdu(mvm, RSS_CONFIG_CMD, 0, sizeof(cmd), &cmd);
+}
+
 static void iwl_free_fw_paging(struct iwl_mvm *mvm)
 {
        int i;
@@ -894,6 +913,16 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
        if (ret)
                goto error;
 
+       /* Init RSS configuration */
+       if (iwl_mvm_has_new_rx_api(mvm)) {
+               ret = iwl_send_rss_cfg_cmd(mvm);
+               if (ret) {
+                       IWL_ERR(mvm, "Failed to configure RSS queues: %d\n",
+                               ret);
+                       goto error;
+               }
+       }
+
        /* init the fw <-> mac80211 STA mapping */
        for (i = 0; i < IWL_MVM_STATION_COUNT; i++)
                RCU_INIT_POINTER(mvm->fw_id_to_mac_id[i], NULL);
index bf1e5eb..535134d 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015 Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -744,7 +744,7 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                 * wake-ups.
                 */
                cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_PROBE_REQUEST);
-               if (mvmvif->ap_assoc_sta_count) {
+               if (mvmvif->ap_assoc_sta_count || !mvm->drop_bcn_ap_mode) {
                        cmd->filter_flags |= cpu_to_le32(MAC_FILTER_IN_BEACON);
                        IWL_DEBUG_HC(mvm, "Asking FW to pass beacons\n");
                } else {
@@ -1462,3 +1462,40 @@ void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                                   iwl_mvm_beacon_loss_iterator,
                                                   mb);
 }
+
+void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
+                                   struct iwl_rx_cmd_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_stored_beacon_notif *sb = (void *)pkt->data;
+       struct ieee80211_rx_status rx_status;
+       struct sk_buff *skb;
+       u32 size = le32_to_cpu(sb->byte_count);
+
+       if (size == 0)
+               return;
+
+       skb = alloc_skb(size, GFP_ATOMIC);
+       if (!skb) {
+               IWL_ERR(mvm, "alloc_skb failed\n");
+               return;
+       }
+
+       /* update rx_status according to the notification's metadata */
+       memset(&rx_status, 0, sizeof(rx_status));
+       rx_status.mactime = le64_to_cpu(sb->tsf);
+       rx_status.device_timestamp = le32_to_cpu(sb->system_time);
+       rx_status.band =
+               (sb->phy_flags & cpu_to_le16(RX_RES_PHY_FLAGS_BAND_24)) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
+       rx_status.freq =
+               ieee80211_channel_to_frequency(le16_to_cpu(sb->channel),
+                                              rx_status.band);
+
+       /* copy the data */
+       memcpy(skb_put(skb, size), sb->data, size);
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+
+       /* pass it as regular rx to mac80211 */
+       ieee80211_rx_napi(mvm->hw, skb, NULL);
+}
index d70a171..01476f5 100644 (file)
@@ -884,10 +884,10 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
                        ret = -EINVAL;
                        break;
                }
-               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true);
+               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);
                break;
        case IEEE80211_AMPDU_RX_STOP:
-               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false);
+               ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);
                break;
        case IEEE80211_AMPDU_TX_START:
                if (!iwl_enable_tx_ampdu(mvm->cfg)) {
index 5f3ac8c..ebe37bb 100644 (file)
@@ -346,8 +346,9 @@ struct iwl_mvm_vif_bf_data {
  * @pm_enabled - Indicate if MAC power management is allowed
  * @monitor_active: indicates that monitor context is configured, and that the
  *     interface should get quota etc.
- * @low_latency: indicates that this interface is in low-latency mode
- *     (VMACLowLatencyMode)
+ * @low_latency_traffic: indicates low latency traffic was detected
+ * @low_latency_dbgfs: low latency mode set from debugfs
+ * @low_latency_vcmd: low latency mode set from vendor command
  * @ps_disabled: indicates that this interface requires PS to be disabled
  * @queue_params: QoS params for this MAC
  * @bcast_sta: station used for broadcast packets. Used by the following
@@ -375,7 +376,7 @@ struct iwl_mvm_vif {
        bool ap_ibss_active;
        bool pm_enabled;
        bool monitor_active;
-       bool low_latency;
+       bool low_latency_traffic, low_latency_dbgfs, low_latency_vcmd;
        bool ps_disabled;
        struct iwl_mvm_vif_bf_data bf_data;
 
@@ -432,6 +433,7 @@ struct iwl_mvm_vif {
        struct iwl_dbgfs_pm dbgfs_pm;
        struct iwl_dbgfs_bf dbgfs_bf;
        struct iwl_mac_power_cmd mac_pwr_cmd;
+       int dbgfs_quota_min;
 #endif
 
        enum ieee80211_smps_mode smps_requests[NUM_IWL_MVM_SMPS_REQ];
@@ -645,6 +647,7 @@ struct iwl_mvm {
        atomic_t pending_frames[IWL_MVM_STATION_COUNT];
        u32 tfd_drained[IWL_MVM_STATION_COUNT];
        u8 rx_ba_sessions;
+       u32 secret_key[IWL_RSS_HASH_KEY_CNT];
 
        /* configured by mac80211 */
        u32 rts_threshold;
@@ -856,6 +859,12 @@ struct iwl_mvm {
 
        u32 ciphers[6];
        struct iwl_mvm_tof_data tof_data;
+
+       /*
+        * Drop beacons from other APs in AP mode when there are no connected
+        * clients.
+        */
+       bool drop_bcn_ap_mode;
 };
 
 /* Extract MVM priv from op_mode and _hw */
@@ -1005,10 +1014,18 @@ static inline bool iwl_mvm_is_mplut_supported(struct iwl_mvm *mvm)
                IWL_MVM_BT_COEX_MPLUT;
 }
 
+static inline
+bool iwl_mvm_is_p2p_standalone_uapsd_supported(struct iwl_mvm *mvm)
+{
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_P2P_STANDALONE_UAPSD) &&
+               IWL_MVM_P2P_UAPSD_STANDALONE;
+}
+
 static inline bool iwl_mvm_has_new_rx_api(struct iwl_mvm *mvm)
 {
-       /* firmware flag isn't defined yet */
-       return false;
+       return fw_has_capa(&mvm->fw->ucode_capa,
+                          IWL_UCODE_TLV_CAPA_MULTI_QUEUE_RX_SUPPORT);
 }
 
 extern const u8 iwl_mvm_ac_to_tx_fifo[];
@@ -1184,6 +1201,8 @@ void iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
                             struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                     struct iwl_rx_cmd_buffer *rxb);
+void iwl_mvm_rx_stored_beacon_notif(struct iwl_mvm *mvm,
+                                   struct iwl_rx_cmd_buffer *rxb);
 void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
                                    struct ieee80211_vif *vif);
 unsigned long iwl_mvm_get_used_hw_queues(struct iwl_mvm *mvm,
@@ -1417,8 +1436,9 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
         * binding, so this has no real impact. For now, just return
         * the current desired low-latency state.
         */
-
-       return mvmvif->low_latency;
+       return mvmvif->low_latency_dbgfs ||
+              mvmvif->low_latency_traffic ||
+              mvmvif->low_latency_vcmd;
 }
 
 /* hw scheduler queue config */
@@ -1481,7 +1501,7 @@ void iwl_mvm_tt_handler(struct iwl_mvm *mvm);
 void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff);
 void iwl_mvm_tt_exit(struct iwl_mvm *mvm);
 void iwl_mvm_set_hw_ctkill_state(struct iwl_mvm *mvm, bool state);
-int iwl_mvm_get_temp(struct iwl_mvm *mvm);
+int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp);
 
 /* Location Aware Regulatory */
 struct iwl_mcc_update_resp *
index 7a3da2d..c446e0d 100644 (file)
@@ -300,7 +300,7 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
        struct iwl_nvm_section *sections = mvm->nvm_sections;
        const __le16 *hw, *sw, *calib, *regulatory, *mac_override, *phy_sku;
        bool lar_enabled;
-       u32 mac_addr0, mac_addr1;
+       __le32 mac_addr0, mac_addr1;
 
        /* Checking for required sections */
        if (mvm->trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) {
@@ -337,8 +337,10 @@ iwl_parse_nvm_sections(struct iwl_mvm *mvm)
                return NULL;
 
        /* read the mac address from WFMP registers */
-       mac_addr0 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_0);
-       mac_addr1 = iwl_trans_read_prph(mvm->trans, WFMP_MAC_ADDR_1);
+       mac_addr0 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+                                                   WFMP_MAC_ADDR_0));
+       mac_addr1 = cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+                                                   WFMP_MAC_ADDR_1));
 
        hw = (const __le16 *)sections[mvm->cfg->nvm_hw_section_num].data;
        sw = (const __le16 *)sections[NVM_SECTION_TYPE_SW].data;
index 89ea70d..09a94a5 100644 (file)
@@ -33,6 +33,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -267,6 +268,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
                   true),
        RX_HANDLER(MFUART_LOAD_NOTIFICATION, iwl_mvm_rx_mfuart_notif, false),
        RX_HANDLER(TOF_NOTIFICATION, iwl_mvm_tof_resp_handler, true),
+       RX_HANDLER_GRP(PROT_OFFLOAD_GROUP, STORED_BEACON_NTF,
+                      iwl_mvm_rx_stored_beacon_notif, false),
 
 };
 #undef RX_HANDLER
@@ -344,6 +347,7 @@ static const struct iwl_hcmd_names iwl_mvm_legacy_names[] = {
        HCMD_NAME(MAC_PM_POWER_TABLE),
        HCMD_NAME(TDLS_CHANNEL_SWITCH_NOTIFICATION),
        HCMD_NAME(MFUART_LOAD_NOTIFICATION),
+       HCMD_NAME(RSS_CONFIG_CMD),
        HCMD_NAME(SCAN_ITERATION_COMPLETE_UMAC),
        HCMD_NAME(REPLY_RX_PHY_CMD),
        HCMD_NAME(REPLY_RX_MPDU_CMD),
@@ -386,13 +390,20 @@ static const struct iwl_hcmd_names iwl_mvm_phy_names[] = {
        HCMD_NAME(DTS_MEASUREMENT_NOTIF_WIDE),
 };
 
+/* Please keep this array *SORTED* by hex value.
+ * Access is done through binary search
+ */
+static const struct iwl_hcmd_names iwl_mvm_prot_offload_names[] = {
+       HCMD_NAME(STORED_BEACON_NTF),
+};
+
 static const struct iwl_hcmd_arr iwl_mvm_groups[] = {
        [LEGACY_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
        [LONG_GROUP] = HCMD_ARR(iwl_mvm_legacy_names),
        [PHY_OPS_GROUP] = HCMD_ARR(iwl_mvm_phy_names),
+       [PROT_OFFLOAD_GROUP] = HCMD_ARR(iwl_mvm_prot_offload_names),
 };
 
-
 /* this forward declaration can avoid to export the function */
 static void iwl_mvm_async_handlers_wk(struct work_struct *wk);
 static void iwl_mvm_d0i3_exit_work(struct work_struct *wk);
@@ -481,6 +492,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
        }
        mvm->sf_state = SF_UNINIT;
        mvm->cur_ucode = IWL_UCODE_INIT;
+       mvm->drop_bcn_ap_mode = true;
 
        mutex_init(&mvm->mutex);
        mutex_init(&mvm->d0i3_suspend_mutex);
@@ -641,6 +653,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
 
        iwl_mvm_tof_init(mvm);
 
+       /* init RSS hash key */
+       get_random_bytes(mvm->secret_key, ARRAY_SIZE(mvm->secret_key));
+
        return op_mode;
 
  out_unregister:
@@ -1196,7 +1211,7 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
        cmd->is_11n_connection = ap_sta->ht_cap.ht_supported;
        cmd->offloading_tid = iter_data->offloading_tid;
        cmd->flags = ENABLE_L3_FILTERING | ENABLE_NBNS_FILTERING |
-               ENABLE_DHCP_FILTERING;
+               ENABLE_DHCP_FILTERING | ENABLE_STORE_BEACON;
        /*
         * The d0i3 uCode takes care of the nonqos counters,
         * so configure only the qos seq ones.
@@ -1217,8 +1232,7 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
        struct iwl_wowlan_config_cmd wowlan_config_cmd = {
                .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME |
                                             IWL_WOWLAN_WAKEUP_BEACON_MISS |
-                                            IWL_WOWLAN_WAKEUP_LINK_CHANGE |
-                                            IWL_WOWLAN_WAKEUP_BCN_FILTERING),
+                                            IWL_WOWLAN_WAKEUP_LINK_CHANGE),
        };
        struct iwl_d3_manager_config d3_cfg_cmd = {
                .min_sleep_time = cpu_to_le32(1000),
@@ -1268,6 +1282,12 @@ int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
 
        /* configure wowlan configuration only if needed */
        if (mvm->d0i3_ap_sta_id != IWL_MVM_STATION_COUNT) {
+               /* wake on beacons only if beacon storing isn't supported */
+               if (!fw_has_capa(&mvm->fw->ucode_capa,
+                                IWL_UCODE_TLV_CAPA_BEACON_STORING))
+                       wowlan_config_cmd.wakeup_filter |=
+                               cpu_to_le32(IWL_WOWLAN_WAKEUP_BCN_FILTERING);
+
                iwl_mvm_wowlan_config_key_params(mvm,
                                                 d0i3_iter_data.connected_vif,
                                                 true, flags);
index 9de159f..f313910 100644 (file)
@@ -7,7 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -34,7 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
- * Copyright(c) 2015        Intel Deutschland GmbH
+ * Copyright(c) 2015 - 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -259,6 +259,26 @@ static void iwl_mvm_power_configure_uapsd(struct iwl_mvm *mvm,
                IWL_MVM_PS_HEAVY_RX_THLD_PERCENT;
 }
 
+static void iwl_mvm_p2p_standalone_iterator(void *_data, u8 *mac,
+                                           struct ieee80211_vif *vif)
+{
+       bool *is_p2p_standalone = _data;
+
+       switch (ieee80211_vif_type_p2p(vif)) {
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_AP:
+               *is_p2p_standalone = false;
+               break;
+       case NL80211_IFTYPE_STATION:
+               if (vif->bss_conf.assoc)
+                       *is_p2p_standalone = false;
+               break;
+
+       default:
+               break;
+       }
+}
+
 static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                                       struct ieee80211_vif *vif)
 {
@@ -268,9 +288,6 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
                    ETH_ALEN))
                return false;
 
-       if (vif->p2p &&
-           !(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_P2P_PS_UAPSD))
-               return false;
        /*
         * Avoid using uAPSD if P2P client is associated to GO that uses
         * opportunistic power save. This is due to current FW limitation.
@@ -287,6 +304,22 @@ static bool iwl_mvm_power_allow_uapsd(struct iwl_mvm *mvm,
        if (iwl_mvm_phy_ctx_count(mvm) >= 2)
                return false;
 
+       if (vif->p2p) {
+               /* Allow U-APSD only if p2p is stand alone */
+               bool is_p2p_standalone = true;
+
+               if (!iwl_mvm_is_p2p_standalone_uapsd_supported(mvm))
+                       return false;
+
+               ieee80211_iterate_active_interfaces_atomic(mvm->hw,
+                                       IEEE80211_IFACE_ITER_NORMAL,
+                                       iwl_mvm_p2p_standalone_iterator,
+                                       &is_p2p_standalone);
+
+               if (!is_p2p_standalone)
+                       return false;
+       }
+
        return true;
 }
 
@@ -544,7 +577,6 @@ void iwl_mvm_power_uapsd_misbehaving_ap_notif(struct iwl_mvm *mvm,
 
 struct iwl_power_vifs {
        struct iwl_mvm *mvm;
-       struct ieee80211_vif *bf_vif;
        struct ieee80211_vif *bss_vif;
        struct ieee80211_vif *p2p_vif;
        struct ieee80211_vif *ap_vif;
@@ -617,11 +649,6 @@ static void iwl_mvm_power_get_vifs_iterator(void *_data, u8 *mac,
                if (mvmvif->phy_ctxt)
                        if (mvmvif->phy_ctxt->id < MAX_PHYS)
                                power_iterator->bss_active = true;
-
-               if (mvmvif->bf_data.bf_enabled &&
-                   !WARN_ON(power_iterator->bf_vif))
-                       power_iterator->bf_vif = vif;
-
                break;
 
        default:
@@ -850,29 +877,9 @@ int iwl_mvm_enable_beacon_filter(struct iwl_mvm *mvm,
        return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, flags, false);
 }
 
-static int iwl_mvm_update_beacon_abort(struct iwl_mvm *mvm,
-                                      struct ieee80211_vif *vif,
-                                      bool enable)
-{
-       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       struct iwl_beacon_filter_cmd cmd = {
-               IWL_BF_CMD_CONFIG_DEFAULTS,
-               .bf_enable_beacon_filter = cpu_to_le32(1),
-       };
-
-       if (!mvmvif->bf_data.bf_enabled)
-               return 0;
-
-       if (mvm->cur_ucode == IWL_UCODE_WOWLAN)
-               cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
-
-       mvmvif->bf_data.ba_enabled = enable;
-       return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false);
-}
-
-int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
-                                 struct ieee80211_vif *vif,
-                                 u32 flags)
+static int _iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                         struct ieee80211_vif *vif,
+                                         u32 flags, bool d0i3)
 {
        struct iwl_beacon_filter_cmd cmd = {};
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -883,12 +890,20 @@ int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
 
        ret = iwl_mvm_beacon_filter_send_cmd(mvm, &cmd, flags);
 
-       if (!ret)
+       /* don't change bf_enabled in case of temporary d0i3 configuration */
+       if (!ret && !d0i3)
                mvmvif->bf_data.bf_enabled = false;
 
        return ret;
 }
 
+int iwl_mvm_disable_beacon_filter(struct iwl_mvm *mvm,
+                                 struct ieee80211_vif *vif,
+                                 u32 flags)
+{
+       return _iwl_mvm_disable_beacon_filter(mvm, vif, flags, false);
+}
+
 static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
 {
        bool disable_ps;
@@ -918,21 +933,26 @@ static int iwl_mvm_power_set_ps(struct iwl_mvm *mvm)
 }
 
 static int iwl_mvm_power_set_ba(struct iwl_mvm *mvm,
-                               struct iwl_power_vifs *vifs)
+                               struct ieee80211_vif *vif)
 {
-       struct iwl_mvm_vif *mvmvif;
-       bool ba_enable;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_beacon_filter_cmd cmd = {
+               IWL_BF_CMD_CONFIG_DEFAULTS,
+               .bf_enable_beacon_filter = cpu_to_le32(1),
+       };
 
-       if (!vifs->bf_vif)
+       if (!mvmvif->bf_data.bf_enabled)
                return 0;
 
-       mvmvif = iwl_mvm_vif_from_mac80211(vifs->bf_vif);
+       if (mvm->cur_ucode == IWL_UCODE_WOWLAN)
+               cmd.ba_escape_timer = cpu_to_le32(IWL_BA_ESCAPE_TIMER_D3);
 
-       ba_enable = !(!mvmvif->pm_enabled || mvm->ps_disabled ||
-                     !vifs->bf_vif->bss_conf.ps ||
-                     iwl_mvm_vif_low_latency(mvmvif));
+       mvmvif->bf_data.ba_enabled = !(!mvmvif->pm_enabled ||
+                                      mvm->ps_disabled ||
+                                      !vif->bss_conf.ps ||
+                                      iwl_mvm_vif_low_latency(mvmvif));
 
-       return iwl_mvm_update_beacon_abort(mvm, vifs->bf_vif, ba_enable);
+       return _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd, 0, false);
 }
 
 int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
@@ -953,7 +973,10 @@ int iwl_mvm_power_update_ps(struct iwl_mvm *mvm)
        if (ret)
                return ret;
 
-       return iwl_mvm_power_set_ba(mvm, &vifs);
+       if (vifs.bss_vif)
+               return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
+
+       return 0;
 }
 
 int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
@@ -988,7 +1011,10 @@ int iwl_mvm_power_update_mac(struct iwl_mvm *mvm)
                        return ret;
        }
 
-       return iwl_mvm_power_set_ba(mvm, &vifs);
+       if (vifs.bss_vif)
+               return iwl_mvm_power_set_ba(mvm, vifs.bss_vif);
+
+       return 0;
 }
 
 int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
@@ -1025,8 +1051,17 @@ int iwl_mvm_update_d0i3_power_mode(struct iwl_mvm *mvm,
                        IWL_BF_CMD_CONFIG_D0I3,
                        .bf_enable_beacon_filter = cpu_to_le32(1),
                };
-               ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
-                                                   flags, true);
+               /*
+                * When beacon storing is supported - disable beacon filtering
+                * altogether - the latest beacon will be sent when exiting d0i3
+                */
+               if (fw_has_capa(&mvm->fw->ucode_capa,
+                               IWL_UCODE_TLV_CAPA_BEACON_STORING))
+                       ret = _iwl_mvm_disable_beacon_filter(mvm, vif, flags,
+                                                            true);
+               else
+                       ret = _iwl_mvm_enable_beacon_filter(mvm, vif, &cmd_bf,
+                                                           flags, true);
        } else {
                if (mvmvif->bf_data.bf_enabled)
                        ret = iwl_mvm_enable_beacon_filter(mvm, vif, flags);
index 0b762b4..2141db5 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2016        Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -74,6 +76,9 @@ struct iwl_mvm_quota_iterator_data {
        int n_interfaces[MAX_BINDINGS];
        int colors[MAX_BINDINGS];
        int low_latency[MAX_BINDINGS];
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       int dbgfs_min[MAX_BINDINGS];
+#endif
        int n_low_latency_bindings;
        struct ieee80211_vif *disabled_vif;
 };
@@ -129,6 +134,12 @@ static void iwl_mvm_quota_iterator(void *_data, u8 *mac,
 
        data->n_interfaces[id]++;
 
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+       if (mvmvif->dbgfs_quota_min)
+               data->dbgfs_min[id] = max(data->dbgfs_min[id],
+                                         mvmvif->dbgfs_quota_min);
+#endif
+
        if (iwl_mvm_vif_low_latency(mvmvif) && !data->low_latency[id]) {
                data->n_low_latency_bindings++;
                data->low_latency[id] = true;
@@ -259,6 +270,11 @@ int iwl_mvm_update_quotas(struct iwl_mvm *mvm,
 
                if (data.n_interfaces[i] <= 0)
                        cmd.quotas[idx].quota = cpu_to_le32(0);
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               else if (data.dbgfs_min[i])
+                       cmd.quotas[idx].quota =
+                               cpu_to_le32(data.dbgfs_min[i] * QUOTA_100 / 100);
+#endif
                else if (data.n_low_latency_bindings == 1 && n_non_lowlat &&
                         data.low_latency[i])
                        /*
index 94caa88..6e7e78a 100644 (file)
@@ -2062,7 +2062,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
        }
 
        /* try decreasing first if applicable */
-       if (weak != TPC_INVALID) {
+       if (sr >= RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) &&
+           weak != TPC_INVALID) {
                if (weak_tpt == IWL_INVALID_VALUE &&
                    (strong_tpt == IWL_INVALID_VALUE ||
                     current_tpt >= strong_tpt)) {
index 0c073e0..615dea1 100644 (file)
@@ -201,25 +201,22 @@ static void iwl_mvm_get_signal_strength(struct iwl_mvm *mvm,
                                        struct iwl_rx_mpdu_desc *desc,
                                        struct ieee80211_rx_status *rx_status)
 {
-       int energy_a, energy_b, energy_c, max_energy;
+       int energy_a, energy_b, max_energy;
 
        energy_a = desc->energy_a;
        energy_a = energy_a ? -energy_a : S8_MIN;
        energy_b = desc->energy_b;
        energy_b = energy_b ? -energy_b : S8_MIN;
-       energy_c = desc->energy_c;
-       energy_c = energy_c ? -energy_c : S8_MIN;
        max_energy = max(energy_a, energy_b);
-       max_energy = max(max_energy, energy_c);
 
-       IWL_DEBUG_STATS(mvm, "energy In A %d B %d C %d , and max %d\n",
-                       energy_a, energy_b, energy_c, max_energy);
+       IWL_DEBUG_STATS(mvm, "energy In A %d B %d, and max %d\n",
+                       energy_a, energy_b, max_energy);
 
        rx_status->signal = max_energy;
        rx_status->chains = 0; /* TODO: phy info */
        rx_status->chain_signal[0] = energy_a;
        rx_status->chain_signal[1] = energy_b;
-       rx_status->chain_signal[2] = energy_c;
+       rx_status->chain_signal[2] = S8_MIN;
 }
 
 static int iwl_mvm_rx_crypto(struct iwl_mvm *mvm, struct ieee80211_hdr *hdr,
@@ -294,7 +291,7 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
        struct ieee80211_rx_status *rx_status;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_rx_mpdu_desc *desc = (void *)pkt->data;
-       struct ieee80211_hdr *hdr = (void *)(desc + 1);
+       struct ieee80211_hdr *hdr = (void *)(pkt->data + sizeof(*desc));
        u32 len = le16_to_cpu(desc->mpdu_len);
        u32 rate_n_flags = le32_to_cpu(desc->rate_n_flags);
        struct ieee80211_sta *sta = NULL;
index 9a15642..1e1ab9d 100644 (file)
@@ -930,8 +930,11 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
        if (WARN_ON(num_channels > mvm->fw->ucode_capa.n_scan_channels))
                return -ENOBUFS;
 
-       if (type == mvm->scan_type)
+       if (type == mvm->scan_type) {
+               IWL_DEBUG_SCAN(mvm,
+                              "Ignoring UMAC scan config of the same type\n");
                return 0;
+       }
 
        cmd_size = sizeof(*scan_config) + mvm->fw->ucode_capa.n_scan_channels;
 
@@ -1109,7 +1112,7 @@ static int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        cmd->general_flags = cpu_to_le32(iwl_mvm_scan_umac_flags(mvm, params,
                                                                 vif));
 
-       if (type == IWL_MVM_SCAN_SCHED)
+       if (type == IWL_MVM_SCAN_SCHED || type == IWL_MVM_SCAN_NETDETECT)
                cmd->flags = cpu_to_le32(IWL_UMAC_SCAN_FLAG_PREEMPTIVE);
 
        if (iwl_mvm_scan_use_ebs(mvm, vif))
@@ -1351,7 +1354,7 @@ int iwl_mvm_sched_scan_start(struct iwl_mvm *mvm,
 
        if (fw_has_capa(&mvm->fw->ucode_capa, IWL_UCODE_TLV_CAPA_UMAC_SCAN)) {
                hcmd.id = iwl_cmd_id(SCAN_REQ_UMAC, IWL_ALWAYS_LONG_GROUP, 0);
-               ret = iwl_mvm_scan_umac(mvm, vif, &params, IWL_MVM_SCAN_SCHED);
+               ret = iwl_mvm_scan_umac(mvm, vif, &params, type);
        } else {
                hcmd.id = SCAN_OFFLOAD_REQUEST_CMD;
                ret = iwl_mvm_scan_lmac(mvm, vif, &params);
index b556e33..4854e79 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -33,6 +34,7 @@
  *
  * Copyright(c) 2012 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "sta.h"
 #include "rs.h"
 
+/*
+ * New version of ADD_STA_sta command added new fields at the end of the
+ * structure, so sending the size of the relevant API's structure is enough to
+ * support both API versions.
+ */
+static inline int iwl_mvm_add_sta_cmd_size(struct iwl_mvm *mvm)
+{
+       return iwl_mvm_has_new_rx_api(mvm) ?
+               sizeof(struct iwl_mvm_add_sta_cmd) :
+               sizeof(struct iwl_mvm_add_sta_cmd_v7);
+}
+
 static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
                                    enum nl80211_iftype iftype)
 {
@@ -187,12 +201,13 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                cpu_to_le32(mpdu_dens << STA_FLG_AGG_MPDU_DENS_SHIFT);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(add_sta_cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &add_sta_cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_ASSOC(mvm, "ADD_STA PASSED\n");
                break;
@@ -357,12 +372,13 @@ int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
        cmd.station_flags_msk = cpu_to_le32(STA_FLG_DRAIN_FLOW);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "Frames for staid %d will drained in fw\n",
                               mvmsta->sta_id);
@@ -623,12 +639,13 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
        if (addr)
                memcpy(cmd.addr, addr, ETH_ALEN);
 
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "Internal station added.\n");
                return 0;
@@ -819,7 +836,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
 #define IWL_MAX_RX_BA_SESSIONS 16
 
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                      int tid, u16 ssn, bool start)
+                      int tid, u16 ssn, bool start, u8 buf_size)
 {
        struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
        struct iwl_mvm_add_sta_cmd cmd = {};
@@ -839,6 +856,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        if (start) {
                cmd.add_immediate_ba_tid = (u8) tid;
                cmd.add_immediate_ba_ssn = cpu_to_le16(ssn);
+               cmd.rx_ba_window = cpu_to_le16((u16)buf_size);
        } else {
                cmd.remove_immediate_ba_tid = (u8) tid;
        }
@@ -846,12 +864,13 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                                  STA_MODIFY_REMOVE_BA_TID;
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                IWL_DEBUG_INFO(mvm, "RX BA Session %sed in fw\n",
                               start ? "start" : "stopp");
@@ -904,12 +923,13 @@ static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
        cmd.tid_disable_tx = cpu_to_le16(mvm_sta->tid_disable_agg);
 
        status = ADD_STA_SUCCESS;
-       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA, sizeof(cmd),
+       ret = iwl_mvm_send_cmd_pdu_status(mvm, ADD_STA,
+                                         iwl_mvm_add_sta_cmd_size(mvm),
                                          &cmd, &status);
        if (ret)
                return ret;
 
-       switch (status) {
+       switch (status & IWL_ADD_STA_STATUS_MASK) {
        case ADD_STA_SUCCESS:
                break;
        default:
@@ -1640,7 +1660,8 @@ void iwl_mvm_sta_modify_ps_wake(struct iwl_mvm *mvm,
        };
        int ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
@@ -1731,7 +1752,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
 
        ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA,
                                   CMD_ASYNC | CMD_WANT_ASYNC_CALLBACK,
-                                  sizeof(cmd), &cmd);
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
@@ -1766,7 +1787,8 @@ void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
        };
        int ret;
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC, sizeof(cmd), &cmd);
+       ret = iwl_mvm_send_cmd_pdu(mvm, ADD_STA, CMD_ASYNC,
+                                  iwl_mvm_add_sta_cmd_size(mvm), &cmd);
        if (ret)
                IWL_ERR(mvm, "Failed to send ADD_STA command (%d)\n", ret);
 }
index 39fdf52..e3b9446 100644 (file)
@@ -401,7 +401,7 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
 
 /* AMPDU */
 int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
-                      int tid, u16 ssn, bool start);
+                      int tid, u16 ssn, bool start, u8 buf_size);
 int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
index fb76004..758d05a 100644 (file)
@@ -194,12 +194,12 @@ static int iwl_mvm_get_temp_cmd(struct iwl_mvm *mvm)
        return iwl_mvm_send_cmd_pdu(mvm, cmdid, 0, sizeof(extcmd), &extcmd);
 }
 
-int iwl_mvm_get_temp(struct iwl_mvm *mvm)
+int iwl_mvm_get_temp(struct iwl_mvm *mvm, s32 *temp)
 {
        struct iwl_notification_wait wait_temp_notif;
        static u16 temp_notif[] = { WIDE_ID(PHY_OPS_GROUP,
                                            DTS_MEASUREMENT_NOTIF_WIDE) };
-       int ret, temp;
+       int ret;
 
        if (!fw_has_api(&mvm->fw->ucode_capa, IWL_UCODE_TLV_API_WIDE_CMD_HDR))
                temp_notif[0] = DTS_MEASUREMENT_NOTIFICATION;
@@ -208,7 +208,7 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm)
 
        iwl_init_notification_wait(&mvm->notif_wait, &wait_temp_notif,
                                   temp_notif, ARRAY_SIZE(temp_notif),
-                                  iwl_mvm_temp_notif_wait, &temp);
+                                  iwl_mvm_temp_notif_wait, temp);
 
        ret = iwl_mvm_get_temp_cmd(mvm);
        if (ret) {
@@ -219,12 +219,10 @@ int iwl_mvm_get_temp(struct iwl_mvm *mvm)
 
        ret = iwl_wait_notification(&mvm->notif_wait, &wait_temp_notif,
                                    IWL_MVM_TEMP_NOTIF_WAIT_TIMEOUT);
-       if (ret) {
+       if (ret)
                IWL_ERR(mvm, "Getting the temperature timed out\n");
-               return ret;
-       }
 
-       return temp;
+       return ret;
 }
 
 static void check_exit_ctkill(struct work_struct *work)
@@ -233,6 +231,7 @@ static void check_exit_ctkill(struct work_struct *work)
        struct iwl_mvm *mvm;
        u32 duration;
        s32 temp;
+       int ret;
 
        tt = container_of(work, struct iwl_mvm_tt_mgmt, ct_kill_exit.work);
        mvm = container_of(tt, struct iwl_mvm, thermal_throttle);
@@ -250,13 +249,13 @@ static void check_exit_ctkill(struct work_struct *work)
                goto reschedule;
        }
 
-       temp = iwl_mvm_get_temp(mvm);
+       ret = iwl_mvm_get_temp(mvm, &temp);
 
        iwl_mvm_unref(mvm, IWL_MVM_REF_CHECK_CTKILL);
 
        __iwl_mvm_mac_stop(mvm);
 
-       if (temp < 0)
+       if (ret)
                goto reschedule;
 
        IWL_DEBUG_TEMP(mvm, "NIC temperature: %d\n", temp);
index 0914ec2..8a1638e 100644 (file)
@@ -736,6 +736,37 @@ static void iwl_mvm_hwrate_to_tx_status(u32 rate_n_flags,
        iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
 }
 
+static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
+                                           u32 status)
+{
+       struct iwl_fw_dbg_trigger_tlv *trig;
+       struct iwl_fw_dbg_trigger_tx_status *status_trig;
+       int i;
+
+       if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS))
+               return;
+
+       trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS);
+       status_trig = (void *)trig->data;
+
+       if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+               return;
+
+       for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
+               /* don't collect on status 0 */
+               if (!status_trig->statuses[i].status)
+                       break;
+
+               if (status_trig->statuses[i].status != (status & TX_STATUS_MSK))
+                       continue;
+
+               iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+                                           "Tx status %d was received",
+                                           status & TX_STATUS_MSK);
+               break;
+       }
+}
+
 static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                                     struct iwl_rx_packet *pkt)
 {
@@ -784,6 +815,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        break;
                }
 
+               iwl_mvm_tx_status_check_trigger(mvm, status);
+
                info->status.rates[0].count = tx_resp->failure_frame + 1;
                iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
                                            info);
index 3a989f5..59453c1 100644 (file)
@@ -937,18 +937,16 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
 }
 
 int iwl_mvm_update_low_latency(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
-                              bool value)
+                              bool prev)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int res;
 
        lockdep_assert_held(&mvm->mutex);
 
-       if (mvmvif->low_latency == value)
+       if (iwl_mvm_vif_low_latency(mvmvif) == prev)
                return 0;
 
-       mvmvif->low_latency = value;
-
        res = iwl_mvm_update_quotas(mvm, false, NULL);
        if (res)
                return res;
index 00335ea..753ec67 100644 (file)
@@ -7,6 +7,7 @@
  *
  * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of version 2 of the GNU General Public License as
@@ -66,6 +67,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/module.h>
+#include <linux/pm_runtime.h>
 #include <linux/pci.h>
 #include <linux/pci-aspm.h>
 #include <linux/acpi.h>
@@ -627,6 +629,15 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (ret)
                goto out_free_drv;
 
+       /* if RTPM is in use, enable it in our device */
+       if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
+               pm_runtime_set_active(&pdev->dev);
+               pm_runtime_set_autosuspend_delay(&pdev->dev,
+                                        iwlwifi_mod_params.d0i3_entry_delay);
+               pm_runtime_use_autosuspend(&pdev->dev);
+               pm_runtime_allow(&pdev->dev);
+       }
+
        return 0;
 
 out_free_drv:
@@ -693,15 +704,132 @@ static int iwl_pci_resume(struct device *device)
        return 0;
 }
 
-static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+
+       if (test_bit(STATUS_FW_ERROR, &trans->status))
+               return 0;
+
+       set_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+       /* config the fw */
+       ret = iwl_op_mode_enter_d0i3(trans->op_mode);
+       if (ret == 1) {
+               IWL_DEBUG_RPM(trans, "aborting d0i3 entrance\n");
+               clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+               return -EBUSY;
+       }
+       if (ret)
+               goto err;
+
+       ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+                                test_bit(STATUS_TRANS_IDLE, &trans->status),
+                                msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+       if (!ret) {
+               IWL_ERR(trans, "Timeout entering D0i3\n");
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+       return 0;
+err:
+       clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+       iwl_trans_fw_error(trans);
+       return ret;
+}
+
+int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+
+       /* sometimes a D0i3 entry is not followed through */
+       if (!test_bit(STATUS_TRANS_IDLE, &trans->status))
+               return 0;
+
+       /* config the fw */
+       ret = iwl_op_mode_exit_d0i3(trans->op_mode);
+       if (ret)
+               goto err;
+
+       /* we clear STATUS_TRANS_IDLE only when D0I3_END command is completed */
+
+       ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+                                !test_bit(STATUS_TRANS_IDLE, &trans->status),
+                                msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+       if (!ret) {
+               IWL_ERR(trans, "Timeout exiting D0i3\n");
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       return 0;
+err:
+       clear_bit(STATUS_TRANS_IDLE, &trans->status);
+       iwl_trans_fw_error(trans);
+       return ret;
+}
+
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+static int iwl_pci_runtime_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+       int ret;
+
+       IWL_DEBUG_RPM(trans, "entering runtime suspend\n");
+
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
+               ret = iwl_pci_fw_enter_d0i3(trans);
+               if (ret < 0)
+                       return ret;
+       }
+
+       trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+
+       iwl_trans_d3_suspend(trans, false, false);
+
+       return 0;
+}
+
+static int iwl_pci_runtime_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct iwl_trans *trans = pci_get_drvdata(pdev);
+       enum iwl_d3_status d3_status;
+
+       IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n");
+
+       iwl_trans_d3_resume(trans, &d3_status, false, false);
+
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+               return iwl_pci_fw_exit_d0i3(trans);
+
+       return 0;
+}
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
+static const struct dev_pm_ops iwl_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend,
+                               iwl_pci_resume)
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+       SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend,
+                          iwl_pci_runtime_resume,
+                          NULL)
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+};
 
 #define IWL_PM_OPS     (&iwl_dev_pm_ops)
 
-#else
+#else /* CONFIG_PM_SLEEP */
 
 #define IWL_PM_OPS     NULL
 
-#endif
+#endif /* CONFIG_PM_SLEEP */
 
 static struct pci_driver iwl_pci_driver = {
        .name = DRV_NAME,
index cc3888e..2f95916 100644 (file)
@@ -2,6 +2,7 @@
  *
  * Copyright(c) 2003 - 2015 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
 #define RX_NUM_QUEUES 1
 #define RX_POST_REQ_ALLOC 2
 #define RX_CLAIM_REQ_ALLOC 8
-#define RX_POOL_SIZE ((RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC) * RX_NUM_QUEUES)
-#define RX_LOW_WATERMARK 8
+#define RX_PENDING_WATERMARK 16
 
 struct iwl_host_cmd;
 
 /*This file includes the declaration that are internal to the
  * trans_pcie layer */
 
+/**
+ * struct iwl_rx_mem_buffer
+ * @page_dma: bus address of rxb page
+ * @page: driver's pointer to the rxb page
+ * @vid: index of this rxb in the global table
+ */
 struct iwl_rx_mem_buffer {
        dma_addr_t page_dma;
        struct page *page;
+       u16 vid;
        struct list_head list;
 };
 
@@ -90,8 +97,12 @@ struct isr_statistics {
 
 /**
  * struct iwl_rxq - Rx queue
- * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
+ * @id: queue index
+ * @bd: driver's pointer to buffer of receive buffer descriptors (rbd).
+ *     Address size is 32 bit in pre-9000 devices and 64 bit in 9000 devices.
  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
+ * @ubd: driver's pointer to buffer of used receive buffer descriptors (rbd)
+ * @ubd_dma: physical address of buffer of used receive buffer descriptors (rbd)
  * @read: Shared index to newest available Rx buffer
  * @write: Shared index to oldest written Rx packet
  * @free_count: Number of pre-allocated buffers in rx_free
@@ -103,32 +114,34 @@ struct isr_statistics {
  * @rb_stts: driver's pointer to receive buffer status
  * @rb_stts_dma: bus address of receive buffer status
  * @lock:
- * @pool: initial pool of iwl_rx_mem_buffer for the queue
- * @queue: actual rx queue
+ * @queue: actual rx queue. Not used for multi-rx queue.
  *
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
 struct iwl_rxq {
-       __le32 *bd;
+       int id;
+       void *bd;
        dma_addr_t bd_dma;
+       __le32 *used_bd;
+       dma_addr_t used_bd_dma;
        u32 read;
        u32 write;
        u32 free_count;
        u32 used_count;
        u32 write_actual;
+       u32 queue_size;
        struct list_head rx_free;
        struct list_head rx_used;
        bool need_update;
        struct iwl_rb_status *rb_stts;
        dma_addr_t rb_stts_dma;
        spinlock_t lock;
-       struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE];
+       struct napi_struct napi;
        struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE];
 };
 
 /**
  * struct iwl_rb_allocator - Rx allocator
- * @pool: initial pool of allocator
  * @req_pending: number of requests the allcator had not processed yet
  * @req_ready: number of requests honored and ready for claiming
  * @rbd_allocated: RBDs with pages allocated and ready to be handled to
@@ -140,7 +153,6 @@ struct iwl_rxq {
  * @rx_alloc: work struct for background calls
  */
 struct iwl_rb_allocator {
-       struct iwl_rx_mem_buffer pool[RX_POOL_SIZE];
        atomic_t req_pending;
        atomic_t req_ready;
        struct list_head rbd_allocated;
@@ -280,6 +292,7 @@ struct iwl_txq {
        bool ampdu;
        bool block;
        unsigned long wd_timeout;
+       struct sk_buff_head overflow_q;
 };
 
 static inline dma_addr_t
@@ -297,6 +310,8 @@ struct iwl_tso_hdr_page {
 /**
  * struct iwl_trans_pcie - PCIe transport specific data
  * @rxq: all the RX queue data
+ * @rx_pool: initial pool of iwl_rx_mem_buffer for all the queues
+ * @global_table: table mapping received VID from hw to rxb
  * @rba: allocator for RX replenishing
  * @drv - pointer to iwl_drv
  * @trans: pointer to the generic transport area
@@ -323,13 +338,14 @@ struct iwl_tso_hdr_page {
  * @fw_mon_size: size of the buffer for the firmware monitor
  */
 struct iwl_trans_pcie {
-       struct iwl_rxq rxq;
+       struct iwl_rxq *rxq;
+       struct iwl_rx_mem_buffer rx_pool[MQ_RX_POOL_SIZE];
+       struct iwl_rx_mem_buffer *global_table[MQ_RX_TABLE_SIZE];
        struct iwl_rb_allocator rba;
        struct iwl_trans *trans;
        struct iwl_drv *drv;
 
        struct net_device napi_dev;
-       struct napi_struct napi;
 
        struct __percpu iwl_tso_hdr_page *tso_hdr_page;
 
@@ -359,6 +375,7 @@ struct iwl_trans_pcie {
        bool ucode_write_complete;
        wait_queue_head_t ucode_write_waitq;
        wait_queue_head_t wait_command_queue;
+       wait_queue_head_t d0i3_waitq;
 
        u8 cmd_queue;
        u8 cmd_fifo;
@@ -579,4 +596,7 @@ static inline int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans)
 }
 #endif
 
+int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans);
+int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans);
+
 #endif /* __iwl_trans_int_pcie_h__ */
index ccafbd8..51314e5 100644 (file)
@@ -2,6 +2,7 @@
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
  */
 static int iwl_rxq_space(const struct iwl_rxq *rxq)
 {
-       /* Make sure RX_QUEUE_SIZE is a power of 2 */
-       BUILD_BUG_ON(RX_QUEUE_SIZE & (RX_QUEUE_SIZE - 1));
+       /* Make sure rx queue size is a power of 2 */
+       WARN_ON(rxq->queue_size & (rxq->queue_size - 1));
 
        /*
         * There can be up to (RX_QUEUE_SIZE - 1) free slots, to avoid ambiguity
@@ -149,7 +150,7 @@ static int iwl_rxq_space(const struct iwl_rxq *rxq)
         * The following is equivalent to modulo by RX_QUEUE_SIZE and is well
         * defined for negative dividends.
         */
-       return (rxq->read - rxq->write - 1) & (RX_QUEUE_SIZE - 1);
+       return (rxq->read - rxq->write - 1) & (rxq->queue_size - 1);
 }
 
 /*
@@ -160,6 +161,12 @@ static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr)
        return cpu_to_le32((u32)(dma_addr >> 8));
 }
 
+static void iwl_pcie_write_prph_64(struct iwl_trans *trans, u64 ofs, u64 val)
+{
+       iwl_write_prph(trans, ofs, val & 0xffffffff);
+       iwl_write_prph(trans, ofs + 4, val >> 32);
+}
+
 /*
  * iwl_pcie_rx_stop - stops the Rx DMA
  */
@@ -173,10 +180,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans)
 /*
  * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue
  */
-static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans)
+static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
+                                   struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        u32 reg;
 
        lockdep_assert_held(&rxq->lock);
@@ -201,24 +207,73 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans)
        }
 
        rxq->write_actual = round_down(rxq->write, 8);
-       iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
+       if (trans->cfg->mq_rx_supported)
+               iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(rxq->id),
+                              rxq->write_actual);
+       else
+               iwl_write32(trans, FH_RSCSR_CHNL0_WPTR, rxq->write_actual);
 }
 
 static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       int i;
 
-       spin_lock(&rxq->lock);
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (!rxq->need_update)
+                       continue;
+               spin_lock(&rxq->lock);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
+               rxq->need_update = false;
+               spin_unlock(&rxq->lock);
+       }
+}
+
+static void iwl_pcie_rxq_mq_restock(struct iwl_trans *trans,
+                                   struct iwl_rxq *rxq)
+{
+       struct iwl_rx_mem_buffer *rxb;
+
+       /*
+        * If the device isn't enabled - no need to try to add buffers...
+        * This can happen when we stop the device and still have an interrupt
+        * pending. We stop the APM before we sync the interrupts because we
+        * have to (see comment there). On the other hand, since the APM is
+        * stopped, we cannot access the HW (in particular not prph).
+        * So don't try to restock if the APM has been already stopped.
+        */
+       if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+               return;
 
-       if (!rxq->need_update)
-               goto exit_unlock;
+       spin_lock(&rxq->lock);
+       while (rxq->free_count) {
+               __le64 *bd = (__le64 *)rxq->bd;
 
-       iwl_pcie_rxq_inc_wr_ptr(trans);
-       rxq->need_update = false;
+               /* Get next free Rx buffer, remove from free list */
+               rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
+                                      list);
+               list_del(&rxb->list);
 
- exit_unlock:
+               /* 12 first bits are expected to be empty */
+               WARN_ON(rxb->page_dma & DMA_BIT_MASK(12));
+               /* Point to Rx buffer via next RBD in circular buffer */
+               bd[rxq->write] = cpu_to_le64(rxb->page_dma | rxb->vid);
+               rxq->write = (rxq->write + 1) & MQ_RX_TABLE_MASK;
+               rxq->free_count--;
+       }
        spin_unlock(&rxq->lock);
+
+       /*
+        * If we've added more space for the firmware to place data, tell it.
+        * Increment device's write pointer in multiples of 8.
+        */
+       if (rxq->write_actual != (rxq->write & ~0x7)) {
+               spin_lock(&rxq->lock);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
+               spin_unlock(&rxq->lock);
+       }
 }
 
 /*
@@ -232,10 +287,8 @@ static void iwl_pcie_rxq_check_wrptr(struct iwl_trans *trans)
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
+static void iwl_pcie_rxq_restock(struct iwl_trans *trans, struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
 
        /*
@@ -251,6 +304,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
 
        spin_lock(&rxq->lock);
        while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) {
+               __le32 *bd = (__le32 *)rxq->bd;
                /* The overwritten rxb must be a used one */
                rxb = rxq->queue[rxq->write];
                BUG_ON(rxb && rxb->page);
@@ -261,7 +315,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                list_del(&rxb->list);
 
                /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
+               bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
                rxq->queue[rxq->write] = rxb;
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
                rxq->free_count--;
@@ -272,7 +326,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
         * Increment device's write pointer in multiples of 8. */
        if (rxq->write_actual != (rxq->write & ~0x7)) {
                spin_lock(&rxq->lock);
-               iwl_pcie_rxq_inc_wr_ptr(trans);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
                spin_unlock(&rxq->lock);
        }
 }
@@ -285,13 +339,9 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
                                           gfp_t priority)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct page *page;
        gfp_t gfp_mask = priority;
 
-       if (rxq->free_count > RX_LOW_WATERMARK)
-               gfp_mask |= __GFP_NOWARN;
-
        if (trans_pcie->rx_page_order > 0)
                gfp_mask |= __GFP_COMP;
 
@@ -301,16 +351,13 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
                if (net_ratelimit())
                        IWL_DEBUG_INFO(trans, "alloc_pages failed, order: %d\n",
                                       trans_pcie->rx_page_order);
-               /* Issue an error if the hardware has consumed more than half
-                * of its free buffer list and we don't have enough
-                * pre-allocated buffers.
+               /*
+                * Issue an error if we don't have enough pre-allocated
+                 * buffers.
 `               */
-               if (rxq->free_count <= RX_LOW_WATERMARK &&
-                   iwl_rxq_space(rxq) > (RX_QUEUE_SIZE / 2) &&
-                   net_ratelimit())
+               if (!(gfp_mask & __GFP_NOWARN) && net_ratelimit())
                        IWL_CRIT(trans,
-                                "Failed to alloc_pages with GFP_KERNEL. Only %u free buffers remaining.\n",
-                                rxq->free_count);
+                                "Failed to alloc_pages\n");
                return NULL;
        }
        return page;
@@ -325,10 +372,10 @@ static struct page *iwl_pcie_rx_alloc_page(struct iwl_trans *trans,
  * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
  * allocated buffers.
  */
-static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority,
+                                  struct iwl_rxq *rxq)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
 
@@ -372,10 +419,6 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
-               /* dma address must be no more than 36 bits */
-               BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-               /* and also 256 byte aligned! */
-               BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
                spin_lock(&rxq->lock);
 
@@ -386,41 +429,24 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
        }
 }
 
-static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
+static void iwl_pcie_free_rbs_pool(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        int i;
 
-       lockdep_assert_held(&rxq->lock);
-
-       for (i = 0; i < RX_QUEUE_SIZE; i++) {
-               if (!rxq->pool[i].page)
+       for (i = 0; i < MQ_RX_POOL_SIZE; i++) {
+               if (!trans_pcie->rx_pool[i].page)
                        continue;
-               dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
+               dma_unmap_page(trans->dev, trans_pcie->rx_pool[i].page_dma,
                               PAGE_SIZE << trans_pcie->rx_page_order,
                               DMA_FROM_DEVICE);
-               __free_pages(rxq->pool[i].page, trans_pcie->rx_page_order);
-               rxq->pool[i].page = NULL;
+               __free_pages(trans_pcie->rx_pool[i].page,
+                            trans_pcie->rx_page_order);
+               trans_pcie->rx_pool[i].page = NULL;
        }
 }
 
 /*
- * iwl_pcie_rx_replenish - Move all used buffers from rx_used to rx_free
- *
- * When moving to rx_free an page is allocated for the slot.
- *
- * Also restock the Rx queue via iwl_pcie_rxq_restock.
- * This is called only during initialization
- */
-static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
-{
-       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
-
-       iwl_pcie_rxq_restock(trans);
-}
-
-/*
  * iwl_pcie_rx_allocator - Allocates pages in the background for RX queues
  *
  * Allocates for each received request 8 pages
@@ -444,6 +470,11 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
        while (pending) {
                int i;
                struct list_head local_allocated;
+               gfp_t gfp_mask = GFP_KERNEL;
+
+               /* Do not post a warning if there are only a few requests */
+               if (pending < RX_PENDING_WATERMARK)
+                       gfp_mask |= __GFP_NOWARN;
 
                INIT_LIST_HEAD(&local_allocated);
 
@@ -463,7 +494,7 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
                        BUG_ON(rxb->page);
 
                        /* Alloc a new receive buffer */
-                       page = iwl_pcie_rx_alloc_page(trans, GFP_KERNEL);
+                       page = iwl_pcie_rx_alloc_page(trans, gfp_mask);
                        if (!page)
                                continue;
                        rxb->page = page;
@@ -477,10 +508,6 @@ static void iwl_pcie_rx_allocator(struct iwl_trans *trans)
                                __free_pages(page, trans_pcie->rx_page_order);
                                continue;
                        }
-                       /* dma address must be no more than 36 bits */
-                       BUG_ON(rxb->page_dma & ~DMA_BIT_MASK(36));
-                       /* and also 256 byte aligned! */
-                       BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
                        /* move the allocated entry to the out list */
                        list_move(&rxb->list, &local_allocated);
@@ -561,38 +588,83 @@ static void iwl_pcie_rx_allocator_work(struct work_struct *data)
 static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
        struct device *dev = trans->dev;
+       int i;
+       int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) :
+                                                     sizeof(__le32);
+
+       if (WARN_ON(trans_pcie->rxq))
+               return -EINVAL;
 
-       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+       trans_pcie->rxq = kcalloc(trans->num_rx_queues, sizeof(struct iwl_rxq),
+                                 GFP_KERNEL);
+       if (!trans_pcie->rxq)
+               return -EINVAL;
 
-       spin_lock_init(&rxq->lock);
        spin_lock_init(&rba->lock);
 
-       if (WARN_ON(rxq->bd || rxq->rb_stts))
-               return -EINVAL;
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
 
-       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                     &rxq->bd_dma, GFP_KERNEL);
-       if (!rxq->bd)
-               goto err_bd;
+               spin_lock_init(&rxq->lock);
+               if (trans->cfg->mq_rx_supported)
+                       rxq->queue_size = MQ_RX_TABLE_SIZE;
+               else
+                       rxq->queue_size = RX_QUEUE_SIZE;
 
-       /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                          &rxq->rb_stts_dma, GFP_KERNEL);
-       if (!rxq->rb_stts)
-               goto err_rb_stts;
+               /*
+                * Allocate the circular buffer of Read Buffer Descriptors
+                * (RBDs)
+                */
+               rxq->bd = dma_zalloc_coherent(dev,
+                                            free_size * rxq->queue_size,
+                                            &rxq->bd_dma, GFP_KERNEL);
+               if (!rxq->bd)
+                       goto err;
+
+               if (trans->cfg->mq_rx_supported) {
+                       rxq->used_bd = dma_zalloc_coherent(dev,
+                                                          sizeof(__le32) *
+                                                          rxq->queue_size,
+                                                          &rxq->used_bd_dma,
+                                                          GFP_KERNEL);
+                       if (!rxq->used_bd)
+                               goto err;
+               }
 
+               /*Allocate the driver's pointer to receive buffer status */
+               rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                                  &rxq->rb_stts_dma,
+                                                  GFP_KERNEL);
+               if (!rxq->rb_stts)
+                       goto err;
+       }
        return 0;
 
-err_rb_stts:
-       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       rxq->bd_dma = 0;
-       rxq->bd = NULL;
-err_bd:
+err:
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (rxq->bd)
+                       dma_free_coherent(dev, free_size * rxq->queue_size,
+                                         rxq->bd, rxq->bd_dma);
+               rxq->bd_dma = 0;
+               rxq->bd = NULL;
+
+               if (rxq->rb_stts)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(struct iwl_rb_status),
+                                         rxq->rb_stts, rxq->rb_stts_dma);
+
+               if (rxq->used_bd)
+                       dma_free_coherent(dev, sizeof(__le32) * rxq->queue_size,
+                                         rxq->used_bd, rxq->used_bd_dma);
+               rxq->used_bd_dma = 0;
+               rxq->used_bd = NULL;
+       }
+       kfree(trans_pcie->rxq);
+
        return -ENOMEM;
 }
 
@@ -659,65 +731,103 @@ static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
                iwl_set_bit(trans, CSR_INT_COALESCING, IWL_HOST_INT_OPER_MODE);
 }
 
-static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
+static void iwl_pcie_rx_mq_hw_init(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 rb_size, enabled = 0;
        int i;
 
-       lockdep_assert_held(&rxq->lock);
-
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-       rxq->free_count = 0;
-       rxq->used_count = 0;
+       switch (trans_pcie->rx_buf_size) {
+       case IWL_AMSDU_4K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_4K;
+               break;
+       case IWL_AMSDU_8K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_8K;
+               break;
+       case IWL_AMSDU_12K:
+               rb_size = RFH_RXF_DMA_RB_SIZE_12K;
+               break;
+       default:
+               WARN_ON(1);
+               rb_size = RFH_RXF_DMA_RB_SIZE_4K;
+       }
 
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
-               list_add(&rxq->pool[i].list, &rxq->rx_used);
-}
+       /* Stop Rx DMA */
+       iwl_write_prph(trans, RFH_RXF_DMA_CFG, 0);
+       /* disable free amd used rx queue operation */
+       iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, 0);
+
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               /* Tell device where to find RBD free table in DRAM */
+               iwl_pcie_write_prph_64(trans, RFH_Q_FRBDCB_BA_LSB(i),
+                                      (u64)(trans_pcie->rxq[i].bd_dma));
+               /* Tell device where to find RBD used table in DRAM */
+               iwl_pcie_write_prph_64(trans, RFH_Q_URBDCB_BA_LSB(i),
+                                      (u64)(trans_pcie->rxq[i].used_bd_dma));
+               /* Tell device where in DRAM to update its Rx status */
+               iwl_pcie_write_prph_64(trans, RFH_Q_URBD_STTS_WPTR_LSB(i),
+                                      trans_pcie->rxq[i].rb_stts_dma);
+               /* Reset device indice tables */
+               iwl_write_prph(trans, RFH_Q_FRBDCB_WIDX(i), 0);
+               iwl_write_prph(trans, RFH_Q_FRBDCB_RIDX(i), 0);
+               iwl_write_prph(trans, RFH_Q_URBDCB_WIDX(i), 0);
+
+               enabled |= BIT(i) | BIT(i + 16);
+       }
 
-static void iwl_pcie_rx_init_rba(struct iwl_rb_allocator *rba)
-{
-       int i;
+       /* restock default queue */
+       iwl_pcie_rxq_mq_restock(trans, &trans_pcie->rxq[0]);
 
-       lockdep_assert_held(&rba->lock);
+       /*
+        * Enable Rx DMA
+        * Single frame mode
+        * Rx buffer size 4 or 8k or 12k
+        * Min RB size 4 or 8
+        * 512 RBDs
+        */
+       iwl_write_prph(trans, RFH_RXF_DMA_CFG,
+                      RFH_DMA_EN_ENABLE_VAL |
+                      rb_size | RFH_RXF_DMA_SINGLE_FRAME_MASK |
+                      RFH_RXF_DMA_MIN_RB_4_8 |
+                      RFH_RXF_DMA_RBDCB_SIZE_512);
 
-       INIT_LIST_HEAD(&rba->rbd_allocated);
-       INIT_LIST_HEAD(&rba->rbd_empty);
+       iwl_write_prph(trans, RFH_GEN_CFG, RFH_GEN_CFG_RFH_DMA_SNOOP |
+                                         RFH_GEN_CFG_SERVICE_DMA_SNOOP);
+       iwl_write_prph(trans, RFH_RXF_RXQ_ACTIVE, enabled);
 
-       for (i = 0; i < RX_POOL_SIZE; i++)
-               list_add(&rba->pool[i].list, &rba->rbd_empty);
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
 }
 
-static void iwl_pcie_rx_free_rba(struct iwl_trans *trans)
+static void iwl_pcie_rx_init_rxb_lists(struct iwl_rxq *rxq)
 {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i;
+       lockdep_assert_held(&rxq->lock);
 
-       lockdep_assert_held(&rba->lock);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+       rxq->free_count = 0;
+       rxq->used_count = 0;
+}
 
-       for (i = 0; i < RX_POOL_SIZE; i++) {
-               if (!rba->pool[i].page)
-                       continue;
-               dma_unmap_page(trans->dev, rba->pool[i].page_dma,
-                              PAGE_SIZE << trans_pcie->rx_page_order,
-                              DMA_FROM_DEVICE);
-               __free_pages(rba->pool[i].page, trans_pcie->rx_page_order);
-               rba->pool[i].page = NULL;
-       }
+static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
+{
+       WARN_ON(1);
+       return 0;
 }
 
 int iwl_pcie_rx_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *def_rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
-       int i, err;
+       int i, err, num_rbds, allocator_pool_size;
 
-       if (!rxq->bd) {
+       if (!trans_pcie->rxq) {
                err = iwl_pcie_rx_alloc(trans);
                if (err)
                        return err;
        }
+       def_rxq = trans_pcie->rxq;
        if (!rba->alloc_wq)
                rba->alloc_wq = alloc_workqueue("rb_allocator",
                                                WQ_HIGHPRI | WQ_UNBOUND, 1);
@@ -726,34 +836,68 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        spin_lock(&rba->lock);
        atomic_set(&rba->req_pending, 0);
        atomic_set(&rba->req_ready, 0);
-       /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rx_free_rba(trans);
-       iwl_pcie_rx_init_rba(rba);
+       INIT_LIST_HEAD(&rba->rbd_allocated);
+       INIT_LIST_HEAD(&rba->rbd_empty);
        spin_unlock(&rba->lock);
 
-       spin_lock(&rxq->lock);
-
        /* free all first - we might be reconfigured for a different size */
-       iwl_pcie_rxq_free_rbs(trans);
-       iwl_pcie_rx_init_rxb_lists(rxq);
+       iwl_pcie_free_rbs_pool(trans);
 
        for (i = 0; i < RX_QUEUE_SIZE; i++)
-               rxq->queue[i] = NULL;
+               def_rxq->queue[i] = NULL;
 
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-       spin_unlock(&rxq->lock);
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
 
-       iwl_pcie_rx_replenish(trans);
+               rxq->id = i;
 
-       iwl_pcie_rx_hw_init(trans, rxq);
+               spin_lock(&rxq->lock);
+               /*
+                * Set read write pointer to reflect that we have processed
+                * and used all buffers, but have not restocked the Rx queue
+                * with fresh buffers
+                */
+               rxq->read = 0;
+               rxq->write = 0;
+               rxq->write_actual = 0;
+               memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
 
-       spin_lock(&rxq->lock);
-       iwl_pcie_rxq_inc_wr_ptr(trans);
-       spin_unlock(&rxq->lock);
+               iwl_pcie_rx_init_rxb_lists(rxq);
+
+               if (!rxq->napi.poll)
+                       netif_napi_add(&trans_pcie->napi_dev, &rxq->napi,
+                                      iwl_pcie_dummy_napi_poll, 64);
+
+               spin_unlock(&rxq->lock);
+       }
+
+       /* move the pool to the default queue and allocator ownerships */
+       num_rbds = trans->cfg->mq_rx_supported ?
+                    MQ_RX_POOL_SIZE : RX_QUEUE_SIZE;
+       allocator_pool_size = trans->num_rx_queues *
+               (RX_CLAIM_REQ_ALLOC - RX_POST_REQ_ALLOC);
+       for (i = 0; i < num_rbds; i++) {
+               struct iwl_rx_mem_buffer *rxb = &trans_pcie->rx_pool[i];
+
+               if (i < allocator_pool_size)
+                       list_add(&rxb->list, &rba->rbd_empty);
+               else
+                       list_add(&rxb->list, &def_rxq->rx_used);
+               trans_pcie->global_table[i] = rxb;
+               rxb->vid = (u16)i;
+       }
+
+       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL, def_rxq);
+       if (trans->cfg->mq_rx_supported) {
+               iwl_pcie_rx_mq_hw_init(trans);
+       } else {
+               iwl_pcie_rxq_restock(trans, def_rxq);
+               iwl_pcie_rx_hw_init(trans, def_rxq);
+       }
+
+       spin_lock(&def_rxq->lock);
+       iwl_pcie_rxq_inc_wr_ptr(trans, def_rxq);
+       spin_unlock(&def_rxq->lock);
 
        return 0;
 }
@@ -761,12 +905,16 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
 void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rb_allocator *rba = &trans_pcie->rba;
+       int free_size = trans->cfg->mq_rx_supported ? sizeof(__le64) :
+                                             sizeof(__le32);
+       int i;
 
-       /*if rxq->bd is NULL, it means that nothing has been allocated,
-        * exit now */
-       if (!rxq->bd) {
+       /*
+        * if rxq is NULL, it means that nothing has been allocated,
+        * exit now
+        */
+       if (!trans_pcie->rxq) {
                IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
                return;
        }
@@ -777,27 +925,37 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
                rba->alloc_wq = NULL;
        }
 
-       spin_lock(&rba->lock);
-       iwl_pcie_rx_free_rba(trans);
-       spin_unlock(&rba->lock);
-
-       spin_lock(&rxq->lock);
-       iwl_pcie_rxq_free_rbs(trans);
-       spin_unlock(&rxq->lock);
-
-       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       rxq->bd_dma = 0;
-       rxq->bd = NULL;
-
-       if (rxq->rb_stts)
-               dma_free_coherent(trans->dev,
-                                 sizeof(struct iwl_rb_status),
-                                 rxq->rb_stts, rxq->rb_stts_dma);
-       else
-               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       rxq->rb_stts_dma = 0;
-       rxq->rb_stts = NULL;
+       iwl_pcie_free_rbs_pool(trans);
+
+       for (i = 0; i < trans->num_rx_queues; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               if (rxq->bd)
+                       dma_free_coherent(trans->dev,
+                                         free_size * rxq->queue_size,
+                                         rxq->bd, rxq->bd_dma);
+               rxq->bd_dma = 0;
+               rxq->bd = NULL;
+
+               if (rxq->rb_stts)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(struct iwl_rb_status),
+                                         rxq->rb_stts, rxq->rb_stts_dma);
+               else
+                       IWL_DEBUG_INFO(trans,
+                                      "Free rxq->rb_stts which is NULL\n");
+
+               if (rxq->used_bd)
+                       dma_free_coherent(trans->dev,
+                                         sizeof(__le32) * rxq->queue_size,
+                                         rxq->used_bd, rxq->used_bd_dma);
+               rxq->used_bd_dma = 0;
+               rxq->used_bd = NULL;
+
+               if (rxq->napi.poll)
+                       netif_napi_del(&rxq->napi);
+       }
+       kfree(trans_pcie->rxq);
 }
 
 /*
@@ -841,11 +999,11 @@ static void iwl_pcie_rx_reuse_rbd(struct iwl_trans *trans,
 }
 
 static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
+                               struct iwl_rxq *rxq,
                                struct iwl_rx_mem_buffer *rxb,
                                bool emergency)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
        bool page_stolen = false;
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
@@ -911,7 +1069,12 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                index = SEQ_TO_INDEX(sequence);
                cmd_index = get_cmd_index(&txq->q, index);
 
-               iwl_op_mode_rx(trans->op_mode, &trans_pcie->napi, &rxcb);
+               if (rxq->id == 0)
+                       iwl_op_mode_rx(trans->op_mode, &rxq->napi,
+                                      &rxcb);
+               else
+                       iwl_op_mode_rx_rss(trans->op_mode, &rxq->napi,
+                                          &rxcb, rxq->id);
 
                if (reclaim) {
                        kzfree(txq->entries[cmd_index].free_buf);
@@ -975,7 +1138,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
 static void iwl_pcie_rx_handle(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *rxq = &trans_pcie->rxq[0];
        u32 r, i, j, count = 0;
        bool emergency = false;
 
@@ -993,16 +1156,26 @@ restart:
        while (i != r) {
                struct iwl_rx_mem_buffer *rxb;
 
-               if (unlikely(rxq->used_count == RX_QUEUE_SIZE / 2))
+               if (unlikely(rxq->used_count == rxq->queue_size / 2))
                        emergency = true;
 
-               rxb = rxq->queue[i];
-               rxq->queue[i] = NULL;
+               if (trans->cfg->mq_rx_supported) {
+                       /*
+                        * used_bd is a 32 bit but only 12 are used to retrieve
+                        * the vid
+                        */
+                       u16 vid = (u16)le32_to_cpu(rxq->used_bd[i]);
+
+                       rxb = trans_pcie->global_table[vid];
+               } else {
+                       rxb = rxq->queue[i];
+                       rxq->queue[i] = NULL;
+               }
 
                IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d\n", r, i);
-               iwl_pcie_rx_handle_rb(trans, rxb, emergency);
+               iwl_pcie_rx_handle_rb(trans, rxq, rxb, emergency);
 
-               i = (i + 1) & RX_QUEUE_MASK;
+               i = (i + 1) & (rxq->queue_size - 1);
 
                /* If we have RX_CLAIM_REQ_ALLOC released rx buffers -
                 * try to claim the pre-allocated buffers from the allocator */
@@ -1040,10 +1213,10 @@ restart:
                        count++;
                        if (count == 8) {
                                count = 0;
-                               if (rxq->used_count < RX_QUEUE_SIZE / 3)
+                               if (rxq->used_count < rxq->queue_size / 3)
                                        emergency = false;
                                spin_unlock(&rxq->lock);
-                               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
+                               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
                                spin_lock(&rxq->lock);
                        }
                }
@@ -1055,7 +1228,10 @@ restart:
                if (rxq->free_count >=  RX_CLAIM_REQ_ALLOC) {
                        rxq->read = i;
                        spin_unlock(&rxq->lock);
-                       iwl_pcie_rxq_restock(trans);
+                       if (trans->cfg->mq_rx_supported)
+                               iwl_pcie_rxq_mq_restock(trans, rxq);
+                       else
+                               iwl_pcie_rxq_restock(trans, rxq);
                        goto restart;
                }
        }
@@ -1077,10 +1253,10 @@ restart:
         * will be restocked by the next call of iwl_pcie_rxq_restock.
         */
        if (unlikely(emergency && count))
-               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
+               iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC, rxq);
 
-       if (trans_pcie->napi.poll)
-               napi_gro_flush(&trans_pcie->napi, false);
+       if (rxq->napi.poll)
+               napi_gro_flush(&rxq->napi, false);
 }
 
 /*
index d60a467..b796952 100644 (file)
@@ -72,6 +72,7 @@
 #include <linux/bitops.h>
 #include <linux/gfp.h>
 #include <linux/vmalloc.h>
+#include <linux/pm_runtime.h>
 
 #include "iwl-drv.h"
 #include "iwl-trans.h"
@@ -1218,11 +1219,12 @@ void iwl_trans_pcie_rf_kill(struct iwl_trans *trans, bool state)
                _iwl_trans_pcie_stop_device(trans, true);
 }
 
-static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
+static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test,
+                                     bool reset)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
+       if (!reset) {
                /* Enable persistence mode to avoid reset */
                iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_PERSIST_MODE);
@@ -1246,7 +1248,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
        iwl_clear_bit(trans, CSR_GP_CNTRL,
                      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D3) {
+       if (reset) {
                /*
                 * reset TX queues -- some of their registers reset during S3
                 * so if we don't reset everything here the D3 image would try
@@ -1260,7 +1262,7 @@ static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
 
 static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
                                    enum iwl_d3_status *status,
-                                   bool test)
+                                   bool test,  bool reset)
 {
        u32 val;
        int ret;
@@ -1295,7 +1297,7 @@ static int iwl_trans_pcie_d3_resume(struct iwl_trans *trans,
 
        iwl_pcie_set_pwr(trans, false);
 
-       if (trans->system_pm_mode == IWL_PLAT_PM_MODE_D0I3) {
+       if (!reset) {
                iwl_clear_bit(trans, CSR_GP_CNTRL,
                              CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        } else {
@@ -1353,6 +1355,10 @@ static int _iwl_trans_pcie_start_hw(struct iwl_trans *trans, bool low_power)
        /* ... rfkill can call stop_device and set it false if needed */
        iwl_trans_pcie_rf_kill(trans, hw_rfkill);
 
+       /* Make sure we sync here, because we'll need full access later */
+       if (low_power)
+               pm_runtime_resume(trans->dev);
+
        return 0;
 }
 
@@ -1422,12 +1428,6 @@ static void iwl_trans_pcie_write_prph(struct iwl_trans *trans, u32 addr,
        iwl_trans_pcie_write32(trans, HBUS_TARG_PRPH_WDAT, val);
 }
 
-static int iwl_pcie_dummy_napi_poll(struct napi_struct *napi, int budget)
-{
-       WARN_ON(1);
-       return 0;
-}
-
 static void iwl_trans_pcie_configure(struct iwl_trans *trans,
                                     const struct iwl_trans_config *trans_cfg)
 {
@@ -1464,11 +1464,8 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
         * As this function may be called again in some corner cases don't
         * do anything if NAPI was already initialized.
         */
-       if (!trans_pcie->napi.poll) {
+       if (trans_pcie->napi_dev.reg_state != NETREG_DUMMY)
                init_dummy_netdev(&trans_pcie->napi_dev);
-               netif_napi_add(&trans_pcie->napi_dev, &trans_pcie->napi,
-                              iwl_pcie_dummy_napi_poll, 64);
-       }
 }
 
 void iwl_trans_pcie_free(struct iwl_trans *trans)
@@ -1476,6 +1473,9 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int i;
 
+       /* TODO: check if this is really needed */
+       pm_runtime_disable(trans->dev);
+
        synchronize_irq(trans_pcie->pci_dev->irq);
 
        iwl_pcie_tx_free(trans);
@@ -1489,9 +1489,6 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
        pci_release_regions(trans_pcie->pci_dev);
        pci_disable_device(trans_pcie->pci_dev);
 
-       if (trans_pcie->napi.poll)
-               netif_napi_del(&trans_pcie->napi);
-
        iwl_pcie_free_fw_monitor(trans);
 
        for_each_possible_cpu(i) {
@@ -1831,6 +1828,7 @@ void iwl_trans_pcie_ref(struct iwl_trans *trans)
        spin_lock_irqsave(&trans_pcie->ref_lock, flags);
        IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
        trans_pcie->ref_count++;
+       pm_runtime_get(&trans_pcie->pci_dev->dev);
        spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
 }
 
@@ -1849,6 +1847,10 @@ void iwl_trans_pcie_unref(struct iwl_trans *trans)
                return;
        }
        trans_pcie->ref_count--;
+
+       pm_runtime_mark_last_busy(&trans_pcie->pci_dev->dev);
+       pm_runtime_put_autosuspend(&trans_pcie->pci_dev->dev);
+
        spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
 }
 
@@ -2001,29 +2003,48 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
 {
        struct iwl_trans *trans = file->private_data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
-       char buf[256];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
-                                               rxq->read);
-       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
-                                               rxq->write);
-       pos += scnprintf(buf + pos, bufsz - pos, "write_actual: %u\n",
-                                               rxq->write_actual);
-       pos += scnprintf(buf + pos, bufsz - pos, "need_update: %d\n",
-                                               rxq->need_update);
-       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
-                                               rxq->free_count);
-       if (rxq->rb_stts) {
-               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
-                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
-       } else {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                       "closed_rb_num: Not Allocated\n");
+       char *buf;
+       int pos = 0, i, ret;
+       size_t bufsz = sizeof(buf);
+
+       bufsz = sizeof(char) * 121 * trans->num_rx_queues;
+
+       if (!trans_pcie->rxq)
+               return -EAGAIN;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (i = 0; i < trans->num_rx_queues && pos < bufsz; i++) {
+               struct iwl_rxq *rxq = &trans_pcie->rxq[i];
+
+               pos += scnprintf(buf + pos, bufsz - pos, "queue#: %2d\n",
+                                i);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tread: %u\n",
+                                rxq->read);
+               pos += scnprintf(buf + pos, bufsz - pos, "\twrite: %u\n",
+                                rxq->write);
+               pos += scnprintf(buf + pos, bufsz - pos, "\twrite_actual: %u\n",
+                                rxq->write_actual);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tneed_update: %2d\n",
+                                rxq->need_update);
+               pos += scnprintf(buf + pos, bufsz - pos, "\tfree_count: %u\n",
+                                rxq->free_count);
+               if (rxq->rb_stts) {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                        "\tclosed_rb_num: %u\n",
+                                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &
+                                        0x0FFF);
+               } else {
+                       pos += scnprintf(buf + pos, bufsz - pos,
+                                        "\tclosed_rb_num: Not Allocated\n");
+       }
        }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+
+       return ret;
 }
 
 static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
@@ -2188,7 +2209,8 @@ static u32 iwl_trans_pcie_dump_rbs(struct iwl_trans *trans,
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
-       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       /* Dump RBs is supported only for pre-9000 devices (1 queue) */
+       struct iwl_rxq *rxq = &trans_pcie->rxq[0];
        u32 i, r, j, rb_len = 0;
 
        spin_lock(&rxq->lock);
@@ -2383,7 +2405,8 @@ static struct iwl_trans_dump_data
        u32 len, num_rbs;
        u32 monitor_len;
        int i, ptr;
-       bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status);
+       bool dump_rbs = test_bit(STATUS_FW_ERROR, &trans->status) &&
+                       !trans->cfg->mq_rx_supported;
 
        /* transport dump header */
        len = sizeof(*dump_data);
@@ -2438,11 +2461,12 @@ static struct iwl_trans_dump_data
        len += sizeof(*data) + (FH_MEM_UPPER_BOUND - FH_MEM_LOWER_BOUND);
 
        if (dump_rbs) {
+               /* Dump RBs is supported only for pre-9000 devices (1 queue) */
+               struct iwl_rxq *rxq = &trans_pcie->rxq[0];
                /* RBs */
-               num_rbs = le16_to_cpu(ACCESS_ONCE(
-                                     trans_pcie->rxq.rb_stts->closed_rb_num))
+               num_rbs = le16_to_cpu(ACCESS_ONCE(rxq->rb_stts->closed_rb_num))
                                      & 0x0FFF;
-               num_rbs = (num_rbs - trans_pcie->rxq.read) & RX_QUEUE_MASK;
+               num_rbs = (num_rbs - rxq->read) & RX_QUEUE_MASK;
                len += num_rbs * (sizeof(*data) +
                                  sizeof(struct iwl_fw_error_dump_rb) +
                                  (PAGE_SIZE << trans_pcie->rx_page_order));
@@ -2493,6 +2517,22 @@ static struct iwl_trans_dump_data
        return dump_data;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
+{
+       if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+               return iwl_pci_fw_enter_d0i3(trans);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_resume(struct iwl_trans *trans)
+{
+       if (trans->runtime_pm_mode == IWL_PLAT_PM_MODE_D0I3)
+               iwl_pci_fw_exit_d0i3(trans);
+}
+#endif /* CONFIG_PM_SLEEP */
+
 static const struct iwl_trans_ops trans_ops_pcie = {
        .start_hw = iwl_trans_pcie_start_hw,
        .op_mode_leave = iwl_trans_pcie_op_mode_leave,
@@ -2503,6 +2543,11 @@ static const struct iwl_trans_ops trans_ops_pcie = {
        .d3_suspend = iwl_trans_pcie_d3_suspend,
        .d3_resume = iwl_trans_pcie_d3_resume,
 
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwl_trans_pcie_suspend,
+       .resume = iwl_trans_pcie_resume,
+#endif /* CONFIG_PM_SLEEP */
+
        .send_cmd = iwl_trans_pcie_send_hcmd,
 
        .tx = iwl_trans_pcie_tx,
@@ -2541,7 +2586,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        struct iwl_trans_pcie *trans_pcie;
        struct iwl_trans *trans;
        u16 pci_cmd;
-       int ret;
+       int ret, addr_size;
 
        trans = iwl_trans_alloc(sizeof(struct iwl_trans_pcie),
                                &pdev->dev, cfg, &trans_ops_pcie, 0);
@@ -2579,11 +2624,17 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                       PCIE_LINK_STATE_CLKPM);
        }
 
+       if (cfg->mq_rx_supported)
+               addr_size = 64;
+       else
+               addr_size = 36;
+
        pci_set_master(pdev);
 
-       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(36));
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(addr_size));
        if (!ret)
-               ret = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(36));
+               ret = pci_set_consistent_dma_mask(pdev,
+                                                 DMA_BIT_MASK(addr_size));
        if (ret) {
                ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
                if (!ret)
@@ -2686,6 +2737,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        /* Initialize the wait queue for commands */
        init_waitqueue_head(&trans_pcie->wait_command_queue);
 
+       init_waitqueue_head(&trans_pcie->d0i3_waitq);
+
        ret = iwl_pcie_alloc_ict(trans);
        if (ret)
                goto out_pci_disable_msi;
@@ -2700,6 +2753,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
 
        trans_pcie->inta_mask = CSR_INI_SET_MASK;
 
+#ifdef CONFIG_IWLWIFI_PCIE_RTPM
+       trans->runtime_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+#else
+       trans->runtime_pm_mode = IWL_PLAT_PM_MODE_DISABLED;
+#endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
        return trans;
 
 out_free_ict:
index 5262028..837a7d5 100644 (file)
@@ -1,7 +1,8 @@
 /******************************************************************************
  *
  * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
- * Copyright(c) 2013 - 2014 Intel Mobile Communications GmbH
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portions of the ieee80211 subsystem header files.
@@ -33,7 +34,6 @@
 #include <linux/sched.h>
 #include <net/ip6_checksum.h>
 #include <net/tso.h>
-#include <net/ip6_checksum.h>
 
 #include "iwl-debug.h"
 #include "iwl-csr.h"
@@ -571,6 +571,7 @@ static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
                return ret;
 
        spin_lock_init(&txq->lock);
+       __skb_queue_head_init(&txq->overflow_q);
 
        /*
         * Tell nic where to find circular buffer of Tx Frame Descriptors for
@@ -621,6 +622,13 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
                q->read_ptr = iwl_queue_inc_wrap(q->read_ptr);
        }
        txq->active = false;
+
+       while (!skb_queue_empty(&txq->overflow_q)) {
+               struct sk_buff *skb = __skb_dequeue(&txq->overflow_q);
+
+               iwl_op_mode_free_skb(trans->op_mode, skb);
+       }
+
        spin_unlock_bh(&txq->lock);
 
        /* just in case - this queue may have been stopped */
@@ -1052,8 +1060,41 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
 
        iwl_pcie_txq_progress(txq);
 
-       if (iwl_queue_space(&txq->q) > txq->q.low_mark)
-               iwl_wake_queue(trans, txq);
+       if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+           test_bit(txq_id, trans_pcie->queue_stopped)) {
+               struct sk_buff_head skbs;
+
+               __skb_queue_head_init(&skbs);
+               skb_queue_splice_init(&txq->overflow_q, &skbs);
+
+               /*
+                * This is tricky: we are in reclaim path which is non
+                * re-entrant, so noone will try to take the access the
+                * txq data from that path. We stopped tx, so we can't
+                * have tx as well. Bottom line, we can unlock and re-lock
+                * later.
+                */
+               spin_unlock_bh(&txq->lock);
+
+               while (!skb_queue_empty(&skbs)) {
+                       struct sk_buff *skb = __skb_dequeue(&skbs);
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+                       u8 dev_cmd_idx = IWL_TRANS_FIRST_DRIVER_DATA + 1;
+                       struct iwl_device_cmd *dev_cmd =
+                               info->driver_data[dev_cmd_idx];
+
+                       /*
+                        * Note that we can very well be overflowing again.
+                        * In that case, iwl_queue_space will be small again
+                        * and we won't wake mac80211's queue.
+                        */
+                       iwl_trans_pcie_tx(trans, skb, dev_cmd, txq_id);
+               }
+               spin_lock_bh(&txq->lock);
+
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+                       iwl_wake_queue(trans, txq);
+       }
 
        if (q->read_ptr == q->write_ptr) {
                IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
@@ -1686,6 +1727,20 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
                wake_up(&trans_pcie->wait_command_queue);
        }
 
+       if (meta->flags & CMD_MAKE_TRANS_IDLE) {
+               IWL_DEBUG_INFO(trans, "complete %s - mark trans as idle\n",
+                              iwl_get_cmd_string(trans, cmd->hdr.cmd));
+               set_bit(STATUS_TRANS_IDLE, &trans->status);
+               wake_up(&trans_pcie->d0i3_waitq);
+       }
+
+       if (meta->flags & CMD_WAKE_UP_TRANS) {
+               IWL_DEBUG_INFO(trans, "complete %s - clear trans idle flag\n",
+                              iwl_get_cmd_string(trans, cmd->hdr.cmd));
+               clear_bit(STATUS_TRANS_IDLE, &trans->status);
+               wake_up(&trans_pcie->d0i3_waitq);
+       }
+
        meta->flags = 0;
 
        spin_unlock_bh(&txq->lock);
@@ -2161,6 +2216,8 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
                csum = skb_checksum(skb, offs, skb->len - offs, 0);
                *(__sum16 *)(skb->data + csum_offs) = csum_fold(csum);
+
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
        }
 
        if (skb_is_nonlinear(skb) &&
@@ -2177,6 +2234,22 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
 
        spin_lock(&txq->lock);
 
+       if (iwl_queue_space(q) < q->high_mark) {
+               iwl_stop_queue(trans, txq);
+
+               /* don't put the packet on the ring, if there is no room */
+               if (unlikely(iwl_queue_space(q) < 3)) {
+                       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+                       info->driver_data[IWL_TRANS_FIRST_DRIVER_DATA + 1] =
+                               dev_cmd;
+                       __skb_queue_tail(&txq->overflow_q, skb);
+
+                       spin_unlock(&txq->lock);
+                       return 0;
+               }
+       }
+
        /* In AGG mode, the index in the ring must correspond to the WiFi
         * sequence number. This is a HW requirements to help the SCD to parse
         * the BA.
@@ -2281,12 +2354,6 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
         * At this point the frame is "transmitted" successfully
         * and we will get a TX status notification eventually.
         */
-       if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr)
-                       iwl_pcie_txq_inc_wr_ptr(trans, txq);
-               else
-                       iwl_stop_queue(trans, txq);
-       }
        spin_unlock(&txq->lock);
        return 0;
 out_err:
index 6df3ee5..515aa3f 100644 (file)
@@ -836,25 +836,30 @@ static int hfa384x_get_rid(struct net_device *dev, u16 rid, void *buf, int len,
        spin_lock_bh(&local->baplock);
 
        res = hfa384x_setup_bap(dev, BAP0, rid, 0);
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
+
+       res = hfa384x_from_bap(dev, BAP0, &rec, sizeof(rec));
+       if (res)
+               goto unlock;
 
        if (le16_to_cpu(rec.len) == 0) {
                /* RID not available */
                res = -ENODATA;
+               goto unlock;
        }
 
        rlen = (le16_to_cpu(rec.len) - 1) * 2;
-       if (!res && exact_len && rlen != len) {
+       if (exact_len && rlen != len) {
                printk(KERN_DEBUG "%s: hfa384x_get_rid - RID len mismatch: "
                       "rid=0x%04x, len=%d (expected %d)\n",
                       dev->name, rid, rlen, len);
                res = -ENODATA;
        }
 
-       if (!res)
-               res = hfa384x_from_bap(dev, BAP0, buf, len);
+       res = hfa384x_from_bap(dev, BAP0, buf, len);
 
+unlock:
        spin_unlock_bh(&local->baplock);
        mutex_unlock(&local->rid_bap_mtx);
 
index 86955c4..2eea76a 100644 (file)
@@ -2039,6 +2039,43 @@ static int lbs_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
 
 
 
+int lbs_set_power_mgmt(struct wiphy *wiphy, struct net_device *dev,
+                      bool enabled, int timeout)
+{
+       struct lbs_private *priv = wiphy_priv(wiphy);
+
+       if  (!(priv->fwcapinfo & FW_CAPINFO_PS)) {
+               if (!enabled)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       /* firmware does not work well with too long latency with power saving
+        * enabled, so do not enable it if there is only polling, no
+        * interrupts (like in some sdio hosts which can only
+        * poll for sdio irqs)
+        */
+       if  (priv->is_polling) {
+               if (!enabled)
+                       return 0;
+               else
+                       return -EINVAL;
+       }
+       if (!enabled) {
+               priv->psmode = LBS802_11POWERMODECAM;
+               if (priv->psstate != PS_STATE_FULL_POWER)
+                       lbs_set_ps_mode(priv,
+                                       PS_MODE_ACTION_EXIT_PS,
+                                       true);
+               return 0;
+       }
+       if (priv->psmode != LBS802_11POWERMODECAM)
+               return 0;
+       priv->psmode = LBS802_11POWERMODEMAX_PSP;
+       if (priv->connect_status == LBS_CONNECTED)
+               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS, true);
+       return 0;
+}
 
 /*
  * Initialization
@@ -2057,6 +2094,7 @@ static struct cfg80211_ops lbs_cfg80211_ops = {
        .change_virtual_intf = lbs_change_intf,
        .join_ibss = lbs_join_ibss,
        .leave_ibss = lbs_leave_ibss,
+       .set_power_mgmt = lbs_set_power_mgmt,
 };
 
 
index 0387a5b..4ddd0e5 100644 (file)
@@ -957,7 +957,7 @@ static void lbs_queue_cmd(struct lbs_private *priv,
 
        /* Exit_PS command needs to be queued in the header always. */
        if (le16_to_cpu(cmdnode->cmdbuf->command) == CMD_802_11_PS_MODE) {
-               struct cmd_ds_802_11_ps_mode *psm = (void *) &cmdnode->cmdbuf;
+               struct cmd_ds_802_11_ps_mode *psm = (void *)cmdnode->cmdbuf;
 
                if (psm->action == cpu_to_le16(PS_MODE_ACTION_EXIT_PS)) {
                        if (priv->psstate != PS_STATE_FULL_POWER)
@@ -1387,7 +1387,7 @@ int lbs_execute_next_command(struct lbs_private *priv)
                                 * PS command. Ignore it if it is not Exit_PS.
                                 * otherwise send it down immediately.
                                 */
-                               struct cmd_ds_802_11_ps_mode *psm = (void *)&cmd[1];
+                               struct cmd_ds_802_11_ps_mode *psm = (void *)cmd;
 
                                lbs_deb_host(
                                       "EXEC_NEXT_CMD: PS cmd, action 0x%02x\n",
@@ -1428,40 +1428,14 @@ int lbs_execute_next_command(struct lbs_private *priv)
                 * check if in power save mode, if yes, put the device back
                 * to PS mode
                 */
-#ifdef TODO
-               /*
-                * This was the old code for libertas+wext. Someone that
-                * understands this beast should re-code it in a sane way.
-                *
-                * I actually don't understand why this is related to WPA
-                * and to connection status, shouldn't powering should be
-                * independ of such things?
-                */
                if ((priv->psmode != LBS802_11POWERMODECAM) &&
                    (priv->psstate == PS_STATE_FULL_POWER) &&
-                   ((priv->connect_status == LBS_CONNECTED) ||
-                   lbs_mesh_connected(priv))) {
-                       if (priv->secinfo.WPAenabled ||
-                           priv->secinfo.WPA2enabled) {
-                               /* check for valid WPA group keys */
-                               if (priv->wpa_mcast_key.len ||
-                                   priv->wpa_unicast_key.len) {
-                                       lbs_deb_host(
-                                              "EXEC_NEXT_CMD: WPA enabled and GTK_SET"
-                                              " go back to PS_SLEEP");
-                                       lbs_set_ps_mode(priv,
-                                                       PS_MODE_ACTION_ENTER_PS,
-                                                       false);
-                               }
-                       } else {
-                               lbs_deb_host(
-                                      "EXEC_NEXT_CMD: cmdpendingq empty, "
-                                      "go back to PS_SLEEP");
-                               lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
-                                               false);
-                       }
+                   (priv->connect_status == LBS_CONNECTED)) {
+                       lbs_deb_host(
+                               "EXEC_NEXT_CMD: cmdpendingq empty, go back to PS_SLEEP");
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_ENTER_PS,
+                                       false);
                }
-#endif
        }
 
        ret = 0;
index e5442e8..c95bf6d 100644 (file)
@@ -123,7 +123,10 @@ int lbs_process_command_response(struct lbs_private *priv, u8 *data, u32 len)
        priv->cmd_timed_out = 0;
 
        if (respcmd == CMD_RET(CMD_802_11_PS_MODE)) {
-               struct cmd_ds_802_11_ps_mode *psmode = (void *) &resp[1];
+               /* struct cmd_ds_802_11_ps_mode also contains
+                * the header
+                */
+               struct cmd_ds_802_11_ps_mode *psmode = (void *)resp;
                u16 action = le16_to_cpu(psmode->action);
 
                lbs_deb_host(
@@ -254,6 +257,10 @@ int lbs_process_event(struct lbs_private *priv, u32 event)
                               "EVENT: in FULL POWER mode, ignoring PS_SLEEP\n");
                        break;
                }
+               if (!list_empty(&priv->cmdpendingq)) {
+                       lbs_deb_cmd("EVENT: commands in queue, do not sleep\n");
+                       break;
+               }
                priv->psstate = PS_STATE_PRE_SLEEP;
 
                lbs_ps_confirm_sleep(priv);
index 6bd1608..edf710b 100644 (file)
@@ -99,6 +99,7 @@ struct lbs_private {
        /* Hardware access */
        void *card;
        bool iface_running;
+       u8 is_polling; /* host has to poll the card irq */
        u8 fw_ready;
        u8 surpriseremoved;
        u8 setup_fw_on_resume;
index 68fd3a9..13eae9f 100644 (file)
@@ -1267,7 +1267,7 @@ static int if_sdio_probe(struct sdio_func *func,
        priv->reset_card = if_sdio_reset_card;
        priv->power_save = if_sdio_power_save;
        priv->power_restore = if_sdio_power_restore;
-
+       priv->is_polling = !(func->card->host->caps & MMC_CAP_SDIO_IRQ);
        ret = if_sdio_power_on(card);
        if (ret)
                goto err_activate_card;
index dff08a2..aba0c99 100644 (file)
@@ -267,6 +267,7 @@ static int if_usb_probe(struct usb_interface *intf,
        priv->enter_deep_sleep = NULL;
        priv->exit_deep_sleep = NULL;
        priv->reset_deep_sleep_wakeup = NULL;
+       priv->is_polling = false;
 #ifdef CONFIG_OLPC
        if (machine_is_olpc())
                priv->reset_card = if_usb_reset_olpc_card;
index 8079560..b35b8bc 100644 (file)
@@ -1060,7 +1060,12 @@ void lbs_remove_card(struct lbs_private *priv)
 
        if (priv->psmode == LBS802_11POWERMODEMAX_PSP) {
                priv->psmode = LBS802_11POWERMODECAM;
-               lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
+               /* no need to wakeup if already woken up,
+                * on suspend, this exit ps command is not processed
+                * the driver hangs
+                */
+               if (priv->psstate != PS_STATE_FULL_POWER)
+                       lbs_set_ps_mode(priv, PS_MODE_ACTION_EXIT_PS, true);
        }
 
        if (priv->is_deep_sleep) {
index 2f0f9b5..24e649b 100644 (file)
@@ -237,4 +237,14 @@ device_dump
 
        cat fw_dump
 
+verext
+       This command is used to get extended firmware version string using
+       different configuration parameters.
+
+       Usage:
+               echo "[version_str_sel]" > verext
+               cat verext
+
+               [version_str_sel]: firmware support several extend version
+                                  string cases, include 0/1/10/20/21/99
 ===============================================================================
index e7adef7..f2dce81 100644 (file)
@@ -1962,6 +1962,9 @@ mwifiex_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev,
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        if (mwifiex_deauthenticate(priv, NULL))
                return -EFAULT;
 
@@ -2217,6 +2220,9 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
                    "info: Trying to associate to %s and bssid %pM\n",
                    (char *)sme->ssid, sme->bssid);
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        ret = mwifiex_cfg80211_assoc(priv, sme->ssid_len, sme->ssid, sme->bssid,
                                     priv->bss_mode, sme->channel, sme, 0);
        if (!ret) {
@@ -2420,6 +2426,9 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
                return -EBUSY;
        }
 
+       if (!mwifiex_stop_bg_scan(priv))
+               cfg80211_sched_scan_stopped_rtnl(priv->wdev.wiphy);
+
        user_scan_cfg = kzalloc(sizeof(*user_scan_cfg), GFP_KERNEL);
        if (!user_scan_cfg)
                return -ENOMEM;
@@ -2487,6 +2496,125 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy,
        return 0;
 }
 
+/* CFG802.11 operation handler for sched_scan_start.
+ *
+ * This function issues a bgscan config request to the firmware based upon
+ * the user specified sched_scan configuration. On successful completion,
+ * firmware will generate BGSCAN_REPORT event, driver should issue bgscan
+ * query command to get sched_scan results from firmware.
+ */
+static int
+mwifiex_cfg80211_sched_scan_start(struct wiphy *wiphy,
+                                 struct net_device *dev,
+                                 struct cfg80211_sched_scan_request *request)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+       int i, offset;
+       struct ieee80211_channel *chan;
+       struct mwifiex_bg_scan_cfg *bgscan_cfg;
+       struct ieee_types_header *ie;
+
+       if (!request || (!request->n_ssids && !request->n_match_sets)) {
+               wiphy_err(wiphy, "%s : Invalid Sched_scan parameters",
+                         __func__);
+               return -EINVAL;
+       }
+
+       wiphy_info(wiphy, "sched_scan start : n_ssids=%d n_match_sets=%d ",
+                  request->n_ssids, request->n_match_sets);
+       wiphy_info(wiphy, "n_channels=%d interval=%d ie_len=%d\n",
+                  request->n_channels, request->scan_plans->interval,
+                  (int)request->ie_len);
+
+       bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
+       if (!bgscan_cfg)
+               return -ENOMEM;
+
+       if (priv->scan_request || priv->scan_aborting)
+               bgscan_cfg->start_later = true;
+
+       bgscan_cfg->num_ssids = request->n_match_sets;
+       bgscan_cfg->ssid_list = request->match_sets;
+
+       if (request->ie && request->ie_len) {
+               offset = 0;
+               for (i = 0; i < MWIFIEX_MAX_VSIE_NUM; i++) {
+                       if (priv->vs_ie[i].mask != MWIFIEX_VSIE_MASK_CLEAR)
+                               continue;
+                       priv->vs_ie[i].mask = MWIFIEX_VSIE_MASK_BGSCAN;
+                       ie = (struct ieee_types_header *)(request->ie + offset);
+                       memcpy(&priv->vs_ie[i].ie, ie, sizeof(*ie) + ie->len);
+                       offset += sizeof(*ie) + ie->len;
+
+                       if (offset >= request->ie_len)
+                               break;
+               }
+       }
+
+       for (i = 0; i < min_t(u32, request->n_channels,
+                             MWIFIEX_BG_SCAN_CHAN_MAX); i++) {
+               chan = request->channels[i];
+               bgscan_cfg->chan_list[i].chan_number = chan->hw_value;
+               bgscan_cfg->chan_list[i].radio_type = chan->band;
+
+               if ((chan->flags & IEEE80211_CHAN_NO_IR) || !request->n_ssids)
+                       bgscan_cfg->chan_list[i].scan_type =
+                                               MWIFIEX_SCAN_TYPE_PASSIVE;
+               else
+                       bgscan_cfg->chan_list[i].scan_type =
+                                               MWIFIEX_SCAN_TYPE_ACTIVE;
+
+               bgscan_cfg->chan_list[i].scan_time = 0;
+       }
+
+       bgscan_cfg->chan_per_scan = min_t(u32, request->n_channels,
+                                         MWIFIEX_BG_SCAN_CHAN_MAX);
+
+       /* Use at least 15 second for per scan cycle */
+       bgscan_cfg->scan_interval = (request->scan_plans->interval >
+                                    MWIFIEX_BGSCAN_INTERVAL) ?
+                               request->scan_plans->interval :
+                               MWIFIEX_BGSCAN_INTERVAL;
+
+       bgscan_cfg->repeat_count = MWIFIEX_BGSCAN_REPEAT_COUNT;
+       bgscan_cfg->report_condition = MWIFIEX_BGSCAN_SSID_MATCH |
+                               MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE;
+       bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
+       bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
+       bgscan_cfg->enable = true;
+       if (request->min_rssi_thold != NL80211_SCAN_RSSI_THOLD_OFF) {
+               bgscan_cfg->report_condition |= MWIFIEX_BGSCAN_SSID_RSSI_MATCH;
+               bgscan_cfg->rssi_threshold = request->min_rssi_thold;
+       }
+
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                            HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
+               kfree(bgscan_cfg);
+               return -EFAULT;
+       }
+
+       priv->sched_scanning = true;
+
+       kfree(bgscan_cfg);
+       return 0;
+}
+
+/* CFG802.11 operation handler for sched_scan_stop.
+ *
+ * This function issues a bgscan config command to disable
+ * previous bgscan configuration in the firmware
+ */
+static int mwifiex_cfg80211_sched_scan_stop(struct wiphy *wiphy,
+                                           struct net_device *dev)
+{
+       struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+       wiphy_info(wiphy, "sched scan stop!");
+       mwifiex_stop_bg_scan(priv);
+
+       return 0;
+}
+
 static void mwifiex_setup_vht_caps(struct ieee80211_sta_vht_cap *vht_info,
                                   struct mwifiex_private *priv)
 {
@@ -2848,6 +2976,9 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
        mwifiex_dev_debugfs_remove(priv);
 #endif
 
+       if (priv->sched_scanning)
+               priv->sched_scanning = false;
+
        mwifiex_stop_net_dev_queue(priv->netdev, adapter);
 
        skb_queue_walk_safe(&priv->bypass_txq, skb, tmp)
@@ -3044,10 +3175,12 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
                                sizeof(byte_seq));
                mef_entry->filter[filt_num].filt_type = TYPE_EQ;
 
-               if (first_pat)
+               if (first_pat) {
                        first_pat = false;
-               else
+                       mwifiex_dbg(priv->adapter, INFO, "Wake on patterns\n");
+               } else {
                        mef_entry->filter[filt_num].filt_action = TYPE_AND;
+               }
 
                filt_num++;
        }
@@ -3073,6 +3206,7 @@ static int mwifiex_set_wowlan_mef_entry(struct mwifiex_private *priv,
                mef_entry->filter[filt_num].offset = 56;
                mef_entry->filter[filt_num].filt_type = TYPE_EQ;
                mef_entry->filter[filt_num].filt_action = TYPE_OR;
+               mwifiex_dbg(priv->adapter, INFO, "Wake on magic packet\n");
        }
        return ret;
 }
@@ -3143,7 +3277,7 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
 
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
 
-       if (!priv->media_connected) {
+       if (!priv->media_connected && !wowlan->nd_config) {
                mwifiex_dbg(adapter, ERROR,
                            "Can not configure WOWLAN in disconnected state\n");
                return 0;
@@ -3155,19 +3289,30 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
                return ret;
        }
 
+       memset(&hs_cfg, 0, sizeof(hs_cfg));
+       hs_cfg.conditions = le32_to_cpu(adapter->hs_cfg.conditions);
+
+       if (wowlan->nd_config) {
+               mwifiex_dbg(adapter, INFO, "Wake on net detect\n");
+               hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
+               mwifiex_cfg80211_sched_scan_start(wiphy, priv->netdev,
+                                                 wowlan->nd_config);
+       }
+
        if (wowlan->disconnect) {
-               memset(&hs_cfg, 0, sizeof(hs_cfg));
-               hs_cfg.is_invoke_hostcmd = false;
-               hs_cfg.conditions = HS_CFG_COND_MAC_EVENT;
-               hs_cfg.gpio = adapter->hs_cfg.gpio;
-               hs_cfg.gap = adapter->hs_cfg.gap;
-               ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
-                                           MWIFIEX_SYNC_CMD, &hs_cfg);
-               if (ret) {
-                       mwifiex_dbg(adapter, ERROR,
-                                   "Failed to set HS params\n");
-                       return ret;
-               }
+               hs_cfg.conditions |= HS_CFG_COND_MAC_EVENT;
+               mwifiex_dbg(priv->adapter, INFO, "Wake on device disconnect\n");
+       }
+
+       hs_cfg.is_invoke_hostcmd = false;
+       hs_cfg.gpio = adapter->hs_cfg.gpio;
+       hs_cfg.gap = adapter->hs_cfg.gap;
+       ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+                                   MWIFIEX_SYNC_CMD, &hs_cfg);
+       if (ret) {
+               mwifiex_dbg(adapter, ERROR,
+                           "Failed to set HS params\n");
+               return ret;
        }
 
        return ret;
@@ -3175,6 +3320,64 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
 
 static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
 {
+       struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+       struct mwifiex_private *priv =
+               mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+       struct mwifiex_ds_wakeup_reason wakeup_reason;
+       struct cfg80211_wowlan_wakeup wakeup_report;
+       int i;
+
+       mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD,
+                                 &wakeup_reason);
+       memset(&wakeup_report, 0, sizeof(struct cfg80211_wowlan_wakeup));
+
+       wakeup_report.pattern_idx = -1;
+
+       switch (wakeup_reason.hs_wakeup_reason) {
+       case NO_HSWAKEUP_REASON:
+               break;
+       case BCAST_DATA_MATCHED:
+               break;
+       case MCAST_DATA_MATCHED:
+               break;
+       case UCAST_DATA_MATCHED:
+               break;
+       case MASKTABLE_EVENT_MATCHED:
+               break;
+       case NON_MASKABLE_EVENT_MATCHED:
+               if (wiphy->wowlan_config->disconnect)
+                       wakeup_report.disconnect = true;
+               if (wiphy->wowlan_config->nd_config)
+                       wakeup_report.net_detect = adapter->nd_info;
+               break;
+       case NON_MASKABLE_CONDITION_MATCHED:
+               break;
+       case MAGIC_PATTERN_MATCHED:
+               if (wiphy->wowlan_config->magic_pkt)
+                       wakeup_report.magic_pkt = true;
+               if (wiphy->wowlan_config->n_patterns)
+                       wakeup_report.pattern_idx = 1;
+               break;
+       case CONTROL_FRAME_MATCHED:
+               break;
+       case    MANAGEMENT_FRAME_MATCHED:
+               break;
+       default:
+               break;
+       }
+
+       if ((wakeup_reason.hs_wakeup_reason > 0) &&
+           (wakeup_reason.hs_wakeup_reason <= 7))
+               cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report,
+                                             GFP_KERNEL);
+
+       if (adapter->nd_info) {
+               for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
+                       kfree(adapter->nd_info->matches[i]);
+               kfree(adapter->nd_info);
+               adapter->nd_info = NULL;
+       }
+
        return 0;
 }
 
@@ -3590,8 +3793,8 @@ static int mwifiex_cfg80211_get_channel(struct wiphy *wiphy,
                freq = ieee80211_channel_to_frequency(curr_bss->channel, band);
                chan = ieee80211_get_channel(wiphy, freq);
 
-               if (curr_bss->bcn_ht_oper) {
-                       second_chan_offset = curr_bss->bcn_ht_oper->ht_param &
+               if (priv->ht_param_present) {
+                       second_chan_offset = priv->assoc_resp_ht_param &
                                        IEEE80211_HT_PARAM_CHA_SEC_OFFSET;
                        chan_type = mwifiex_sec_chan_offset_to_chan_type
                                                        (second_chan_offset);
@@ -3701,6 +3904,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
        .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
        .set_antenna = mwifiex_cfg80211_set_antenna,
        .del_station = mwifiex_cfg80211_del_station,
+       .sched_scan_start = mwifiex_cfg80211_sched_scan_start,
+       .sched_scan_stop = mwifiex_cfg80211_sched_scan_stop,
 #ifdef CONFIG_PM
        .suspend = mwifiex_cfg80211_suspend,
        .resume = mwifiex_cfg80211_resume,
@@ -3720,11 +3925,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
 
 #ifdef CONFIG_PM
 static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
-       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+       .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT |
+               WIPHY_WOWLAN_NET_DETECT,
        .n_patterns = MWIFIEX_MEF_MAX_FILTERS,
        .pattern_min_len = 1,
        .pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
        .max_pkt_offset = MWIFIEX_MAX_OFFSET_LEN,
+       .max_nd_match_sets = MWIFIEX_MAX_ND_MATCH_SETS,
 };
 #endif
 
@@ -3829,6 +4036,7 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
        wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
                        WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
                        WIPHY_FLAG_AP_UAPSD |
+                       WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                        WIPHY_FLAG_HAS_CHANNEL_SWITCH |
                        WIPHY_FLAG_PS_ON_BY_DEFAULT;
@@ -3847,6 +4055,10 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
                                    NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
 
+       wiphy->max_sched_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
+       wiphy->max_sched_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
+       wiphy->max_match_sets = MWIFIEX_MAX_SSID_LIST_LENGTH;
+
        wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1;
        wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1;
 
index cb25aa7..a12adee 100644 (file)
@@ -1657,3 +1657,16 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
 
        return 0;
 }
+
+/* This function handles the command response of hs wakeup reason
+ * command.
+ */
+int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv,
+                             struct host_cmd_ds_command *resp,
+                             struct host_cmd_ds_wakeup_reason *wakeup_reason)
+{
+       wakeup_reason->wakeup_reason =
+               resp->params.hs_wakeup_reason.wakeup_reason;
+
+       return 0;
+}
index 0b9c580..df28836 100644 (file)
@@ -95,8 +95,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
 
        mwifiex_drv_get_driver_version(priv->adapter, fmt, sizeof(fmt) - 1);
 
-       if (!priv->version_str[0])
-               mwifiex_get_ver_ext(priv);
+       mwifiex_get_ver_ext(priv, 0);
 
        p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
        p += sprintf(p, "driver_version = %s", fmt);
@@ -583,6 +582,52 @@ done:
        return ret;
 }
 
+/* debugfs verext file write handler.
+ * This function is called when the 'verext' file is opened for write
+ */
+static ssize_t
+mwifiex_verext_write(struct file *file, const char __user *ubuf,
+                    size_t count, loff_t *ppos)
+{
+       int ret;
+       u32 versionstrsel;
+       struct mwifiex_private *priv = (void *)file->private_data;
+       char buf[16];
+
+       memset(buf, 0, sizeof(buf));
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       ret = kstrtou32(buf, 10, &versionstrsel);
+       if (ret)
+               return ret;
+
+       priv->versionstrsel = versionstrsel;
+
+       return count;
+}
+
+/* Proc verext file read handler.
+ * This function is called when the 'verext' file is opened for reading
+ * This function can be used read driver exteneed verion string.
+ */
+static ssize_t
+mwifiex_verext_read(struct file *file, char __user *ubuf,
+                   size_t count, loff_t *ppos)
+{
+       struct mwifiex_private *priv =
+               (struct mwifiex_private *)file->private_data;
+       char buf[256];
+       int ret;
+
+       mwifiex_get_ver_ext(priv, priv->versionstrsel);
+       ret = snprintf(buf, sizeof(buf), "version string: %s\n",
+                      priv->version_str);
+
+       return simple_read_from_buffer(ubuf, count, ppos, buf, ret);
+}
+
 /* Proc memrw file write handler.
  * This function is called when the 'memrw' file is opened for writing
  * This function can be used to write to a memory location.
@@ -940,6 +985,7 @@ MWIFIEX_DFS_FILE_OPS(histogram);
 MWIFIEX_DFS_FILE_OPS(debug_mask);
 MWIFIEX_DFS_FILE_OPS(timeshare_coex);
 MWIFIEX_DFS_FILE_WRITE_OPS(reset);
+MWIFIEX_DFS_FILE_OPS(verext);
 
 /*
  * This function creates the debug FS directory structure and the files.
@@ -968,6 +1014,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
        MWIFIEX_DFS_ADD_FILE(debug_mask);
        MWIFIEX_DFS_ADD_FILE(timeshare_coex);
        MWIFIEX_DFS_ADD_FILE(reset);
+       MWIFIEX_DFS_ADD_FILE(verext);
 }
 
 /*
index d9c15cd..bec300b 100644 (file)
 #define BLOCK_NUMBER_OFFSET            15
 #define SDIO_HEADER_OFFSET             28
 
+#define MWIFIEX_SIZE_4K 0x4000
+
 enum mwifiex_bss_type {
        MWIFIEX_BSS_TYPE_STA = 0,
        MWIFIEX_BSS_TYPE_UAP = 1,
@@ -270,4 +272,26 @@ struct mwifiex_11h_intf_state {
        bool is_11h_enabled;
        bool is_11h_active;
 } __packed;
+
+#define MWIFIEX_FW_DUMP_IDX            0xff
+#define MWIFIEX_FW_DUMP_MAX_MEMSIZE     0x160000
+#define MWIFIEX_DRV_INFO_IDX           20
+#define FW_DUMP_MAX_NAME_LEN           8
+#define FW_DUMP_HOST_READY      0xEE
+#define FW_DUMP_DONE                   0xFF
+#define FW_DUMP_READ_DONE              0xFE
+
+struct memory_type_mapping {
+       u8 mem_name[FW_DUMP_MAX_NAME_LEN];
+       u8 *mem_ptr;
+       u32 mem_size;
+       u8 done_flag;
+};
+
+enum rdwr_status {
+       RDWR_STATUS_SUCCESS = 0,
+       RDWR_STATUS_FAILURE = 1,
+       RDWR_STATUS_DONE = 2
+};
+
 #endif /* !_MWIFIEX_DECL_H_ */
index ced7af2..c134cf8 100644 (file)
@@ -96,7 +96,7 @@ enum KEY_TYPE_ID {
 #define WAPI_KEY_LEN                   (WLAN_KEY_LEN_SMS4 + PN_LEN + 2)
 
 #define MAX_POLL_TRIES                 100
-#define MAX_FIRMWARE_POLL_TRIES                        100
+#define MAX_FIRMWARE_POLL_TRIES                        150
 
 #define FIRMWARE_READY_SDIO                            0xfedc
 #define FIRMWARE_READY_PCIE                            0xfedcba00
@@ -144,6 +144,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_WILDCARDSSID       (PROPRIETARY_TLV_BASE_ID + 18)
 #define TLV_TYPE_TSFTIMESTAMP       (PROPRIETARY_TLV_BASE_ID + 19)
 #define TLV_TYPE_RSSI_HIGH          (PROPRIETARY_TLV_BASE_ID + 22)
+#define TLV_TYPE_BGSCAN_START_LATER (PROPRIETARY_TLV_BASE_ID + 30)
 #define TLV_TYPE_AUTH_TYPE          (PROPRIETARY_TLV_BASE_ID + 31)
 #define TLV_TYPE_STA_MAC_ADDR       (PROPRIETARY_TLV_BASE_ID + 32)
 #define TLV_TYPE_BSSID              (PROPRIETARY_TLV_BASE_ID + 35)
@@ -177,6 +178,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define TLV_TYPE_TX_PAUSE           (PROPRIETARY_TLV_BASE_ID + 148)
 #define TLV_TYPE_COALESCE_RULE      (PROPRIETARY_TLV_BASE_ID + 154)
 #define TLV_TYPE_KEY_PARAM_V2       (PROPRIETARY_TLV_BASE_ID + 156)
+#define TLV_TYPE_REPEAT_COUNT       (PROPRIETARY_TLV_BASE_ID + 176)
 #define TLV_TYPE_MULTI_CHAN_INFO    (PROPRIETARY_TLV_BASE_ID + 183)
 #define TLV_TYPE_MC_GROUP_INFO      (PROPRIETARY_TLV_BASE_ID + 184)
 #define TLV_TYPE_TDLS_IDLE_TIMEOUT  (PROPRIETARY_TLV_BASE_ID + 194)
@@ -331,6 +333,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_802_11_MAC_ADDRESS                0x004D
 #define HostCmd_CMD_802_11D_DOMAIN_INFO               0x005b
 #define HostCmd_CMD_802_11_KEY_MATERIAL               0x005e
+#define HostCmd_CMD_802_11_BG_SCAN_CONFIG             0x006b
 #define HostCmd_CMD_802_11_BG_SCAN_QUERY              0x006c
 #define HostCmd_CMD_WMM_GET_STATUS                    0x0071
 #define HostCmd_CMD_802_11_SUBSCRIBE_EVENT            0x0075
@@ -370,6 +373,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
 #define HostCmd_CMD_MGMT_FRAME_REG                    0x010c
 #define HostCmd_CMD_REMAIN_ON_CHAN                    0x010d
 #define HostCmd_CMD_11AC_CFG                         0x0112
+#define HostCmd_CMD_HS_WAKEUP_REASON                  0x0116
 #define HostCmd_CMD_TDLS_CONFIG                       0x0100
 #define HostCmd_CMD_MC_POLICY                         0x0121
 #define HostCmd_CMD_TDLS_OPER                         0x0122
@@ -523,6 +527,7 @@ enum P2P_MODES {
 #define EVENT_CHANNEL_REPORT_RDY        0x00000054
 #define EVENT_TX_DATA_PAUSE             0x00000055
 #define EVENT_EXT_SCAN_REPORT           0x00000058
+#define EVENT_BG_SCAN_STOPPED           0x00000065
 #define EVENT_REMAIN_ON_CHAN_EXPIRED    0x0000005f
 #define EVENT_MULTI_CHAN_INFO           0x0000006a
 #define EVENT_TX_STATUS_REPORT         0x00000074
@@ -539,6 +544,8 @@ enum P2P_MODES {
 
 #define MWIFIEX_MAX_PATTERN_LEN                40
 #define MWIFIEX_MAX_OFFSET_LEN         100
+#define MWIFIEX_MAX_ND_MATCH_SETS      10
+
 #define STACK_NBYTES                   100
 #define TYPE_DNUM                      1
 #define TYPE_BYTESEQ                   2
@@ -601,6 +608,20 @@ struct mwifiex_ie_types_data {
 #define MWIFIEX_RXPD_FLAGS_TDLS_PACKET      0x01
 #define MWIFIEX_TXPD_FLAGS_REQ_TX_STATUS    0x20
 
+enum HS_WAKEUP_REASON {
+       NO_HSWAKEUP_REASON = 0,
+       BCAST_DATA_MATCHED,
+       MCAST_DATA_MATCHED,
+       UCAST_DATA_MATCHED,
+       MASKTABLE_EVENT_MATCHED,
+       NON_MASKABLE_EVENT_MATCHED,
+       NON_MASKABLE_CONDITION_MATCHED,
+       MAGIC_PATTERN_MATCHED,
+       CONTROL_FRAME_MATCHED,
+       MANAGEMENT_FRAME_MATCHED,
+       RESERVED
+};
+
 struct txpd {
        u8 bss_type;
        u8 bss_num;
@@ -733,6 +754,21 @@ struct mwifiex_ie_types_num_probes {
        __le16 num_probes;
 } __packed;
 
+struct mwifiex_ie_types_repeat_count {
+       struct mwifiex_ie_types_header header;
+       __le16 repeat_count;
+} __packed;
+
+struct mwifiex_ie_types_min_rssi_threshold {
+       struct mwifiex_ie_types_header header;
+       __le16 rssi_threshold;
+} __packed;
+
+struct mwifiex_ie_types_bgscan_start_later {
+       struct mwifiex_ie_types_header header;
+       __le16 start_later;
+} __packed;
+
 struct mwifiex_ie_types_scan_chan_gap {
        struct mwifiex_ie_types_header header;
        /* time gap in TUs to be used between two consecutive channels scan */
@@ -1027,7 +1063,7 @@ struct ieee_types_assoc_rsp {
        __le16 cap_info_bitmap;
        __le16 status_code;
        __le16 a_id;
-       u8 ie_buffer[1];
+       u8 ie_buffer[0];
 } __packed;
 
 struct host_cmd_ds_802_11_associate_rsp {
@@ -1425,6 +1461,36 @@ struct mwifiex_user_scan_cfg {
        u16 scan_chan_gap;
 } __packed;
 
+#define MWIFIEX_BG_SCAN_CHAN_MAX 38
+#define MWIFIEX_BSS_MODE_INFRA 1
+#define MWIFIEX_BGSCAN_ACT_GET     0x0000
+#define MWIFIEX_BGSCAN_ACT_SET     0x0001
+#define MWIFIEX_BGSCAN_ACT_SET_ALL 0xff01
+/** ssid match */
+#define MWIFIEX_BGSCAN_SSID_MATCH          0x0001
+/** ssid match and RSSI exceeded */
+#define MWIFIEX_BGSCAN_SSID_RSSI_MATCH     0x0004
+/**wait for all channel scan to complete to report scan result*/
+#define MWIFIEX_BGSCAN_WAIT_ALL_CHAN_DONE  0x80000000
+
+struct mwifiex_bg_scan_cfg {
+       u16 action;
+       u8 enable;
+       u8 bss_type;
+       u8 chan_per_scan;
+       u32 scan_interval;
+       u32 report_condition;
+       u8 num_probes;
+       u8 rssi_threshold;
+       u8 snr_threshold;
+       u16 repeat_count;
+       u16 start_later;
+       struct cfg80211_match_set *ssid_list;
+       u8 num_ssids;
+       struct mwifiex_user_scan_chan chan_list[MWIFIEX_BG_SCAN_CHAN_MAX];
+       u16 scan_chan_gap;
+} __packed;
+
 struct ie_body {
        u8 grp_key_oui[4];
        u8 ptk_cnt[2];
@@ -1470,6 +1536,20 @@ struct mwifiex_ie_types_bss_scan_info {
        __le64 tsf;
 } __packed;
 
+struct host_cmd_ds_802_11_bg_scan_config {
+       __le16 action;
+       u8 enable;
+       u8 bss_type;
+       u8 chan_per_scan;
+       u8 reserved;
+       __le16 reserved1;
+       __le32 scan_interval;
+       __le32 reserved2;
+       __le32 report_condition;
+       __le16 reserved3;
+       u8 tlv[0];
+} __packed;
+
 struct host_cmd_ds_802_11_bg_scan_query {
        u8 flush;
 } __packed;
@@ -2099,6 +2179,10 @@ struct host_cmd_ds_robust_coex {
        __le16 reserved;
 } __packed;
 
+struct host_cmd_ds_wakeup_reason {
+       u16  wakeup_reason;
+} __packed;
+
 struct host_cmd_ds_command {
        __le16 command;
        __le16 size;
@@ -2124,6 +2208,7 @@ struct host_cmd_ds_command {
                struct host_cmd_ds_802_11_scan scan;
                struct host_cmd_ds_802_11_scan_ext ext_scan;
                struct host_cmd_ds_802_11_scan_rsp scan_resp;
+               struct host_cmd_ds_802_11_bg_scan_config bg_scan_config;
                struct host_cmd_ds_802_11_bg_scan_query bg_scan_query;
                struct host_cmd_ds_802_11_bg_scan_query_rsp bg_scan_query_resp;
                struct host_cmd_ds_802_11_associate associate;
@@ -2170,6 +2255,7 @@ struct host_cmd_ds_command {
                struct host_cmd_sdio_sp_rx_aggr_cfg sdio_rx_aggr_cfg;
                struct host_cmd_ds_multi_chan_policy mc_policy;
                struct host_cmd_ds_robust_coex coex;
+               struct host_cmd_ds_wakeup_reason hs_wakeup_reason;
        } params;
 } __packed;
 
index 6f7876e..517653b 100644 (file)
@@ -741,8 +741,6 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
        u32 poll_num = 1;
 
        if (adapter->if_ops.check_fw_status) {
-               adapter->winner = 0;
-
                /* check if firmware is already running */
                ret = adapter->if_ops.check_fw_status(adapter, poll_num);
                if (!ret) {
@@ -750,13 +748,23 @@ int mwifiex_dnld_fw(struct mwifiex_adapter *adapter,
                                    "WLAN FW already running! Skip FW dnld\n");
                        return 0;
                }
+       }
+
+       /* check if we are the winner for downloading FW */
+       if (adapter->if_ops.check_winner_status) {
+               adapter->winner = 0;
+               ret = adapter->if_ops.check_winner_status(adapter);
 
                poll_num = MAX_FIRMWARE_POLL_TRIES;
+               if (ret) {
+                       mwifiex_dbg(adapter, MSG,
+                                   "WLAN read winner status failed!\n");
+                       return ret;
+               }
 
-               /* check if we are the winner for downloading FW */
                if (!adapter->winner) {
                        mwifiex_dbg(adapter, MSG,
-                                   "FW already running! Skip FW dnld\n");
+                                   "WLAN is not the winner! Skip FW dnld\n");
                        goto poll_fw;
                }
        }
index 4f0174c..14cfa37 100644 (file)
@@ -271,6 +271,10 @@ struct mwifiex_ds_hs_cfg {
        u32 gap;
 };
 
+struct mwifiex_ds_wakeup_reason {
+       u16  hs_wakeup_reason;
+};
+
 #define DEEP_SLEEP_ON  1
 #define DEEP_SLEEP_OFF 0
 #define DEEP_SLEEP_IDLE_TIME   100
@@ -414,6 +418,7 @@ struct mwifiex_ds_mef_cfg {
 #define MWIFIEX_VSIE_MASK_SCAN     0x01
 #define MWIFIEX_VSIE_MASK_ASSOC    0x02
 #define MWIFIEX_VSIE_MASK_ADHOC    0x04
+#define MWIFIEX_VSIE_MASK_BGSCAN   0x08
 
 enum {
        MWIFIEX_FUNC_INIT = 1,
index cc09a81..62211fc 100644 (file)
@@ -644,6 +644,8 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
        struct mwifiex_bssdescriptor *bss_desc;
        bool enable_data = true;
        u16 cap_info, status_code, aid;
+       const u8 *ie_ptr;
+       struct ieee80211_ht_operation *assoc_resp_ht_oper;
 
        assoc_rsp = (struct ieee_types_assoc_rsp *) &resp->params;
 
@@ -733,6 +735,19 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
                        = ((bss_desc->wmm_ie.qos_info_bitmap &
                                IEEE80211_WMM_IE_AP_QOSINFO_UAPSD) ? 1 : 0);
 
+       /* Store the bandwidth information from assoc response */
+       ie_ptr = cfg80211_find_ie(WLAN_EID_HT_OPERATION, assoc_rsp->ie_buffer,
+                                 priv->assoc_rsp_size
+                                 - sizeof(struct ieee_types_assoc_rsp));
+       if (ie_ptr) {
+               assoc_resp_ht_oper = (struct ieee80211_ht_operation *)(ie_ptr
+                                       + sizeof(struct ieee_types_header));
+               priv->assoc_resp_ht_param = assoc_resp_ht_oper->ht_param;
+               priv->ht_param_present = true;
+       } else {
+               priv->ht_param_present = false;
+       }
+
        mwifiex_dbg(priv->adapter, INFO,
                    "info: ASSOC_RESP: curr_pkt_filter is %#x\n",
                    priv->curr_pkt_filter);
index 79c16de..3cfa946 100644 (file)
@@ -132,6 +132,13 @@ static int mwifiex_unregister(struct mwifiex_adapter *adapter)
                }
        }
 
+       if (adapter->nd_info) {
+               for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
+                       kfree(adapter->nd_info->matches[i]);
+               kfree(adapter->nd_info);
+               adapter->nd_info = NULL;
+       }
+
        vfree(adapter->chan_stats);
        kfree(adapter);
        return 0;
@@ -746,6 +753,13 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
 
        mwifiex_queue_main_work(priv->adapter);
 
+       if (priv->sched_scanning) {
+               mwifiex_dbg(priv->adapter, INFO,
+                           "aborting bgscan on ndo_stop\n");
+               mwifiex_stop_bg_scan(priv);
+               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+       }
+
        return 0;
 }
 
index 2f7f478..aea7aee 100644 (file)
@@ -198,6 +198,11 @@ do {                                                               \
                               buf, len, false);                \
 } while (0)
 
+/** Min BGSCAN interval 15 second */
+#define MWIFIEX_BGSCAN_INTERVAL 15000
+/** default repeat count */
+#define MWIFIEX_BGSCAN_REPEAT_COUNT 6
+
 struct mwifiex_dbg {
        u32 num_cmd_host_to_card_failure;
        u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -293,6 +298,7 @@ struct mwifiex_tid_tbl {
 #define WMM_HIGHEST_PRIORITY           7
 #define HIGH_PRIO_TID                          7
 #define LOW_PRIO_TID                           0
+#define MWIFIEX_WMM_DRV_DELAY_MAX 510
 
 struct mwifiex_wmm_desc {
        struct mwifiex_tid_tbl tid_tbl_ptr[MAX_NUM_TID];
@@ -483,26 +489,6 @@ struct mwifiex_roc_cfg {
        struct ieee80211_channel chan;
 };
 
-#define MWIFIEX_FW_DUMP_IDX            0xff
-#define MWIFIEX_DRV_INFO_IDX           20
-#define FW_DUMP_MAX_NAME_LEN           8
-#define FW_DUMP_HOST_READY             0xEE
-#define FW_DUMP_DONE                   0xFF
-#define FW_DUMP_READ_DONE              0xFE
-
-struct memory_type_mapping {
-       u8 mem_name[FW_DUMP_MAX_NAME_LEN];
-       u8 *mem_ptr;
-       u32 mem_size;
-       u8 done_flag;
-};
-
-enum rdwr_status {
-       RDWR_STATUS_SUCCESS = 0,
-       RDWR_STATUS_FAILURE = 1,
-       RDWR_STATUS_DONE = 2
-};
-
 enum mwifiex_iface_work_flags {
        MWIFIEX_IFACE_WORK_DEVICE_DUMP,
        MWIFIEX_IFACE_WORK_CARD_RESET,
@@ -616,6 +602,7 @@ struct mwifiex_private {
        spinlock_t curr_bcn_buf_lock;
        struct wireless_dev wdev;
        struct mwifiex_chan_freq_power cfp;
+       u32 versionstrsel;
        char version_str[128];
 #ifdef CONFIG_DEBUG_FS
        struct dentry *dfs_dev_dir;
@@ -640,6 +627,7 @@ struct mwifiex_private {
        u32 mgmt_frame_mask;
        struct mwifiex_roc_cfg roc_cfg;
        bool scan_aborting;
+       u8 sched_scanning;
        u8 csa_chan;
        unsigned long csa_expire_time;
        u8 del_list_idx;
@@ -667,6 +655,8 @@ struct mwifiex_private {
        struct mwifiex_ds_mem_rw mem_rw;
        struct sk_buff_head bypass_txq;
        struct mwifiex_user_scan_chan hidden_chan[MWIFIEX_USER_SCAN_CHAN_MAX];
+       u8 assoc_resp_ht_param;
+       bool ht_param_present;
 };
 
 
@@ -791,6 +781,7 @@ struct mwifiex_if_ops {
        int (*init_if) (struct mwifiex_adapter *);
        void (*cleanup_if) (struct mwifiex_adapter *);
        int (*check_fw_status) (struct mwifiex_adapter *, u32);
+       int (*check_winner_status)(struct mwifiex_adapter *);
        int (*prog_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
        int (*register_dev) (struct mwifiex_adapter *);
        void (*unregister_dev) (struct mwifiex_adapter *);
@@ -994,6 +985,7 @@ struct mwifiex_adapter {
        u8 active_scan_triggered;
        bool usb_mc_status;
        bool usb_mc_setup;
+       struct cfg80211_wowlan_nd_info *nd_info;
 };
 
 void mwifiex_process_tx_queue(struct mwifiex_adapter *adapter);
@@ -1196,6 +1188,10 @@ int mwifiex_ret_802_11_scan_ext(struct mwifiex_private *priv,
                                struct host_cmd_ds_command *resp);
 int mwifiex_handle_event_ext_scan_report(struct mwifiex_private *priv,
                                         void *buf);
+int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
+                                     struct host_cmd_ds_command *cmd,
+                                     void *data_buf);
+int mwifiex_stop_bg_scan(struct mwifiex_private *priv);
 
 /*
  * This function checks if the queuing is RA based or not.
@@ -1417,7 +1413,7 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
 
 int mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len);
 
-int mwifiex_get_ver_ext(struct mwifiex_private *priv);
+int mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel);
 
 int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
                               struct ieee80211_channel *chan,
@@ -1586,6 +1582,12 @@ void mwifiex_drv_info_dump(struct mwifiex_adapter *adapter);
 void mwifiex_upload_device_dump(struct mwifiex_adapter *adapter);
 void *mwifiex_alloc_dma_align_buf(int rx_len, gfp_t flags);
 void mwifiex_queue_main_work(struct mwifiex_adapter *adapter);
+int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
+                             int cmd_type,
+                             struct mwifiex_ds_wakeup_reason *wakeup_reason);
+int mwifiex_ret_wakeup_reason(struct mwifiex_private *priv,
+                             struct host_cmd_ds_command *resp,
+                             struct host_cmd_ds_wakeup_reason *wakeup_reason);
 void mwifiex_coex_ampdu_rxwinsize(struct mwifiex_adapter *adapter);
 void mwifiex_11n_delba(struct mwifiex_private *priv, int tid);
 int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy);
index 6d0dc40..cc07214 100644 (file)
@@ -37,17 +37,6 @@ static struct mwifiex_if_ops pcie_ops;
 
 static struct semaphore add_remove_card_sem;
 
-static struct memory_type_mapping mem_type_mapping_tbl[] = {
-       {"ITCM", NULL, 0, 0xF0},
-       {"DTCM", NULL, 0, 0xF1},
-       {"SQRAM", NULL, 0, 0xF2},
-       {"IRAM", NULL, 0, 0xF3},
-       {"APU", NULL, 0, 0xF4},
-       {"CIU", NULL, 0, 0xF5},
-       {"ICU", NULL, 0, 0xF6},
-       {"MAC", NULL, 0, 0xF7},
-};
-
 static int
 mwifiex_map_pci_memory(struct mwifiex_adapter *adapter, struct sk_buff *skb,
                       size_t size, int flags)
@@ -206,6 +195,8 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
                card->pcie.blksz_fw_dl = data->blksz_fw_dl;
                card->pcie.tx_buf_size = data->tx_buf_size;
                card->pcie.can_dump_fw = data->can_dump_fw;
+               card->pcie.mem_type_mapping_tbl = data->mem_type_mapping_tbl;
+               card->pcie.num_mem_types = data->num_mem_types;
                card->pcie.can_ext_scan = data->can_ext_scan;
        }
 
@@ -323,6 +314,8 @@ static int mwifiex_read_reg(struct mwifiex_adapter *adapter, int reg, u32 *data)
        struct pcie_service_card *card = adapter->card;
 
        *data = ioread32(card->pci_mmap1 + reg);
+       if (*data == 0xffffffff)
+               return 0xffffffff;
 
        return 0;
 }
@@ -2007,14 +2000,12 @@ done:
 
 /*
  * This function checks the firmware status in card.
- *
- * The winner interface is also determined by this function.
  */
 static int
 mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 {
        int ret = 0;
-       u32 firmware_stat, winner_status;
+       u32 firmware_stat;
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
        u32 tries;
@@ -2054,19 +2045,28 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
                }
        }
 
-       if (ret) {
-               if (mwifiex_read_reg(adapter, reg->fw_status,
-                                    &winner_status))
-                       ret = -1;
-               else if (!winner_status) {
-                       mwifiex_dbg(adapter, INFO,
-                                   "PCI-E is the winner\n");
-                       adapter->winner = 1;
-               } else {
-                       mwifiex_dbg(adapter, ERROR,
-                                   "PCI-E is not the winner <%#x,%d>, exit dnld\n",
-                                   ret, adapter->winner);
-               }
+       return ret;
+}
+
+/* This function checks if WLAN is the winner.
+ */
+static int
+mwifiex_check_winner_status(struct mwifiex_adapter *adapter)
+{
+       u32 winner = 0;
+       int ret = 0;
+       struct pcie_service_card *card = adapter->card;
+       const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
+
+       if (mwifiex_read_reg(adapter, reg->fw_status, &winner)) {
+               ret = -1;
+       } else if (!winner) {
+               mwifiex_dbg(adapter, INFO, "PCI-E is the winner\n");
+               adapter->winner = 1;
+       } else {
+               mwifiex_dbg(adapter, ERROR,
+                           "PCI-E is not the winner <%#x,%d>, exit dnld\n",
+                           ret, adapter->winner);
        }
 
        return ret;
@@ -2075,20 +2075,28 @@ mwifiex_check_fw_status(struct mwifiex_adapter *adapter, u32 poll_num)
 /*
  * This function reads the interrupt status from card.
  */
-static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
+static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter,
+                                    int msg_id)
 {
        u32 pcie_ireg;
        unsigned long flags;
+       struct pcie_service_card *card = adapter->card;
 
        if (!mwifiex_pcie_ok_to_access_hw(adapter))
                return;
 
-       if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS, &pcie_ireg)) {
-               mwifiex_dbg(adapter, ERROR, "Read register failed\n");
-               return;
-       }
+       if (card->msix_enable && msg_id >= 0) {
+               pcie_ireg = BIT(msg_id);
+       } else {
+               if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
+                                    &pcie_ireg)) {
+                       mwifiex_dbg(adapter, ERROR, "Read register failed\n");
+                       return;
+               }
+
+               if ((pcie_ireg == 0xFFFFFFFF) || !pcie_ireg)
+                       return;
 
-       if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
 
                mwifiex_pcie_disable_host_int(adapter);
 
@@ -2099,21 +2107,24 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
                                    "Write register failed\n");
                        return;
                }
-               spin_lock_irqsave(&adapter->int_lock, flags);
-               adapter->int_status |= pcie_ireg;
-               spin_unlock_irqrestore(&adapter->int_lock, flags);
-
-               if (!adapter->pps_uapsd_mode &&
-                   adapter->ps_state == PS_STATE_SLEEP &&
-                   mwifiex_pcie_ok_to_access_hw(adapter)) {
-                               /* Potentially for PCIe we could get other
-                                * interrupts like shared. Don't change power
-                                * state until cookie is set */
-                               adapter->ps_state = PS_STATE_AWAKE;
-                               adapter->pm_wakeup_fw_try = false;
-                               del_timer(&adapter->wakeup_timer);
-               }
        }
+
+       if (!adapter->pps_uapsd_mode &&
+           adapter->ps_state == PS_STATE_SLEEP &&
+           mwifiex_pcie_ok_to_access_hw(adapter)) {
+               /* Potentially for PCIe we could get other
+                * interrupts like shared. Don't change power
+                * state until cookie is set
+                */
+               adapter->ps_state = PS_STATE_AWAKE;
+               adapter->pm_wakeup_fw_try = false;
+               del_timer(&adapter->wakeup_timer);
+       }
+
+       spin_lock_irqsave(&adapter->int_lock, flags);
+       adapter->int_status |= pcie_ireg;
+       spin_unlock_irqrestore(&adapter->int_lock, flags);
+       mwifiex_dbg(adapter, INTR, "ireg: 0x%08x\n", pcie_ireg);
 }
 
 /*
@@ -2124,7 +2135,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
  */
 static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
 {
-       struct pci_dev *pdev = (struct pci_dev *)context;
+       struct mwifiex_msix_context *ctx = context;
+       struct pci_dev *pdev = ctx->dev;
        struct pcie_service_card *card;
        struct mwifiex_adapter *adapter;
 
@@ -2144,7 +2156,11 @@ static irqreturn_t mwifiex_pcie_interrupt(int irq, void *context)
        if (adapter->surprise_removed)
                goto exit;
 
-       mwifiex_interrupt_status(adapter);
+       if (card->msix_enable)
+               mwifiex_interrupt_status(adapter, ctx->msg_id);
+       else
+               mwifiex_interrupt_status(adapter, -1);
+
        mwifiex_queue_main_work(adapter);
 
 exit:
@@ -2164,7 +2180,7 @@ exit:
  * In case of Rx packets received, the packets are uploaded from card to
  * host and processed accordingly.
  */
-static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
 {
        int ret;
        u32 pcie_ireg;
@@ -2244,6 +2260,69 @@ static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
        return 0;
 }
 
+static int mwifiex_process_msix_int(struct mwifiex_adapter *adapter)
+{
+       int ret;
+       u32 pcie_ireg;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->int_lock, flags);
+       /* Clear out unused interrupts */
+       pcie_ireg = adapter->int_status;
+       adapter->int_status = 0;
+       spin_unlock_irqrestore(&adapter->int_lock, flags);
+
+       if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: TX DNLD Done\n");
+               ret = mwifiex_pcie_send_data_complete(adapter);
+               if (ret)
+                       return ret;
+       }
+       if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: Rx DATA\n");
+               ret = mwifiex_pcie_process_recv_data(adapter);
+               if (ret)
+                       return ret;
+       }
+       if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+               mwifiex_dbg(adapter, INTR,
+                           "info: Rx EVENT\n");
+               ret = mwifiex_pcie_process_event_ready(adapter);
+               if (ret)
+                       return ret;
+       }
+
+       if (pcie_ireg & HOST_INTR_CMD_DONE) {
+               if (adapter->cmd_sent) {
+                       mwifiex_dbg(adapter, INTR,
+                                   "info: CMD sent Interrupt\n");
+                       adapter->cmd_sent = false;
+               }
+               /* Handle command response */
+               ret = mwifiex_pcie_process_cmd_complete(adapter);
+               if (ret)
+                       return ret;
+       }
+
+       mwifiex_dbg(adapter, INTR,
+                   "info: cmd_sent=%d data_sent=%d\n",
+                   adapter->cmd_sent, adapter->data_sent);
+
+       return 0;
+}
+
+static int mwifiex_process_int_status(struct mwifiex_adapter *adapter)
+{
+       struct pcie_service_card *card = adapter->card;
+
+       if (card->msix_enable)
+               return mwifiex_process_msix_int(adapter);
+       else
+               return mwifiex_process_pcie_int(adapter);
+}
+
 /*
  * This function downloads data from driver to card.
  *
@@ -2278,10 +2357,15 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
 {
        int ret, tries;
        u8 ctrl_data;
+       u32 fw_status;
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg = card->pcie.reg;
 
-       ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl, FW_DUMP_HOST_READY);
+       if (mwifiex_read_reg(adapter, reg->fw_status, &fw_status))
+               return RDWR_STATUS_FAILURE;
+
+       ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
+                               reg->fw_dump_host_ready);
        if (ret) {
                mwifiex_dbg(adapter, ERROR,
                            "PCIE write err\n");
@@ -2294,11 +2378,11 @@ mwifiex_pcie_rdwr_firmware(struct mwifiex_adapter *adapter, u8 doneflag)
                        return RDWR_STATUS_SUCCESS;
                if (doneflag && ctrl_data == doneflag)
                        return RDWR_STATUS_DONE;
-               if (ctrl_data != FW_DUMP_HOST_READY) {
+               if (ctrl_data != reg->fw_dump_host_ready) {
                        mwifiex_dbg(adapter, WARN,
                                    "The ctrl reg was changed, re-try again!\n");
                        ret = mwifiex_write_reg(adapter, reg->fw_dump_ctrl,
-                                               FW_DUMP_HOST_READY);
+                                               reg->fw_dump_host_ready);
                        if (ret) {
                                mwifiex_dbg(adapter, ERROR,
                                            "PCIE write err\n");
@@ -2318,7 +2402,8 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *creg = card->pcie.reg;
        unsigned int reg, reg_start, reg_end;
-       u8 *dbg_ptr, *end_ptr, dump_num, idx, i, read_reg, doneflag = 0;
+       u8 *dbg_ptr, *end_ptr, *tmp_ptr, fw_dump_num, dump_num;
+       u8 idx, i, read_reg, doneflag = 0;
        enum rdwr_status stat;
        u32 memory_size;
        int ret;
@@ -2326,8 +2411,9 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
        if (!card->pcie.can_dump_fw)
                return;
 
-       for (idx = 0; idx < ARRAY_SIZE(mem_type_mapping_tbl); idx++) {
-               struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
+       for (idx = 0; idx < adapter->num_mem_types; idx++) {
+               struct memory_type_mapping *entry =
+                               &adapter->mem_type_mapping_tbl[idx];
 
                if (entry->mem_ptr) {
                        vfree(entry->mem_ptr);
@@ -2336,7 +2422,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                entry->mem_size = 0;
        }
 
-       mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump start ==\n");
+       mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump start ==\n");
 
        /* Read the number of the memories which will dump */
        stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
@@ -2344,28 +2430,38 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                return;
 
        reg = creg->fw_dump_start;
-       mwifiex_read_reg_byte(adapter, reg, &dump_num);
+       mwifiex_read_reg_byte(adapter, reg, &fw_dump_num);
+
+       /* W8997 chipset firmware dump will be restore in single region*/
+       if (fw_dump_num == 0)
+               dump_num = 1;
+       else
+               dump_num = fw_dump_num;
 
        /* Read the length of every memory which will dump */
        for (idx = 0; idx < dump_num; idx++) {
-               struct memory_type_mapping *entry = &mem_type_mapping_tbl[idx];
-
-               stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
-               if (stat == RDWR_STATUS_FAILURE)
-                       return;
-
+               struct memory_type_mapping *entry =
+                               &adapter->mem_type_mapping_tbl[idx];
                memory_size = 0;
-               reg = creg->fw_dump_start;
-               for (i = 0; i < 4; i++) {
-                       mwifiex_read_reg_byte(adapter, reg, &read_reg);
-                       memory_size |= (read_reg << (i * 8));
+               if (fw_dump_num != 0) {
+                       stat = mwifiex_pcie_rdwr_firmware(adapter, doneflag);
+                       if (stat == RDWR_STATUS_FAILURE)
+                               return;
+
+                       reg = creg->fw_dump_start;
+                       for (i = 0; i < 4; i++) {
+                               mwifiex_read_reg_byte(adapter, reg, &read_reg);
+                               memory_size |= (read_reg << (i * 8));
                        reg++;
+                       }
+               } else {
+                       memory_size = MWIFIEX_FW_DUMP_MAX_MEMSIZE;
                }
 
                if (memory_size == 0) {
                        mwifiex_dbg(adapter, MSG, "Firmware dump Finished!\n");
                        ret = mwifiex_write_reg(adapter, creg->fw_dump_ctrl,
-                                               FW_DUMP_READ_DONE);
+                                               creg->fw_dump_read_done);
                        if (ret) {
                                mwifiex_dbg(adapter, ERROR, "PCIE write err\n");
                                return;
@@ -2400,11 +2496,21 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                                mwifiex_read_reg_byte(adapter, reg, dbg_ptr);
                                if (dbg_ptr < end_ptr) {
                                        dbg_ptr++;
-                               } else {
-                                       mwifiex_dbg(adapter, ERROR,
-                                                   "Allocated buf not enough\n");
-                                       return;
+                                       continue;
                                }
+                               mwifiex_dbg(adapter, ERROR,
+                                           "pre-allocated buf not enough\n");
+                               tmp_ptr =
+                                       vzalloc(memory_size + MWIFIEX_SIZE_4K);
+                               if (!tmp_ptr)
+                                       return;
+                               memcpy(tmp_ptr, entry->mem_ptr, memory_size);
+                               vfree(entry->mem_ptr);
+                               entry->mem_ptr = tmp_ptr;
+                               tmp_ptr = NULL;
+                               dbg_ptr = entry->mem_ptr + memory_size;
+                               memory_size += MWIFIEX_SIZE_4K;
+                               end_ptr = entry->mem_ptr + memory_size;
                        }
 
                        if (stat != RDWR_STATUS_DONE)
@@ -2416,7 +2522,7 @@ static void mwifiex_pcie_fw_dump(struct mwifiex_adapter *adapter)
                        break;
                } while (true);
        }
-       mwifiex_dbg(adapter, DUMP, "== mwifiex firmware dump end ==\n");
+       mwifiex_dbg(adapter, MSG, "== mwifiex firmware dump end ==\n");
 }
 
 static void mwifiex_pcie_device_dump_work(struct mwifiex_adapter *adapter)
@@ -2595,10 +2701,43 @@ static void mwifiex_pcie_cleanup(struct mwifiex_adapter *adapter)
 
 static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
 {
-       int ret;
+       int ret, i, j;
        struct pcie_service_card *card = adapter->card;
        struct pci_dev *pdev = card->dev;
 
+       if (card->pcie.reg->msix_support) {
+               for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                       card->msix_entries[i].entry = i;
+               ret = pci_enable_msix_exact(pdev, card->msix_entries,
+                                           MWIFIEX_NUM_MSIX_VECTORS);
+               if (!ret) {
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++) {
+                               card->msix_ctx[i].dev = pdev;
+                               card->msix_ctx[i].msg_id = i;
+
+                               ret = request_irq(card->msix_entries[i].vector,
+                                                 mwifiex_pcie_interrupt, 0,
+                                                 "MWIFIEX_PCIE_MSIX",
+                                                 &card->msix_ctx[i]);
+                               if (ret)
+                                       break;
+                       }
+
+                       if (ret) {
+                               mwifiex_dbg(adapter, INFO, "request_irq fail: %d\n",
+                                           ret);
+                               for (j = 0; j < i; j++)
+                                       free_irq(card->msix_entries[j].vector,
+                                                &card->msix_ctx[i]);
+                               pci_disable_msix(pdev);
+                       } else {
+                               mwifiex_dbg(adapter, MSG, "MSIx enabled!");
+                               card->msix_enable = 1;
+                               return 0;
+                       }
+               }
+       }
+
        if (pci_enable_msi(pdev) != 0)
                pci_disable_msi(pdev);
        else
@@ -2606,8 +2745,10 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
 
        mwifiex_dbg(adapter, INFO, "msi_enable = %d\n", card->msi_enable);
 
+       card->share_irq_ctx.dev = pdev;
+       card->share_irq_ctx.msg_id = -1;
        ret = request_irq(pdev->irq, mwifiex_pcie_interrupt, IRQF_SHARED,
-                         "MRVL_PCIE", pdev);
+                         "MRVL_PCIE", &card->share_irq_ctx);
        if (ret) {
                pr_err("request_irq failed: ret=%d\n", ret);
                adapter->card = NULL;
@@ -2635,8 +2776,8 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
                return -1;
 
        adapter->tx_buf_size = card->pcie.tx_buf_size;
-       adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
-       adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
+       adapter->mem_type_mapping_tbl = card->pcie.mem_type_mapping_tbl;
+       adapter->num_mem_types = card->pcie.num_mem_types;
        strcpy(adapter->fw_name, card->pcie.firmware);
        adapter->ext_scan = card->pcie.can_ext_scan;
 
@@ -2653,11 +2794,28 @@ static void mwifiex_unregister_dev(struct mwifiex_adapter *adapter)
 {
        struct pcie_service_card *card = adapter->card;
        const struct mwifiex_pcie_card_reg *reg;
+       struct pci_dev *pdev = card->dev;
+       int i;
 
        if (card) {
-               mwifiex_dbg(adapter, INFO,
-                           "%s(): calling free_irq()\n", __func__);
-               free_irq(card->dev->irq, card->dev);
+               if (card->msix_enable) {
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                               synchronize_irq(card->msix_entries[i].vector);
+
+                       for (i = 0; i < MWIFIEX_NUM_MSIX_VECTORS; i++)
+                               free_irq(card->msix_entries[i].vector,
+                                        &card->msix_ctx[i]);
+
+                       card->msix_enable = 0;
+                       pci_disable_msix(pdev);
+              } else {
+                       mwifiex_dbg(adapter, INFO,
+                                   "%s(): calling free_irq()\n", __func__);
+                      free_irq(card->dev->irq, &card->share_irq_ctx);
+
+                       if (card->msi_enable)
+                               pci_disable_msi(pdev);
+              }
 
                reg = card->pcie.reg;
                if (reg->sleep_cookie)
@@ -2675,6 +2833,7 @@ static struct mwifiex_if_ops pcie_ops = {
        .init_if =                      mwifiex_pcie_init,
        .cleanup_if =                   mwifiex_pcie_cleanup,
        .check_fw_status =              mwifiex_check_fw_status,
+       .check_winner_status =          mwifiex_check_winner_status,
        .prog_fw =                      mwifiex_prog_fw_w_helper,
        .register_dev =                 mwifiex_register_dev,
        .unregister_dev =               mwifiex_unregister_dev,
index 6fc2873..29e58ce 100644 (file)
@@ -26,6 +26,7 @@
 #include    <linux/pcieport_if.h>
 #include    <linux/interrupt.h>
 
+#include    "decl.h"
 #include    "main.h"
 
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
@@ -135,6 +136,9 @@ struct mwifiex_pcie_card_reg {
        u16 fw_dump_ctrl;
        u16 fw_dump_start;
        u16 fw_dump_end;
+       u8 fw_dump_host_ready;
+       u8 fw_dump_read_done;
+       u8 msix_support;
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
@@ -166,6 +170,7 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8766 = {
        .ring_tx_start_ptr = 0,
        .pfu_enabled = 0,
        .sleep_cookie = 1,
+       .msix_support = 0,
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
@@ -200,6 +205,9 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8897 = {
        .fw_dump_ctrl = 0xcf4,
        .fw_dump_start = 0xcf8,
        .fw_dump_end = 0xcff,
+       .fw_dump_host_ready = 0xee,
+       .fw_dump_read_done = 0xfe,
+       .msix_support = 0,
 };
 
 static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
@@ -231,6 +239,27 @@ static const struct mwifiex_pcie_card_reg mwifiex_reg_8997 = {
        .ring_tx_start_ptr = MWIFIEX_BD_FLAG_TX_START_PTR,
        .pfu_enabled = 1,
        .sleep_cookie = 0,
+       .fw_dump_ctrl = 0xcf4,
+       .fw_dump_start = 0xcf8,
+       .fw_dump_end = 0xcff,
+       .fw_dump_host_ready = 0xcc,
+       .fw_dump_read_done = 0xdd,
+       .msix_support = 1,
+};
+
+static struct memory_type_mapping mem_type_mapping_tbl_w8897[] = {
+       {"ITCM", NULL, 0, 0xF0},
+       {"DTCM", NULL, 0, 0xF1},
+       {"SQRAM", NULL, 0, 0xF2},
+       {"IRAM", NULL, 0, 0xF3},
+       {"APU", NULL, 0, 0xF4},
+       {"CIU", NULL, 0, 0xF5},
+       {"ICU", NULL, 0, 0xF6},
+       {"MAC", NULL, 0, 0xF7},
+};
+
+static struct memory_type_mapping mem_type_mapping_tbl_w8997[] = {
+       {"DUMP", NULL, 0, 0xDD},
 };
 
 struct mwifiex_pcie_device {
@@ -239,6 +268,8 @@ struct mwifiex_pcie_device {
        u16 blksz_fw_dl;
        u16 tx_buf_size;
        bool can_dump_fw;
+       struct memory_type_mapping *mem_type_mapping_tbl;
+       u8 num_mem_types;
        bool can_ext_scan;
 };
 
@@ -257,6 +288,8 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
        .can_dump_fw = true,
+       .mem_type_mapping_tbl = mem_type_mapping_tbl_w8897,
+       .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8897),
        .can_ext_scan = true,
 };
 
@@ -265,7 +298,9 @@ static const struct mwifiex_pcie_device mwifiex_pcie8997 = {
        .reg            = &mwifiex_reg_8997,
        .blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
        .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
-       .can_dump_fw = false,
+       .can_dump_fw = true,
+       .mem_type_mapping_tbl = mem_type_mapping_tbl_w8997,
+       .num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl_w8997),
        .can_ext_scan = true,
 };
 
@@ -290,6 +325,13 @@ struct mwifiex_pfu_buf_desc {
        u32 reserved;
 } __packed;
 
+#define MWIFIEX_NUM_MSIX_VECTORS   4
+
+struct mwifiex_msix_context {
+       struct pci_dev *dev;
+       u16 msg_id;
+};
+
 struct pcie_service_card {
        struct pci_dev *dev;
        struct mwifiex_adapter *adapter;
@@ -327,6 +369,12 @@ struct pcie_service_card {
        void __iomem *pci_mmap;
        void __iomem *pci_mmap1;
        int msi_enable;
+       int msix_enable;
+#ifdef CONFIG_PCI
+       struct msix_entry msix_entries[MWIFIEX_NUM_MSIX_VECTORS];
+#endif
+       struct mwifiex_msix_context msix_ctx[MWIFIEX_NUM_MSIX_VECTORS];
+       struct mwifiex_msix_context share_irq_ctx;
 };
 
 static inline int
index c20017c..489f7a9 100644 (file)
@@ -547,6 +547,61 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
        return chan_idx;
 }
 
+/* This function creates a channel list tlv for bgscan config, based
+ * on region/band information.
+ */
+static int
+mwifiex_bgscan_create_channel_list(struct mwifiex_private *priv,
+                                  const struct mwifiex_bg_scan_cfg
+                                               *bgscan_cfg_in,
+                                  struct mwifiex_chan_scan_param_set
+                                               *scan_chan_list)
+{
+       enum ieee80211_band band;
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *ch;
+       struct mwifiex_adapter *adapter = priv->adapter;
+       int chan_idx = 0, i;
+
+       for (band = 0; (band < IEEE80211_NUM_BANDS); band++) {
+               if (!priv->wdev.wiphy->bands[band])
+                       continue;
+
+               sband = priv->wdev.wiphy->bands[band];
+
+               for (i = 0; (i < sband->n_channels) ; i++) {
+                       ch = &sband->channels[i];
+                       if (ch->flags & IEEE80211_CHAN_DISABLED)
+                               continue;
+                       scan_chan_list[chan_idx].radio_type = band;
+
+                       if (bgscan_cfg_in->chan_list[0].scan_time)
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16((u16)bgscan_cfg_in->
+                                       chan_list[0].scan_time);
+                       else if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16(adapter->passive_scan_time);
+                       else
+                               scan_chan_list[chan_idx].max_scan_time =
+                                       cpu_to_le16(adapter->
+                                                   specific_scan_time);
+
+                       if (ch->flags & IEEE80211_CHAN_NO_IR)
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                                       |= MWIFIEX_PASSIVE_SCAN;
+                       else
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                                       &= ~MWIFIEX_PASSIVE_SCAN;
+
+                       scan_chan_list[chan_idx].chan_number =
+                                                       (u32)ch->hw_value;
+                       chan_idx++;
+               }
+       }
+       return chan_idx;
+}
+
 /* This function appends rate TLV to scan config command. */
 static int
 mwifiex_append_rate_tlv(struct mwifiex_private *priv,
@@ -2037,6 +2092,8 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
        u8 is_bgscan_resp;
        __le64 fw_tsf = 0;
        u8 *radio_type;
+       struct cfg80211_wowlan_nd_match *pmatch;
+       struct cfg80211_sched_scan_request *nd_config = NULL;
 
        is_bgscan_resp = (le16_to_cpu(resp->command)
                          == HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -2099,6 +2156,21 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                             (struct mwifiex_ie_types_data **)
                                             &chan_band_tlv);
 
+#ifdef CONFIG_PM
+       if (priv->wdev.wiphy->wowlan_config)
+               nd_config = priv->wdev.wiphy->wowlan_config->nd_config;
+#endif
+
+       if (nd_config) {
+               adapter->nd_info =
+                       kzalloc(sizeof(struct cfg80211_wowlan_nd_match) +
+                               sizeof(struct cfg80211_wowlan_nd_match *) *
+                               scan_rsp->number_of_sets, GFP_ATOMIC);
+
+               if (adapter->nd_info)
+                       adapter->nd_info->n_matches = scan_rsp->number_of_sets;
+       }
+
        for (idx = 0; idx < scan_rsp->number_of_sets && bytes_left; idx++) {
                /*
                 * If the TSF TLV was appended to the scan results, save this
@@ -2117,6 +2189,23 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        radio_type = NULL;
                }
 
+               if (chan_band_tlv && adapter->nd_info) {
+                       adapter->nd_info->matches[idx] =
+                               kzalloc(sizeof(*pmatch) +
+                               sizeof(u32), GFP_ATOMIC);
+
+                       pmatch = adapter->nd_info->matches[idx];
+
+                       if (pmatch) {
+                               memset(pmatch, 0, sizeof(*pmatch));
+                               if (chan_band_tlv) {
+                                       pmatch->n_channels = 1;
+                                       pmatch->channels[0] =
+                                               chan_band->chan_number;
+                               }
+                       }
+               }
+
                ret = mwifiex_parse_single_response_buf(priv, &bss_info,
                                                        &bytes_left,
                                                        le64_to_cpu(fw_tsf),
@@ -2155,6 +2244,227 @@ int mwifiex_cmd_802_11_scan_ext(struct mwifiex_private *priv,
        return 0;
 }
 
+/* This function prepares an background scan config command to be sent
+ * to the firmware
+ */
+int mwifiex_cmd_802_11_bg_scan_config(struct mwifiex_private *priv,
+                                     struct host_cmd_ds_command *cmd,
+                                     void *data_buf)
+{
+       struct host_cmd_ds_802_11_bg_scan_config *bgscan_config =
+                                       &cmd->params.bg_scan_config;
+       struct mwifiex_bg_scan_cfg *bgscan_cfg_in = data_buf;
+       u8 *tlv_pos = bgscan_config->tlv;
+       u8 num_probes;
+       u32 ssid_len, chan_idx, scan_type, scan_dur, chan_num;
+       int i;
+       struct mwifiex_ie_types_num_probes *num_probes_tlv;
+       struct mwifiex_ie_types_repeat_count *repeat_count_tlv;
+       struct mwifiex_ie_types_min_rssi_threshold *rssi_threshold_tlv;
+       struct mwifiex_ie_types_bgscan_start_later *start_later_tlv;
+       struct mwifiex_ie_types_wildcard_ssid_params *wildcard_ssid_tlv;
+       struct mwifiex_ie_types_chan_list_param_set *chan_list_tlv;
+       struct mwifiex_chan_scan_param_set *temp_chan;
+
+       cmd->command = cpu_to_le16(HostCmd_CMD_802_11_BG_SCAN_CONFIG);
+       cmd->size = cpu_to_le16(sizeof(*bgscan_config) + S_DS_GEN);
+
+       bgscan_config->action = cpu_to_le16(bgscan_cfg_in->action);
+       bgscan_config->enable = bgscan_cfg_in->enable;
+       bgscan_config->bss_type = bgscan_cfg_in->bss_type;
+       bgscan_config->scan_interval =
+               cpu_to_le32(bgscan_cfg_in->scan_interval);
+       bgscan_config->report_condition =
+               cpu_to_le32(bgscan_cfg_in->report_condition);
+
+       /*  stop sched scan  */
+       if (!bgscan_config->enable)
+               return 0;
+
+       bgscan_config->chan_per_scan = bgscan_cfg_in->chan_per_scan;
+
+       num_probes = (bgscan_cfg_in->num_probes ? bgscan_cfg_in->
+                     num_probes : priv->adapter->scan_probes);
+
+       if (num_probes) {
+               num_probes_tlv = (struct mwifiex_ie_types_num_probes *)tlv_pos;
+               num_probes_tlv->header.type = cpu_to_le16(TLV_TYPE_NUMPROBES);
+               num_probes_tlv->header.len =
+                       cpu_to_le16(sizeof(num_probes_tlv->num_probes));
+               num_probes_tlv->num_probes = cpu_to_le16((u16)num_probes);
+
+               tlv_pos += sizeof(num_probes_tlv->header) +
+                       le16_to_cpu(num_probes_tlv->header.len);
+       }
+
+       if (bgscan_cfg_in->repeat_count) {
+               repeat_count_tlv =
+                       (struct mwifiex_ie_types_repeat_count *)tlv_pos;
+               repeat_count_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_REPEAT_COUNT);
+               repeat_count_tlv->header.len =
+                       cpu_to_le16(sizeof(repeat_count_tlv->repeat_count));
+               repeat_count_tlv->repeat_count =
+                       cpu_to_le16(bgscan_cfg_in->repeat_count);
+
+               tlv_pos += sizeof(repeat_count_tlv->header) +
+                       le16_to_cpu(repeat_count_tlv->header.len);
+       }
+
+       if (bgscan_cfg_in->rssi_threshold) {
+               rssi_threshold_tlv =
+                       (struct mwifiex_ie_types_min_rssi_threshold *)tlv_pos;
+               rssi_threshold_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_RSSI_LOW);
+               rssi_threshold_tlv->header.len =
+                       cpu_to_le16(sizeof(rssi_threshold_tlv->rssi_threshold));
+               rssi_threshold_tlv->rssi_threshold =
+                       cpu_to_le16(bgscan_cfg_in->rssi_threshold);
+
+               tlv_pos += sizeof(rssi_threshold_tlv->header) +
+                       le16_to_cpu(rssi_threshold_tlv->header.len);
+       }
+
+       for (i = 0; i < bgscan_cfg_in->num_ssids; i++) {
+               ssid_len = bgscan_cfg_in->ssid_list[i].ssid.ssid_len;
+
+               wildcard_ssid_tlv =
+                       (struct mwifiex_ie_types_wildcard_ssid_params *)tlv_pos;
+               wildcard_ssid_tlv->header.type =
+                               cpu_to_le16(TLV_TYPE_WILDCARDSSID);
+               wildcard_ssid_tlv->header.len = cpu_to_le16(
+                               (u16)(ssid_len + sizeof(wildcard_ssid_tlv->
+                                                        max_ssid_length)));
+
+               /* max_ssid_length = 0 tells firmware to perform
+                * specific scan for the SSID filled, whereas
+                * max_ssid_length = IEEE80211_MAX_SSID_LEN is for
+                * wildcard scan.
+                */
+               if (ssid_len)
+                       wildcard_ssid_tlv->max_ssid_length = 0;
+               else
+                       wildcard_ssid_tlv->max_ssid_length =
+                                               IEEE80211_MAX_SSID_LEN;
+
+               memcpy(wildcard_ssid_tlv->ssid,
+                      bgscan_cfg_in->ssid_list[i].ssid.ssid, ssid_len);
+
+               tlv_pos += (sizeof(wildcard_ssid_tlv->header)
+                               + le16_to_cpu(wildcard_ssid_tlv->header.len));
+       }
+
+       chan_list_tlv = (struct mwifiex_ie_types_chan_list_param_set *)tlv_pos;
+
+       if (bgscan_cfg_in->chan_list[0].chan_number) {
+               dev_dbg(priv->adapter->dev, "info: bgscan: Using supplied channel list\n");
+
+               chan_list_tlv->header.type = cpu_to_le16(TLV_TYPE_CHANLIST);
+
+               for (chan_idx = 0;
+                    chan_idx < MWIFIEX_BG_SCAN_CHAN_MAX &&
+                    bgscan_cfg_in->chan_list[chan_idx].chan_number;
+                    chan_idx++) {
+                       temp_chan = chan_list_tlv->chan_scan_param + chan_idx;
+
+                       /* Increment the TLV header length by size appended */
+                       le16_add_cpu(&chan_list_tlv->header.len,
+                                    sizeof(chan_list_tlv->chan_scan_param));
+
+                       temp_chan->chan_number =
+                               bgscan_cfg_in->chan_list[chan_idx].chan_number;
+                       temp_chan->radio_type =
+                               bgscan_cfg_in->chan_list[chan_idx].radio_type;
+
+                       scan_type =
+                               bgscan_cfg_in->chan_list[chan_idx].scan_type;
+
+                       if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
+                               temp_chan->chan_scan_mode_bitmap
+                                       |= MWIFIEX_PASSIVE_SCAN;
+                       else
+                               temp_chan->chan_scan_mode_bitmap
+                                       &= ~MWIFIEX_PASSIVE_SCAN;
+
+                       if (bgscan_cfg_in->chan_list[chan_idx].scan_time) {
+                               scan_dur = (u16)bgscan_cfg_in->
+                                       chan_list[chan_idx].scan_time;
+                       } else {
+                               scan_dur = (scan_type ==
+                                           MWIFIEX_SCAN_TYPE_PASSIVE) ?
+                                           priv->adapter->passive_scan_time :
+                                           priv->adapter->specific_scan_time;
+                       }
+
+                       temp_chan->min_scan_time = cpu_to_le16(scan_dur);
+                       temp_chan->max_scan_time = cpu_to_le16(scan_dur);
+               }
+       } else {
+               dev_dbg(priv->adapter->dev,
+                       "info: bgscan: Creating full region channel list\n");
+               chan_num =
+                       mwifiex_bgscan_create_channel_list(priv, bgscan_cfg_in,
+                                                          chan_list_tlv->
+                                                          chan_scan_param);
+               le16_add_cpu(&chan_list_tlv->header.len,
+                            chan_num *
+                            sizeof(chan_list_tlv->chan_scan_param[0]));
+       }
+
+       tlv_pos += (sizeof(chan_list_tlv->header)
+                       + le16_to_cpu(chan_list_tlv->header.len));
+
+       if (bgscan_cfg_in->start_later) {
+               start_later_tlv =
+                       (struct mwifiex_ie_types_bgscan_start_later *)tlv_pos;
+               start_later_tlv->header.type =
+                       cpu_to_le16(TLV_TYPE_BGSCAN_START_LATER);
+               start_later_tlv->header.len =
+                       cpu_to_le16(sizeof(start_later_tlv->start_later));
+               start_later_tlv->start_later =
+                       cpu_to_le16(bgscan_cfg_in->start_later);
+
+               tlv_pos += sizeof(start_later_tlv->header) +
+                       le16_to_cpu(start_later_tlv->header.len);
+       }
+
+       /* Append vendor specific IE TLV */
+       mwifiex_cmd_append_vsie_tlv(priv, MWIFIEX_VSIE_MASK_BGSCAN, &tlv_pos);
+
+       le16_add_cpu(&cmd->size, tlv_pos - bgscan_config->tlv);
+
+       return 0;
+}
+
+int mwifiex_stop_bg_scan(struct mwifiex_private *priv)
+{
+       struct mwifiex_bg_scan_cfg *bgscan_cfg;
+
+       if (!priv->sched_scanning) {
+               dev_dbg(priv->adapter->dev, "bgscan already stopped!\n");
+               return 0;
+       }
+
+       bgscan_cfg = kzalloc(sizeof(*bgscan_cfg), GFP_KERNEL);
+       if (!bgscan_cfg)
+               return -ENOMEM;
+
+       bgscan_cfg->bss_type = MWIFIEX_BSS_MODE_INFRA;
+       bgscan_cfg->action = MWIFIEX_BGSCAN_ACT_SET;
+       bgscan_cfg->enable = false;
+
+       if (mwifiex_send_cmd(priv, HostCmd_CMD_802_11_BG_SCAN_CONFIG,
+                            HostCmd_ACT_GEN_SET, 0, bgscan_cfg, true)) {
+               kfree(bgscan_cfg);
+               return -EFAULT;
+       }
+
+       kfree(bgscan_cfg);
+       priv->sched_scanning = false;
+
+       return 0;
+}
+
 static void
 mwifiex_update_chan_statistics(struct mwifiex_private *priv,
                               struct mwifiex_ietypes_chanstats *tlv_stat)
index 4c8cae6..abf15db 100644 (file)
@@ -181,7 +181,7 @@ static int mwifiex_sdio_resume(struct device *dev)
 
        /* Disable Host Sleep */
        mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
-                         MWIFIEX_ASYNC_CMD);
+                         MWIFIEX_SYNC_CMD);
 
        return 0;
 }
@@ -1039,19 +1039,14 @@ done:
 
 /*
  * This function checks the firmware status in card.
- *
- * The winner interface is also determined by this function.
  */
 static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
                                   u32 poll_num)
 {
-       struct sdio_mmc_card *card = adapter->card;
        int ret = 0;
        u16 firmware_stat;
        u32 tries;
-       u8 winner_status;
 
-       /* Wait for firmware initialization event */
        for (tries = 0; tries < poll_num; tries++) {
                ret = mwifiex_sdio_read_fw_status(adapter, &firmware_stat);
                if (ret)
@@ -1065,16 +1060,25 @@ static int mwifiex_check_fw_status(struct mwifiex_adapter *adapter,
                }
        }
 
-       if (ret) {
-               if (mwifiex_read_reg
-                   (adapter, card->reg->status_reg_0, &winner_status))
-                       winner_status = 0;
+       return ret;
+}
+
+/* This function checks if WLAN is the winner.
+ */
+static int mwifiex_check_winner_status(struct mwifiex_adapter *adapter)
+{
+       int ret = 0;
+       u8 winner = 0;
+       struct sdio_mmc_card *card = adapter->card;
+
+       if (mwifiex_read_reg(adapter, card->reg->status_reg_0, &winner))
+               return -1;
+
+       if (winner)
+               adapter->winner = 0;
+       else
+               adapter->winner = 1;
 
-               if (winner_status)
-                       adapter->winner = 0;
-               else
-                       adapter->winner = 1;
-       }
        return ret;
 }
 
@@ -2620,6 +2624,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .init_if = mwifiex_init_sdio,
        .cleanup_if = mwifiex_cleanup_sdio,
        .check_fw_status = mwifiex_check_fw_status,
+       .check_winner_status = mwifiex_check_winner_status,
        .prog_fw = mwifiex_prog_fw_w_helper,
        .register_dev = mwifiex_register_dev,
        .unregister_dev = mwifiex_unregister_dev,
index e486867..30f1526 100644 (file)
@@ -1813,6 +1813,22 @@ static int mwifiex_cmd_sdio_rx_aggr_cfg(struct host_cmd_ds_command *cmd,
        return 0;
 }
 
+/* This function prepares command to get HS wakeup reason.
+ *
+ * Preparation includes -
+ *      - Setting command ID, action and proper size
+ *      - Ensuring correct endian-ness
+ */
+static int mwifiex_cmd_get_wakeup_reason(struct mwifiex_private *priv,
+                                        struct host_cmd_ds_command *cmd)
+{
+       cmd->command = cpu_to_le16(HostCmd_CMD_HS_WAKEUP_REASON);
+       cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_wakeup_reason) +
+                               S_DS_GEN);
+
+       return 0;
+}
+
 /*
  * This function prepares the commands before sending them to the firmware.
  *
@@ -1873,6 +1889,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
        case HostCmd_CMD_802_11_SCAN:
                ret = mwifiex_cmd_802_11_scan(cmd_ptr, data_buf);
                break;
+       case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+               ret = mwifiex_cmd_802_11_bg_scan_config(priv, cmd_ptr,
+                                                       data_buf);
+               break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
                ret = mwifiex_cmd_802_11_bg_scan_query(cmd_ptr);
                break;
@@ -2063,6 +2083,9 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
                ret = mwifiex_cmd_sdio_rx_aggr_cfg(cmd_ptr, cmd_action,
                                                   data_buf);
                break;
+       case HostCmd_CMD_HS_WAKEUP_REASON:
+               ret = mwifiex_cmd_get_wakeup_reason(priv, cmd_ptr);
+               break;
        case HostCmd_CMD_MC_POLICY:
                ret = mwifiex_cmd_set_mc_policy(priv, cmd_ptr, cmd_action,
                                                data_buf);
index 9ac7aa2..d96523e 100644 (file)
@@ -1076,9 +1076,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
                break;
        case HostCmd_CMD_802_11_BG_SCAN_QUERY:
                ret = mwifiex_ret_802_11_scan(priv, resp);
+               cfg80211_sched_scan_results(priv->wdev.wiphy);
                mwifiex_dbg(adapter, CMD,
                            "info: CMD_RESP: BG_SCAN result is ready!\n");
                break;
+       case HostCmd_CMD_802_11_BG_SCAN_CONFIG:
+               break;
        case HostCmd_CMD_TXPWR_CFG:
                ret = mwifiex_ret_tx_power_cfg(priv, resp);
                break;
@@ -1233,6 +1236,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
        case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:
                ret = mwifiex_ret_sdio_rx_aggr_cfg(priv, resp);
                break;
+       case HostCmd_CMD_HS_WAKEUP_REASON:
+               ret = mwifiex_ret_wakeup_reason(priv, resp, data_buf);
+               break;
        case HostCmd_CMD_TDLS_CONFIG:
                break;
        case HostCmd_CMD_ROBUST_COEX:
index ff3ee9d..070bce4 100644 (file)
@@ -92,6 +92,9 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        priv->is_data_rate_auto = true;
        priv->data_rate = 0;
 
+       priv->assoc_resp_ht_param = 0;
+       priv->ht_param_present = false;
+
        if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
             GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data)
                mwifiex_hist_data_reset(priv);
@@ -607,11 +610,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
 
        case EVENT_PS_AWAKE:
                mwifiex_dbg(adapter, EVENT, "info: EVENT: AWAKE\n");
-               if (!adapter->pps_uapsd_mode && priv->port_open &&
+               if (!adapter->pps_uapsd_mode &&
+                   (priv->port_open ||
+                    (priv->bss_mode == NL80211_IFTYPE_ADHOC)) &&
                    priv->media_connected && adapter->sleep_period.period) {
-                               adapter->pps_uapsd_mode = true;
-                               mwifiex_dbg(adapter, EVENT,
-                                           "event: PPS/UAPSD mode activated\n");
+                       adapter->pps_uapsd_mode = true;
+                       mwifiex_dbg(adapter, EVENT,
+                                   "event: PPS/UAPSD mode activated\n");
                }
                adapter->tx_lock_flag = false;
                if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
@@ -686,6 +691,13 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                                       HostCmd_ACT_GEN_GET, 0, NULL, false);
                break;
 
+       case EVENT_BG_SCAN_STOPPED:
+               dev_dbg(adapter->dev, "event: BGS_STOPPED\n");
+               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+               if (priv->sched_scanning)
+                       priv->sched_scanning = false;
+               break;
+
        case EVENT_PORT_RELEASE:
                mwifiex_dbg(adapter, EVENT, "event: PORT RELEASE\n");
                priv->port_open = true;
index 6a4fc5d..5cbee58 100644 (file)
@@ -504,6 +504,20 @@ int mwifiex_enable_hs(struct mwifiex_adapter *adapter)
                }
        }
 
+       priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+       if (priv && priv->sched_scanning) {
+#ifdef CONFIG_PM
+               if (!priv->wdev.wiphy->wowlan_config->nd_config) {
+#endif
+                       mwifiex_dbg(adapter, CMD, "aborting bgscan!\n");
+                       mwifiex_stop_bg_scan(priv);
+                       cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+#ifdef CONFIG_PM
+               }
+#endif
+       }
+
        if (adapter->hs_activated) {
                mwifiex_dbg(adapter, CMD,
                            "cmd: HS Already activated\n");
@@ -1114,11 +1128,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, struct key_params *kp,
  * with requisite parameters and calls the IOCTL handler.
  */
 int
-mwifiex_get_ver_ext(struct mwifiex_private *priv)
+mwifiex_get_ver_ext(struct mwifiex_private *priv, u32 version_str_sel)
 {
        struct mwifiex_ver_ext ver_ext;
 
        memset(&ver_ext, 0, sizeof(struct host_cmd_ds_version_ext));
+       ver_ext.version_str_sel = version_str_sel;
        if (mwifiex_send_cmd(priv, HostCmd_CMD_VERSION_EXT,
                             HostCmd_ACT_GEN_GET, 0, &ver_ext, true))
                return -1;
@@ -1450,3 +1465,19 @@ mwifiex_set_gen_ie(struct mwifiex_private *priv, const u8 *ie, int ie_len)
 
        return 0;
 }
+
+/* This function get Host Sleep wake up reason.
+ *
+ */
+int mwifiex_get_wakeup_reason(struct mwifiex_private *priv, u16 action,
+                             int cmd_type,
+                             struct mwifiex_ds_wakeup_reason *wakeup_reason)
+{
+       int status = 0;
+
+       status = mwifiex_send_cmd(priv, HostCmd_CMD_HS_WAKEUP_REASON,
+                                 HostCmd_ACT_GEN_GET, 0, wakeup_reason,
+                                 cmd_type == MWIFIEX_SYNC_CMD);
+
+       return status;
+}
index acccd67..0eb2465 100644 (file)
@@ -438,6 +438,7 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter)
                mwifiex_set_ba_params(priv);
                mwifiex_reset_11n_rx_seq_num(priv);
 
+               priv->wmm.drv_pkt_delay_max = MWIFIEX_WMM_DRV_DELAY_MAX;
                atomic_set(&priv->wmm.tx_pkts_queued, 0);
                atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID);
        }
@@ -475,7 +476,8 @@ mwifiex_wmm_lists_empty(struct mwifiex_adapter *adapter)
                priv = adapter->priv[i];
                if (!priv)
                        continue;
-               if (!priv->port_open)
+               if (!priv->port_open &&
+                   (priv->bss_mode != NL80211_IFTYPE_ADHOC))
                        continue;
                if (adapter->if_ops.is_port_ready &&
                    !adapter->if_ops.is_port_ready(priv))
@@ -1099,7 +1101,8 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
 
                        priv_tmp = adapter->bss_prio_tbl[j].bss_prio_cur->priv;
 
-                       if (!priv_tmp->port_open ||
+                       if (((priv_tmp->bss_mode != NL80211_IFTYPE_ADHOC) &&
+                            !priv_tmp->port_open) ||
                            (atomic_read(&priv_tmp->wmm.tx_pkts_queued) == 0))
                                continue;
 
index 2642714..6418620 100644 (file)
  * amount of bytes needed to move the data.
  */
 #define ALIGN_SIZE(__skb, __header) \
-       (  ((unsigned long)((__skb)->data + (__header))) & 3 )
+       (((unsigned long)((__skb)->data + (__header))) & 3)
 
 /*
  * Constants for extra TX headroom for alignment purposes.
 #define SLOT_TIME              20
 #define SHORT_SLOT_TIME                9
 #define SIFS                   10
-#define PIFS                   ( SIFS + SLOT_TIME )
-#define SHORT_PIFS             ( SIFS + SHORT_SLOT_TIME )
-#define DIFS                   ( PIFS + SLOT_TIME )
-#define SHORT_DIFS             ( SHORT_PIFS + SHORT_SLOT_TIME )
-#define EIFS                   ( SIFS + DIFS + \
-                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
-#define SHORT_EIFS             ( SIFS + SHORT_DIFS + \
-                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
+#define PIFS                   (SIFS + SLOT_TIME)
+#define SHORT_PIFS             (SIFS + SHORT_SLOT_TIME)
+#define DIFS                   (PIFS + SLOT_TIME)
+#define SHORT_DIFS             (SHORT_PIFS + SHORT_SLOT_TIME)
+#define EIFS                   (SIFS + DIFS + \
+                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
+#define SHORT_EIFS             (SIFS + SHORT_DIFS + \
+                                 GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
 
 enum rt2x00_chip_intf {
        RT2X00_CHIP_INTF_PCI,
index 90fdb02..25ee3cb 100644 (file)
@@ -629,7 +629,7 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
        data += sprintf(data, "register\tbase\twords\twordsize\n");
 #define RT2X00DEBUGFS_SPRINTF_REGISTER(__name)                 \
 {                                                              \
-       if(debug->__name.read)                                  \
+       if (debug->__name.read)                                 \
                data += sprintf(data, __stringify(__name)       \
                                "\t%d\t%d\t%d\n",               \
                                debug->__name.word_base,        \
@@ -699,7 +699,7 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev)
 
 #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name)                    \
 ({                                                                             \
-       if(debug->__name.read) {                                                \
+       if (debug->__name.read) {                                               \
                (__intf)->__name##_off_entry =                                  \
                debugfs_create_u32(__stringify(__name) "_offset",               \
                                       S_IRUSR | S_IWUSR,                       \
index 1442075..ab86415 100644 (file)
 #define PAIRWISE_TA_TABLE_BASE         0x1a00
 
 #define SHARED_KEY_ENTRY(__idx) \
-       ( SHARED_KEY_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_key_entry)) )
+       (SHARED_KEY_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_key_entry)))
 #define PAIRWISE_KEY_ENTRY(__idx) \
-       ( PAIRWISE_KEY_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_key_entry)) )
+       (PAIRWISE_KEY_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_key_entry)))
 #define PAIRWISE_TA_ENTRY(__idx) \
-       ( PAIRWISE_TA_TABLE_BASE + \
-               ((__idx) * sizeof(struct hw_pairwise_ta_entry)) )
+       (PAIRWISE_TA_TABLE_BASE + \
+               ((__idx) * sizeof(struct hw_pairwise_ta_entry)))
 
 struct hw_key_entry {
        u8 key[16];
@@ -180,7 +180,7 @@ struct hw_pairwise_ta_entry {
 #define HW_BEACON_BASE3                        0x2f00
 
 #define HW_BEACON_OFFSET(__index) \
-       ( HW_BEACON_BASE0 + (__index * 0x0100) )
+       (HW_BEACON_BASE0 + (__index * 0x0100))
 
 /*
  * HOST-MCU shared memory.
@@ -1287,9 +1287,9 @@ struct hw_pairwise_ta_entry {
 /*
  * DMA descriptor defines.
  */
-#define TXD_DESC_SIZE                  ( 16 * sizeof(__le32) )
-#define TXINFO_SIZE                    ( 6 * sizeof(__le32) )
-#define RXD_DESC_SIZE                  ( 16 * sizeof(__le32) )
+#define TXD_DESC_SIZE                  (16 * sizeof(__le32))
+#define TXINFO_SIZE                    (6 * sizeof(__le32))
+#define RXD_DESC_SIZE                  (16 * sizeof(__le32))
 
 /*
  * TX descriptor format for TX, PRIO and Beacon Ring.
index 969c9d7..8a8f1e7 100644 (file)
@@ -13,7 +13,7 @@ config WLCORE
 
 config WLCORE_SPI
        tristate "TI wlcore SPI support"
-       depends on WLCORE && SPI_MASTER
+       depends on WLCORE && SPI_MASTER && OF
        select CRC7
        ---help---
          This module adds support for the SPI interface of adapters using
index c964054..4b59f67 100644 (file)
@@ -38,7 +38,7 @@
 
 int wlcore_event_fw_logger(struct wl1271 *wl)
 {
-       u32 ret;
+       int ret;
        struct fw_logger_information fw_log;
        u8  *buffer;
        u32 internal_fw_addrbase = WL18XX_DATA_RAM_BASE_ADDRESS;
index 44f059f..020ac1a 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/spi/spi.h>
 #include <linux/wl12xx.h>
 #include <linux/platform_device.h>
+#include <linux/of_irq.h>
+#include <linux/regulator/consumer.h>
 
 #include "wlcore.h"
 #include "wl12xx_80211.h"
@@ -81,6 +83,7 @@
 struct wl12xx_spi_glue {
        struct device *dev;
        struct platform_device *core;
+       struct regulator *reg; /* Power regulator */
 };
 
 static void wl12xx_spi_reset(struct device *child)
@@ -318,14 +321,76 @@ static int __must_check wl12xx_spi_raw_write(struct device *child, int addr,
        return 0;
 }
 
+/**
+ * wl12xx_spi_set_power - power on/off the wl12xx unit
+ * @child: wl12xx device handle.
+ * @enable: true/false to power on/off the unit.
+ *
+ * use the WiFi enable regulator to enable/disable the WiFi unit.
+ */
+static int wl12xx_spi_set_power(struct device *child, bool enable)
+{
+       int ret = 0;
+       struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent);
+
+       WARN_ON(!glue->reg);
+
+       /* Update regulator state */
+       if (enable) {
+               ret = regulator_enable(glue->reg);
+               if (ret)
+                       dev_err(child, "Power enable failure\n");
+       } else {
+               ret =  regulator_disable(glue->reg);
+               if (ret)
+                       dev_err(child, "Power disable failure\n");
+       }
+
+       return ret;
+}
+
 static struct wl1271_if_operations spi_ops = {
        .read           = wl12xx_spi_raw_read,
        .write          = wl12xx_spi_raw_write,
        .reset          = wl12xx_spi_reset,
        .init           = wl12xx_spi_init,
+       .power          = wl12xx_spi_set_power,
        .set_block_size = NULL,
 };
 
+static const struct of_device_id wlcore_spi_of_match_table[] = {
+       { .compatible = "ti,wl1271" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, wlcore_spi_of_match_table);
+
+/**
+ * wlcore_probe_of - DT node parsing.
+ * @spi: SPI slave device parameters.
+ * @res: resource parameters.
+ * @glue: wl12xx SPI bus to slave device glue parameters.
+ * @pdev_data: wlcore device parameters
+ */
+static int wlcore_probe_of(struct spi_device *spi, struct wl12xx_spi_glue *glue,
+                          struct wlcore_platdev_data *pdev_data)
+{
+       struct device_node *dt_node = spi->dev.of_node;
+       int ret;
+
+       if (of_find_property(dt_node, "clock-xtal", NULL))
+               pdev_data->ref_clock_xtal = true;
+
+       ret = of_property_read_u32(dt_node, "ref-clock-frequency",
+                                  &pdev_data->ref_clock_freq);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(glue->dev,
+                       "can't get reference clock frequency (%d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int wl1271_probe(struct spi_device *spi)
 {
        struct wl12xx_spi_glue *glue;
@@ -335,8 +400,6 @@ static int wl1271_probe(struct spi_device *spi)
 
        memset(&pdev_data, 0x00, sizeof(pdev_data));
 
-       /* TODO: add DT parsing when needed */
-
        pdev_data.if_ops = &spi_ops;
 
        glue = devm_kzalloc(&spi->dev, sizeof(*glue), GFP_KERNEL);
@@ -353,6 +416,21 @@ static int wl1271_probe(struct spi_device *spi)
         * comes from the board-peripherals file */
        spi->bits_per_word = 32;
 
+       glue->reg = devm_regulator_get(&spi->dev, "vwlan");
+       if (PTR_ERR(glue->reg) == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+       if (IS_ERR(glue->reg)) {
+               dev_err(glue->dev, "can't get regulator\n");
+               return PTR_ERR(glue->reg);
+       }
+
+       ret = wlcore_probe_of(spi, glue, &pdev_data);
+       if (IS_ERR_VALUE(ret)) {
+               dev_err(glue->dev,
+                       "can't get device tree parameters (%d)\n", ret);
+               return ret;
+       }
+
        ret = spi_setup(spi);
        if (ret < 0) {
                dev_err(glue->dev, "spi_setup failed\n");
@@ -370,7 +448,7 @@ static int wl1271_probe(struct spi_device *spi)
        memset(res, 0x00, sizeof(res));
 
        res[0].start = spi->irq;
-       res[0].flags = IORESOURCE_IRQ;
+       res[0].flags = IORESOURCE_IRQ | irq_get_trigger_type(spi->irq);
        res[0].name = "irq";
 
        ret = platform_device_add_resources(glue->core, res, ARRAY_SIZE(res));
@@ -408,10 +486,10 @@ static int wl1271_remove(struct spi_device *spi)
        return 0;
 }
 
-
 static struct spi_driver wl1271_spi_driver = {
        .driver = {
                .name           = "wl1271_spi",
+               .of_match_table = of_match_ptr(wlcore_spi_of_match_table),
        },
 
        .probe          = wl1271_probe,
index 3feb1b2..0367c63 100644 (file)
@@ -151,6 +151,8 @@ struct bcma_host_ops {
 #define BCMA_CORE_PCIE2                        0x83C   /* PCI Express Gen2 */
 #define BCMA_CORE_USB30_DEV            0x83D
 #define BCMA_CORE_ARM_CR4              0x83E
+#define BCMA_CORE_GCI                  0x840
+#define BCMA_CORE_CMEM                 0x846   /* CNDS DDR2/3 memory controller */
 #define BCMA_CORE_ARM_CA7              0x847
 #define BCMA_CORE_SYS_MEM              0x849
 #define BCMA_CORE_DEFAULT              0xFFF
@@ -199,6 +201,7 @@ struct bcma_host_ops {
 #define  BCMA_PKG_ID_BCM4707   1
 #define  BCMA_PKG_ID_BCM4708   2
 #define  BCMA_PKG_ID_BCM4709   0
+#define BCMA_CHIP_ID_BCM47094  53030
 #define BCMA_CHIP_ID_BCM53018  53018
 
 /* Board types (on PCI usually equals to the subsystem dev id) */
index db51a6f..700d0c6 100644 (file)
 #define         BCMA_CC_CLKDIV_JTAG_SHIFT      8
 #define         BCMA_CC_CLKDIV_UART            0x000000FF
 #define BCMA_CC_CAP_EXT                        0x00AC          /* Capabilities */
+#define  BCMA_CC_CAP_EXT_SECI_PRESENT  0x00000001
+#define  BCMA_CC_CAP_EXT_GSIO_PRESENT  0x00000002
+#define  BCMA_CC_CAP_EXT_GCI_PRESENT   0x00000004
+#define  BCMA_CC_CAP_EXT_SECI_PUART_PRESENT            0x00000008    /* UART present */
+#define  BCMA_CC_CAP_EXT_AOB_PRESENT   0x00000040
 #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_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
+#define BCMA_CC_PMU_CHIPCTL_ADDR       0x0650
+#define BCMA_CC_PMU_CHIPCTL_DATA       0x0654
+#define BCMA_CC_PMU_REGCTL_ADDR                0x0658
+#define BCMA_CC_PMU_REGCTL_DATA                0x065C
+#define BCMA_CC_PMU_PLLCTL_ADDR                0x0660
+#define BCMA_CC_PMU_PLLCTL_DATA                0x0664
 #define BCMA_CC_PMU_STRAPOPT           0x0668 /* (corerev >= 28) */
 #define BCMA_CC_PMU_XTAL_FREQ          0x066C /* (pmurev >= 10) */
 #define  BCMA_CC_PMU_XTAL_FREQ_ILPCTL_MASK     0x00001FFF
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
  */
 struct bcma_chipcommon_pmu {
+       struct bcma_device *core;       /* Can be separated core or just ChipCommon one */
        u8 rev;                 /* PMU revision */
        u32 crystalfreq;        /* The active crystal frequency (in kHz) */
 };
@@ -660,6 +666,19 @@ struct bcma_drv_cc_b {
 #define bcma_cc_maskset32(cc, offset, mask, set) \
        bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
 
+/* PMU registers access */
+#define bcma_pmu_read32(cc, offset) \
+       bcma_read32((cc)->pmu.core, offset)
+#define bcma_pmu_write32(cc, offset, val) \
+       bcma_write32((cc)->pmu.core, offset, val)
+
+#define bcma_pmu_mask32(cc, offset, mask) \
+       bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) & (mask))
+#define bcma_pmu_set32(cc, offset, set) \
+       bcma_pmu_write32(cc, offset, bcma_pmu_read32(cc, offset) | (set))
+#define bcma_pmu_maskset32(cc, offset, mask, set) \
+       bcma_pmu_write32(cc, offset, (bcma_pmu_read32(cc, offset) & (mask)) | (set))
+
 extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
 
 extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);