diff options
367 files changed, 15167 insertions, 25119 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index f3e214f9e256..42e7f030cb16 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -404,7 +404,6 @@ !Finclude/net/mac80211.h ieee80211_get_tkip_p1k !Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv !Finclude/net/mac80211.h ieee80211_get_tkip_p2k -!Finclude/net/mac80211.h ieee80211_key_removed </chapter> <chapter id="powersave"> diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt index 320f9336c781..89a339c9b079 100644 --- a/Documentation/nfc/nfc-hci.txt +++ b/Documentation/nfc/nfc-hci.txt @@ -178,3 +178,36 @@ ANY_GET_PARAMETER to the reader A gate to get information on the target that was discovered). Typically, such an event will be propagated to NFC Core from MSGRXWQ context. + +Error management +---------------- + +Errors that occur synchronously with the execution of an NFC Core request are +simply returned as the execution result of the request. These are easy. + +Errors that occur asynchronously (e.g. in a background protocol handling thread) +must be reported such that upper layers don't stay ignorant that something +went wrong below and know that expected events will probably never happen. +Handling of these errors is done as follows: + +- driver (pn544) fails to deliver an incoming frame: it stores the error such +that any subsequent call to the driver will result in this error. Then it calls +the standard nfc_shdlc_recv_frame() with a NULL argument to report the problem +above. shdlc stores a EREMOTEIO sticky status, which will trigger SMW to +report above in turn. + +- SMW is basically a background thread to handle incoming and outgoing shdlc +frames. This thread will also check the shdlc sticky status and report to HCI +when it discovers it is not able to run anymore because of an unrecoverable +error that happened within shdlc or below. If the problem occurs during shdlc +connection, the error is reported through the connect completion. + +- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an +error from a lower layer, HCI will either complete the currently executing +command with that error, or notify NFC Core directly if no command is executing. + +- NFC Core: when NFC Core is notified of an error from below and polling is +active, it will send a tag discovered event with an empty tag list to the user +space to let it know that the poll operation will never be able to detect a tag. +If polling is not active and the error was sticky, lower levels will return it +at next invocation. diff --git a/MAINTAINERS b/MAINTAINERS index 3075a2a29511..1b2b77da1584 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1595,6 +1595,7 @@ M: Arend van Spriel <arend@broadcom.com> M: Franky (Zhenhui) Lin <frankyl@broadcom.com> M: Kan Yan <kanyan@broadcom.com> L: linux-wireless@vger.kernel.org +L: brcm80211-dev-list@broadcom.com S: Supported F: drivers/net/wireless/brcm80211/ @@ -3653,14 +3654,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git S: Supported F: drivers/net/wireless/iwlwifi/ -INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi) -M: Samuel Ortiz <samuel.ortiz@intel.com> -M: Intel Linux Wireless <ilw@linux.intel.com> -L: linux-wireless@vger.kernel.org -S: Supported -W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi -F: drivers/net/wireless/iwmc3200wifi/ - INTEL MANAGEMENT ENGINE (mei) M: Tomas Winkler <tomas.winkler@intel.com> L: linux-kernel@vger.kernel.org diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index b81755bb4798..f6589eb7c45f 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -10,6 +10,15 @@ #define BCMA_CORE_SIZE 0x1000 +#define bcma_err(bus, fmt, ...) \ + pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) +#define bcma_warn(bus, fmt, ...) \ + pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) +#define bcma_info(bus, fmt, ...) \ + pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) +#define bcma_debug(bus, fmt, ...) \ + pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__) + struct bcma_bus; /* main.c */ diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index bc6e89212ad3..63c8b470536f 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c @@ -75,7 +75,7 @@ void bcma_core_set_clockmode(struct bcma_device *core, udelay(10); } if (i) - pr_err("HT force timeout\n"); + bcma_err(core->bus, "HT force timeout\n"); break; case BCMA_CLKMODE_DYNAMIC: bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); @@ -102,9 +102,9 @@ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on) udelay(10); } if (i) - pr_err("PLL enable timeout\n"); + bcma_err(core->bus, "PLL enable timeout\n"); } else { - pr_warn("Disabling PLL not supported yet!\n"); + bcma_warn(core->bus, "Disabling PLL not supported yet!\n"); } } EXPORT_SYMBOL_GPL(bcma_core_pll_ctl); @@ -120,8 +120,8 @@ u32 bcma_core_dma_translation(struct bcma_device *core) else return BCMA_DMA_TRANSLATION_DMA32_CMT; default: - pr_err("DMA translation unknown for host %d\n", - core->bus->hosttype); + bcma_err(core->bus, "DMA translation unknown for host %d\n", + core->bus->hosttype); } return BCMA_DMA_TRANSLATION_NONE; } diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c index e9f1b3fd252c..a4c3ebcc4c86 100644 --- a/drivers/bcma/driver_chipcommon.c +++ b/drivers/bcma/driver_chipcommon.c @@ -44,7 +44,7 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc) if (cc->capabilities & BCMA_CC_CAP_PMU) bcma_pmu_init(cc); if (cc->capabilities & BCMA_CC_CAP_PCTL) - pr_err("Power control not implemented!\n"); + bcma_err(cc->core->bus, "Power control not implemented!\n"); if (cc->core->id.rev >= 16) { if (cc->core->bus->sprom.leddc_on_time && @@ -137,8 +137,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc) | BCMA_CC_CORECTL_UARTCLKEN); } } else { - pr_err("serial not supported on this device ccrev: 0x%x\n", - ccrev); + bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev); return; } diff --git a/drivers/bcma/driver_chipcommon_pmu.c b/drivers/bcma/driver_chipcommon_pmu.c index 61ce4054b3c3..44326178db29 100644 --- a/drivers/bcma/driver_chipcommon_pmu.c +++ b/drivers/bcma/driver_chipcommon_pmu.c @@ -3,7 +3,8 @@ * ChipCommon Power Management Unit driver * * Copyright 2009, Michael Buesch <m@bues.ch> - * Copyright 2007, Broadcom Corporation + * Copyright 2007, 2011, Broadcom Corporation + * Copyright 2011, 2012, Hauke Mehrtens <hauke@hauke-m.de> * * Licensed under the GNU/GPL. See COPYING for details. */ @@ -54,39 +55,19 @@ void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, } EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset); -static void bcma_pmu_pll_init(struct bcma_drv_cc *cc) -{ - struct bcma_bus *bus = cc->core->bus; - - switch (bus->chipinfo.id) { - case 0x4313: - case 0x4331: - case 43224: - case 43225: - break; - default: - pr_err("PLL init unknown for device 0x%04X\n", - bus->chipinfo.id); - } -} - static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; u32 min_msk = 0, max_msk = 0; switch (bus->chipinfo.id) { - case 0x4313: + case BCMA_CHIP_ID_BCM4313: min_msk = 0x200D; max_msk = 0xFFFF; break; - case 0x4331: - case 43224: - case 43225: - break; default: - pr_err("PMU resource config unknown for device 0x%04X\n", - bus->chipinfo.id); + bcma_debug(bus, "PMU resource config unknown or not needed for device 0x%04X\n", + bus->chipinfo.id); } /* Set the resource masks. */ @@ -94,22 +75,9 @@ static void bcma_pmu_resources_init(struct bcma_drv_cc *cc) bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk); if (max_msk) bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk); -} - -void bcma_pmu_swreg_init(struct bcma_drv_cc *cc) -{ - struct bcma_bus *bus = cc->core->bus; - switch (bus->chipinfo.id) { - case 0x4313: - case 0x4331: - case 43224: - case 43225: - break; - default: - pr_err("PMU switch/regulators init unknown for device " - "0x%04X\n", bus->chipinfo.id); - } + /* Add some delay; allow resources to come up and settle. */ + mdelay(2); } /* Disable to allow reading SPROM. Don't know the adventages of enabling it. */ @@ -123,8 +91,11 @@ void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable) val |= BCMA_CHIPCTL_4331_EXTPA_EN; if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11) val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; + else if (bus->chipinfo.rev > 0) + val |= BCMA_CHIPCTL_4331_EXTPA_EN2; } else { val &= ~BCMA_CHIPCTL_4331_EXTPA_EN; + val &= ~BCMA_CHIPCTL_4331_EXTPA_EN2; val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5; } bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val); @@ -135,28 +106,38 @@ void bcma_pmu_workarounds(struct bcma_drv_cc *cc) struct bcma_bus *bus = cc->core->bus; switch (bus->chipinfo.id) { - case 0x4313: - bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7); + case BCMA_CHIP_ID_BCM4313: + /* enable 12 mA drive strenth for 4313 and set chipControl + register bit 1 */ + bcma_chipco_chipctl_maskset(cc, 0, + BCMA_CCTRL_4313_12MA_LED_DRIVE, + BCMA_CCTRL_4313_12MA_LED_DRIVE); break; - case 0x4331: - case 43431: + case BCMA_CHIP_ID_BCM4331: + case BCMA_CHIP_ID_BCM43431: /* Ext PA lines must be enabled for tx on BCM4331 */ bcma_chipco_bcm4331_ext_pa_lines_ctl(cc, true); break; - case 43224: + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43421: + /* enable 12 mA drive strenth for 43224 and set chipControl + register bit 15 */ if (bus->chipinfo.rev == 0) { - pr_err("Workarounds for 43224 rev 0 not fully " - "implemented\n"); - bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0); + bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL, + BCMA_CCTRL_43224_GPIO_TOGGLE, + BCMA_CCTRL_43224_GPIO_TOGGLE); + bcma_chipco_chipctl_maskset(cc, 0, + BCMA_CCTRL_43224A0_12MA_LED_DRIVE, + BCMA_CCTRL_43224A0_12MA_LED_DRIVE); } else { - bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0); + bcma_chipco_chipctl_maskset(cc, 0, + BCMA_CCTRL_43224B0_12MA_LED_DRIVE, + BCMA_CCTRL_43224B0_12MA_LED_DRIVE); } break; - case 43225: - break; default: - pr_err("Workarounds unknown for device 0x%04X\n", - bus->chipinfo.id); + bcma_debug(bus, "Workarounds unknown or not needed for device 0x%04X\n", + bus->chipinfo.id); } } @@ -167,8 +148,8 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP); cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION); - pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev, - pmucap); + bcma_debug(cc->core->bus, "Found rev %u PMU (capabilities 0x%08X)\n", + cc->pmu.rev, pmucap); if (cc->pmu.rev == 1) bcma_cc_mask32(cc, BCMA_CC_PMU_CTL, @@ -177,12 +158,7 @@ void bcma_pmu_init(struct bcma_drv_cc *cc) bcma_cc_set32(cc, BCMA_CC_PMU_CTL, BCMA_CC_PMU_CTL_NOILPONW); - if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2) - pr_err("Fix for 4329b0 bad LPOM state not implemented!\n"); - - bcma_pmu_pll_init(cc); bcma_pmu_resources_init(cc); - bcma_pmu_swreg_init(cc); bcma_pmu_workarounds(cc); } @@ -191,23 +167,22 @@ u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc) struct bcma_bus *bus = cc->core->bus; switch (bus->chipinfo.id) { - case 0x4716: - case 0x4748: - case 47162: - case 0x4313: - case 0x5357: - case 0x4749: - case 53572: + case BCMA_CHIP_ID_BCM4716: + case BCMA_CHIP_ID_BCM4748: + case BCMA_CHIP_ID_BCM47162: + case BCMA_CHIP_ID_BCM4313: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM4749: + case BCMA_CHIP_ID_BCM53572: /* always 20Mhz */ return 20000 * 1000; - case 0x5356: - case 0x5300: + case BCMA_CHIP_ID_BCM5356: + case BCMA_CHIP_ID_BCM4706: /* always 25Mhz */ return 25000 * 1000; default: - pr_warn("No ALP clock specified for %04X device, " - "pmu rev. %d, using default %d Hz\n", - bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); + bcma_warn(bus, "No ALP clock specified for %04X device, pmu rev. %d, using default %d Hz\n", + bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK); } return BCMA_CC_PMU_ALP_CLOCK; } @@ -224,7 +199,8 @@ static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) BUG_ON(!m || m > 4); - if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) { /* Detect failure in clock setting */ tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); if (tmp & 0x40000) @@ -250,33 +226,62 @@ static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m) return (fc / div) * 1000000; } +static u32 bcma_pmu_clock_bcm4706(struct bcma_drv_cc *cc, u32 pll0, u32 m) +{ + u32 tmp, ndiv, p1div, p2div; + u32 clock; + + BUG_ON(!m || m > 4); + + /* Get N, P1 and P2 dividers to determine CPU clock */ + tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PMU6_4706_PROCPLL_OFF); + ndiv = (tmp & BCMA_CC_PMU6_4706_PROC_NDIV_INT_MASK) + >> BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT; + p1div = (tmp & BCMA_CC_PMU6_4706_PROC_P1DIV_MASK) + >> BCMA_CC_PMU6_4706_PROC_P1DIV_SHIFT; + p2div = (tmp & BCMA_CC_PMU6_4706_PROC_P2DIV_MASK) + >> BCMA_CC_PMU6_4706_PROC_P2DIV_SHIFT; + + tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT); + if (tmp & BCMA_CC_CHIPST_4706_PKG_OPTION) + /* Low cost bonding: Fixed reference clock 25MHz and m = 4 */ + clock = (25000000 / 4) * ndiv * p2div / p1div; + else + /* Fixed reference clock 25MHz and m = 2 */ + clock = (25000000 / 2) * ndiv * p2div / p1div; + + if (m == BCMA_CC_PMU5_MAINPLL_SSB) + clock = clock / 4; + + return clock; +} + /* query bus clock frequency for PMU-enabled chipcommon */ u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; switch (bus->chipinfo.id) { - case 0x4716: - case 0x4748: - case 47162: + case BCMA_CHIP_ID_BCM4716: + case BCMA_CHIP_ID_BCM4748: + case BCMA_CHIP_ID_BCM47162: return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0, BCMA_CC_PMU5_MAINPLL_SSB); - case 0x5356: + case BCMA_CHIP_ID_BCM5356: return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0, BCMA_CC_PMU5_MAINPLL_SSB); - case 0x5357: - case 0x4749: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM4749: return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0, BCMA_CC_PMU5_MAINPLL_SSB); - case 0x5300: - return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, - BCMA_CC_PMU5_MAINPLL_SSB); - case 53572: + case BCMA_CHIP_ID_BCM4706: + return bcma_pmu_clock_bcm4706(cc, BCMA_CC_PMU4706_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_SSB); + case BCMA_CHIP_ID_BCM53572: return 75000000; default: - pr_warn("No backplane clock specified for %04X device, " - "pmu rev. %d, using default %d Hz\n", - bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); + bcma_warn(bus, "No backplane clock specified for %04X device, pmu rev. %d, using default %d Hz\n", + bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK); } return BCMA_CC_PMU_HT_CLOCK; } @@ -286,17 +291,21 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) { struct bcma_bus *bus = cc->core->bus; - if (bus->chipinfo.id == 53572) + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) return 300000000; if (cc->pmu.rev >= 5) { u32 pll; switch (bus->chipinfo.id) { - case 0x5356: + case BCMA_CHIP_ID_BCM4706: + return bcma_pmu_clock_bcm4706(cc, + BCMA_CC_PMU4706_MAINPLL_PLL0, + BCMA_CC_PMU5_MAINPLL_CPU); + case BCMA_CHIP_ID_BCM5356: pll = BCMA_CC_PMU5356_MAINPLL_PLL0; break; - case 0x5357: - case 0x4749: + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM4749: pll = BCMA_CC_PMU5357_MAINPLL_PLL0; break; default: @@ -304,10 +313,188 @@ u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc) break; } - /* TODO: if (bus->chipinfo.id == 0x5300) - return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */ return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU); } return bcma_pmu_get_clockcontrol(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); +} + +void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid) +{ + u32 tmp = 0; + u8 phypll_offset = 0; + u8 bcm5357_bcm43236_p1div[] = {0x1, 0x5, 0x5}; + u8 bcm5357_bcm43236_ndiv[] = {0x30, 0xf6, 0xfc}; + struct bcma_bus *bus = cc->core->bus; + + switch (bus->chipinfo.id) { + case BCMA_CHIP_ID_BCM5357: + case BCMA_CHIP_ID_BCM4749: + case BCMA_CHIP_ID_BCM53572: + /* 5357[ab]0, 43236[ab]0, and 6362b0 */ + + /* BCM5357 needs to touch PLL1_PLLCTL[02], + so offset PLL0_PLLCTL[02] by 6 */ + phypll_offset = (bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM4749 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM53572) ? 6 : 0; + + /* RMW only the P1 divider */ + bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, + BCMA_CC_PMU_PLL_CTL0 + phypll_offset); + tmp = bcma_cc_read32(cc, BCMA_CC_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); + + /* RMW only the int feedback divider */ + bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, + BCMA_CC_PMU_PLL_CTL2 + phypll_offset); + tmp = bcma_cc_read32(cc, BCMA_CC_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); + + tmp = 1 << 10; + break; + + case BCMA_CHIP_ID_BCM4331: + case BCMA_CHIP_ID_BCM43431: + if (spuravoid == 2) { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11500014); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x0FC00a08); + } else if (spuravoid == 1) { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11500014); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x0F600a08); + } else { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11100014); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x03000a08); + } + tmp = 1 << 10; + break; + + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43225: + case BCMA_CHIP_ID_BCM43421: + if (spuravoid == 1) { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11500010); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x000C0C06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x0F600a08); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x2001E920); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } else { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11100010); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x000c0c06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x03000a08); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x200005c0); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } + tmp = 1 << 10; + break; + + case BCMA_CHIP_ID_BCM4716: + case BCMA_CHIP_ID_BCM4748: + case BCMA_CHIP_ID_BCM47162: + if (spuravoid == 1) { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11500060); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x080C0C06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x0F600000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x2001E924); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } else { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11100060); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x080c0c06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x03000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x200005c0); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } + + tmp = 3 << 9; + break; + + case BCMA_CHIP_ID_BCM43227: + case BCMA_CHIP_ID_BCM43228: + case BCMA_CHIP_ID_BCM43428: + /* LCNXN */ + /* PLL Settings for spur avoidance on/off mode, + no on2 support for 43228A0 */ + if (spuravoid == 1) { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x01100014); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x040C0C06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x03140A08); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00333333); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x202C2820); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } else { + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL0, + 0x11100014); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL1, + 0x040c0c06); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL2, + 0x03000a08); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL3, + 0x00000000); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL4, + 0x200005c0); + bcma_pmu_spuravoid_pll_write(cc, BCMA_CC_PMU_PLL_CTL5, + 0x88888815); + } + tmp = 1 << 10; + break; + default: + bcma_err(bus, "Unknown spuravoidance settings for chip 0x%04X, not changing PLL\n", + bus->chipinfo.id); + break; + } + + tmp |= bcma_cc_read32(cc, BCMA_CC_PMU_CTL); + bcma_cc_write32(cc, BCMA_CC_PMU_CTL, tmp); +} +EXPORT_SYMBOL_GPL(bcma_pmu_spuravoid_pllupdate); diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index c3e9dff4224e..ef34ed25bf00 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -22,15 +22,15 @@ /* The 47162a0 hangs when reading MIPS DMP registers registers */ static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev) { - return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 && - dev->id.id == BCMA_CORE_MIPS_74K; + return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 && + dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K; } /* The 5357b0 hangs when reading USB20H DMP registers */ static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev) { - return (dev->bus->chipinfo.id == 0x5357 || - dev->bus->chipinfo.id == 0x4749) && + return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 || + dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) && dev->bus->chipinfo.pkg == 11 && dev->id.id == BCMA_CORE_USB20_HOST; } @@ -143,8 +143,8 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq) 1 << irqflag); } - pr_info("set_irq: core 0x%04x, irq %d => %d\n", - dev->id.id, oldirq + 2, irq + 2); + bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n", + dev->id.id, oldirq + 2, irq + 2); } static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq) @@ -173,7 +173,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore) if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU) return bcma_pmu_get_clockcpu(&bus->drv_cc); - pr_err("No PMU available, need this to get the cpu clock\n"); + bcma_err(bus, "No PMU available, need this to get the cpu clock\n"); return 0; } EXPORT_SYMBOL(bcma_cpu_clock); @@ -185,10 +185,10 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: case BCMA_CC_FLASHT_ATSER: - pr_err("Serial flash not supported.\n"); + bcma_err(bus, "Serial flash not supported.\n"); break; case BCMA_CC_FLASHT_PARA: - pr_info("found parallel flash.\n"); + bcma_info(bus, "found parallel flash.\n"); bus->drv_cc.pflash.window = 0x1c000000; bus->drv_cc.pflash.window_size = 0x02000000; @@ -199,7 +199,7 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) bus->drv_cc.pflash.buswidth = 2; break; default: - pr_err("flash not supported.\n"); + bcma_err(bus, "flash not supported.\n"); } } @@ -209,7 +209,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) struct bcma_device *core; bus = mcore->core->bus; - pr_info("Initializing MIPS core...\n"); + bcma_info(bus, "Initializing MIPS core...\n"); if (!mcore->setup_done) mcore->assigned_irqs = 1; @@ -244,7 +244,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore) break; } } - pr_info("IRQ reconfiguration done\n"); + bcma_info(bus, "IRQ reconfiguration done\n"); bcma_core_mips_dump_irq(bus); if (mcore->setup_done) diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index b9a86edfec39..cbae2c231336 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -36,7 +36,7 @@ bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc) return false; if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) { - pr_info("This PCI core is disabled and not working\n"); + bcma_info(bus, "This PCI core is disabled and not working\n"); return false; } @@ -215,7 +215,8 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, } else { writel(val, mmio); - if (chipid == 0x4716 || chipid == 0x4748) + if (chipid == BCMA_CHIP_ID_BCM4716 || + chipid == BCMA_CHIP_ID_BCM4748) readl(mmio); } @@ -340,6 +341,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc, */ static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc) { + struct bcma_bus *bus = pc->core->bus; u8 cap_ptr, root_ctrl, root_cap, dev; u16 val16; int i; @@ -378,7 +380,8 @@ static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc) udelay(10); } if (val16 == 0x1) - pr_err("PCI: Broken device in slot %d\n", dev); + bcma_err(bus, "PCI: Broken device in slot %d\n", + dev); } } } @@ -391,11 +394,11 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) u32 pci_membase_1G; unsigned long io_map_base; - pr_info("PCIEcore in host mode found\n"); + bcma_info(bus, "PCIEcore in host mode found\n"); pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL); if (!pc_host) { - pr_err("can not allocate memory"); + bcma_err(bus, "can not allocate memory"); return; } @@ -434,13 +437,14 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) * as mips can't generate 64-bit address on the * backplane. */ - if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) { + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4716 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM4748) { pc_host->mem_resource.start = BCMA_SOC_PCI_MEM; pc_host->mem_resource.end = BCMA_SOC_PCI_MEM + BCMA_SOC_PCI_MEM_SZ - 1; pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0, BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM); - } else if (bus->chipinfo.id == 0x5300) { + } else if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { tmp = BCMA_CORE_PCI_SBTOPCI_MEM; tmp |= BCMA_CORE_PCI_SBTOPCI_PREF; tmp |= BCMA_CORE_PCI_SBTOPCI_BURST; diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index 6c05cf470f96..11b32d2642df 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -18,7 +18,7 @@ static void bcma_host_pci_switch_core(struct bcma_device *core) pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2, core->wrap); core->bus->mapped_core = core; - pr_debug("Switched to core: 0x%X\n", core->id.id); + bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id); } /* Provides access to the requested core. Returns base offset that has to be @@ -188,7 +188,7 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev, /* SSB needed additional powering up, do we have any AMBA PCI cards? */ if (!pci_is_pcie(dev)) - pr_err("PCI card detected, report problems.\n"); + bcma_err(bus, "PCI card detected, report problems.\n"); /* Map MMIO */ err = -ENOMEM; @@ -268,6 +268,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend, static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) }, diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7e138ec21357..7ff4bac6f9e1 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -118,8 +118,9 @@ static int bcma_register_cores(struct bcma_bus *bus) err = device_register(&core->dev); if (err) { - pr_err("Could not register dev for core 0x%03X\n", - core->id.id); + bcma_err(bus, + "Could not register dev for core 0x%03X\n", + core->id.id); continue; } core->dev_registered = true; @@ -151,7 +152,7 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) /* Scan for devices (cores) */ err = bcma_bus_scan(bus); if (err) { - pr_err("Failed to scan: %d\n", err); + bcma_err(bus, "Failed to scan: %d\n", err); return -1; } @@ -179,14 +180,14 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) /* Try to get SPROM */ err = bcma_sprom_get(bus); if (err == -ENOENT) { - pr_err("No SPROM available\n"); + bcma_err(bus, "No SPROM available\n"); } else if (err) - pr_err("Failed to get SPROM: %d\n", err); + bcma_err(bus, "Failed to get SPROM: %d\n", err); /* Register found cores */ bcma_register_cores(bus); - pr_info("Bus registered\n"); + bcma_info(bus, "Bus registered\n"); return 0; } @@ -214,7 +215,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, /* Scan for chip common core */ err = bcma_bus_scan_early(bus, &match, core_cc); if (err) { - pr_err("Failed to scan for common core: %d\n", err); + bcma_err(bus, "Failed to scan for common core: %d\n", err); return -1; } @@ -226,7 +227,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, /* Scan for mips core */ err = bcma_bus_scan_early(bus, &match, core_mips); if (err) { - pr_err("Failed to scan for mips core: %d\n", err); + bcma_err(bus, "Failed to scan for mips core: %d\n", err); return -1; } @@ -244,7 +245,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, bcma_core_mips_init(&bus->drv_mips); } - pr_info("Early bus registered\n"); + bcma_info(bus, "Early bus registered\n"); return 0; } diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 5ed0718fc660..a0272bbfc4f6 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -28,6 +28,12 @@ static const struct bcma_device_id_name bcma_arm_device_names[] = { static const struct bcma_device_id_name bcma_bcm_device_names[] = { { BCMA_CORE_OOB_ROUTER, "OOB Router" }, + { BCMA_CORE_4706_CHIPCOMMON, "BCM4706 ChipCommon" }, + { BCMA_CORE_4706_SOC_RAM, "BCM4706 SOC RAM" }, + { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" }, + { BCMA_CORE_AMEMC, "AMEMC (DDR)" }, + { BCMA_CORE_ALTA, "ALTA (I2S)" }, + { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" }, { BCMA_CORE_INVALID, "Invalid" }, { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, { BCMA_CORE_ILINE20, "ILine 20" }, @@ -334,7 +340,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, if (tmp <= 0) { return -EILSEQ; } else { - pr_info("Bridge found\n"); + bcma_info(bus, "Bridge found\n"); return -ENXIO; } } @@ -421,8 +427,8 @@ void bcma_init_bus(struct bcma_bus *bus) chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT; chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT; chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT; - pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", - chipinfo->id, chipinfo->rev, chipinfo->pkg); + bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n", + chipinfo->id, chipinfo->rev, chipinfo->pkg); bus->init_done = true; } @@ -476,11 +482,10 @@ int bcma_bus_scan(struct bcma_bus *bus) other_core = bcma_find_core_reverse(bus, core->id.id); core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1; - pr_info("Core %d found: %s " - "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", - core->core_index, bcma_device_name(&core->id), - core->id.manuf, core->id.id, core->id.rev, - core->id.class); + bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + core->core_index, bcma_device_name(&core->id), + core->id.manuf, core->id.id, core->id.rev, + core->id.class); list_add(&core->list, &bus->cores); } @@ -532,11 +537,10 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus, core->core_index = core_num++; bus->nr_cores++; - pr_info("Core %d found: %s " - "(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", - core->core_index, bcma_device_name(&core->id), - core->id.manuf, core->id.id, core->id.rev, - core->id.class); + bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n", + core->core_index, bcma_device_name(&core->id), + core->id.manuf, core->id.id, core->id.rev, + core->id.class); list_add(&core->list, &bus->cores); err = 0; diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index f16f42d36071..26823d97fd9f 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -60,11 +60,11 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus, if (err) goto fail; - pr_debug("Using SPROM revision %d provided by" - " platform.\n", bus->sprom.revision); + bcma_debug(bus, "Using SPROM revision %d provided by platform.\n", + bus->sprom.revision); return 0; fail: - pr_warn("Using fallback SPROM failed (err %d)\n", err); + bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err); return err; } @@ -468,11 +468,11 @@ static bool bcma_sprom_ext_available(struct bcma_bus *bus) /* older chipcommon revisions use chip status register */ chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { - case 0x4313: + case BCMA_CHIP_ID_BCM4313: present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT; break; - case 0x4331: + case BCMA_CHIP_ID_BCM4331: present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT; break; @@ -494,16 +494,16 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus) chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT); switch (bus->chipinfo.id) { - case 0x4313: + case BCMA_CHIP_ID_BCM4313: present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT; break; - case 0x4331: + case BCMA_CHIP_ID_BCM4331: present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT; break; - case 43224: - case 43225: + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43225: /* for these chips OTP is always available */ present = true; break; @@ -579,13 +579,15 @@ int bcma_sprom_get(struct bcma_bus *bus) if (!sprom) return -ENOMEM; - if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false); - pr_debug("SPROM offset 0x%x\n", offset); + bcma_debug(bus, "SPROM offset 0x%x\n", offset); bcma_sprom_read(bus, offset, sprom); - if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431) + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM43431) bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true); err = bcma_sprom_valid(sprom); diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index ad591bd240ec..10308cd8a7ed 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -63,6 +63,7 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0CF3, 0x3002) }, + { USB_DEVICE(0x0CF3, 0xE019) }, { USB_DEVICE(0x13d3, 0x3304) }, { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0489, 0xE03D) }, @@ -77,6 +78,7 @@ static struct usb_device_id ath3k_table[] = { { USB_DEVICE(0x04CA, 0x3005) }, { USB_DEVICE(0x13d3, 0x3362) }, { USB_DEVICE(0x0CF3, 0xE004) }, + { USB_DEVICE(0x0930, 0x0219) }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, @@ -101,6 +103,7 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU22 with sflash firmware */ { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 1fcd92380356..585c88e01893 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; - register unsigned int offset; - register unsigned char command; - register unsigned long ready_bit; + unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int offset; + unsigned char command; + unsigned long ready_bit; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index 609861a53c28..29caaed2d715 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->flush = bpa10x_flush; hdev->send = bpa10x_send_frame; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); err = hci_register_dev(hdev); if (err < 0) { diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index 308c8599ab55..b2b0fbbb43b5 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info) return; do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; if (!pcmcia_dev_present(info->p_dev)) break; diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 94f2d65131c4..27068d149380 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -136,7 +136,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv); void btmrvl_interrupt(struct btmrvl_private *priv); -void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); +bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 681ca9d18e12..dc304def8400 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -44,23 +44,33 @@ void btmrvl_interrupt(struct btmrvl_private *priv) } EXPORT_SYMBOL_GPL(btmrvl_interrupt); -void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) +bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; struct hci_ev_cmd_complete *ec; - u16 opcode, ocf; + u16 opcode, ocf, ogf; if (hdr->evt == HCI_EV_CMD_COMPLETE) { ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); ocf = hci_opcode_ocf(opcode); + ogf = hci_opcode_ogf(opcode); + if (ocf == BT_CMD_MODULE_CFG_REQ && priv->btmrvl_dev.sendcmdflag) { priv->btmrvl_dev.sendcmdflag = false; priv->adapter->cmd_complete = true; wake_up_interruptible(&priv->adapter->cmd_wait_q); } + + if (ogf == OGF) { + BT_DBG("vendor event skipped: ogf 0x%4.4x", ogf); + kfree_skb(skb); + return false; + } } + + return true; } EXPORT_SYMBOL_GPL(btmrvl_check_evtpkt); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index a853244e7fd7..cf7588edba0d 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = { /* Marvell SD8787 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A), .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, + /* Marvell SD8787 Bluetooth AMP device */ + { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B), + .driver_data = (unsigned long) &btmrvl_sdio_sd8787 }, /* Marvell SD8797 Bluetooth device */ { SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A), .driver_data = (unsigned long) &btmrvl_sdio_sd8797 }, @@ -562,10 +565,12 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) skb_put(skb, buf_len); skb_pull(skb, SDIO_HEADER_LEN); - if (type == HCI_EVENT_PKT) - btmrvl_check_evtpkt(priv, skb); + if (type == HCI_EVENT_PKT) { + if (btmrvl_check_evtpkt(priv, skb)) + hci_recv_frame(skb); + } else + hci_recv_frame(skb); - hci_recv_frame(skb); hdev->stat.byte_rx += buf_len; break; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index c4fc2f3fc32c..65b8d996840c 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c9463af8e564..e27221411036 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -21,15 +21,7 @@ * */ -#include <linux/kernel.h> #include <linux/module.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/types.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/skbuff.h> - #include <linux/usb.h> #include <net/bluetooth/bluetooth.h> @@ -125,6 +117,7 @@ static struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x13d3, 0x3304), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, @@ -139,6 +132,7 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, + { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 }, /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, @@ -1026,7 +1020,7 @@ static int btusb_probe(struct usb_interface *intf, data->isoc = usb_ifnum_to_if(data->udev, 1); if (!reset) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) @@ -1038,7 +1032,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_DIGIANSWER) { data->cmdreq_type = USB_TYPE_VENDOR; - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); } if (id->driver_info & BTUSB_CSR) { @@ -1046,7 +1040,7 @@ static int btusb_probe(struct usb_interface *intf, /* Old firmware would otherwise execute USB reset */ if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); } if (id->driver_info & BTUSB_SNIFFER) { diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index 6e8d96189684..b1b37ccd3cd4 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info) } do { - register unsigned int iobase = info->p_dev->resource[0]->start; + unsigned int iobase = info->p_dev->resource[0]->start; register struct sk_buff *skb; - register int len; + int len; clear_bit(XMIT_WAKEUP, &(info->tx_state)); diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 661a8dc4d2f8..57e502e06080 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp) static int bcsp_recv(struct hci_uart *hu, void *data, int count) { struct bcsp_struct *bcsp = hu->priv; - register unsigned char *ptr; + unsigned char *ptr; BT_DBG("hu %p count %d rx_state %d rx_count %ld", hu, count, bcsp->rx_state, bcsp->rx_count); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 748329468d26..c60623f206d4 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) static inline int h4_check_data_len(struct h4_struct *h4, int len) { - register int room = skb_tailroom(h4->rx_skb); + int room = skb_tailroom(h4->rx_skb); BT_DBG("len %d room %d", len, room); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index e564579a6115..2f9b796e106e 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags)) - set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks); if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags)) hdev->dev_type = HCI_AMP; diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index b874c0efde24..ff6d589c34a5 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb) static inline int ll_check_data_len(struct ll_struct *ll, int len) { - register int room = skb_tailroom(ll->rx_skb); + int room = skb_tailroom(ll->rx_skb); BT_DBG("len %d room %d", len, room); @@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len) static int ll_recv(struct hci_uart *hu, void *data, int count) { struct ll_struct *ll = hu->priv; - register char *ptr; + char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; - register int len, type, dlen; + int len, type, dlen; BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2661f6e366f9..154f3ef07631 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -511,7 +511,6 @@ config USB_SWITCH_FSA9480 source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" -source "drivers/misc/iwmc3200top/Kconfig" source "drivers/misc/ti-st/Kconfig" source "drivers/misc/lis3lv02d/Kconfig" source "drivers/misc/carma/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 456972faaeb3..b88df7a350b8 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -36,7 +36,6 @@ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o obj-$(CONFIG_DS1682) += ds1682.o obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o obj-$(CONFIG_C2PORT) += c2port/ -obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/ obj-$(CONFIG_HMC6352) += hmc6352.o obj-y += eeprom/ obj-y += cb710/ diff --git a/drivers/misc/iwmc3200top/Kconfig b/drivers/misc/iwmc3200top/Kconfig deleted file mode 100644 index 9e4b88fb57f1..000000000000 --- a/drivers/misc/iwmc3200top/Kconfig +++ /dev/null @@ -1,20 +0,0 @@ -config IWMC3200TOP - tristate "Intel Wireless MultiCom Top Driver" - depends on MMC && EXPERIMENTAL - select FW_LOADER - ---help--- - Intel Wireless MultiCom 3200 Top driver is responsible for - for firmware load and enabled coms enumeration - -config IWMC3200TOP_DEBUG - bool "Enable full debug output of iwmc3200top Driver" - depends on IWMC3200TOP - ---help--- - Enable full debug output of iwmc3200top Driver - -config IWMC3200TOP_DEBUGFS - bool "Enable Debugfs debugging interface for iwmc3200top" - depends on IWMC3200TOP - ---help--- - Enable creation of debugfs files for iwmc3200top - diff --git a/drivers/misc/iwmc3200top/Makefile b/drivers/misc/iwmc3200top/Makefile deleted file mode 100644 index fbf53fb4634e..000000000000 --- a/drivers/misc/iwmc3200top/Makefile +++ /dev/null @@ -1,29 +0,0 @@ -# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver -# drivers/misc/iwmc3200top/Makefile -# -# Copyright (C) 2009 Intel Corporation. All rights reserved. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License version -# 2 as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# -# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> -# - -# -# - -obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o -iwmc3200top-objs := main.o fw-download.o -iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o -iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o diff --git a/drivers/misc/iwmc3200top/debugfs.c b/drivers/misc/iwmc3200top/debugfs.c deleted file mode 100644 index 62fbaec48207..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/debufs.c - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio.h> -#include <linux/debugfs.h> - -#include "iwmc3200top.h" -#include "fw-msg.h" -#include "log.h" -#include "debugfs.h" - - - -/* Constants definition */ -#define HEXADECIMAL_RADIX 16 - -/* Functions definition */ - - -#define DEBUGFS_ADD(name, parent) do { \ - dbgfs->dbgfs_##parent##_files.file_##name = \ - debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \ - &iwmct_dbgfs_##name##_ops); \ -} while (0) - -#define DEBUGFS_RM(name) do { \ - debugfs_remove(name); \ - name = NULL; \ -} while (0) - -#define DEBUGFS_READ_FUNC(name) \ -ssize_t iwmct_dbgfs_##name##_read(struct file *file, \ - char __user *user_buf, \ - size_t count, loff_t *ppos); - -#define DEBUGFS_WRITE_FUNC(name) \ -ssize_t iwmct_dbgfs_##name##_write(struct file *file, \ - const char __user *user_buf, \ - size_t count, loff_t *ppos); - -#define DEBUGFS_READ_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name) \ - static const struct file_operations iwmct_dbgfs_##name##_ops = { \ - .read = iwmct_dbgfs_##name##_read, \ - .open = iwmct_dbgfs_open_file_generic, \ - .llseek = generic_file_llseek, \ - }; - -#define DEBUGFS_WRITE_FILE_OPS(name) \ - DEBUGFS_WRITE_FUNC(name) \ - static const struct file_operations iwmct_dbgfs_##name##_ops = { \ - .write = iwmct_dbgfs_##name##_write, \ - .open = iwmct_dbgfs_open_file_generic, \ - .llseek = generic_file_llseek, \ - }; - -#define DEBUGFS_READ_WRITE_FILE_OPS(name) \ - DEBUGFS_READ_FUNC(name) \ - DEBUGFS_WRITE_FUNC(name) \ - static const struct file_operations iwmct_dbgfs_##name##_ops = {\ - .write = iwmct_dbgfs_##name##_write, \ - .read = iwmct_dbgfs_##name##_read, \ - .open = iwmct_dbgfs_open_file_generic, \ - .llseek = generic_file_llseek, \ - }; - - -/* Debugfs file ops definitions */ - -/* - * Create the debugfs files and directories - * - */ -void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) -{ - struct iwmct_debugfs *dbgfs; - - dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL); - if (!dbgfs) { - LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n", - sizeof(struct iwmct_debugfs)); - return; - } - - priv->dbgfs = dbgfs; - dbgfs->name = name; - dbgfs->dir_drv = debugfs_create_dir(name, NULL); - if (!dbgfs->dir_drv) { - LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n"); - return; - } - - return; -} - -/** - * Remove the debugfs files and directories - * - */ -void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) -{ - if (!dbgfs) - return; - - DEBUGFS_RM(dbgfs->dir_drv); - kfree(dbgfs); - dbgfs = NULL; -} - diff --git a/drivers/misc/iwmc3200top/debugfs.h b/drivers/misc/iwmc3200top/debugfs.h deleted file mode 100644 index 71d45759b40f..000000000000 --- a/drivers/misc/iwmc3200top/debugfs.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/debufs.h - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#ifndef __DEBUGFS_H__ -#define __DEBUGFS_H__ - - -#ifdef CONFIG_IWMC3200TOP_DEBUGFS - -struct iwmct_debugfs { - const char *name; - struct dentry *dir_drv; - struct dir_drv_files { - } dbgfs_drv_files; -}; - -void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name); -void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs); - -#else /* CONFIG_IWMC3200TOP_DEBUGFS */ - -struct iwmct_debugfs; - -static inline void -iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name) -{} - -static inline void -iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs) -{} - -#endif /* CONFIG_IWMC3200TOP_DEBUGFS */ - -#endif /* __DEBUGFS_H__ */ - diff --git a/drivers/misc/iwmc3200top/fw-download.c b/drivers/misc/iwmc3200top/fw-download.c deleted file mode 100644 index e27afde6e99f..000000000000 --- a/drivers/misc/iwmc3200top/fw-download.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/fw-download.c - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#include <linux/firmware.h> -#include <linux/mmc/sdio_func.h> -#include <linux/slab.h> -#include <asm/unaligned.h> - -#include "iwmc3200top.h" -#include "log.h" -#include "fw-msg.h" - -#define CHECKSUM_BYTES_NUM sizeof(u32) - -/** - init parser struct with file - */ -static int iwmct_fw_parser_init(struct iwmct_priv *priv, const u8 *file, - size_t file_size, size_t block_size) -{ - struct iwmct_parser *parser = &priv->parser; - struct iwmct_fw_hdr *fw_hdr = &parser->versions; - - LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); - - LOG_INFO(priv, FW_DOWNLOAD, "file_size=%zd\n", file_size); - - parser->file = file; - parser->file_size = file_size; - parser->cur_pos = 0; - parser->entry_point = 0; - parser->buf = kzalloc(block_size, GFP_KERNEL); - if (!parser->buf) { - LOG_ERROR(priv, FW_DOWNLOAD, "kzalloc error\n"); - return -ENOMEM; - } - parser->buf_size = block_size; - - /* extract fw versions */ - memcpy(fw_hdr, parser->file, sizeof(struct iwmct_fw_hdr)); - LOG_INFO(priv, FW_DOWNLOAD, "fw versions are:\n" - "top %u.%u.%u gps %u.%u.%u bt %u.%u.%u tic %s\n", - fw_hdr->top_major, fw_hdr->top_minor, fw_hdr->top_revision, - fw_hdr->gps_major, fw_hdr->gps_minor, fw_hdr->gps_revision, - fw_hdr->bt_major, fw_hdr->bt_minor, fw_hdr->bt_revision, - fw_hdr->tic_name); - - parser->cur_pos += sizeof(struct iwmct_fw_hdr); - - LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); - return 0; -} - -static bool iwmct_checksum(struct iwmct_priv *priv) -{ - struct iwmct_parser *parser = &priv->parser; - __le32 *file = (__le32 *)parser->file; - int i, pad, steps; - u32 accum = 0; - u32 checksum; - u32 mask = 0xffffffff; - - pad = (parser->file_size - CHECKSUM_BYTES_NUM) % 4; - steps = (parser->file_size - CHECKSUM_BYTES_NUM) / 4; - - LOG_INFO(priv, FW_DOWNLOAD, "pad=%d steps=%d\n", pad, steps); - - for (i = 0; i < steps; i++) - accum += le32_to_cpu(file[i]); - - if (pad) { - mask <<= 8 * (4 - pad); - accum += le32_to_cpu(file[steps]) & mask; - } - - checksum = get_unaligned_le32((__le32 *)(parser->file + - parser->file_size - CHECKSUM_BYTES_NUM)); - - LOG_INFO(priv, FW_DOWNLOAD, - "compare checksum accum=0x%x to checksum=0x%x\n", - accum, checksum); - - return checksum == accum; -} - -static int iwmct_parse_next_section(struct iwmct_priv *priv, const u8 **p_sec, - size_t *sec_size, __le32 *sec_addr) -{ - struct iwmct_parser *parser = &priv->parser; - struct iwmct_dbg *dbg = &priv->dbg; - struct iwmct_fw_sec_hdr *sec_hdr; - - LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); - - while (parser->cur_pos + sizeof(struct iwmct_fw_sec_hdr) - <= parser->file_size) { - - sec_hdr = (struct iwmct_fw_sec_hdr *) - (parser->file + parser->cur_pos); - parser->cur_pos += sizeof(struct iwmct_fw_sec_hdr); - - LOG_INFO(priv, FW_DOWNLOAD, - "sec hdr: type=%s addr=0x%x size=%d\n", - sec_hdr->type, sec_hdr->target_addr, - sec_hdr->data_size); - - if (strcmp(sec_hdr->type, "ENT") == 0) - parser->entry_point = le32_to_cpu(sec_hdr->target_addr); - else if (strcmp(sec_hdr->type, "LBL") == 0) - strcpy(dbg->label_fw, parser->file + parser->cur_pos); - else if (((strcmp(sec_hdr->type, "TOP") == 0) && - (priv->barker & BARKER_DNLOAD_TOP_MSK)) || - ((strcmp(sec_hdr->type, "GPS") == 0) && - (priv->barker & BARKER_DNLOAD_GPS_MSK)) || - ((strcmp(sec_hdr->type, "BTH") == 0) && - (priv->barker & BARKER_DNLOAD_BT_MSK))) { - *sec_addr = sec_hdr->target_addr; - *sec_size = le32_to_cpu(sec_hdr->data_size); - *p_sec = parser->file + parser->cur_pos; - parser->cur_pos += le32_to_cpu(sec_hdr->data_size); - return 1; - } else if (strcmp(sec_hdr->type, "LOG") != 0) - LOG_WARNING(priv, FW_DOWNLOAD, - "skipping section type %s\n", - sec_hdr->type); - - parser->cur_pos += le32_to_cpu(sec_hdr->data_size); - LOG_INFO(priv, FW_DOWNLOAD, - "finished with section cur_pos=%zd\n", parser->cur_pos); - } - - LOG_TRACE(priv, INIT, "<--\n"); - return 0; -} - -static int iwmct_download_section(struct iwmct_priv *priv, const u8 *p_sec, - size_t sec_size, __le32 addr) -{ - struct iwmct_parser *parser = &priv->parser; - struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; - const u8 *cur_block = p_sec; - size_t sent = 0; - int cnt = 0; - int ret = 0; - u32 cmd = 0; - - LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); - LOG_INFO(priv, FW_DOWNLOAD, "Download address 0x%x size 0x%zx\n", - addr, sec_size); - - while (sent < sec_size) { - int i; - u32 chksm = 0; - u32 reset = atomic_read(&priv->reset); - /* actual FW data */ - u32 data_size = min(parser->buf_size - sizeof(*hdr), - sec_size - sent); - /* Pad to block size */ - u32 trans_size = (data_size + sizeof(*hdr) + - IWMC_SDIO_BLK_SIZE - 1) & - ~(IWMC_SDIO_BLK_SIZE - 1); - ++cnt; - - /* in case of reset, interrupt FW DOWNLAOD */ - if (reset) { - LOG_INFO(priv, FW_DOWNLOAD, - "Reset detected. Abort FW download!!!"); - ret = -ECANCELED; - goto exit; - } - - memset(parser->buf, 0, parser->buf_size); - cmd |= IWMC_OPCODE_WRITE << CMD_HDR_OPCODE_POS; - cmd |= IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; - cmd |= (priv->dbg.direct ? 1 : 0) << CMD_HDR_DIRECT_ACCESS_POS; - cmd |= (priv->dbg.checksum ? 1 : 0) << CMD_HDR_USE_CHECKSUM_POS; - hdr->data_size = cpu_to_le32(data_size); - hdr->target_addr = addr; - - /* checksum is allowed for sizes divisible by 4 */ - if (data_size & 0x3) - cmd &= ~CMD_HDR_USE_CHECKSUM_MSK; - - memcpy(hdr->data, cur_block, data_size); - - - if (cmd & CMD_HDR_USE_CHECKSUM_MSK) { - - chksm = data_size + le32_to_cpu(addr) + cmd; - for (i = 0; i < data_size >> 2; i++) - chksm += ((u32 *)cur_block)[i]; - - hdr->block_chksm = cpu_to_le32(chksm); - LOG_INFO(priv, FW_DOWNLOAD, "Checksum = 0x%X\n", - hdr->block_chksm); - } - - LOG_INFO(priv, FW_DOWNLOAD, "trans#%d, len=%d, sent=%zd, " - "sec_size=%zd, startAddress 0x%X\n", - cnt, trans_size, sent, sec_size, addr); - - if (priv->dbg.dump) - LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, trans_size); - - - hdr->cmd = cpu_to_le32(cmd); - /* send it down */ - /* TODO: add more proper sending and error checking */ - ret = iwmct_tx(priv, parser->buf, trans_size); - if (ret != 0) { - LOG_INFO(priv, FW_DOWNLOAD, - "iwmct_tx returned %d\n", ret); - goto exit; - } - - addr = cpu_to_le32(le32_to_cpu(addr) + data_size); - sent += data_size; - cur_block = p_sec + sent; - - if (priv->dbg.blocks && (cnt + 1) >= priv->dbg.blocks) { - LOG_INFO(priv, FW_DOWNLOAD, - "Block number limit is reached [%d]\n", - priv->dbg.blocks); - break; - } - } - - if (sent < sec_size) - ret = -EINVAL; -exit: - LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); - return ret; -} - -static int iwmct_kick_fw(struct iwmct_priv *priv, bool jump) -{ - struct iwmct_parser *parser = &priv->parser; - struct iwmct_fw_load_hdr *hdr = (struct iwmct_fw_load_hdr *)parser->buf; - int ret; - u32 cmd; - - LOG_TRACE(priv, FW_DOWNLOAD, "-->\n"); - - memset(parser->buf, 0, parser->buf_size); - cmd = IWMC_CMD_SIGNATURE << CMD_HDR_SIGNATURE_POS; - if (jump) { - cmd |= IWMC_OPCODE_JUMP << CMD_HDR_OPCODE_POS; - hdr->target_addr = cpu_to_le32(parser->entry_point); - LOG_INFO(priv, FW_DOWNLOAD, "jump address 0x%x\n", - parser->entry_point); - } else { - cmd |= IWMC_OPCODE_LAST_COMMAND << CMD_HDR_OPCODE_POS; - LOG_INFO(priv, FW_DOWNLOAD, "last command\n"); - } - - hdr->cmd = cpu_to_le32(cmd); - - LOG_HEXDUMP(FW_DOWNLOAD, parser->buf, sizeof(*hdr)); - /* send it down */ - /* TODO: add more proper sending and error checking */ - ret = iwmct_tx(priv, parser->buf, IWMC_SDIO_BLK_SIZE); - if (ret) - LOG_INFO(priv, FW_DOWNLOAD, "iwmct_tx returned %d", ret); - - LOG_TRACE(priv, FW_DOWNLOAD, "<--\n"); - return 0; -} - -int iwmct_fw_load(struct iwmct_priv *priv) -{ - const u8 *fw_name = FW_NAME(FW_API_VER); - const struct firmware *raw; - const u8 *pdata; - size_t len; - __le32 addr; - int ret; - - - LOG_INFO(priv, FW_DOWNLOAD, "barker download request 0x%x is:\n", - priv->barker); - LOG_INFO(priv, FW_DOWNLOAD, "******* Top FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_TOP_MSK) ? "was" : "not"); - LOG_INFO(priv, FW_DOWNLOAD, "******* GPS FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_GPS_MSK) ? "was" : "not"); - LOG_INFO(priv, FW_DOWNLOAD, "******* BT FW %s requested ********\n", - (priv->barker & BARKER_DNLOAD_BT_MSK) ? "was" : "not"); - - - /* get the firmware */ - ret = request_firmware(&raw, fw_name, &priv->func->dev); - if (ret < 0) { - LOG_ERROR(priv, FW_DOWNLOAD, "%s request_firmware failed %d\n", - fw_name, ret); - goto exit; - } - - if (raw->size < sizeof(struct iwmct_fw_sec_hdr)) { - LOG_ERROR(priv, FW_DOWNLOAD, "%s smaller then (%zd) (%zd)\n", - fw_name, sizeof(struct iwmct_fw_sec_hdr), raw->size); - goto exit; - } - - LOG_INFO(priv, FW_DOWNLOAD, "Read firmware '%s'\n", fw_name); - - /* clear parser struct */ - ret = iwmct_fw_parser_init(priv, raw->data, raw->size, priv->trans_len); - if (ret < 0) { - LOG_ERROR(priv, FW_DOWNLOAD, - "iwmct_parser_init failed: Reason %d\n", ret); - goto exit; - } - - if (!iwmct_checksum(priv)) { - LOG_ERROR(priv, FW_DOWNLOAD, "checksum error\n"); - ret = -EINVAL; - goto exit; - } - - /* download firmware to device */ - while (iwmct_parse_next_section(priv, &pdata, &len, &addr)) { - ret = iwmct_download_section(priv, pdata, len, addr); - if (ret) { - LOG_ERROR(priv, FW_DOWNLOAD, - "%s download section failed\n", fw_name); - goto exit; - } - } - - ret = iwmct_kick_fw(priv, !!(priv->barker & BARKER_DNLOAD_JUMP_MSK)); - -exit: - kfree(priv->parser.buf); - release_firmware(raw); - return ret; -} diff --git a/drivers/misc/iwmc3200top/fw-msg.h b/drivers/misc/iwmc3200top/fw-msg.h deleted file mode 100644 index 9e26b75bd482..000000000000 --- a/drivers/misc/iwmc3200top/fw-msg.h +++ /dev/null @@ -1,113 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/fw-msg.h - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#ifndef __FWMSG_H__ -#define __FWMSG_H__ - -#define COMM_TYPE_D2H 0xFF -#define COMM_TYPE_H2D 0xEE - -#define COMM_CATEGORY_OPERATIONAL 0x00 -#define COMM_CATEGORY_DEBUG 0x01 -#define COMM_CATEGORY_TESTABILITY 0x02 -#define COMM_CATEGORY_DIAGNOSTICS 0x03 - -#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A) - -#define FW_LOG_SRC_MAX 32 -#define FW_LOG_SRC_ALL 255 - -#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000) - -#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001) -#define CMD_TST_DEV_RESET cpu_to_le16(0x0060) -#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062) -#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064) -#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065) -#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080) -#define CMD_TST_WAKEUP cpu_to_le16(0x0081) -#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082) -#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083) -#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096) - -#define OP_OPR_ALIVE cpu_to_le16(0x0010) -#define OP_OPR_CMD_ACK cpu_to_le16(0x001F) -#define OP_OPR_CMD_NACK cpu_to_le16(0x0020) -#define OP_TST_MEM_DUMP cpu_to_le16(0x0043) - -#define CMD_FLAG_PADDING_256 0x80 - -#define FW_HCMD_BLOCK_SIZE 256 - -struct msg_hdr { - u8 type; - u8 category; - __le16 opcode; - u8 seqnum; - u8 flags; - __le16 length; -} __attribute__((__packed__)); - -struct log_hdr { - __le32 timestamp; - u8 severity; - u8 logsource; - __le16 reserved; -} __attribute__((__packed__)); - -struct mdump_hdr { - u8 dmpid; - u8 frag; - __le16 size; - __le32 addr; -} __attribute__((__packed__)); - -struct top_msg { - struct msg_hdr hdr; - union { - /* D2H messages */ - struct { - struct log_hdr log_hdr; - u8 data[1]; - } __attribute__((__packed__)) log; - - struct { - struct log_hdr log_hdr; - struct mdump_hdr md_hdr; - u8 data[1]; - } __attribute__((__packed__)) mdump; - - /* H2D messages */ - struct { - u8 logsource; - u8 sevmask; - } __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX]; - struct mdump_hdr mdump_req; - } u; -} __attribute__((__packed__)); - - -#endif /* __FWMSG_H__ */ diff --git a/drivers/misc/iwmc3200top/iwmc3200top.h b/drivers/misc/iwmc3200top/iwmc3200top.h deleted file mode 100644 index 620973ed8bf9..000000000000 --- a/drivers/misc/iwmc3200top/iwmc3200top.h +++ /dev/null @@ -1,205 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/iwmc3200top.h - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#ifndef __IWMC3200TOP_H__ -#define __IWMC3200TOP_H__ - -#include <linux/workqueue.h> - -#define DRV_NAME "iwmc3200top" -#define FW_API_VER 1 -#define _FW_NAME(api) DRV_NAME "." #api ".fw" -#define FW_NAME(api) _FW_NAME(api) - -#define IWMC_SDIO_BLK_SIZE 256 -#define IWMC_DEFAULT_TR_BLK 64 -#define IWMC_SDIO_DATA_ADDR 0x0 -#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14 -#define IWMC_SDIO_INTR_STATUS_ADDR 0x13 -#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13 -#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C - -#define COMM_HUB_HEADER_LENGTH 16 -#define LOGGER_HEADER_LENGTH 10 - - -#define BARKER_DNLOAD_BT_POS 0 -#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS) -#define BARKER_DNLOAD_GPS_POS 1 -#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS) -#define BARKER_DNLOAD_TOP_POS 2 -#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS) -#define BARKER_DNLOAD_RESERVED1_POS 3 -#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS) -#define BARKER_DNLOAD_JUMP_POS 4 -#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS) -#define BARKER_DNLOAD_SYNC_POS 5 -#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS) -#define BARKER_DNLOAD_RESERVED2_POS 6 -#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS) -#define BARKER_DNLOAD_BARKER_POS 8 -#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS) - -#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS) -/* whole field barker */ -#define IWMC_BARKER_ACK 0xfeedbabe - -#define IWMC_CMD_SIGNATURE 0xcbbc - -#define CMD_HDR_OPCODE_POS 0 -#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS) -#define CMD_HDR_RESPONSE_CODE_POS 4 -#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS) -#define CMD_HDR_USE_CHECKSUM_POS 8 -#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS) -#define CMD_HDR_RESPONSE_REQUIRED_POS 9 -#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS) -#define CMD_HDR_DIRECT_ACCESS_POS 10 -#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS) -#define CMD_HDR_RESERVED_POS 11 -#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS) -#define CMD_HDR_SIGNATURE_POS 16 -#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS) - -enum { - IWMC_OPCODE_PING = 0, - IWMC_OPCODE_READ = 1, - IWMC_OPCODE_WRITE = 2, - IWMC_OPCODE_JUMP = 3, - IWMC_OPCODE_REBOOT = 4, - IWMC_OPCODE_PERSISTENT_WRITE = 5, - IWMC_OPCODE_PERSISTENT_READ = 6, - IWMC_OPCODE_READ_MODIFY_WRITE = 7, - IWMC_OPCODE_LAST_COMMAND = 15 -}; - -struct iwmct_fw_load_hdr { - __le32 cmd; - __le32 target_addr; - __le32 data_size; - __le32 block_chksm; - u8 data[0]; -}; - -/** - * struct iwmct_fw_hdr - * holds all sw components versions - */ -struct iwmct_fw_hdr { - u8 top_major; - u8 top_minor; - u8 top_revision; - u8 gps_major; - u8 gps_minor; - u8 gps_revision; - u8 bt_major; - u8 bt_minor; - u8 bt_revision; - u8 tic_name[31]; -}; - -/** - * struct iwmct_fw_sec_hdr - * @type: function type - * @data_size: section's data size - * @target_addr: download address - */ -struct iwmct_fw_sec_hdr { - u8 type[4]; - __le32 data_size; - __le32 target_addr; -}; - -/** - * struct iwmct_parser - * @file: fw image - * @file_size: fw size - * @cur_pos: position in file - * @buf: temp buf for download - * @buf_size: size of buf - * @entry_point: address to jump in fw kick-off - */ -struct iwmct_parser { - const u8 *file; - size_t file_size; - size_t cur_pos; - u8 *buf; - size_t buf_size; - u32 entry_point; - struct iwmct_fw_hdr versions; -}; - - -struct iwmct_work_struct { - struct list_head list; - ssize_t iosize; -}; - -struct iwmct_dbg { - int blocks; - bool dump; - bool jump; - bool direct; - bool checksum; - bool fw_download; - int block_size; - int download_trans_blks; - - char label_fw[256]; -}; - -struct iwmct_debugfs; - -struct iwmct_priv { - struct sdio_func *func; - struct iwmct_debugfs *dbgfs; - struct iwmct_parser parser; - atomic_t reset; - atomic_t dev_sync; - u32 trans_len; - u32 barker; - struct iwmct_dbg dbg; - - /* drivers work items */ - struct work_struct bus_rescan_worker; - struct work_struct isr_worker; - - /* drivers wait queue */ - wait_queue_head_t wait_q; - - /* rx request list */ - struct list_head read_req_list; -}; - -extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count); -extern int iwmct_fw_load(struct iwmct_priv *priv); - -extern void iwmct_dbg_init_params(struct iwmct_priv *drv); -extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv); -extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv); -extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len); - -#endif /* __IWMC3200TOP_H__ */ diff --git a/drivers/misc/iwmc3200top/log.c b/drivers/misc/iwmc3200top/log.c deleted file mode 100644 index a36a55a49cac..000000000000 --- a/drivers/misc/iwmc3200top/log.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/log.c - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#include <linux/kernel.h> -#include <linux/mmc/sdio_func.h> -#include <linux/slab.h> -#include <linux/ctype.h> -#include "fw-msg.h" -#include "iwmc3200top.h" -#include "log.h" - -/* Maximal hexadecimal string size of the FW memdump message */ -#define LOG_MSG_SIZE_MAX 12400 - -/* iwmct_logdefs is a global used by log macros */ -u8 iwmct_logdefs[LOG_SRC_MAX]; -static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX]; - - -static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask) -{ - int i; - - if (src < size) - logdefs[src] = logmask; - else if (src == LOG_SRC_ALL) - for (i = 0; i < size; i++) - logdefs[i] = logmask; - else - return -1; - - return 0; -} - - -int iwmct_log_set_filter(u8 src, u8 logmask) -{ - return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask); -} - - -int iwmct_log_set_fw_filter(u8 src, u8 logmask) -{ - return _log_set_log_filter(iwmct_fw_logdefs, - FW_LOG_SRC_MAX, src, logmask); -} - - -static int log_msg_format_hex(char *str, int slen, u8 *ibuf, - int ilen, char *pref) -{ - int pos = 0; - int i; - int len; - - for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++) - str[pos] = pref[i]; - - for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++) - len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]); - - if (i < ilen) - return -1; - - return 0; -} - -/* NOTE: This function is not thread safe. - Currently it's called only from sdio rx worker - no race there -*/ -void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len) -{ - struct top_msg *msg; - static char logbuf[LOG_MSG_SIZE_MAX]; - - msg = (struct top_msg *)buf; - - if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) { - LOG_ERROR(priv, FW_MSG, "Log message from TOP " - "is too short %d (expected %zd)\n", - len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)); - return; - } - - if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] & - BIT(msg->u.log.log_hdr.severity)) || - !(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity))) - return; - - switch (msg->hdr.category) { - case COMM_CATEGORY_TESTABILITY: - if (!(iwmct_logdefs[LOG_SRC_TST] & - BIT(msg->u.log.log_hdr.severity))) - return; - if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, - le16_to_cpu(msg->hdr.length) + - sizeof(msg->hdr), "<TST>")) - LOG_WARNING(priv, TST, - "TOP TST message is too long, truncating..."); - LOG_WARNING(priv, TST, "%s\n", logbuf); - break; - case COMM_CATEGORY_DEBUG: - if (msg->hdr.opcode == OP_DBG_ZSTR_MSG) - LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>", - ((u8 *)msg) + sizeof(msg->hdr) - + sizeof(msg->u.log.log_hdr)); - else { - if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf, - le16_to_cpu(msg->hdr.length) - + sizeof(msg->hdr), - "<DBG>")) - LOG_WARNING(priv, FW_MSG, - "TOP DBG message is too long," - "truncating..."); - LOG_WARNING(priv, FW_MSG, "%s\n", logbuf); - } - break; - default: - break; - } -} - -static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size) -{ - int i, pos, len; - for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) { - len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,", - i, logdefs[i]); - pos += len; - } - buf[pos-1] = '\n'; - buf[pos] = '\0'; - - if (i < logdefsz) - return -1; - return 0; -} - -int log_get_filter_str(char *buf, int size) -{ - return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size); -} - -int log_get_fw_filter_str(char *buf, int size) -{ - return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size); -} - -#define HEXADECIMAL_RADIX 16 -#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */ - -ssize_t show_iwmct_log_level(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwmct_priv *priv = dev_get_drvdata(d); - char *str_buf; - int buf_size; - ssize_t ret; - - buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1; - str_buf = kzalloc(buf_size, GFP_KERNEL); - if (!str_buf) { - LOG_ERROR(priv, DEBUGFS, - "failed to allocate %d bytes\n", buf_size); - ret = -ENOMEM; - goto exit; - } - - if (log_get_filter_str(str_buf, buf_size) < 0) { - ret = -EINVAL; - goto exit; - } - - ret = sprintf(buf, "%s", str_buf); - -exit: - kfree(str_buf); - return ret; -} - -ssize_t store_iwmct_log_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwmct_priv *priv = dev_get_drvdata(d); - char *token, *str_buf = NULL; - long val; - ssize_t ret = count; - u8 src, mask; - - if (!count) - goto exit; - - str_buf = kzalloc(count, GFP_KERNEL); - if (!str_buf) { - LOG_ERROR(priv, DEBUGFS, - "failed to allocate %zd bytes\n", count); - ret = -ENOMEM; - goto exit; - } - - memcpy(str_buf, buf, count); - - while ((token = strsep(&str_buf, ",")) != NULL) { - while (isspace(*token)) - ++token; - if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { - LOG_ERROR(priv, DEBUGFS, - "failed to convert string to long %s\n", - token); - ret = -EINVAL; - goto exit; - } - - mask = val & 0xFF; - src = (val & 0XFF00) >> 8; - iwmct_log_set_filter(src, mask); - } - -exit: - kfree(str_buf); - return ret; -} - -ssize_t show_iwmct_log_level_fw(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwmct_priv *priv = dev_get_drvdata(d); - char *str_buf; - int buf_size; - ssize_t ret; - - buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2; - - str_buf = kzalloc(buf_size, GFP_KERNEL); - if (!str_buf) { - LOG_ERROR(priv, DEBUGFS, - "failed to allocate %d bytes\n", buf_size); - ret = -ENOMEM; - goto exit; - } - - if (log_get_fw_filter_str(str_buf, buf_size) < 0) { - ret = -EINVAL; - goto exit; - } - - ret = sprintf(buf, "%s", str_buf); - -exit: - kfree(str_buf); - return ret; -} - -ssize_t store_iwmct_log_level_fw(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwmct_priv *priv = dev_get_drvdata(d); - struct top_msg cmd; - char *token, *str_buf = NULL; - ssize_t ret = count; - u16 cmdlen = 0; - int i; - long val; - u8 src, mask; - - if (!count) - goto exit; - - str_buf = kzalloc(count, GFP_KERNEL); - if (!str_buf) { - LOG_ERROR(priv, DEBUGFS, - "failed to allocate %zd bytes\n", count); - ret = -ENOMEM; - goto exit; - } - - memcpy(str_buf, buf, count); - - cmd.hdr.type = COMM_TYPE_H2D; - cmd.hdr.category = COMM_CATEGORY_DEBUG; - cmd.hdr.opcode = CMD_DBG_LOG_LEVEL; - - for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) && - (i < FW_LOG_SRC_MAX); i++) { - - while (isspace(*token)) - ++token; - - if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) { - LOG_ERROR(priv, DEBUGFS, - "failed to convert string to long %s\n", - token); - ret = -EINVAL; - goto exit; - } - - mask = val & 0xFF; /* LSB */ - src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */ - iwmct_log_set_fw_filter(src, mask); - - cmd.u.logdefs[i].logsource = src; - cmd.u.logdefs[i].sevmask = mask; - } - - cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0])); - cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr)); - - ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen); - if (ret) { - LOG_ERROR(priv, DEBUGFS, - "Failed to send %d bytes of fwcmd, ret=%zd\n", - cmdlen, ret); - goto exit; - } else - LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen); - - ret = count; - -exit: - kfree(str_buf); - return ret; -} - diff --git a/drivers/misc/iwmc3200top/log.h b/drivers/misc/iwmc3200top/log.h deleted file mode 100644 index 4434bb16cea7..000000000000 --- a/drivers/misc/iwmc3200top/log.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/log.h - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#ifndef __LOG_H__ -#define __LOG_H__ - - -/* log severity: - * The log levels here match FW log levels - * so values need to stay as is */ -#define LOG_SEV_CRITICAL 0 -#define LOG_SEV_ERROR 1 -#define LOG_SEV_WARNING 2 -#define LOG_SEV_INFO 3 -#define LOG_SEV_INFOEX 4 - -/* Log levels not defined for FW */ -#define LOG_SEV_TRACE 5 -#define LOG_SEV_DUMP 6 - -#define LOG_SEV_FW_FILTER_ALL \ - (BIT(LOG_SEV_CRITICAL) | \ - BIT(LOG_SEV_ERROR) | \ - BIT(LOG_SEV_WARNING) | \ - BIT(LOG_SEV_INFO) | \ - BIT(LOG_SEV_INFOEX)) - -#define LOG_SEV_FILTER_ALL \ - (BIT(LOG_SEV_CRITICAL) | \ - BIT(LOG_SEV_ERROR) | \ - BIT(LOG_SEV_WARNING) | \ - BIT(LOG_SEV_INFO) | \ - BIT(LOG_SEV_INFOEX) | \ - BIT(LOG_SEV_TRACE) | \ - BIT(LOG_SEV_DUMP)) - -/* log source */ -#define LOG_SRC_INIT 0 -#define LOG_SRC_DEBUGFS 1 -#define LOG_SRC_FW_DOWNLOAD 2 -#define LOG_SRC_FW_MSG 3 -#define LOG_SRC_TST 4 -#define LOG_SRC_IRQ 5 - -#define LOG_SRC_MAX 6 -#define LOG_SRC_ALL 0xFF - -/** - * Default intitialization runtime log level - */ -#ifndef LOG_SEV_FILTER_RUNTIME -#define LOG_SEV_FILTER_RUNTIME \ - (BIT(LOG_SEV_CRITICAL) | \ - BIT(LOG_SEV_ERROR) | \ - BIT(LOG_SEV_WARNING)) -#endif - -#ifndef FW_LOG_SEV_FILTER_RUNTIME -#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL -#endif - -#ifdef CONFIG_IWMC3200TOP_DEBUG -/** - * Log macros - */ - -#define priv2dev(priv) (&(priv->func)->dev) - -#define LOG_CRITICAL(priv, src, fmt, args...) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \ - dev_crit(priv2dev(priv), "%s %d: " fmt, \ - __func__, __LINE__, ##args); \ -} while (0) - -#define LOG_ERROR(priv, src, fmt, args...) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \ - dev_err(priv2dev(priv), "%s %d: " fmt, \ - __func__, __LINE__, ##args); \ -} while (0) - -#define LOG_WARNING(priv, src, fmt, args...) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \ - dev_warn(priv2dev(priv), "%s %d: " fmt, \ - __func__, __LINE__, ##args); \ -} while (0) - -#define LOG_INFO(priv, src, fmt, args...) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \ - dev_info(priv2dev(priv), "%s %d: " fmt, \ - __func__, __LINE__, ##args); \ -} while (0) - -#define LOG_TRACE(priv, src, fmt, args...) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \ - dev_dbg(priv2dev(priv), "%s %d: " fmt, \ - __func__, __LINE__, ##args); \ -} while (0) - -#define LOG_HEXDUMP(src, ptr, len) \ -do { \ - if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \ - print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \ - 16, 1, ptr, len, false); \ -} while (0) - -void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len); - -extern u8 iwmct_logdefs[]; - -int iwmct_log_set_filter(u8 src, u8 logmask); -int iwmct_log_set_fw_filter(u8 src, u8 logmask); - -ssize_t show_iwmct_log_level(struct device *d, - struct device_attribute *attr, char *buf); -ssize_t store_iwmct_log_level(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count); -ssize_t show_iwmct_log_level_fw(struct device *d, - struct device_attribute *attr, char *buf); -ssize_t store_iwmct_log_level_fw(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count); - -#else - -#define LOG_CRITICAL(priv, src, fmt, args...) -#define LOG_ERROR(priv, src, fmt, args...) -#define LOG_WARNING(priv, src, fmt, args...) -#define LOG_INFO(priv, src, fmt, args...) -#define LOG_TRACE(priv, src, fmt, args...) -#define LOG_HEXDUMP(src, ptr, len) - -static inline void iwmct_log_top_message(struct iwmct_priv *priv, - u8 *buf, int len) {} -static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; } -static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; } - -#endif /* CONFIG_IWMC3200TOP_DEBUG */ - -int log_get_filter_str(char *buf, int size); -int log_get_fw_filter_str(char *buf, int size); - -#endif /* __LOG_H__ */ diff --git a/drivers/misc/iwmc3200top/main.c b/drivers/misc/iwmc3200top/main.c deleted file mode 100644 index 701eb600b127..000000000000 --- a/drivers/misc/iwmc3200top/main.c +++ /dev/null @@ -1,662 +0,0 @@ -/* - * iwmc3200top - Intel Wireless MultiCom 3200 Top Driver - * drivers/misc/iwmc3200top/main.c - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com> - * - - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/kernel.h> -#include <linux/debugfs.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/sdio_func.h> -#include <linux/mmc/sdio.h> - -#include "iwmc3200top.h" -#include "log.h" -#include "fw-msg.h" -#include "debugfs.h" - - -#define DRIVER_DESCRIPTION "Intel(R) IWMC 3200 Top Driver" -#define DRIVER_COPYRIGHT "Copyright (c) 2008 Intel Corporation." - -#define DRIVER_VERSION "0.1.62" - -MODULE_DESCRIPTION(DRIVER_DESCRIPTION); -MODULE_VERSION(DRIVER_VERSION); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(DRIVER_COPYRIGHT); -MODULE_FIRMWARE(FW_NAME(FW_API_VER)); - - -static inline int __iwmct_tx(struct iwmct_priv *priv, void *src, int count) -{ - return sdio_memcpy_toio(priv->func, IWMC_SDIO_DATA_ADDR, src, count); - -} -int iwmct_tx(struct iwmct_priv *priv, void *src, int count) -{ - int ret; - sdio_claim_host(priv->func); - ret = __iwmct_tx(priv, src, count); - sdio_release_host(priv->func); - return ret; -} -/* - * This workers main task is to wait for OP_OPR_ALIVE - * from TOP FW until ALIVE_MSG_TIMOUT timeout is elapsed. - * When OP_OPR_ALIVE received it will issue - * a call to "bus_rescan_devices". - */ -static void iwmct_rescan_worker(struct work_struct *ws) -{ - struct iwmct_priv *priv; - int ret; - - priv = container_of(ws, struct iwmct_priv, bus_rescan_worker); - - LOG_INFO(priv, FW_MSG, "Calling bus_rescan\n"); - - ret = bus_rescan_devices(priv->func->dev.bus); - if (ret < 0) - LOG_INFO(priv, INIT, "bus_rescan_devices FAILED!!!\n"); -} - -static void op_top_message(struct iwmct_priv *priv, struct top_msg *msg) -{ - switch (msg->hdr.opcode) { - case OP_OPR_ALIVE: - LOG_INFO(priv, FW_MSG, "Got ALIVE from device, wake rescan\n"); - schedule_work(&priv->bus_rescan_worker); - break; - default: - LOG_INFO(priv, FW_MSG, "Received msg opcode 0x%X\n", - msg->hdr.opcode); - break; - } -} - - -static void handle_top_message(struct iwmct_priv *priv, u8 *buf, int len) -{ - struct top_msg *msg; - - msg = (struct top_msg *)buf; - - if (msg->hdr.type != COMM_TYPE_D2H) { - LOG_ERROR(priv, FW_MSG, - "Message from TOP with invalid message type 0x%X\n", - msg->hdr.type); - return; - } - - if (len < sizeof(msg->hdr)) { - LOG_ERROR(priv, FW_MSG, - "Message from TOP is too short for message header " - "received %d bytes, expected at least %zd bytes\n", - len, sizeof(msg->hdr)); - return; - } - - if (len < le16_to_cpu(msg->hdr.length) + sizeof(msg->hdr)) { - LOG_ERROR(priv, FW_MSG, - "Message length (%d bytes) is shorter than " - "in header (%d bytes)\n", - len, le16_to_cpu(msg->hdr.length)); - return; - } - - switch (msg->hdr.category) { - case COMM_CATEGORY_OPERATIONAL: - op_top_message(priv, (struct top_msg *)buf); - break; - - case COMM_CATEGORY_DEBUG: - case COMM_CATEGORY_TESTABILITY: - case COMM_CATEGORY_DIAGNOSTICS: - iwmct_log_top_message(priv, buf, len); - break; - - default: - LOG_ERROR(priv, FW_MSG, - "Message from TOP with unknown category 0x%X\n", - msg->hdr.category); - break; - } -} - -int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len) -{ - int ret; - u8 *buf; - - LOG_TRACE(priv, FW_MSG, "Sending hcmd:\n"); - - /* add padding to 256 for IWMC */ - ((struct top_msg *)cmd)->hdr.flags |= CMD_FLAG_PADDING_256; - - LOG_HEXDUMP(FW_MSG, cmd, len); - - if (len > FW_HCMD_BLOCK_SIZE) { - LOG_ERROR(priv, FW_MSG, "size %d exceeded hcmd max size %d\n", - len, FW_HCMD_BLOCK_SIZE); - return -1; - } - - buf = kzalloc(FW_HCMD_BLOCK_SIZE, GFP_KERNEL); - if (!buf) { - LOG_ERROR(priv, FW_MSG, "kzalloc error, buf size %d\n", - FW_HCMD_BLOCK_SIZE); - return -1; - } - - memcpy(buf, cmd, len); - ret = iwmct_tx(priv, buf, FW_HCMD_BLOCK_SIZE); - - kfree(buf); - return ret; -} - - -static void iwmct_irq_read_worker(struct work_struct *ws) -{ - struct iwmct_priv *priv; - struct iwmct_work_struct *read_req; - __le32 *buf = NULL; - int ret; - int iosize; - u32 barker; - bool is_barker; - - priv = container_of(ws, struct iwmct_priv, isr_worker); - - LOG_TRACE(priv, IRQ, "enter iwmct_irq_read_worker %p\n", ws); - - /* --------------------- Handshake with device -------------------- */ - sdio_claim_host(priv->func); - - /* all list manipulations have to be protected by - * sdio_claim_host/sdio_release_host */ - if (list_empty(&priv->read_req_list)) { - LOG_ERROR(priv, IRQ, "read_req_list empty in read worker\n"); - goto exit_release; - } - - read_req = list_entry(priv->read_req_list.next, - struct iwmct_work_struct, list); - - list_del(&read_req->list); - iosize = read_req->iosize; - kfree(read_req); - - buf = kzalloc(iosize, GFP_KERNEL); - if (!buf) { - LOG_ERROR(priv, IRQ, "kzalloc error, buf size %d\n", iosize); - goto exit_release; - } - - LOG_INFO(priv, IRQ, "iosize=%d, buf=%p, func=%d\n", - iosize, buf, priv->func->num); - - /* read from device */ - ret = sdio_memcpy_fromio(priv->func, buf, IWMC_SDIO_DATA_ADDR, iosize); - if (ret) { - LOG_ERROR(priv, IRQ, "error %d reading buffer\n", ret); - goto exit_release; - } - - LOG_HEXDUMP(IRQ, (u8 *)buf, iosize); - - barker = le32_to_cpu(buf[0]); - - /* Verify whether it's a barker and if not - treat as regular Rx */ - if (barker == IWMC_BARKER_ACK || - (barker & BARKER_DNLOAD_BARKER_MSK) == IWMC_BARKER_REBOOT) { - - /* Valid Barker is equal on first 4 dwords */ - is_barker = (buf[1] == buf[0]) && - (buf[2] == buf[0]) && - (buf[3] == buf[0]); - - if (!is_barker) { - LOG_WARNING(priv, IRQ, - "Potentially inconsistent barker " - "%08X_%08X_%08X_%08X\n", - le32_to_cpu(buf[0]), le32_to_cpu(buf[1]), - le32_to_cpu(buf[2]), le32_to_cpu(buf[3])); - } - } else { - is_barker = false; - } - - /* Handle Top CommHub message */ - if (!is_barker) { - sdio_release_host(priv->func); - handle_top_message(priv, (u8 *)buf, iosize); - goto exit; - } else if (barker == IWMC_BARKER_ACK) { /* Handle barkers */ - if (atomic_read(&priv->dev_sync) == 0) { - LOG_ERROR(priv, IRQ, - "ACK barker arrived out-of-sync\n"); - goto exit_release; - } - - /* Continuing to FW download (after Sync is completed)*/ - atomic_set(&priv->dev_sync, 0); - LOG_INFO(priv, IRQ, "ACK barker arrived " - "- starting FW download\n"); - } else { /* REBOOT barker */ - LOG_INFO(priv, IRQ, "Received reboot barker: %x\n", barker); - priv->barker = barker; - - if (barker & BARKER_DNLOAD_SYNC_MSK) { - /* Send the same barker back */ - ret = __iwmct_tx(priv, buf, iosize); - if (ret) { - LOG_ERROR(priv, IRQ, - "error %d echoing barker\n", ret); - goto exit_release; - } - LOG_INFO(priv, IRQ, "Echoing barker to device\n"); - atomic_set(&priv->dev_sync, 1); - goto exit_release; - } - - /* Continuing to FW download (without Sync) */ - LOG_INFO(priv, IRQ, "No sync requested " - "- starting FW download\n"); - } - - sdio_release_host(priv->func); - - if (priv->dbg.fw_download) - iwmct_fw_load(priv); - else - LOG_ERROR(priv, IRQ, "FW download not allowed\n"); - - goto exit; - -exit_release: - sdio_release_host(priv->func); -exit: - kfree(buf); - LOG_TRACE(priv, IRQ, "exit iwmct_irq_read_worker\n"); -} - -static void iwmct_irq(struct sdio_func *func) -{ - struct iwmct_priv *priv; - int val, ret; - int iosize; - int addr = IWMC_SDIO_INTR_GET_SIZE_ADDR; - struct iwmct_work_struct *read_req; - - priv = sdio_get_drvdata(func); - - LOG_TRACE(priv, IRQ, "enter iwmct_irq\n"); - - /* read the function's status register */ - val = sdio_readb(func, IWMC_SDIO_INTR_STATUS_ADDR, &ret); - - LOG_TRACE(priv, IRQ, "iir value = %d, ret=%d\n", val, ret); - - if (!val) { - LOG_ERROR(priv, IRQ, "iir = 0, exiting ISR\n"); - goto exit_clear_intr; - } - - - /* - * read 2 bytes of the transaction size - * IMPORTANT: sdio transaction size has to be read before clearing - * sdio interrupt!!! - */ - val = sdio_readb(priv->func, addr++, &ret); - iosize = val; - val = sdio_readb(priv->func, addr++, &ret); - iosize += val << 8; - - LOG_INFO(priv, IRQ, "READ size %d\n", iosize); - - if (iosize == 0) { - LOG_ERROR(priv, IRQ, "READ size %d, exiting ISR\n", iosize); - goto exit_clear_intr; - } - - /* allocate a work structure to pass iosize to the worker */ - read_req = kzalloc(sizeof(struct iwmct_work_struct), GFP_KERNEL); - if (!read_req) { - LOG_ERROR(priv, IRQ, "failed to allocate read_req, exit ISR\n"); - goto exit_clear_intr; - } - - INIT_LIST_HEAD(&read_req->list); - read_req->iosize = iosize; - - list_add_tail(&priv->read_req_list, &read_req->list); - - /* clear the function's interrupt request bit (write 1 to clear) */ - sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); - - schedule_work(&priv->isr_worker); - - LOG_TRACE(priv, IRQ, "exit iwmct_irq\n"); - - return; - -exit_clear_intr: - /* clear the function's interrupt request bit (write 1 to clear) */ - sdio_writeb(func, 1, IWMC_SDIO_INTR_CLEAR_ADDR, &ret); -} - - -static int blocks; -module_param(blocks, int, 0604); -MODULE_PARM_DESC(blocks, "max_blocks_to_send"); - -static bool dump; -module_param(dump, bool, 0604); -MODULE_PARM_DESC(dump, "dump_hex_content"); - -static bool jump = 1; -module_param(jump, bool, 0604); - -static bool direct = 1; -module_param(direct, bool, 0604); - -static bool checksum = 1; -module_param(checksum, bool, 0604); - -static bool fw_download = 1; -module_param(fw_download, bool, 0604); - -static int block_size = IWMC_SDIO_BLK_SIZE; -module_param(block_size, int, 0404); - -static int download_trans_blks = IWMC_DEFAULT_TR_BLK; -module_param(download_trans_blks, int, 0604); - -static bool rubbish_barker; -module_param(rubbish_barker, bool, 0604); - -#ifdef CONFIG_IWMC3200TOP_DEBUG -static int log_level[LOG_SRC_MAX]; -static unsigned int log_level_argc; -module_param_array(log_level, int, &log_level_argc, 0604); -MODULE_PARM_DESC(log_level, "log_level"); - -static int log_level_fw[FW_LOG_SRC_MAX]; -static unsigned int log_level_fw_argc; -module_param_array(log_level_fw, int, &log_level_fw_argc, 0604); -MODULE_PARM_DESC(log_level_fw, "log_level_fw"); -#endif - -void iwmct_dbg_init_params(struct iwmct_priv *priv) -{ -#ifdef CONFIG_IWMC3200TOP_DEBUG - int i; - - for (i = 0; i < log_level_argc; i++) { - dev_notice(&priv->func->dev, "log_level[%d]=0x%X\n", - i, log_level[i]); - iwmct_log_set_filter((log_level[i] >> 8) & 0xFF, - log_level[i] & 0xFF); - } - for (i = 0; i < log_level_fw_argc; i++) { - dev_notice(&priv->func->dev, "log_level_fw[%d]=0x%X\n", - i, log_level_fw[i]); - iwmct_log_set_fw_filter((log_level_fw[i] >> 8) & 0xFF, - log_level_fw[i] & 0xFF); - } -#endif - - priv->dbg.blocks = blocks; - LOG_INFO(priv, INIT, "blocks=%d\n", blocks); - priv->dbg.dump = (bool)dump; - LOG_INFO(priv, INIT, "dump=%d\n", dump); - priv->dbg.jump = (bool)jump; - LOG_INFO(priv, INIT, "jump=%d\n", jump); - priv->dbg.direct = (bool)direct; - LOG_INFO(priv, INIT, "direct=%d\n", direct); - priv->dbg.checksum = (bool)checksum; - LOG_INFO(priv, INIT, "checksum=%d\n", checksum); - priv->dbg.fw_download = (bool)fw_download; - LOG_INFO(priv, INIT, "fw_download=%d\n", fw_download); - priv->dbg.block_size = block_size; - LOG_INFO(priv, INIT, "block_size=%d\n", block_size); - priv->dbg.download_trans_blks = download_trans_blks; - LOG_INFO(priv, INIT, "download_trans_blks=%d\n", download_trans_blks); -} - -/***************************************************************************** - * - * sysfs attributes - * - *****************************************************************************/ -static ssize_t show_iwmct_fw_version(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwmct_priv *priv = dev_get_drvdata(d); - return sprintf(buf, "%s\n", priv->dbg.label_fw); -} -static DEVICE_ATTR(cc_label_fw, S_IRUGO, show_iwmct_fw_version, NULL); - -#ifdef CONFIG_IWMC3200TOP_DEBUG -static DEVICE_ATTR(log_level, S_IWUSR | S_IRUGO, - show_iwmct_log_level, store_iwmct_log_level); -static DEVICE_ATTR(log_level_fw, S_IWUSR | S_IRUGO, - show_iwmct_log_level_fw, store_iwmct_log_level_fw); -#endif - -static struct attribute *iwmct_sysfs_entries[] = { - &dev_attr_cc_label_fw.attr, -#ifdef CONFIG_IWMC3200TOP_DEBUG - &dev_attr_log_level.attr, - &dev_attr_log_level_fw.attr, -#endif - NULL -}; - -static struct attribute_group iwmct_attribute_group = { - .name = NULL, /* put in device directory */ - .attrs = iwmct_sysfs_entries, -}; - - -static int iwmct_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct iwmct_priv *priv; - int ret; - int val = 1; - int addr = IWMC_SDIO_INTR_ENABLE_ADDR; - - dev_dbg(&func->dev, "enter iwmct_probe\n"); - - dev_dbg(&func->dev, "IRQ polling period id %u msecs, HZ is %d\n", - jiffies_to_msecs(2147483647), HZ); - - priv = kzalloc(sizeof(struct iwmct_priv), GFP_KERNEL); - if (!priv) { - dev_err(&func->dev, "kzalloc error\n"); - return -ENOMEM; - } - priv->func = func; - sdio_set_drvdata(func, priv); - - INIT_WORK(&priv->bus_rescan_worker, iwmct_rescan_worker); - INIT_WORK(&priv->isr_worker, iwmct_irq_read_worker); - - init_waitqueue_head(&priv->wait_q); - - sdio_claim_host(func); - /* FIXME: Remove after it is fixed in the Boot ROM upgrade */ - func->enable_timeout = 10; - - /* In our HW, setting the block size also wakes up the boot rom. */ - ret = sdio_set_block_size(func, priv->dbg.block_size); - if (ret) { - LOG_ERROR(priv, INIT, - "sdio_set_block_size() failure: %d\n", ret); - goto error_sdio_enable; - } - - ret = sdio_enable_func(func); - if (ret) { - LOG_ERROR(priv, INIT, "sdio_enable_func() failure: %d\n", ret); - goto error_sdio_enable; - } - - /* init reset and dev_sync states */ - atomic_set(&priv->reset, 0); - atomic_set(&priv->dev_sync, 0); - - /* init read req queue */ - INIT_LIST_HEAD(&priv->read_req_list); - - /* process configurable parameters */ - iwmct_dbg_init_params(priv); - ret = sysfs_create_group(&func->dev.kobj, &iwmct_attribute_group); - if (ret) { - LOG_ERROR(priv, INIT, "Failed to register attributes and " - "initialize module_params\n"); - goto error_dev_attrs; - } - - iwmct_dbgfs_register(priv, DRV_NAME); - - if (!priv->dbg.direct && priv->dbg.download_trans_blks > 8) { - LOG_INFO(priv, INIT, - "Reducing transaction to 8 blocks = 2K (from %d)\n", - priv->dbg.download_trans_blks); - priv->dbg.download_trans_blks = 8; - } - priv->trans_len = priv->dbg.download_trans_blks * priv->dbg.block_size; - LOG_INFO(priv, INIT, "Transaction length = %d\n", priv->trans_len); - - ret = sdio_claim_irq(func, iwmct_irq); - if (ret) { - LOG_ERROR(priv, INIT, "sdio_claim_irq() failure: %d\n", ret); - goto error_claim_irq; - } - - - /* Enable function's interrupt */ - sdio_writeb(priv->func, val, addr, &ret); - if (ret) { - LOG_ERROR(priv, INIT, "Failure writing to " - "Interrupt Enable Register (%d): %d\n", addr, ret); - goto error_enable_int; - } - - sdio_release_host(func); - - LOG_INFO(priv, INIT, "exit iwmct_probe\n"); - - return ret; - -error_enable_int: - sdio_release_irq(func); -error_claim_irq: - sdio_disable_func(func); -error_dev_attrs: - iwmct_dbgfs_unregister(priv->dbgfs); - sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); -error_sdio_enable: - sdio_release_host(func); - return ret; -} - -static void iwmct_remove(struct sdio_func *func) -{ - struct iwmct_work_struct *read_req; - struct iwmct_priv *priv = sdio_get_drvdata(func); - - LOG_INFO(priv, INIT, "enter\n"); - - sdio_claim_host(func); - sdio_release_irq(func); - sdio_release_host(func); - - /* Make sure works are finished */ - flush_work_sync(&priv->bus_rescan_worker); - flush_work_sync(&priv->isr_worker); - - sdio_claim_host(func); - sdio_disable_func(func); - sysfs_remove_group(&func->dev.kobj, &iwmct_attribute_group); - iwmct_dbgfs_unregister(priv->dbgfs); - sdio_release_host(func); - - /* free read requests */ - while (!list_empty(&priv->read_req_list)) { - read_req = list_entry(priv->read_req_list.next, - struct iwmct_work_struct, list); - - list_del(&read_req->list); - kfree(read_req); - } - - kfree(priv); -} - - -static const struct sdio_device_id iwmct_ids[] = { - /* Intel Wireless MultiCom 3200 Top Driver */ - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1404)}, - { }, /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE(sdio, iwmct_ids); - -static struct sdio_driver iwmct_driver = { - .probe = iwmct_probe, - .remove = iwmct_remove, - .name = DRV_NAME, - .id_table = iwmct_ids, -}; - -static int __init iwmct_init(void) -{ - int rc; - - /* Default log filter settings */ - iwmct_log_set_filter(LOG_SRC_ALL, LOG_SEV_FILTER_RUNTIME); - iwmct_log_set_filter(LOG_SRC_FW_MSG, LOG_SEV_FW_FILTER_ALL); - iwmct_log_set_fw_filter(LOG_SRC_ALL, FW_LOG_SEV_FILTER_RUNTIME); - - rc = sdio_register_driver(&iwmct_driver); - - return rc; -} - -static void __exit iwmct_exit(void) -{ - sdio_unregister_driver(&iwmct_driver); -} - -module_init(iwmct_init); -module_exit(iwmct_exit); - diff --git a/drivers/net/wimax/i2400m/Kconfig b/drivers/net/wimax/i2400m/Kconfig index 672de18a776c..71453db14258 100644 --- a/drivers/net/wimax/i2400m/Kconfig +++ b/drivers/net/wimax/i2400m/Kconfig @@ -7,9 +7,6 @@ config WIMAX_I2400M comment "Enable USB support to see WiMAX USB drivers" depends on USB = n -comment "Enable MMC support to see WiMAX SDIO drivers" - depends on MMC = n - config WIMAX_I2400M_USB tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)" depends on WIMAX && USB @@ -21,25 +18,6 @@ config WIMAX_I2400M_USB If unsure, it is safe to select M (module). -config WIMAX_I2400M_SDIO - tristate "Intel Wireless WiMAX Connection 2400 over SDIO" - depends on WIMAX && MMC - select WIMAX_I2400M - help - Select if you have a device based on the Intel WiMAX - Connection 2400 over SDIO. - - If unsure, it is safe to select M (module). - -config WIMAX_IWMC3200_SDIO - bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO (EXPERIMENTAL)" - depends on WIMAX_I2400M_SDIO - depends on EXPERIMENTAL - select IWMC3200TOP - help - Select if you have a device based on the Intel Multicom WiMAX - Connection 3200 over SDIO. - config WIMAX_I2400M_DEBUG_LEVEL int "WiMAX i2400m debug level" depends on WIMAX_I2400M diff --git a/drivers/net/wimax/i2400m/Makefile b/drivers/net/wimax/i2400m/Makefile index 5d9e018d31af..f6d19c348082 100644 --- a/drivers/net/wimax/i2400m/Makefile +++ b/drivers/net/wimax/i2400m/Makefile @@ -1,7 +1,6 @@ obj-$(CONFIG_WIMAX_I2400M) += i2400m.o obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o -obj-$(CONFIG_WIMAX_I2400M_SDIO) += i2400m-sdio.o i2400m-y := \ control.o \ @@ -21,10 +20,3 @@ i2400m-usb-y := \ usb-tx.o \ usb-rx.o \ usb.o - - -i2400m-sdio-y := \ - sdio.o \ - sdio-tx.o \ - sdio-fw.o \ - sdio-rx.o diff --git a/drivers/net/wimax/i2400m/driver.c b/drivers/net/wimax/i2400m/driver.c index 47cae7150bc1..850b8bc38bee 100644 --- a/drivers/net/wimax/i2400m/driver.c +++ b/drivers/net/wimax/i2400m/driver.c @@ -754,8 +754,7 @@ EXPORT_SYMBOL_GPL(i2400m_error_recovery); /* * Alloc the command and ack buffers for boot mode * - * Get the buffers needed to deal with boot mode messages. These - * buffers need to be allocated before the sdio receive irq is setup. + * Get the buffers needed to deal with boot mode messages. */ static int i2400m_bm_buf_alloc(struct i2400m *i2400m) diff --git a/drivers/net/wimax/i2400m/fw.c b/drivers/net/wimax/i2400m/fw.c index 7cbd7d231e11..7632f8cf09df 100644 --- a/drivers/net/wimax/i2400m/fw.c +++ b/drivers/net/wimax/i2400m/fw.c @@ -51,8 +51,7 @@ * firmware. Normal hardware takes only signed firmware. * * On boot mode, in USB, we write to the device using the bulk out - * endpoint and read from it in the notification endpoint. In SDIO we - * talk to it via the write address and read from the read address. + * endpoint and read from it in the notification endpoint. * * Upon entrance to boot mode, the device sends (preceded with a few * zero length packets (ZLPs) on the notification endpoint in USB) a diff --git a/drivers/net/wimax/i2400m/i2400m-sdio.h b/drivers/net/wimax/i2400m/i2400m-sdio.h deleted file mode 100644 index 1d63ffdedfde..000000000000 --- a/drivers/net/wimax/i2400m/i2400m-sdio.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * SDIO-specific i2400m driver definitions - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Brian Bian <brian.bian@intel.com> - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - Initial implementation - * - * - * This driver implements the bus-specific part of the i2400m for - * SDIO. Check i2400m.h for a generic driver description. - * - * ARCHITECTURE - * - * This driver sits under the bus-generic i2400m driver, providing the - * connection to the device. - * - * When probed, all the function pointers are setup and then the - * bus-generic code called. The generic driver will then use the - * provided pointers for uploading firmware (i2400ms_bus_bm*() in - * sdio-fw.c) and then setting up the device (i2400ms_dev_*() in - * sdio.c). - * - * Once firmware is uploaded, TX functions (sdio-tx.c) are called when - * data is ready for transmission in the TX fifo; then the SDIO IRQ is - * fired and data is available (sdio-rx.c), it is sent to the generic - * driver for processing with i2400m_rx. - */ - -#ifndef __I2400M_SDIO_H__ -#define __I2400M_SDIO_H__ - -#include "i2400m.h" - -/* Host-Device interface for SDIO */ -enum { - I2400M_SDIO_BOOT_RETRIES = 3, - I2400MS_BLK_SIZE = 256, - I2400MS_PL_SIZE_MAX = 0x3E00, - - I2400MS_DATA_ADDR = 0x0, - I2400MS_INTR_STATUS_ADDR = 0x13, - I2400MS_INTR_CLEAR_ADDR = 0x13, - I2400MS_INTR_ENABLE_ADDR = 0x14, - I2400MS_INTR_GET_SIZE_ADDR = 0x2C, - /* The number of ticks to wait for the device to signal that - * it is ready */ - I2400MS_INIT_SLEEP_INTERVAL = 100, - /* How long to wait for the device to settle after reset */ - I2400MS_SETTLE_TIME = 40, - /* The number of msec to wait for IOR after sending IOE */ - IWMC3200_IOR_TIMEOUT = 10, -}; - - -/** - * struct i2400ms - descriptor for a SDIO connected i2400m - * - * @i2400m: bus-generic i2400m implementation; has to be first (see - * it's documentation in i2400m.h). - * - * @func: pointer to our SDIO function - * - * @tx_worker: workqueue struct used to TX data when the bus-generic - * code signals packets are pending for transmission to the device. - * - * @tx_workqueue: workqeueue used for data TX; we don't use the - * system's workqueue as that might cause deadlocks with code in - * the bus-generic driver. The read/write operation to the queue - * is protected with spinlock (tx_lock in struct i2400m) to avoid - * the queue being destroyed in the middle of a the queue read/write - * operation. - * - * @debugfs_dentry: dentry for the SDIO specific debugfs files - * - * Note this value is set to NULL upon destruction; this is - * because some routinges use it to determine if we are inside the - * probe() path or some other path. When debugfs is disabled, - * creation sets the dentry to '(void*) -ENODEV', which is valid - * for the test. - */ -struct i2400ms { - struct i2400m i2400m; /* FIRST! See doc */ - struct sdio_func *func; - - struct work_struct tx_worker; - struct workqueue_struct *tx_workqueue; - char tx_wq_name[32]; - - struct dentry *debugfs_dentry; - - wait_queue_head_t bm_wfa_wq; - int bm_wait_result; - size_t bm_ack_size; - - /* Device is any of the iwmc3200 SKUs */ - unsigned iwmc3200:1; -}; - - -static inline -void i2400ms_init(struct i2400ms *i2400ms) -{ - i2400m_init(&i2400ms->i2400m); -} - - -extern int i2400ms_rx_setup(struct i2400ms *); -extern void i2400ms_rx_release(struct i2400ms *); - -extern int i2400ms_tx_setup(struct i2400ms *); -extern void i2400ms_tx_release(struct i2400ms *); -extern void i2400ms_bus_tx_kick(struct i2400m *); - -extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *, - const struct i2400m_bootrom_header *, - size_t, int); -extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *, - struct i2400m_bootrom_header *, - size_t); -extern void i2400ms_bus_bm_release(struct i2400m *); -extern int i2400ms_bus_bm_setup(struct i2400m *); - -#endif /* #ifndef __I2400M_SDIO_H__ */ diff --git a/drivers/net/wimax/i2400m/i2400m.h b/drivers/net/wimax/i2400m/i2400m.h index c806d4550212..79c6505b5c20 100644 --- a/drivers/net/wimax/i2400m/i2400m.h +++ b/drivers/net/wimax/i2400m/i2400m.h @@ -46,7 +46,7 @@ * - bus generic driver (this part) * * The bus specific driver sets up stuff specific to the bus the - * device is connected to (USB, SDIO, PCI, tam-tam...non-authoritative + * device is connected to (USB, PCI, tam-tam...non-authoritative * nor binding list) which is basically the device-model management * (probe/disconnect, etc), moving data from device to kernel and * back, doing the power saving details and reseting the device. @@ -238,14 +238,13 @@ struct i2400m_barker_db; * amount needed for loading firmware, where us dev_start/stop setup * the rest needed to do full data/control traffic. * - * @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16, - * so we have a tx_blk_size variable that the bus layer sets to - * tell the engine how much of that we need. + * @bus_tx_block_size: [fill] USB imposes a 16 block size, but other + * busses will differ. So we have a tx_blk_size variable that the + * bus layer sets to tell the engine how much of that we need. * * @bus_tx_room_min: [fill] Minimum room required while allocating - * TX queue's buffer space for message header. SDIO requires - * 224 bytes and USB 16 bytes. Refer bus specific driver code - * for details. + * TX queue's buffer space for message header. USB requires + * 16 bytes. Refer to bus specific driver code for details. * * @bus_pl_size_max: [fill] Maximum payload size. * diff --git a/drivers/net/wimax/i2400m/sdio-debug-levels.h b/drivers/net/wimax/i2400m/sdio-debug-levels.h deleted file mode 100644 index c51998741301..000000000000 --- a/drivers/net/wimax/i2400m/sdio-debug-levels.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * debug levels control file for the i2400m module's - */ -#ifndef __debug_levels__h__ -#define __debug_levels__h__ - -/* Maximum compile and run time debug level for all submodules */ -#define D_MODULENAME i2400m_sdio -#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL - -#include <linux/wimax/debug.h> - -/* List of all the enabled modules */ -enum d_module { - D_SUBMODULE_DECLARE(main), - D_SUBMODULE_DECLARE(tx), - D_SUBMODULE_DECLARE(rx), - D_SUBMODULE_DECLARE(fw) -}; - - -#endif /* #ifndef __debug_levels__h__ */ diff --git a/drivers/net/wimax/i2400m/sdio-fw.c b/drivers/net/wimax/i2400m/sdio-fw.c deleted file mode 100644 index 8e025418f5be..000000000000 --- a/drivers/net/wimax/i2400m/sdio-fw.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Firmware uploader's SDIO specifics - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Initial implementation - * - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - Bus generic/specific split for USB - * - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * - Initial implementation for SDIO - * - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * - SDIO rehash for changes in the bus-driver model - * - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * - Make it IRQ based, not polling - * - * THE PROCEDURE - * - * See fw.c for the generic description of this procedure. - * - * This file implements only the SDIO specifics. It boils down to how - * to send a command and waiting for an acknowledgement from the - * device. - * - * All this code is sequential -- all i2400ms_bus_bm_*() functions are - * executed in the same thread, except i2400ms_bm_irq() [on its own by - * the SDIO driver]. This makes it possible to avoid locking. - * - * COMMAND EXECUTION - * - * The generic firmware upload code will call i2400m_bus_bm_cmd_send() - * to send commands. - * - * The SDIO devices expects things in 256 byte blocks, so it will pad - * it, compute the checksum (if needed) and pass it to SDIO. - * - * ACK RECEPTION - * - * This works in IRQ mode -- the fw loader says when to wait for data - * and for that it calls i2400ms_bus_bm_wait_for_ack(). - * - * This checks if there is any data available (RX size > 0); if not, - * waits for the IRQ handler to notify about it. Once there is data, - * it is read and passed to the caller. Doing it this way we don't - * need much coordination/locking, and it makes it much more difficult - * for an interrupt to be lost and the wait_for_ack() function getting - * stuck even when data is pending. - */ -#include <linux/mmc/sdio_func.h> -#include "i2400m-sdio.h" - - -#define D_SUBMODULE fw -#include "sdio-debug-levels.h" - - -/* - * Send a boot-mode command to the SDIO function - * - * We use a bounce buffer (i2400m->bm_cmd_buf) because we need to - * touch the header if the RAW flag is not set. - * - * @flags: pass thru from i2400m_bm_cmd() - * @return: cmd_size if ok, < 0 errno code on error. - * - * Note the command is padded to the SDIO block size for the device. - */ -ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m, - const struct i2400m_bootrom_header *_cmd, - size_t cmd_size, int flags) -{ - ssize_t result; - struct device *dev = i2400m_dev(i2400m); - struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); - int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd); - struct i2400m_bootrom_header *cmd; - /* SDIO restriction */ - size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE); - - d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n", - i2400m, _cmd, cmd_size); - result = -E2BIG; - if (cmd_size > I2400M_BM_CMD_BUF_SIZE) - goto error_too_big; - - if (_cmd != i2400m->bm_cmd_buf) - memmove(i2400m->bm_cmd_buf, _cmd, cmd_size); - cmd = i2400m->bm_cmd_buf; - if (cmd_size_a > cmd_size) /* Zero pad space */ - memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size); - if ((flags & I2400M_BM_CMD_RAW) == 0) { - if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0)) - dev_warn(dev, "SW BUG: response_required == 0\n"); - i2400m_bm_cmd_prepare(cmd); - } - d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n", - opcode, cmd_size, cmd_size_a); - d_dump(5, dev, cmd, cmd_size); - - sdio_claim_host(i2400ms->func); /* Send & check */ - result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR, - i2400m->bm_cmd_buf, cmd_size_a); - sdio_release_host(i2400ms->func); - if (result < 0) { - dev_err(dev, "BM cmd %d: cannot send: %ld\n", - opcode, (long) result); - goto error_cmd_send; - } - result = cmd_size; -error_cmd_send: -error_too_big: - d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n", - i2400m, _cmd, cmd_size, (int) result); - return result; -} - - -/* - * Read an ack from the device's boot-mode - * - * @i2400m: - * @_ack: pointer to where to store the read data - * @ack_size: how many bytes we should read - * - * Returns: < 0 errno code on error; otherwise, amount of received bytes. - * - * The ACK for a BM command is always at least sizeof(*ack) bytes, so - * check for that. We don't need to check for device reboots - * - */ -ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m, - struct i2400m_bootrom_header *ack, - size_t ack_size) -{ - ssize_t result; - struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - int size; - - BUG_ON(sizeof(*ack) > ack_size); - - d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n", - i2400m, ack, ack_size); - - result = wait_event_timeout(i2400ms->bm_wfa_wq, - i2400ms->bm_ack_size != -EINPROGRESS, - 2 * HZ); - if (result == 0) { - result = -ETIMEDOUT; - dev_err(dev, "BM: error waiting for an ack\n"); - goto error_timeout; - } - - spin_lock(&i2400m->rx_lock); - result = i2400ms->bm_ack_size; - BUG_ON(result == -EINPROGRESS); - if (result < 0) /* so we exit when rx_release() is called */ - dev_err(dev, "BM: %s failed: %zd\n", __func__, result); - else { - size = min(ack_size, i2400ms->bm_ack_size); - memcpy(ack, i2400m->bm_ack_buf, size); - } - /* - * Remember always to clear the bm_ack_size to -EINPROGRESS - * after the RX data is processed - */ - i2400ms->bm_ack_size = -EINPROGRESS; - spin_unlock(&i2400m->rx_lock); - -error_timeout: - d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n", - i2400m, ack, ack_size, result); - return result; -} diff --git a/drivers/net/wimax/i2400m/sdio-rx.c b/drivers/net/wimax/i2400m/sdio-rx.c deleted file mode 100644 index fb6396dd115f..000000000000 --- a/drivers/net/wimax/i2400m/sdio-rx.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * SDIO RX handling - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * - Initial implementation - * - * - * This handles the RX path on SDIO. - * - * The SDIO bus driver calls the "irq" routine when data is available. - * This is not a traditional interrupt routine since the SDIO bus - * driver calls us from its irq thread context. Because of this - * sleeping in the SDIO RX IRQ routine is okay. - * - * From there on, we obtain the size of the data that is available, - * allocate an skb, copy it and then pass it to the generic driver's - * RX routine [i2400m_rx()]. - * - * ROADMAP - * - * i2400ms_irq() - * i2400ms_rx() - * __i2400ms_rx_get_size() - * i2400m_is_boot_barker() - * i2400m_rx() - * - * i2400ms_rx_setup() - * - * i2400ms_rx_release() - */ -#include <linux/workqueue.h> -#include <linux/wait.h> -#include <linux/skbuff.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sdio_func.h> -#include <linux/slab.h> -#include "i2400m-sdio.h" - -#define D_SUBMODULE rx -#include "sdio-debug-levels.h" - -static const __le32 i2400m_ACK_BARKER[4] = { - __constant_cpu_to_le32(I2400M_ACK_BARKER), - __constant_cpu_to_le32(I2400M_ACK_BARKER), - __constant_cpu_to_le32(I2400M_ACK_BARKER), - __constant_cpu_to_le32(I2400M_ACK_BARKER) -}; - - -/* - * Read and return the amount of bytes available for RX - * - * The RX size has to be read like this: byte reads of three - * sequential locations; then glue'em together. - * - * sdio_readl() doesn't work. - */ -static ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms) -{ - int ret, cnt, val; - ssize_t rx_size; - unsigned xfer_size_addr; - struct sdio_func *func = i2400ms->func; - struct device *dev = &i2400ms->func->dev; - - d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms); - xfer_size_addr = I2400MS_INTR_GET_SIZE_ADDR; - rx_size = 0; - for (cnt = 0; cnt < 3; cnt++) { - val = sdio_readb(func, xfer_size_addr + cnt, &ret); - if (ret < 0) { - dev_err(dev, "RX: Can't read byte %d of RX size from " - "0x%08x: %d\n", cnt, xfer_size_addr + cnt, ret); - rx_size = ret; - goto error_read; - } - rx_size = rx_size << 8 | (val & 0xff); - } - d_printf(6, dev, "RX: rx_size is %ld\n", (long) rx_size); -error_read: - d_fnend(7, dev, "(i2400ms %p) = %ld\n", i2400ms, (long) rx_size); - return rx_size; -} - - -/* - * Read data from the device (when in normal) - * - * Allocate an SKB of the right size, read the data in and then - * deliver it to the generic layer. - * - * We also check for a reboot barker. That means the device died and - * we have to reboot it. - */ -static -void i2400ms_rx(struct i2400ms *i2400ms) -{ - int ret; - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - struct i2400m *i2400m = &i2400ms->i2400m; - struct sk_buff *skb; - ssize_t rx_size; - - d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms); - rx_size = __i2400ms_rx_get_size(i2400ms); - if (rx_size < 0) { - ret = rx_size; - goto error_get_size; - } - /* - * Hardware quirk: make sure to clear the INTR status register - * AFTER getting the data transfer size. - */ - sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret); - - ret = -ENOMEM; - skb = alloc_skb(rx_size, GFP_ATOMIC); - if (NULL == skb) { - dev_err(dev, "RX: unable to alloc skb\n"); - goto error_alloc_skb; - } - ret = sdio_memcpy_fromio(func, skb->data, - I2400MS_DATA_ADDR, rx_size); - if (ret < 0) { - dev_err(dev, "RX: SDIO data read failed: %d\n", ret); - goto error_memcpy_fromio; - } - - rmb(); /* make sure we get boot_mode from dev_reset_handle */ - if (unlikely(i2400m->boot_mode == 1)) { - spin_lock(&i2400m->rx_lock); - i2400ms->bm_ack_size = rx_size; - spin_unlock(&i2400m->rx_lock); - memcpy(i2400m->bm_ack_buf, skb->data, rx_size); - wake_up(&i2400ms->bm_wfa_wq); - d_printf(5, dev, "RX: SDIO boot mode message\n"); - kfree_skb(skb); - goto out; - } - ret = -EIO; - if (unlikely(rx_size < sizeof(__le32))) { - dev_err(dev, "HW BUG? only %zu bytes received\n", rx_size); - goto error_bad_size; - } - if (likely(i2400m_is_d2h_barker(skb->data))) { - skb_put(skb, rx_size); - i2400m_rx(i2400m, skb); - } else if (unlikely(i2400m_is_boot_barker(i2400m, - skb->data, rx_size))) { - ret = i2400m_dev_reset_handle(i2400m, "device rebooted"); - dev_err(dev, "RX: SDIO reboot barker\n"); - kfree_skb(skb); - } else { - i2400m_unknown_barker(i2400m, skb->data, rx_size); - kfree_skb(skb); - } -out: - d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms); - return; - -error_memcpy_fromio: - kfree_skb(skb); -error_alloc_skb: -error_get_size: -error_bad_size: - d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret); -} - - -/* - * Process an interrupt from the SDIO card - * - * FIXME: need to process other events that are not just ready-to-read - * - * Checks there is data ready and then proceeds to read it. - */ -static -void i2400ms_irq(struct sdio_func *func) -{ - int ret; - struct i2400ms *i2400ms = sdio_get_drvdata(func); - struct device *dev = &func->dev; - int val; - - d_fnstart(6, dev, "(i2400ms %p)\n", i2400ms); - val = sdio_readb(func, I2400MS_INTR_STATUS_ADDR, &ret); - if (ret < 0) { - dev_err(dev, "RX: Can't read interrupt status: %d\n", ret); - goto error_no_irq; - } - if (!val) { - dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n"); - goto error_no_irq; - } - i2400ms_rx(i2400ms); -error_no_irq: - d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms); -} - - -/* - * Setup SDIO RX - * - * Hooks up the IRQ handler and then enables IRQs. - */ -int i2400ms_rx_setup(struct i2400ms *i2400ms) -{ - int result; - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - struct i2400m *i2400m = &i2400ms->i2400m; - - d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); - - init_waitqueue_head(&i2400ms->bm_wfa_wq); - spin_lock(&i2400m->rx_lock); - i2400ms->bm_wait_result = -EINPROGRESS; - /* - * Before we are about to enable the RX interrupt, make sure - * bm_ack_size is cleared to -EINPROGRESS which indicates - * no RX interrupt happened yet or the previous interrupt - * has been handled, we are ready to take the new interrupt - */ - i2400ms->bm_ack_size = -EINPROGRESS; - spin_unlock(&i2400m->rx_lock); - - sdio_claim_host(func); - result = sdio_claim_irq(func, i2400ms_irq); - if (result < 0) { - dev_err(dev, "Cannot claim IRQ: %d\n", result); - goto error_irq_claim; - } - result = 0; - sdio_writeb(func, 1, I2400MS_INTR_ENABLE_ADDR, &result); - if (result < 0) { - sdio_release_irq(func); - dev_err(dev, "Failed to enable interrupts %d\n", result); - } -error_irq_claim: - sdio_release_host(func); - d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); - return result; -} - - -/* - * Tear down SDIO RX - * - * Disables IRQs in the device and removes the IRQ handler. - */ -void i2400ms_rx_release(struct i2400ms *i2400ms) -{ - int result; - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - struct i2400m *i2400m = &i2400ms->i2400m; - - d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); - spin_lock(&i2400m->rx_lock); - i2400ms->bm_ack_size = -EINTR; - spin_unlock(&i2400m->rx_lock); - wake_up_all(&i2400ms->bm_wfa_wq); - sdio_claim_host(func); - sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result); - sdio_release_irq(func); - sdio_release_host(func); - d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); -} diff --git a/drivers/net/wimax/i2400m/sdio-tx.c b/drivers/net/wimax/i2400m/sdio-tx.c deleted file mode 100644 index b53cd1c80e3e..000000000000 --- a/drivers/net/wimax/i2400m/sdio-tx.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * SDIO TX transaction backends - * - * - * Copyright (C) 2007-2008 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <linux-wimax@intel.com> - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * - Initial implementation - * - * - * Takes the TX messages in the i2400m's driver TX FIFO and sends them - * to the device until there are no more. - * - * If we fail sending the message, we just drop it. There isn't much - * we can do at this point. Most of the traffic is network, which has - * recovery methods for dropped packets. - * - * The SDIO functions are not atomic, so we can't run from the context - * where i2400m->bus_tx_kick() [i2400ms_bus_tx_kick()] is being called - * (some times atomic). Thus, the actual TX work is deferred to a - * workqueue. - * - * ROADMAP - * - * i2400ms_bus_tx_kick() - * i2400ms_tx_submit() [through workqueue] - * - * i2400m_tx_setup() - * - * i2400m_tx_release() - */ -#include <linux/mmc/sdio_func.h> -#include "i2400m-sdio.h" - -#define D_SUBMODULE tx -#include "sdio-debug-levels.h" - - -/* - * Pull TX transations from the TX FIFO and send them to the device - * until there are no more. - */ -static -void i2400ms_tx_submit(struct work_struct *ws) -{ - int result; - struct i2400ms *i2400ms = container_of(ws, struct i2400ms, tx_worker); - struct i2400m *i2400m = &i2400ms->i2400m; - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - struct i2400m_msg_hdr *tx_msg; - size_t tx_msg_size; - - d_fnstart(4, dev, "(i2400ms %p, i2400m %p)\n", i2400ms, i2400ms); - - while (NULL != (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) { - d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size); - d_dump(5, dev, tx_msg, tx_msg_size); - - sdio_claim_host(func); - result = sdio_memcpy_toio(func, 0, tx_msg, tx_msg_size); - sdio_release_host(func); - - i2400m_tx_msg_sent(i2400m); - - if (result < 0) { - dev_err(dev, "TX: cannot submit TX; tx_msg @%zu %zu B:" - " %d\n", (void *) tx_msg - i2400m->tx_buf, - tx_msg_size, result); - } - - if (result == -ETIMEDOUT) { - i2400m_error_recovery(i2400m); - break; - } - d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size); - } - - d_fnend(4, dev, "(i2400ms %p) = void\n", i2400ms); -} - - -/* - * The generic driver notifies us that there is data ready for TX - * - * Schedule a run of i2400ms_tx_submit() to handle it. - */ -void i2400ms_bus_tx_kick(struct i2400m *i2400m) -{ - struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); - struct device *dev = &i2400ms->func->dev; - unsigned long flags; - - d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m); - - /* schedule tx work, this is because tx may block, therefore - * it has to run in a thread context. - */ - spin_lock_irqsave(&i2400m->tx_lock, flags); - if (i2400ms->tx_workqueue != NULL) - queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker); - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - d_fnend(3, dev, "(i2400m %p) = void\n", i2400m); -} - -int i2400ms_tx_setup(struct i2400ms *i2400ms) -{ - int result; - struct device *dev = &i2400ms->func->dev; - struct i2400m *i2400m = &i2400ms->i2400m; - struct workqueue_struct *tx_workqueue; - unsigned long flags; - - d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms); - - INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit); - snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name), - "%s-tx", i2400m->wimax_dev.name); - tx_workqueue = - create_singlethread_workqueue(i2400ms->tx_wq_name); - if (tx_workqueue == NULL) { - dev_err(dev, "TX: failed to create workqueue\n"); - result = -ENOMEM; - } else - result = 0; - spin_lock_irqsave(&i2400m->tx_lock, flags); - i2400ms->tx_workqueue = tx_workqueue; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result); - return result; -} - -void i2400ms_tx_release(struct i2400ms *i2400ms) -{ - struct i2400m *i2400m = &i2400ms->i2400m; - struct workqueue_struct *tx_workqueue; - unsigned long flags; - - tx_workqueue = i2400ms->tx_workqueue; - - spin_lock_irqsave(&i2400m->tx_lock, flags); - i2400ms->tx_workqueue = NULL; - spin_unlock_irqrestore(&i2400m->tx_lock, flags); - - if (tx_workqueue) - destroy_workqueue(tx_workqueue); -} diff --git a/drivers/net/wimax/i2400m/sdio.c b/drivers/net/wimax/i2400m/sdio.c deleted file mode 100644 index 21a9edd6e75d..000000000000 --- a/drivers/net/wimax/i2400m/sdio.c +++ /dev/null @@ -1,602 +0,0 @@ -/* - * Intel Wireless WiMAX Connection 2400m - * Linux driver model glue for the SDIO device, reset & fw upload - * - * - * Copyright (C) 2007-2008 Intel Corporation <linux-wimax@intel.com> - * Dirk Brandewie <dirk.j.brandewie@intel.com> - * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com> - * Yanir Lubetkin <yanirx.lubetkin@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - * - * See i2400m-sdio.h for a general description of this driver. - * - * This file implements driver model glue, and hook ups for the - * generic driver to implement the bus-specific functions (device - * communication setup/tear down, firmware upload and resetting). - * - * ROADMAP - * - * i2400m_probe() - * alloc_netdev() - * i2400ms_netdev_setup() - * i2400ms_init() - * i2400m_netdev_setup() - * i2400ms_enable_function() - * i2400m_setup() - * - * i2400m_remove() - * i2400m_release() - * free_netdev(net_dev) - * - * i2400ms_bus_reset() Called by i2400m_reset - * __i2400ms_reset() - * __i2400ms_send_barker() - */ - -#include <linux/slab.h> -#include <linux/debugfs.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sdio_func.h> -#include "i2400m-sdio.h" -#include <linux/wimax/i2400m.h> -#include <linux/module.h> - -#define D_SUBMODULE main -#include "sdio-debug-levels.h" - -/* IOE WiMAX function timeout in seconds */ -static int ioe_timeout = 2; -module_param(ioe_timeout, int, 0); - -static char i2400ms_debug_params[128]; -module_param_string(debug, i2400ms_debug_params, sizeof(i2400ms_debug_params), - 0644); -MODULE_PARM_DESC(debug, - "String of space-separated NAME:VALUE pairs, where NAMEs " - "are the different debug submodules and VALUE are the " - "initial debug value to set."); - -/* Our firmware file name list */ -static const char *i2400ms_bus_fw_names[] = { -#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf" - I2400MS_FW_FILE_NAME, - NULL -}; - - -static const struct i2400m_poke_table i2400ms_pokes[] = { - I2400M_FW_POKE(0x6BE260, 0x00000088), - I2400M_FW_POKE(0x080550, 0x00000005), - I2400M_FW_POKE(0xAE0000, 0x00000000), - I2400M_FW_POKE(0x000000, 0x00000000), /* MUST be 0 terminated or bad - * things will happen */ -}; - -/* - * Enable the SDIO function - * - * Tries to enable the SDIO function; might fail if it is still not - * ready (in some hardware, the SDIO WiMAX function is only enabled - * when we ask it to explicitly doing). Tries until a timeout is - * reached. - * - * The @maxtries argument indicates how many times (at most) it should - * be tried to enable the function. 0 means forever. This acts along - * with the timeout (ie: it'll stop trying as soon as the maximum - * number of tries is reached _or_ as soon as the timeout is reached). - * - * The reverse of this is...sdio_disable_function() - * - * Returns: 0 if the SDIO function was enabled, < 0 errno code on - * error (-ENODEV when it was unable to enable the function). - */ -static -int i2400ms_enable_function(struct i2400ms *i2400ms, unsigned maxtries) -{ - struct sdio_func *func = i2400ms->func; - u64 timeout; - int err; - struct device *dev = &func->dev; - unsigned tries = 0; - - d_fnstart(3, dev, "(func %p)\n", func); - /* Setup timeout (FIXME: This needs to read the CIS table to - * get a real timeout) and then wait for the device to signal - * it is ready */ - timeout = get_jiffies_64() + ioe_timeout * HZ; - err = -ENODEV; - while (err != 0 && time_before64(get_jiffies_64(), timeout)) { - sdio_claim_host(func); - /* - * There is a sillicon bug on the IWMC3200, where the - * IOE timeout will cause problems on Moorestown - * platforms (system hang). We explicitly overwrite - * func->enable_timeout here to work around the issue. - */ - if (i2400ms->iwmc3200) - func->enable_timeout = IWMC3200_IOR_TIMEOUT; - err = sdio_enable_func(func); - if (0 == err) { - sdio_release_host(func); - d_printf(2, dev, "SDIO function enabled\n"); - goto function_enabled; - } - d_printf(2, dev, "SDIO function failed to enable: %d\n", err); - sdio_release_host(func); - if (maxtries > 0 && ++tries >= maxtries) { - err = -ETIME; - break; - } - msleep(I2400MS_INIT_SLEEP_INTERVAL); - } - /* If timed out, device is not there yet -- get -ENODEV so - * the device driver core will retry later on. */ - if (err == -ETIME) { - dev_err(dev, "Can't enable WiMAX function; " - " has the function been enabled?\n"); - err = -ENODEV; - } -function_enabled: - d_fnend(3, dev, "(func %p) = %d\n", func, err); - return err; -} - - -/* - * Setup minimal device communication infrastructure needed to at - * least be able to update the firmware. - * - * Note the ugly trick: if we are in the probe path - * (i2400ms->debugfs_dentry == NULL), we only retry function - * enablement one, to avoid racing with the iwmc3200 top controller. - */ -static -int i2400ms_bus_setup(struct i2400m *i2400m) -{ - int result; - struct i2400ms *i2400ms = - container_of(i2400m, struct i2400ms, i2400m); - struct device *dev = i2400m_dev(i2400m); - struct sdio_func *func = i2400ms->func; - int retries; - - sdio_claim_host(func); - result = sdio_set_block_size(func, I2400MS_BLK_SIZE); - sdio_release_host(func); - if (result < 0) { - dev_err(dev, "Failed to set block size: %d\n", result); - goto error_set_blk_size; - } - - if (i2400ms->iwmc3200 && i2400ms->debugfs_dentry == NULL) - retries = 1; - else - retries = 0; - result = i2400ms_enable_function(i2400ms, retries); - if (result < 0) { - dev_err(dev, "Cannot enable SDIO function: %d\n", result); - goto error_func_enable; - } - - result = i2400ms_tx_setup(i2400ms); - if (result < 0) - goto error_tx_setup; - result = i2400ms_rx_setup(i2400ms); - if (result < 0) - goto error_rx_setup; - return 0; - -error_rx_setup: - i2400ms_tx_release(i2400ms); -error_tx_setup: - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -error_func_enable: -error_set_blk_size: - return result; -} - - -/* - * Tear down minimal device communication infrastructure needed to at - * least be able to update the firmware. - */ -static -void i2400ms_bus_release(struct i2400m *i2400m) -{ - struct i2400ms *i2400ms = - container_of(i2400m, struct i2400ms, i2400m); - struct sdio_func *func = i2400ms->func; - - i2400ms_rx_release(i2400ms); - i2400ms_tx_release(i2400ms); - sdio_claim_host(func); - sdio_disable_func(func); - sdio_release_host(func); -} - - -/* - * Setup driver resources needed to communicate with the device - * - * The fw needs some time to settle, and it was just uploaded, - * so give it a break first. I'd prefer to just wait for the device to - * send something, but seems the poking we do to enable SDIO stuff - * interferes with it, so just give it a break before starting... - */ -static -int i2400ms_bus_dev_start(struct i2400m *i2400m) -{ - struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - - d_fnstart(3, dev, "(i2400m %p)\n", i2400m); - msleep(200); - d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, 0); - return 0; -} - - -/* - * Sends a barker buffer to the device - * - * This helper will allocate a kmalloced buffer and use it to transmit - * (then free it). Reason for this is that the SDIO host controller - * expects alignment (unknown exactly which) which the stack won't - * really provide and certain arches/host-controller combinations - * cannot use stack/vmalloc/text areas for DMA transfers. - */ -static -int __i2400ms_send_barker(struct i2400ms *i2400ms, - const __le32 *barker, size_t barker_size) -{ - int ret; - struct sdio_func *func = i2400ms->func; - struct device *dev = &func->dev; - void *buffer; - - ret = -ENOMEM; - buffer = kmalloc(I2400MS_BLK_SIZE, GFP_KERNEL); - if (buffer == NULL) - goto error_kzalloc; - - memcpy(buffer, barker, barker_size); - sdio_claim_host(func); - ret = sdio_memcpy_toio(func, 0, buffer, I2400MS_BLK_SIZE); - sdio_release_host(func); - - if (ret < 0) - d_printf(0, dev, "E: barker error: %d\n", ret); - - kfree(buffer); -error_kzalloc: - return ret; -} - - -/* - * Reset a device at different levels (warm, cold or bus) - * - * @i2400ms: device descriptor - * @reset_type: soft, warm or bus reset (I2400M_RT_WARM/SOFT/BUS) - * - * FIXME: not tested -- need to confirm expected effects - * - * Warm and cold resets get an SDIO reset if they fail (unimplemented) - * - * Warm reset: - * - * The device will be fully reset internally, but won't be - * disconnected from the bus (so no reenumeration will - * happen). Firmware upload will be necessary. - * - * The device will send a reboot barker that will trigger the driver - * to reinitialize the state via __i2400m_dev_reset_handle. - * - * - * Cold and bus reset: - * - * The device will be fully reset internally, disconnected from the - * bus an a reenumeration will happen. Firmware upload will be - * necessary. Thus, we don't do any locking or struct - * reinitialization, as we are going to be fully disconnected and - * reenumerated. - * - * Note we need to return -ENODEV if a warm reset was requested and we - * had to resort to a bus reset. See i2400m_op_reset(), wimax_reset() - * and wimax_dev->op_reset. - * - * WARNING: no driver state saved/fixed - */ -static -int i2400ms_bus_reset(struct i2400m *i2400m, enum i2400m_reset_type rt) -{ - int result = 0; - struct i2400ms *i2400ms = - container_of(i2400m, struct i2400ms, i2400m); - struct device *dev = i2400m_dev(i2400m); - static const __le32 i2400m_WARM_BOOT_BARKER[4] = { - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - cpu_to_le32(I2400M_WARM_RESET_BARKER), - }; - static const __le32 i2400m_COLD_BOOT_BARKER[4] = { - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - cpu_to_le32(I2400M_COLD_RESET_BARKER), - }; - - if (rt == I2400M_RT_WARM) - result = __i2400ms_send_barker(i2400ms, i2400m_WARM_BOOT_BARKER, - sizeof(i2400m_WARM_BOOT_BARKER)); - else if (rt == I2400M_RT_COLD) - result = __i2400ms_send_barker(i2400ms, i2400m_COLD_BOOT_BARKER, - sizeof(i2400m_COLD_BOOT_BARKER)); - else if (rt == I2400M_RT_BUS) { -do_bus_reset: - - i2400ms_bus_release(i2400m); - - /* Wait for the device to settle */ - msleep(40); - - result = i2400ms_bus_setup(i2400m); - } else - BUG(); - if (result < 0 && rt != I2400M_RT_BUS) { - dev_err(dev, "%s reset failed (%d); trying SDIO reset\n", - rt == I2400M_RT_WARM ? "warm" : "cold", result); - rt = I2400M_RT_BUS; - goto do_bus_reset; - } - return result; -} - - -static -void i2400ms_netdev_setup(struct net_device *net_dev) -{ - struct i2400m *i2400m = net_dev_to_i2400m(net_dev); - struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m); - i2400ms_init(i2400ms); - i2400m_netdev_setup(net_dev); -} - - -/* - * Debug levels control; see debug.h - */ -struct d_level D_LEVEL[] = { - D_SUBMODULE_DEFINE(main), - D_SUBMODULE_DEFINE(tx), - D_SUBMODULE_DEFINE(rx), - D_SUBMODULE_DEFINE(fw), -}; -size_t D_LEVEL_SIZE = ARRAY_SIZE(D_LEVEL); - - -#define __debugfs_register(prefix, name, parent) \ -do { \ - result = d_level_register_debugfs(prefix, name, parent); \ - if (result < 0) \ - goto error; \ -} while (0) - - -static -int i2400ms_debugfs_add(struct i2400ms *i2400ms) -{ - int result; - struct dentry *dentry = i2400ms->i2400m.wimax_dev.debugfs_dentry; - - dentry = debugfs_create_dir("i2400m-sdio", dentry); - result = PTR_ERR(dentry); - if (IS_ERR(dentry)) { - if (result == -ENODEV) - result = 0; /* No debugfs support */ - goto error; - } - i2400ms->debugfs_dentry = dentry; - __debugfs_register("dl_", main, dentry); - __debugfs_register("dl_", tx, dentry); - __debugfs_register("dl_", rx, dentry); - __debugfs_register("dl_", fw, dentry); - - return 0; - -error: - debugfs_remove_recursive(i2400ms->debugfs_dentry); - i2400ms->debugfs_dentry = NULL; - return result; -} - - -static struct device_type i2400ms_type = { - .name = "wimax", -}; - -/* - * Probe a i2400m interface and register it - * - * @func: SDIO function - * @id: SDIO device ID - * @returns: 0 if ok, < 0 errno code on error. - * - * Alloc a net device, initialize the bus-specific details and then - * calls the bus-generic initialization routine. That will register - * the wimax and netdev devices, upload the firmware [using - * _bus_bm_*()], call _bus_dev_start() to finalize the setup of the - * communication with the device and then will start to talk to it to - * finnish setting it up. - * - * Initialization is tricky; some instances of the hw are packed with - * others in a way that requires a third driver that enables the WiMAX - * function. In those cases, we can't enable the SDIO function and - * we'll return with -ENODEV. When the driver that enables the WiMAX - * function does its thing, it has to do a bus_rescan_devices() on the - * SDIO bus so this driver is called again to enumerate the WiMAX - * function. - */ -static -int i2400ms_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - int result; - struct net_device *net_dev; - struct device *dev = &func->dev; - struct i2400m *i2400m; - struct i2400ms *i2400ms; - - /* Allocate instance [calls i2400m_netdev_setup() on it]. */ - result = -ENOMEM; - net_dev = alloc_netdev(sizeof(*i2400ms), "wmx%d", - i2400ms_netdev_setup); - if (net_dev == NULL) { - dev_err(dev, "no memory for network device instance\n"); - goto error_alloc_netdev; - } - SET_NETDEV_DEV(net_dev, dev); - SET_NETDEV_DEVTYPE(net_dev, &i2400ms_type); - i2400m = net_dev_to_i2400m(net_dev); - i2400ms = container_of(i2400m, struct i2400ms, i2400m); - i2400m->wimax_dev.net_dev = net_dev; - i2400ms->func = func; - sdio_set_drvdata(func, i2400ms); - - i2400m->bus_tx_block_size = I2400MS_BLK_SIZE; - /* - * Room required in the TX queue for SDIO message to accommodate - * a smallest payload while allocating header space is 224 bytes, - * which is the smallest message size(the block size 256 bytes) - * minus the smallest message header size(32 bytes). - */ - i2400m->bus_tx_room_min = I2400MS_BLK_SIZE - I2400M_PL_ALIGN * 2; - i2400m->bus_pl_size_max = I2400MS_PL_SIZE_MAX; - i2400m->bus_setup = i2400ms_bus_setup; - i2400m->bus_dev_start = i2400ms_bus_dev_start; - i2400m->bus_dev_stop = NULL; - i2400m->bus_release = i2400ms_bus_release; - i2400m->bus_tx_kick = i2400ms_bus_tx_kick; - i2400m->bus_reset = i2400ms_bus_reset; - /* The iwmc3200-wimax sometimes requires the driver to try - * hard when we paint it into a corner. */ - i2400m->bus_bm_retries = I2400M_SDIO_BOOT_RETRIES; - i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send; - i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack; - i2400m->bus_fw_names = i2400ms_bus_fw_names; - i2400m->bus_bm_mac_addr_impaired = 1; - i2400m->bus_bm_pokes_table = &i2400ms_pokes[0]; - - switch (func->device) { - case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX: - case SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5: - i2400ms->iwmc3200 = 1; - break; - default: - i2400ms->iwmc3200 = 0; - } - - result = i2400m_setup(i2400m, I2400M_BRI_NO_REBOOT); - if (result < 0) { - dev_err(dev, "cannot setup device: %d\n", result); - goto error_setup; - } - - result = i2400ms_debugfs_add(i2400ms); - if (result < 0) { - dev_err(dev, "cannot create SDIO debugfs: %d\n", - result); - goto error_debugfs_add; - } - return 0; - -error_debugfs_add: - i2400m_release(i2400m); -error_setup: - sdio_set_drvdata(func, NULL); - free_netdev(net_dev); -error_alloc_netdev: - return result; -} - - -static -void i2400ms_remove(struct sdio_func *func) -{ - struct device *dev = &func->dev; - struct i2400ms *i2400ms = sdio_get_drvdata(func); - struct i2400m *i2400m = &i2400ms->i2400m; - struct net_device *net_dev = i2400m->wimax_dev.net_dev; - - d_fnstart(3, dev, "SDIO func %p\n", func); - debugfs_remove_recursive(i2400ms->debugfs_dentry); - i2400ms->debugfs_dentry = NULL; - i2400m_release(i2400m); - sdio_set_drvdata(func, NULL); - free_netdev(net_dev); - d_fnend(3, dev, "SDIO func %p\n", func); -} - -static -const struct sdio_device_id i2400ms_sdio_ids[] = { - /* Intel: i2400m WiMAX (iwmc3200) over SDIO */ - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, - SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX) }, - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, - SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX_2G5) }, - { /* end: all zeroes */ }, -}; -MODULE_DEVICE_TABLE(sdio, i2400ms_sdio_ids); - - -static -struct sdio_driver i2400m_sdio_driver = { - .name = KBUILD_MODNAME, - .probe = i2400ms_probe, - .remove = i2400ms_remove, - .id_table = i2400ms_sdio_ids, -}; - - -static -int __init i2400ms_driver_init(void) -{ - d_parse_params(D_LEVEL, D_LEVEL_SIZE, i2400ms_debug_params, - "i2400m_sdio.debug"); - return sdio_register_driver(&i2400m_sdio_driver); -} -module_init(i2400ms_driver_init); - - -static -void __exit i2400ms_driver_exit(void) -{ - sdio_unregister_driver(&i2400m_sdio_driver); -} -module_exit(i2400ms_driver_exit); - - -MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>"); -MODULE_DESCRIPTION("Intel 2400M WiMAX networking for SDIO"); -MODULE_LICENSE("GPL"); -MODULE_FIRMWARE(I2400MS_FW_FILE_NAME); diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 5f58fa53238c..6deaae18db57 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -276,7 +276,6 @@ source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/iwlegacy/Kconfig" -source "drivers/net/wireless/iwmc3200wifi/Kconfig" source "drivers/net/wireless/libertas/Kconfig" source "drivers/net/wireless/orinoco/Kconfig" source "drivers/net/wireless/p54/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0ce218b931d4..062dfdff6364 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -53,8 +53,6 @@ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o obj-$(CONFIG_WL_TI) += ti/ -obj-$(CONFIG_IWM) += iwmc3200wifi/ - obj-$(CONFIG_MWIFIEX) += mwifiex/ obj-$(CONFIG_BRCMFMAC) += brcm80211/ diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 520a4b2eb9cc..a747c632597a 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -7233,8 +7233,8 @@ static int airo_get_aplist(struct net_device *dev, } } else { dwrq->flags = 1; /* Should be define'd */ - memcpy(extra + sizeof(struct sockaddr)*i, - &qual, sizeof(struct iw_quality)*i); + memcpy(extra + sizeof(struct sockaddr) * i, qual, + sizeof(struct iw_quality) * i); } dwrq->length = i; diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index c54b7d37bff1..420d69b2674c 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -143,6 +143,7 @@ struct ath_common { u32 keymax; DECLARE_BITMAP(keymap, ATH_KEYMAX); DECLARE_BITMAP(tkip_keymap, ATH_KEYMAX); + DECLARE_BITMAP(ccmp_keymap, ATH_KEYMAX); enum ath_crypt_caps crypt_caps; unsigned int clockrate; diff --git a/drivers/net/wireless/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index e18a9aa7b6ca..338c5c42357d 100644 --- a/drivers/net/wireless/ath/ath5k/Kconfig +++ b/drivers/net/wireless/ath/ath5k/Kconfig @@ -64,3 +64,11 @@ config ATH5K_PCI ---help--- This adds support for PCI type chipsets of the 5xxx Atheros family. + +config ATH5K_TEST_CHANNELS + bool "Enables testing channels on ath5k" + depends on ATH5K && CFG80211_CERTIFICATION_ONUS + ---help--- + This enables non-standard IEEE 802.11 channels on ath5k, which + can be used for research purposes. This option should be disabled + unless doing research. diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c index fbaa30930076..8c4c040a47b8 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -74,10 +74,6 @@ bool ath5k_modparam_nohwcrypt; module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO); MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); -static bool modparam_all_channels; -module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO); -MODULE_PARM_DESC(all_channels, "Expose all channels the device can use."); - static bool modparam_fastchanswitch; module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO); MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios."); @@ -258,8 +254,15 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re \********************/ /* - * Returns true for the channel numbers used without all_channels modparam. + * Returns true for the channel numbers used. */ +#ifdef CONFIG_ATH5K_TEST_CHANNELS +static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) +{ + return true; +} + +#else static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) { if (band == IEEE80211_BAND_2GHZ && chan <= 14) @@ -276,6 +279,7 @@ static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band) /* 802.11j 4.9GHz (20MHz) */ (chan == 184 || chan == 188 || chan == 192 || chan == 196)); } +#endif static unsigned int ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, @@ -316,8 +320,7 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels, if (!ath5k_channel_ok(ah, &channels[count])) continue; - if (!modparam_all_channels && - !ath5k_is_standard_channel(ch, band)) + if (!ath5k_is_standard_channel(ch, band)) continue; count++; @@ -1045,11 +1048,11 @@ ath5k_drain_tx_buffs(struct ath5k_hw *ah) ath5k_txbuf_free_skb(ah, bf); - spin_lock_bh(&ah->txbuflock); + spin_lock(&ah->txbuflock); list_move_tail(&bf->list, &ah->txbuf); ah->txbuf_len++; txq->txq_len--; - spin_unlock_bh(&ah->txbuflock); + spin_unlock(&ah->txbuflock); } txq->link = NULL; txq->txq_poll_mark = false; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index f27e9732951d..86aeef4b9d7e 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -53,6 +53,11 @@ #define DEFAULT_BG_SCAN_PERIOD 60 +struct ath6kl_cfg80211_match_probe_ssid { + struct cfg80211_ssid ssid; + u8 flag; +}; + static struct ieee80211_rate ath6kl_rates[] = { RATETAB_ENT(10, 0x1, 0), RATETAB_ENT(20, 0x2, 0), @@ -576,6 +581,9 @@ static int ath6kl_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, vif->nw_type = vif->next_mode; + /* enable enhanced bmiss detection if applicable */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, true); + if (vif->wdev.iftype == NL80211_IFTYPE_P2P_CLIENT) nw_subtype = SUBTYPE_P2PCLIENT; @@ -852,20 +860,6 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, } } - /* - * Send a disconnect command to target when a disconnect event is - * received with reason code other than 3 (DISCONNECT_CMD - disconnect - * request from host) to make the firmware stop trying to connect even - * after giving disconnect event. There will be one more disconnect - * event for this disconnect command with reason code DISCONNECT_CMD - * which will be notified to cfg80211. - */ - - if (reason != DISCONNECT_CMD) { - ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); - return; - } - clear_bit(CONNECT_PEND, &vif->flags); if (vif->sme_state == SME_CONNECTING) { @@ -875,32 +869,96 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, WLAN_STATUS_UNSPECIFIED_FAILURE, GFP_KERNEL); } else if (vif->sme_state == SME_CONNECTED) { - cfg80211_disconnected(vif->ndev, reason, + cfg80211_disconnected(vif->ndev, proto_reason, NULL, 0, GFP_KERNEL); } vif->sme_state = SME_DISCONNECTED; + + /* + * Send a disconnect command to target when a disconnect event is + * received with reason code other than 3 (DISCONNECT_CMD - disconnect + * request from host) to make the firmware stop trying to connect even + * after giving disconnect event. There will be one more disconnect + * event for this disconnect command with reason code DISCONNECT_CMD + * which won't be notified to cfg80211. + */ + if (reason != DISCONNECT_CMD) + ath6kl_wmi_disconnect_cmd(ar->wmi, vif->fw_vif_idx); } static int ath6kl_set_probed_ssids(struct ath6kl *ar, struct ath6kl_vif *vif, - struct cfg80211_ssid *ssids, int n_ssids) + struct cfg80211_ssid *ssids, int n_ssids, + struct cfg80211_match_set *match_set, + int n_match_ssid) { - u8 i; + u8 i, j, index_to_add, ssid_found = false; + struct ath6kl_cfg80211_match_probe_ssid ssid_list[MAX_PROBED_SSIDS]; + + memset(ssid_list, 0, sizeof(ssid_list)); - if (n_ssids > MAX_PROBED_SSID_INDEX) + if (n_ssids > MAX_PROBED_SSIDS || + n_match_ssid > MAX_PROBED_SSIDS) return -EINVAL; for (i = 0; i < n_ssids; i++) { + memcpy(ssid_list[i].ssid.ssid, + ssids[i].ssid, + ssids[i].ssid_len); + ssid_list[i].ssid.ssid_len = ssids[i].ssid_len; + + if (ssids[i].ssid_len) + ssid_list[i].flag = SPECIFIC_SSID_FLAG; + else + ssid_list[i].flag = ANY_SSID_FLAG; + + if (n_match_ssid == 0) + ssid_list[i].flag |= MATCH_SSID_FLAG; + } + + index_to_add = i; + + for (i = 0; i < n_match_ssid; i++) { + ssid_found = false; + + for (j = 0; j < n_ssids; j++) { + if ((match_set[i].ssid.ssid_len == + ssid_list[j].ssid.ssid_len) && + (!memcmp(ssid_list[j].ssid.ssid, + match_set[i].ssid.ssid, + match_set[i].ssid.ssid_len))) { + ssid_list[j].flag |= MATCH_SSID_FLAG; + ssid_found = true; + break; + } + } + + if (ssid_found) + continue; + + if (index_to_add >= MAX_PROBED_SSIDS) + continue; + + ssid_list[index_to_add].ssid.ssid_len = + match_set[i].ssid.ssid_len; + memcpy(ssid_list[index_to_add].ssid.ssid, + match_set[i].ssid.ssid, + match_set[i].ssid.ssid_len); + ssid_list[index_to_add].flag |= MATCH_SSID_FLAG; + index_to_add++; + } + + for (i = 0; i < index_to_add; i++) { ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, - ssids[i].ssid_len ? - SPECIFIC_SSID_FLAG : ANY_SSID_FLAG, - ssids[i].ssid_len, - ssids[i].ssid); + ssid_list[i].flag, + ssid_list[i].ssid.ssid_len, + ssid_list[i].ssid.ssid); + } /* Make sure no old entries are left behind */ - for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) { + for (i = index_to_add; i < MAX_PROBED_SSIDS; i++) { ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, DISABLE_SSID_FLAG, 0, NULL); } @@ -908,11 +966,11 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar, return 0; } -static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, +static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { - struct ath6kl *ar = ath6kl_priv(ndev); - struct ath6kl_vif *vif = netdev_priv(ndev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); s8 n_channels = 0; u16 *channels = NULL; int ret = 0; @@ -934,7 +992,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, } ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, - request->n_ssids); + request->n_ssids, NULL, 0); if (ret < 0) return ret; @@ -943,7 +1001,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); if (ret) { - ath6kl_err("failed to set Probe Request appie for scan"); + ath6kl_err("failed to set Probe Request appie for scan\n"); return ret; } @@ -1429,14 +1487,14 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, return 0; } -static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ath6kl *ar = wiphy_priv(wiphy); - struct net_device *ndev; + struct wireless_dev *wdev; u8 if_idx, nw_type; if (ar->num_vif == ar->vif_max) { @@ -1449,20 +1507,20 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); - if (!ndev) + wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); + if (!wdev) return ERR_PTR(-ENOMEM); ar->num_vif++; - return ndev; + return wdev; } static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, - struct net_device *ndev) + struct wireless_dev *wdev) { struct ath6kl *ar = wiphy_priv(wiphy); - struct ath6kl_vif *vif = netdev_priv(ndev); + struct ath6kl_vif *vif = netdev_priv(wdev->netdev); spin_lock_bh(&ar->list_lock); list_del(&vif->list); @@ -1512,6 +1570,9 @@ static int ath6kl_cfg80211_change_iface(struct wiphy *wiphy, } } + /* need to clean up enhanced bmiss detection fw state */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, false); + set_iface_type: switch (type) { case NL80211_IFTYPE_STATION: @@ -2074,7 +2135,9 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) return -EINVAL; - if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) { + if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) && + test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, + ar->fw_capabilities)) { ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, false); if (ret) @@ -2209,7 +2272,9 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ar->state = ATH6KL_STATE_ON; - if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) { + if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) && + test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, + ar->fw_capabilities)) { ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, true); if (ret) @@ -2475,7 +2540,7 @@ void ath6kl_check_wow_status(struct ath6kl *ar) static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, bool ht_enable) { - struct ath6kl_htcap *htcap = &vif->htcap; + struct ath6kl_htcap *htcap = &vif->htcap[band]; if (htcap->ht_enable == ht_enable) return 0; @@ -2585,6 +2650,30 @@ static int ath6kl_set_ies(struct ath6kl_vif *vif, return 0; } +void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable) +{ + int err; + + if (WARN_ON(!test_bit(WMI_READY, &vif->ar->flag))) + return; + + if (vif->nw_type != INFRA_NETWORK) + return; + + if (!test_bit(ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, + vif->ar->fw_capabilities)) + return; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s fw bmiss enhance\n", + enable ? "enable" : "disable"); + + err = ath6kl_wmi_sta_bmiss_enhance_cmd(vif->ar->wmi, + vif->fw_vif_idx, enable); + if (err) + ath6kl_err("failed to %s enhanced bmiss detection: %d\n", + enable ? "enable" : "disable", err); +} + static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, u8 *rsn_capab) { @@ -2665,9 +2754,15 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, /* TODO: * info->interval - * info->dtim_period */ + ret = ath6kl_wmi_ap_set_dtim_cmd(ar->wmi, vif->fw_vif_idx, + info->dtim_period); + + /* ignore error, just print a warning and continue normally */ + if (ret) + ath6kl_warn("Failed to set dtim_period in beacon: %d\n", ret); + if (info->beacon.head == NULL) return -EINVAL; mgmt = (struct ieee80211_mgmt *) info->beacon.head; @@ -2880,14 +2975,14 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, } static int ath6kl_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); u32 id; /* TODO: if already pending or ongoing remain-on-channel, @@ -2904,11 +2999,11 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy, } static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); if (cookie != vif->last_roc_id) return -ENOENT; @@ -3039,15 +3134,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) return false; } -static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); u32 id; const struct ieee80211_mgmt *mgmt; bool more_data, queued; @@ -3092,10 +3187,10 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg) { - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", __func__, frame_type, reg); @@ -3131,10 +3226,24 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, ath6kl_cfg80211_scan_complete_event(vif, true); ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, - request->n_ssids); + request->n_ssids, + request->match_sets, + request->n_match_sets); if (ret < 0) return ret; + if (!request->n_match_sets) { + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + ALL_BSS_FILTER, 0); + if (ret < 0) + return ret; + } else { + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + MATCHED_SSID_FILTER, 0); + if (ret < 0) + return ret; + } + /* fw uses seconds, also make sure that it's >0 */ interval = max_t(u16, 1, request->interval / 1000); @@ -3156,7 +3265,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); if (ret) { - ath6kl_warn("Failed to set probe request IE for scheduled scan: %d", + ath6kl_warn("Failed to set probe request IE for scheduled scan: %d\n", ret); return ret; } @@ -3188,6 +3297,18 @@ static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy, return 0; } +static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy, + struct net_device *dev, + const u8 *addr, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath6kl *ar = ath6kl_priv(dev); + struct ath6kl_vif *vif = netdev_priv(dev); + + return ath6kl_wmi_set_bitrate_mask(ar->wmi, vif->fw_vif_idx, + mask); +} + static const struct ieee80211_txrx_stypes ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_STATION] = { @@ -3253,6 +3374,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = { .mgmt_frame_register = ath6kl_mgmt_frame_register, .sched_scan_start = ath6kl_cfg80211_sscan_start, .sched_scan_stop = ath6kl_cfg80211_sscan_stop, + .set_bitrate_mask = ath6kl_cfg80211_set_bitrate, }; void ath6kl_cfg80211_stop(struct ath6kl_vif *vif) @@ -3355,9 +3477,9 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) ar->num_vif--; } -struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, - enum nl80211_iftype type, u8 fw_vif_idx, - u8 nw_type) +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, + enum nl80211_iftype type, + u8 fw_vif_idx, u8 nw_type) { struct net_device *ndev; struct ath6kl_vif *vif; @@ -3380,7 +3502,8 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; vif->bg_scan_period = 0; - vif->htcap.ht_enable = true; + vif->htcap[IEEE80211_BAND_2GHZ].ht_enable = true; + vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); if (fw_vif_idx != 0) @@ -3410,7 +3533,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, list_add_tail(&vif->list, &ar->vif_list); spin_unlock_bh(&ar->list_lock); - return ndev; + return &vif->wdev; err: aggr_module_destroy(vif->aggr_cntxt); @@ -3440,7 +3563,13 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) } /* max num of ssids that can be probed during scanning */ - wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; + wiphy->max_scan_ssids = MAX_PROBED_SSIDS; + + /* max num of ssids that can be matched after scan */ + if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + ar->fw_capabilities)) + wiphy->max_match_sets = MAX_PROBED_SSIDS; + wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ switch (ar->hw.cap) { case WMI_11AN_CAP: @@ -3477,6 +3606,17 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ath6kl_band_5ghz.ht_cap.cap = 0; ath6kl_band_5ghz.ht_cap.ht_supported = false; } + + if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) { + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[1] = 0xff; + } else { + ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff; + ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff; + } + if (band_2gig) wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; if (band_5gig) @@ -3487,6 +3627,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->cipher_suites = cipher_suites; wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); +#ifdef CONFIG_PM wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT | WIPHY_WOWLAN_GTK_REKEY_FAILURE | @@ -3496,8 +3637,9 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST; wiphy->wowlan.pattern_min_len = 1; wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; +#endif - wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX; + wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAVE_AP_SME | diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index 5ea8cbb79f43..56b1ebe79812 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -25,9 +25,9 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; -struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, - enum nl80211_iftype type, - u8 fw_vif_idx, u8 nw_type); +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, + enum nl80211_iftype type, + u8 fw_vif_idx, u8 nw_type); void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, enum wmi_phy_mode mode); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); @@ -62,5 +62,7 @@ void ath6kl_cfg80211_cleanup(struct ath6kl *ar); struct ath6kl *ath6kl_cfg80211_create(void); void ath6kl_cfg80211_destroy(struct ath6kl *ar); +/* TODO: remove this once ath6kl_vif_cleanup() is moved to cfg80211.c */ +void ath6kl_cfg80211_sta_bmiss_enhance(struct ath6kl_vif *vif, bool enable); #endif /* ATH6KL_CFG80211_H */ diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index fdb3b1decc76..82c4dd2a960e 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -56,7 +56,7 @@ EXPORT_SYMBOL(ath6kl_core_rx_complete); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) { struct ath6kl_bmi_target_info targ_info; - struct net_device *ndev; + struct wireless_dev *wdev; int ret = 0, i; switch (htc_type) { @@ -187,12 +187,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) rtnl_lock(); /* Add an initial station interface */ - ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, + wdev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, INFRA_NETWORK); rtnl_unlock(); - if (!ndev) { + if (!wdev) { ath6kl_err("Failed to instantiate a network device\n"); ret = -ENOMEM; wiphy_unregister(ar->wiphy); @@ -200,7 +200,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) } ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", - __func__, ndev->name, ndev, ar); + __func__, wdev->netdev->name, wdev->netdev, ar); return ret; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 8443b2a4133e..cec49a31029a 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -100,6 +100,21 @@ enum ath6kl_fw_capability { /* Firmware has support to override rsn cap of rsn ie */ ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + /* + * Multicast support in WOW and host awake mode. + * Allow all multicast in host awake mode. + * Apply multicast filter in WOW mode. + */ + ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, + + /* Firmware supports enhanced bmiss detection */ + ATH6KL_FW_CAPABILITY_BMISS_ENHANCE, + + /* + * FW supports matching of ssid in schedule scan + */ + ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; @@ -112,6 +127,10 @@ struct ath6kl_fw_ie { u8 data[0]; }; +enum ath6kl_hw_flags { + ATH6KL_HW_FLAG_64BIT_RATES = BIT(0), +}; + #define ATH6KL_FW_API2_FILE "fw-2.bin" #define ATH6KL_FW_API3_FILE "fw-3.bin" @@ -196,7 +215,7 @@ struct ath6kl_fw_ie { #define AGGR_NUM_OF_FREE_NETBUFS 16 -#define AGGR_RX_TIMEOUT 400 /* in ms */ +#define AGGR_RX_TIMEOUT 100 /* in ms */ #define WMI_TIMEOUT (2 * HZ) @@ -245,7 +264,6 @@ struct skb_hold_q { struct rxtid { bool aggr; - bool progress; bool timer_mon; u16 win_sz; u16 seq_next; @@ -254,9 +272,15 @@ struct rxtid { struct sk_buff_head q; /* - * FIXME: No clue what this should protect. Apparently it should - * protect some of the fields above but they are also accessed - * without taking the lock. + * lock mainly protects seq_next and hold_q. Movement of seq_next + * needs to be protected between aggr_timeout() and + * aggr_process_recv_frm(). hold_q will be holding the pending + * reorder frames and it's access should also be protected. + * Some of the other fields like hold_q_sz, win_sz and aggr are + * initialized/reset when receiving addba/delba req, also while + * deleting aggr state all the pending buffers are flushed before + * resetting these fields, so there should not be any race in accessing + * these fields. */ spinlock_t lock; }; @@ -541,7 +565,7 @@ struct ath6kl_vif { struct ath6kl_wep_key wep_key_list[WMI_MAX_KEY_INDEX + 1]; struct ath6kl_key keys[WMI_MAX_KEY_INDEX + 1]; struct aggr_info *aggr_cntxt; - struct ath6kl_htcap htcap; + struct ath6kl_htcap htcap[IEEE80211_NUM_BANDS]; struct timer_list disconnect_timer; struct timer_list sched_scan_timer; @@ -565,6 +589,11 @@ struct ath6kl_vif { struct list_head mc_filter; }; +static inline struct ath6kl_vif *ath6kl_vif_from_wdev(struct wireless_dev *wdev) +{ + return container_of(wdev, struct ath6kl_vif, wdev); +} + #define WOW_LIST_ID 0 #define WOW_HOST_REQ_DELAY 500 /* ms */ @@ -684,6 +713,8 @@ struct ath6kl { u32 testscript_addr; enum wmi_phy_cap cap; + u32 flags; + struct ath6kl_hw_fw { const char *dir; const char *otp; diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 2798624d3a9d..cd0e1ba410d6 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -1309,7 +1309,7 @@ static int ath6kl_htc_rx_packet(struct htc_target *target, } ath6kl_dbg(ATH6KL_DBG_HTC, - "htc rx 0x%p hdr x%x len %d mbox 0x%x\n", + "htc rx 0x%p hdr 0x%x len %d mbox 0x%x\n", packet, packet->info.rx.exp_hdr, padded_len, dev->ar->mbox_info.htc_addr); diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 7eb0515f458a..f90b5db741cf 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -42,6 +42,7 @@ static const struct ath6kl_hw hw_list[] = { .reserved_ram_size = 6912, .refclk_hz = 26000000, .uarttx_pin = 8, + .flags = 0, /* hw2.0 needs override address hardcoded */ .app_start_override_addr = 0x944C00, @@ -67,6 +68,7 @@ static const struct ath6kl_hw hw_list[] = { .refclk_hz = 26000000, .uarttx_pin = 8, .testscript_addr = 0x57ef74, + .flags = 0, .fw = { .dir = AR6003_HW_2_1_1_FW_DIR, @@ -91,6 +93,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x433900, .refclk_hz = 26000000, .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, .fw = { .dir = AR6004_HW_1_0_FW_DIR, @@ -110,6 +113,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x43d400, .refclk_hz = 40000000, .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, .fw = { .dir = AR6004_HW_1_1_FW_DIR, @@ -129,6 +133,7 @@ static const struct ath6kl_hw hw_list[] = { .board_addr = 0x435c00, .refclk_hz = 40000000, .uarttx_pin = 11, + .flags = ATH6KL_HW_FLAG_64BIT_RATES, .fw = { .dir = AR6004_HW_1_2_FW_DIR, @@ -938,6 +943,14 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) } switch (ie_id) { + case ATH6KL_FW_IE_FW_VERSION: + strlcpy(ar->wiphy->fw_version, data, + sizeof(ar->wiphy->fw_version)); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "found fw version %s\n", + ar->wiphy->fw_version); + break; case ATH6KL_FW_IE_OTP_IMAGE: ath6kl_dbg(ATH6KL_DBG_BOOT, "found otp image ie (%zd B)\n", ie_len); @@ -991,9 +1004,6 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) ar->hw.reserved_ram_size); break; case ATH6KL_FW_IE_CAPABILITIES: - if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8)) - break; - ath6kl_dbg(ATH6KL_DBG_BOOT, "found firmware capabilities ie (%zd B)\n", ie_len); @@ -1002,6 +1012,9 @@ static int ath6kl_fetch_fw_apin(struct ath6kl *ar, const char *name) index = i / 8; bit = i % 8; + if (index == ie_len) + break; + if (data[index] & (1 << bit)) __set_bit(i, ar->fw_capabilities); } @@ -1392,6 +1405,12 @@ static int ath6kl_init_upload(struct ath6kl *ar) ar->version.target_ver == AR6003_HW_2_1_1_VERSION) { ath6kl_err("temporary war to avoid sdio crc error\n"); + param = 0x28; + address = GPIO_BASE_ADDRESS + GPIO_PIN9_ADDRESS; + status = ath6kl_bmi_reg_write(ar, address, param); + if (status) + return status; + param = 0x20; address = GPIO_BASE_ADDRESS + GPIO_PIN10_ADDRESS; @@ -1659,6 +1678,9 @@ void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready) cfg80211_scan_done(vif->scan_req, true); vif->scan_req = NULL; } + + /* need to clean up enhanced bmiss detection fw state */ + ath6kl_cfg80211_sta_bmiss_enhance(vif, false); } void ath6kl_stop_txrx(struct ath6kl *ar) diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index b836f2795114..c189e28e86a9 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -554,20 +554,24 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, struct ath6kl *ar = devt; memcpy(ar->mac_addr, datap, ETH_ALEN); - ath6kl_dbg(ATH6KL_DBG_TRC, "%s: mac addr = %pM\n", - __func__, ar->mac_addr); + + ath6kl_dbg(ATH6KL_DBG_BOOT, + "ready event mac addr %pM sw_ver 0x%x abi_ver 0x%x cap 0x%x\n", + ar->mac_addr, sw_ver, abi_ver, cap); ar->version.wlan_ver = sw_ver; ar->version.abi_ver = abi_ver; ar->hw.cap = cap; - snprintf(ar->wiphy->fw_version, - sizeof(ar->wiphy->fw_version), - "%u.%u.%u.%u", - (ar->version.wlan_ver & 0xf0000000) >> 28, - (ar->version.wlan_ver & 0x0f000000) >> 24, - (ar->version.wlan_ver & 0x00ff0000) >> 16, - (ar->version.wlan_ver & 0x0000ffff)); + if (strlen(ar->wiphy->fw_version) == 0) { + snprintf(ar->wiphy->fw_version, + sizeof(ar->wiphy->fw_version), + "%u.%u.%u.%u", + (ar->version.wlan_ver & 0xf0000000) >> 28, + (ar->version.wlan_ver & 0x0f000000) >> 24, + (ar->version.wlan_ver & 0x00ff0000) >> 16, + (ar->version.wlan_ver & 0x0000ffff)); + } /* indicate to the waiting thread that the ready event was received */ set_bit(WMI_READY, &ar->flag); @@ -1166,7 +1170,10 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) else clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); - mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); + if (test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER, + vif->ar->fw_capabilities)) { + mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); + } if (!(ndev->flags & IFF_MULTICAST)) { mc_all_on = false; diff --git a/drivers/net/wireless/ath/ath6kl/target.h b/drivers/net/wireless/ath/ath6kl/target.h index 78e0ef4567a5..a98c12ba70c1 100644 --- a/drivers/net/wireless/ath/ath6kl/target.h +++ b/drivers/net/wireless/ath/ath6kl/target.h @@ -45,6 +45,7 @@ #define LPO_CAL_ENABLE_S 20 #define LPO_CAL_ENABLE 0x00100000 +#define GPIO_PIN9_ADDRESS 0x0000004c #define GPIO_PIN10_ADDRESS 0x00000050 #define GPIO_PIN11_ADDRESS 0x00000054 #define GPIO_PIN12_ADDRESS 0x00000058 diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 67206aedea6c..7dfa0fd86d7b 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -1036,6 +1036,7 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, rxtid = &agg_conn->rx_tid[tid]; stats = &agg_conn->stat[tid]; + spin_lock_bh(&rxtid->lock); idx = AGGR_WIN_IDX(rxtid->seq_next, rxtid->hold_q_sz); /* @@ -1054,8 +1055,6 @@ static void aggr_deque_frms(struct aggr_info_conn *agg_conn, u8 tid, seq_end = seq_no ? seq_no : rxtid->seq_next; idx_end = AGGR_WIN_IDX(seq_end, rxtid->hold_q_sz); - spin_lock_bh(&rxtid->lock); - do { node = &rxtid->hold_q[idx]; if ((order == 1) && (!node->skb)) @@ -1127,11 +1126,13 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, ((end > extended_end) && (cur > extended_end) && (cur < end))) { aggr_deque_frms(agg_conn, tid, 0, 0); + spin_lock_bh(&rxtid->lock); if (cur >= rxtid->hold_q_sz - 1) rxtid->seq_next = cur - (rxtid->hold_q_sz - 1); else rxtid->seq_next = ATH6KL_MAX_SEQ_NO - (rxtid->hold_q_sz - 2 - cur); + spin_unlock_bh(&rxtid->lock); } else { /* * Dequeue only those frames that are outside the @@ -1185,25 +1186,25 @@ static bool aggr_process_recv_frm(struct aggr_info_conn *agg_conn, u8 tid, aggr_deque_frms(agg_conn, tid, 0, 1); if (agg_conn->timer_scheduled) - rxtid->progress = true; - else - for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { - if (rxtid->hold_q[idx].skb) { - /* - * There is a frame in the queue and no - * timer so start a timer to ensure that - * the frame doesn't remain stuck - * forever. - */ - agg_conn->timer_scheduled = true; - mod_timer(&agg_conn->timer, - (jiffies + - HZ * (AGGR_RX_TIMEOUT) / 1000)); - rxtid->progress = false; - rxtid->timer_mon = true; - break; - } + return is_queued; + + spin_lock_bh(&rxtid->lock); + for (idx = 0 ; idx < rxtid->hold_q_sz; idx++) { + if (rxtid->hold_q[idx].skb) { + /* + * There is a frame in the queue and no + * timer so start a timer to ensure that + * the frame doesn't remain stuck + * forever. + */ + agg_conn->timer_scheduled = true; + mod_timer(&agg_conn->timer, + (jiffies + (HZ * AGGR_RX_TIMEOUT) / 1000)); + rxtid->timer_mon = true; + break; } + } + spin_unlock_bh(&rxtid->lock); return is_queued; } @@ -1608,7 +1609,7 @@ static void aggr_timeout(unsigned long arg) rxtid = &aggr_conn->rx_tid[i]; stats = &aggr_conn->stat[i]; - if (!rxtid->aggr || !rxtid->timer_mon || rxtid->progress) + if (!rxtid->aggr || !rxtid->timer_mon) continue; stats->num_timeouts++; @@ -1626,14 +1627,15 @@ static void aggr_timeout(unsigned long arg) rxtid = &aggr_conn->rx_tid[i]; if (rxtid->aggr && rxtid->hold_q) { + spin_lock_bh(&rxtid->lock); for (j = 0; j < rxtid->hold_q_sz; j++) { if (rxtid->hold_q[j].skb) { aggr_conn->timer_scheduled = true; rxtid->timer_mon = true; - rxtid->progress = false; break; } } + spin_unlock_bh(&rxtid->lock); if (j >= rxtid->hold_q_sz) rxtid->timer_mon = false; @@ -1660,7 +1662,6 @@ static void aggr_delete_tid_state(struct aggr_info_conn *aggr_conn, u8 tid) aggr_deque_frms(aggr_conn, tid, 0, 0); rxtid->aggr = false; - rxtid->progress = false; rxtid->timer_mon = false; rxtid->win_sz = 0; rxtid->seq_next = 0; @@ -1739,7 +1740,6 @@ void aggr_conn_init(struct ath6kl_vif *vif, struct aggr_info *aggr_info, for (i = 0; i < NUM_OF_TIDS; i++) { rxtid = &aggr_conn->rx_tid[i]; rxtid->aggr = false; - rxtid->progress = false; rxtid->timer_mon = false; skb_queue_head_init(&rxtid->q); spin_lock_init(&rxtid->lock); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index ee8ec2394c2c..c30ab4b11d61 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, return -EINVAL; } id = vif->last_roc_id; - cfg80211_ready_on_channel(vif->ndev, id, chan, NL80211_CHAN_NO_HT, + cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, dur, GFP_ATOMIC); return 0; @@ -513,7 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, else id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ vif->last_cancel_roc_id = 0; - cfg80211_remain_on_channel_expired(vif->ndev, id, chan, + cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, GFP_ATOMIC); return 0; @@ -533,7 +533,7 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len, ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", id, ev->ack_status); if (wmi->last_mgmt_tx_frame) { - cfg80211_mgmt_tx_status(vif->ndev, id, + cfg80211_mgmt_tx_status(&vif->wdev, id, wmi->last_mgmt_tx_frame, wmi->last_mgmt_tx_frame_len, !!ev->ack_status, GFP_ATOMIC); @@ -568,7 +568,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, 0, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, GFP_ATOMIC); return 0; @@ -608,7 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, 0, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, GFP_ATOMIC); return 0; @@ -743,7 +743,6 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) return -ENOMEM; cmd = (struct roam_ctrl_cmd *) skb->data; - memset(cmd, 0, sizeof(*cmd)); memcpy(cmd->info.bssid, bssid, ETH_ALEN); cmd->roam_ctrl = WMI_FORCE_ROAM; @@ -753,6 +752,22 @@ int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid) NO_SYNC_WMIFLAG); } +int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period) +{ + struct sk_buff *skb; + struct set_dtim_cmd *cmd; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct set_dtim_cmd *) skb->data; + + cmd->dtim_period = cpu_to_le32(dtim_period); + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_AP_SET_DTIM_CMDID, NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode) { struct sk_buff *skb; @@ -763,7 +778,6 @@ int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode) return -ENOMEM; cmd = (struct roam_ctrl_cmd *) skb->data; - memset(cmd, 0, sizeof(*cmd)); cmd->info.roam_mode = mode; cmd->roam_ctrl = WMI_SET_ROAM_MODE; @@ -1995,7 +2009,7 @@ int ath6kl_wmi_probedssid_cmd(struct wmi *wmi, u8 if_idx, u8 index, u8 flag, struct wmi_probed_ssid_cmd *cmd; int ret; - if (index > MAX_PROBED_SSID_INDEX) + if (index >= MAX_PROBED_SSIDS) return -EINVAL; if (ssid_len > sizeof(cmd->ssid)) @@ -2599,6 +2613,115 @@ static void ath6kl_wmi_relinquish_implicit_pstream_credits(struct wmi *wmi) spin_unlock_bh(&wmi->lock); } +static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct sk_buff *skb; + int ret, mode, band; + u64 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + struct wmi_set_tx_select_rates64_cmd *cmd; + + memset(&ratemask, 0, sizeof(ratemask)); + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + /* copy legacy rate mask */ + ratemask[band] = mask->control[band].legacy; + if (band == IEEE80211_BAND_5GHZ) + ratemask[band] = + mask->control[band].legacy << 4; + + /* copy mcs rate mask */ + mcsrate = mask->control[band].mcs[1]; + mcsrate <<= 8; + mcsrate |= mask->control[band].mcs[0]; + ratemask[band] |= mcsrate << 12; + ratemask[band] |= mcsrate << 28; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Ratemask 64 bit: 2.4:%llx 5:%llx\n", + ratemask[0], ratemask[1]); + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_tx_select_rates64_cmd *) skb->data; + for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) { + /* A mode operate in 5GHZ band */ + if (mode == WMI_RATES_MODE_11A || + mode == WMI_RATES_MODE_11A_HT20 || + mode == WMI_RATES_MODE_11A_HT40) + band = IEEE80211_BAND_5GHZ; + else + band = IEEE80211_BAND_2GHZ; + cmd->ratemask[mode] = cpu_to_le64(ratemask[band]); + } + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_TX_SELECT_RATES_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct sk_buff *skb; + int ret, mode, band; + u32 mcsrate, ratemask[IEEE80211_NUM_BANDS]; + struct wmi_set_tx_select_rates32_cmd *cmd; + + memset(&ratemask, 0, sizeof(ratemask)); + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + /* copy legacy rate mask */ + ratemask[band] = mask->control[band].legacy; + if (band == IEEE80211_BAND_5GHZ) + ratemask[band] = + mask->control[band].legacy << 4; + + /* copy mcs rate mask */ + mcsrate = mask->control[band].mcs[0]; + ratemask[band] |= mcsrate << 12; + ratemask[band] |= mcsrate << 20; + } + + ath6kl_dbg(ATH6KL_DBG_WMI, + "Ratemask 32 bit: 2.4:%x 5:%x\n", + ratemask[0], ratemask[1]); + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd) * WMI_RATES_MODE_MAX); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_set_tx_select_rates32_cmd *) skb->data; + for (mode = 0; mode < WMI_RATES_MODE_MAX; mode++) { + /* A mode operate in 5GHZ band */ + if (mode == WMI_RATES_MODE_11A || + mode == WMI_RATES_MODE_11A_HT20 || + mode == WMI_RATES_MODE_11A_HT40) + band = IEEE80211_BAND_5GHZ; + else + band = IEEE80211_BAND_2GHZ; + cmd->ratemask[mode] = cpu_to_le32(ratemask[band]); + } + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_TX_SELECT_RATES_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + +int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask) +{ + struct ath6kl *ar = wmi->parent_dev; + + if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) + return ath6kl_set_bitrate_mask64(wmi, if_idx, mask); + else + return ath6kl_set_bitrate_mask32(wmi, if_idx, mask); +} + int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_host_mode host_mode) { @@ -2997,6 +3120,25 @@ int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, return ret; } +int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance) +{ + struct sk_buff *skb; + struct wmi_sta_bmiss_enhance_cmd *cmd; + int ret; + + skb = ath6kl_wmi_get_new_buf(sizeof(*cmd)); + if (!skb) + return -ENOMEM; + + cmd = (struct wmi_sta_bmiss_enhance_cmd *) skb->data; + cmd->enable = enhance ? 1 : 0; + + ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_STA_BMISS_ENHANCE_CMDID, + NO_SYNC_WMIFLAG); + return ret; +} + s32 ath6kl_wmi_get_rate(s8 rate_index) { if (rate_index == RATE_AUTO) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 9076bec3a2ba..43339aca585d 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -624,6 +624,10 @@ enum wmi_cmd_id { WMI_SEND_MGMT_CMDID, WMI_BEGIN_SCAN_CMDID, + WMI_SET_BLACK_LIST, + WMI_SET_MCASTRATE, + + WMI_STA_BMISS_ENHANCE_CMDID, }; enum wmi_mgmt_frame_type { @@ -960,6 +964,9 @@ enum wmi_bss_filter { /* beacons matching probed ssid */ PROBED_SSID_FILTER, + /* beacons matching matched ssid */ + MATCHED_SSID_FILTER, + /* marker only */ LAST_BSS_FILTER, }; @@ -978,7 +985,7 @@ struct wmi_bss_filter_cmd { } __packed; /* WMI_SET_PROBED_SSID_CMDID */ -#define MAX_PROBED_SSID_INDEX 9 +#define MAX_PROBED_SSIDS 16 enum wmi_ssid_flag { /* disables entry */ @@ -989,10 +996,13 @@ enum wmi_ssid_flag { /* probes for any ssid */ ANY_SSID_FLAG = 0x02, + + /* match for ssid */ + MATCH_SSID_FLAG = 0x08, }; struct wmi_probed_ssid_cmd { - /* 0 to MAX_PROBED_SSID_INDEX */ + /* 0 to MAX_PROBED_SSIDS - 1 */ u8 entry_index; /* see, enum wmi_ssid_flg */ @@ -1017,6 +1027,11 @@ struct wmi_bmiss_time_cmd { __le16 num_beacons; }; +/* WMI_STA_ENHANCE_BMISS_CMDID */ +struct wmi_sta_bmiss_enhance_cmd { + u8 enable; +} __packed; + /* WMI_SET_POWER_MODE_CMDID */ enum wmi_power_mode { REC_POWER = 0x01, @@ -1048,6 +1063,36 @@ struct wmi_power_params_cmd { __le16 ps_fail_event_policy; } __packed; +/* + * Ratemask for below modes should be passed + * to WMI_SET_TX_SELECT_RATES_CMDID. + * AR6003 has 32 bit mask for each modes. + * First 12 bits for legacy rates, 13 to 20 + * bits for HT 20 rates and 21 to 28 bits for + * HT 40 rates + */ +enum wmi_mode_phy { + WMI_RATES_MODE_11A = 0, + WMI_RATES_MODE_11G, + WMI_RATES_MODE_11B, + WMI_RATES_MODE_11GONLY, + WMI_RATES_MODE_11A_HT20, + WMI_RATES_MODE_11G_HT20, + WMI_RATES_MODE_11A_HT40, + WMI_RATES_MODE_11G_HT40, + WMI_RATES_MODE_MAX +}; + +/* WMI_SET_TX_SELECT_RATES_CMDID */ +struct wmi_set_tx_select_rates32_cmd { + __le32 ratemask[WMI_RATES_MODE_MAX]; +} __packed; + +/* WMI_SET_TX_SELECT_RATES_CMDID */ +struct wmi_set_tx_select_rates64_cmd { + __le64 ratemask[WMI_RATES_MODE_MAX]; +} __packed; + /* WMI_SET_DISC_TIMEOUT_CMDID */ struct wmi_disc_timeout_cmd { /* seconds */ @@ -1572,6 +1617,10 @@ struct roam_ctrl_cmd { u8 roam_ctrl; } __packed; +struct set_dtim_cmd { + __le32 dtim_period; +} __packed; + /* BSS INFO HDR version 2.0 */ struct wmi_bss_info_hdr2 { __le16 ch; /* frequency in MHz */ @@ -2532,6 +2581,8 @@ int ath6kl_wmi_set_ip_cmd(struct wmi *wmi, u8 if_idx, __be32 ips0, __be32 ips1); int ath6kl_wmi_set_host_sleep_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_host_mode host_mode); +int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx, + const struct cfg80211_bitrate_mask *mask); int ath6kl_wmi_set_wow_mode_cmd(struct wmi *wmi, u8 if_idx, enum ath6kl_wow_mode wow_mode, u32 filter, u16 host_req_delay); @@ -2542,11 +2593,14 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx, u16 list_id, u16 filter_id); int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi); +int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period); int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid); int ath6kl_wmi_set_roam_mode_cmd(struct wmi *wmi, enum wmi_roam_mode mode); int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on); int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, u8 *filter, bool add_filter); +int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable); + /* AP mode uAPSD */ int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable); diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 4a4e8a2b9d2c..3a69804f4c16 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -35,6 +35,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = { .name = "ar934x_wmac", .driver_data = AR9300_DEVID_AR9340, }, + { + .name = "qca955x_wmac", + .driver_data = AR9300_DEVID_QCA955X, + }, {}, }; diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c index b4c77f9d7470..ff007f500feb 100644 --- a/drivers/net/wireless/ath/ath9k/ani.c +++ b/drivers/net/wireless/ath/ath9k/ani.c @@ -104,11 +104,6 @@ static const struct ani_cck_level_entry cck_level_table[] = { #define ATH9K_ANI_CCK_DEF_LEVEL \ 2 /* default level - matches the INI settings */ -static bool use_new_ani(struct ath_hw *ah) -{ - return AR_SREV_9300_20_OR_LATER(ah) || modparam_force_new_ani; -} - static void ath9k_hw_update_mibstats(struct ath_hw *ah, struct ath9k_mib_stats *stats) { @@ -122,8 +117,6 @@ static void ath9k_hw_update_mibstats(struct ath_hw *ah, static void ath9k_ani_restart(struct ath_hw *ah) { struct ar5416AniState *aniState; - struct ath_common *common = ath9k_hw_common(ah); - u32 ofdm_base = 0, cck_base = 0; if (!DO_ANI(ah)) return; @@ -131,18 +124,10 @@ static void ath9k_ani_restart(struct ath_hw *ah) aniState = &ah->curchan->ani; aniState->listenTime = 0; - if (!use_new_ani(ah)) { - ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; - cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; - } - - ath_dbg(common, ANI, "Writing ofdmbase=%u cckbase=%u\n", - ofdm_base, cck_base); - ENABLE_REGWRITE_BUFFER(ah); - REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); - REG_WRITE(ah, AR_PHY_ERR_2, cck_base); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); @@ -154,129 +139,23 @@ static void ath9k_ani_restart(struct ath_hw *ah) aniState->cckPhyErrCount = 0; } -static void ath9k_hw_ani_ofdm_err_trigger_old(struct ath_hw *ah) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = &ah->curchan->ani; - - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - - if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel + 1)) { - return; - } - } - - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrHigh) { - if (!aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false)) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - return; - } - } - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } else { - if ((conf->channel->band == IEEE80211_BAND_2GHZ) && - !conf_is_ht(conf)) { - if (!aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false); - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, 0); - return; - } - } -} - -static void ath9k_hw_ani_cck_err_trigger_old(struct ath_hw *ah) -{ - struct ieee80211_conf *conf = &ath9k_hw_common(ah)->hw->conf; - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = &ah->curchan->ani; - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrLow) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } else { - if ((conf->channel->band == IEEE80211_BAND_2GHZ) && - !conf_is_ht(conf)) { - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, 0); - } - } -} - /* Adjust the OFDM Noise Immunity Level */ -static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) +static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel, + bool scan) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; - - aniState->noiseFloor = BEACON_RSSI(ah); + bool weak_sig; ath_dbg(common, ANI, "**** ofdmlevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->ofdmNoiseImmunityLevel, - immunityLevel, aniState->noiseFloor, + immunityLevel, BEACON_RSSI(ah), aniState->rssiThrLow, aniState->rssiThrHigh); - if (aniState->update_ani) - aniState->ofdmNoiseImmunityLevel = - (immunityLevel > ATH9K_ANI_OFDM_DEF_LEVEL) ? - immunityLevel : ATH9K_ANI_OFDM_DEF_LEVEL; + if (!scan) + aniState->ofdmNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -292,12 +171,22 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel) ATH9K_ANI_FIRSTEP_LEVEL, entry_ofdm->fir_step_level); - if ((aniState->noiseFloor >= aniState->rssiThrHigh) && - (!aniState->ofdmWeakSigDetectOff != - entry_ofdm->ofdm_weak_signal_on)) { + weak_sig = entry_ofdm->ofdm_weak_signal_on; + if (ah->opmode == NL80211_IFTYPE_STATION && + BEACON_RSSI(ah) <= aniState->rssiThrHigh) + weak_sig = true; + + if (aniState->ofdmWeakSigDetect != weak_sig) ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, entry_ofdm->ofdm_weak_signal_on); + + if (aniState->ofdmNoiseImmunityLevel >= ATH9K_ANI_OFDM_DEF_LEVEL) { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI; + } else { + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; } } @@ -308,43 +197,35 @@ static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hw *ah) if (!DO_ANI(ah)) return; - if (!use_new_ani(ah)) { - ath9k_hw_ani_ofdm_err_trigger_old(ah); - return; - } - aniState = &ah->curchan->ani; if (aniState->ofdmNoiseImmunityLevel < ATH9K_ANI_OFDM_MAX_LEVEL) - ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1); + ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel + 1, false); } /* * Set the ANI settings to match an CCK level. */ -static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) +static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel, + bool scan) { struct ar5416AniState *aniState = &ah->curchan->ani; struct ath_common *common = ath9k_hw_common(ah); const struct ani_ofdm_level_entry *entry_ofdm; const struct ani_cck_level_entry *entry_cck; - aniState->noiseFloor = BEACON_RSSI(ah); ath_dbg(common, ANI, "**** ccklevel %d=>%d, rssi=%d[lo=%d hi=%d]\n", aniState->cckNoiseImmunityLevel, immunityLevel, - aniState->noiseFloor, aniState->rssiThrLow, + BEACON_RSSI(ah), aniState->rssiThrLow, aniState->rssiThrHigh); - if ((ah->opmode == NL80211_IFTYPE_STATION || - ah->opmode == NL80211_IFTYPE_ADHOC) && - aniState->noiseFloor <= aniState->rssiThrLow && + if (ah->opmode == NL80211_IFTYPE_STATION && + BEACON_RSSI(ah) <= aniState->rssiThrLow && immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI) immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI; - if (aniState->update_ani) - aniState->cckNoiseImmunityLevel = - (immunityLevel > ATH9K_ANI_CCK_DEF_LEVEL) ? - immunityLevel : ATH9K_ANI_CCK_DEF_LEVEL; + if (!scan) + aniState->cckNoiseImmunityLevel = immunityLevel; entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel]; entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel]; @@ -359,7 +240,7 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel) if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah)) return; - if (aniState->mrcCCKOff == entry_cck->mrc_cck_on) + if (aniState->mrcCCK != entry_cck->mrc_cck_on) ath9k_hw_ani_control(ah, ATH9K_ANI_MRC_CCK, entry_cck->mrc_cck_on); @@ -372,68 +253,11 @@ static void ath9k_hw_ani_cck_err_trigger(struct ath_hw *ah) if (!DO_ANI(ah)) return; - if (!use_new_ani(ah)) { - ath9k_hw_ani_cck_err_trigger_old(ah); - return; - } - aniState = &ah->curchan->ani; if (aniState->cckNoiseImmunityLevel < ATH9K_ANI_CCK_MAX_LEVEL) - ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1); -} - -static void ath9k_hw_ani_lower_immunity_old(struct ath_hw *ah) -{ - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = &ah->curchan->ani; - - if (ah->opmode == NL80211_IFTYPE_AP) { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) - return; - } - } else { - rssi = BEACON_RSSI(ah); - if (rssi > aniState->rssiThrHigh) { - /* XXX: Handle me */ - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true)) - return; - } - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) - return; - } - } else { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) - return; - } - } - } - - if (aniState->spurImmunityLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel - 1)) - return; - } - - if (aniState->noiseImmunityLevel > 0) { - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel - 1); - return; - } + ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel + 1, + false); } /* @@ -446,87 +270,18 @@ static void ath9k_hw_ani_lower_immunity(struct ath_hw *ah) aniState = &ah->curchan->ani; - if (!use_new_ani(ah)) { - ath9k_hw_ani_lower_immunity_old(ah); - return; - } - /* lower OFDM noise immunity */ if (aniState->ofdmNoiseImmunityLevel > 0 && (aniState->ofdmsTurn || aniState->cckNoiseImmunityLevel == 0)) { - ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1); + ath9k_hw_set_ofdm_nil(ah, aniState->ofdmNoiseImmunityLevel - 1, + false); return; } /* lower CCK noise immunity */ if (aniState->cckNoiseImmunityLevel > 0) - ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1); -} - -static void ath9k_ani_reset_old(struct ath_hw *ah, bool is_scanning) -{ - struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->curchan; - struct ath_common *common = ath9k_hw_common(ah); - - if (!DO_ANI(ah)) - return; - - aniState = &ah->curchan->ani; - - if (ah->opmode != NL80211_IFTYPE_STATION - && ah->opmode != NL80211_IFTYPE_ADHOC) { - ath_dbg(common, ANI, "Reset ANI state opmode %u\n", ah->opmode); - ah->stats.ast_ani_reset++; - - if (ah->opmode == NL80211_IFTYPE_AP) { - /* - * ath9k_hw_ani_control() will only process items set on - * ah->ani_function - */ - if (IS_CHAN_2GHZ(chan)) - ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - else - ah->ani_function = 0; - } - - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !ATH9K_ANI_USE_OFDM_WEAK_SIG); - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - ATH9K_ANI_CCK_WEAK_SIG_THR); - - ath9k_ani_restart(ah); - return; - } - - if (aniState->noiseImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel); - if (aniState->spurImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel); - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !aniState->ofdmWeakSigDetectOff); - if (aniState->cckWeakSigThreshold) - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - aniState->cckWeakSigThreshold); - if (aniState->firstepLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel); - - ath9k_ani_restart(ah); - - ENABLE_REGWRITE_BUFFER(ah); - - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - REGWRITE_BUFFER_FLUSH(ah); + ath9k_hw_set_cck_nil(ah, aniState->cckNoiseImmunityLevel - 1, + false); } /* @@ -539,13 +294,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) struct ar5416AniState *aniState = &ah->curchan->ani; struct ath9k_channel *chan = ah->curchan; struct ath_common *common = ath9k_hw_common(ah); + int ofdm_nil, cck_nil; if (!DO_ANI(ah)) return; - if (!use_new_ani(ah)) - return ath9k_ani_reset_old(ah, is_scanning); - BUG_ON(aniState == NULL); ah->stats.ast_ani_reset++; @@ -563,6 +316,11 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) /* always allow mode (on/off) to be controlled */ ah->ani_function |= ATH9K_ANI_MODE; + ofdm_nil = max_t(int, ATH9K_ANI_OFDM_DEF_LEVEL, + aniState->ofdmNoiseImmunityLevel); + cck_nil = max_t(int, ATH9K_ANI_CCK_DEF_LEVEL, + aniState->cckNoiseImmunityLevel); + if (is_scanning || (ah->opmode != NL80211_IFTYPE_STATION && ah->opmode != NL80211_IFTYPE_ADHOC)) { @@ -585,9 +343,8 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); - aniState->update_ani = false; - ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL); - ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL); + ofdm_nil = ATH9K_ANI_OFDM_DEF_LEVEL; + cck_nil = ATH9K_ANI_CCK_DEF_LEVEL; } } else { /* @@ -601,13 +358,9 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning) is_scanning, aniState->ofdmNoiseImmunityLevel, aniState->cckNoiseImmunityLevel); - - aniState->update_ani = true; - ath9k_hw_set_ofdm_nil(ah, - aniState->ofdmNoiseImmunityLevel); - ath9k_hw_set_cck_nil(ah, - aniState->cckNoiseImmunityLevel); } + ath9k_hw_set_ofdm_nil(ah, ofdm_nil, is_scanning); + ath9k_hw_set_cck_nil(ah, cck_nil, is_scanning); /* * enable phy counters if hw supports or if not, enable phy @@ -627,9 +380,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) { struct ath_common *common = ath9k_hw_common(ah); struct ar5416AniState *aniState = &ah->curchan->ani; - u32 ofdm_base = 0; - u32 cck_base = 0; - u32 ofdmPhyErrCnt, cckPhyErrCnt; u32 phyCnt1, phyCnt2; int32_t listenTime; @@ -642,11 +392,6 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) return false; } - if (!use_new_ani(ah)) { - ofdm_base = AR_PHY_COUNTMAX - ah->config.ofdm_trig_high; - cck_base = AR_PHY_COUNTMAX - ah->config.cck_trig_high; - } - aniState->listenTime += listenTime; ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); @@ -654,35 +399,12 @@ static bool ath9k_hw_ani_read_counters(struct ath_hw *ah) phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (!use_new_ani(ah) && (phyCnt1 < ofdm_base || phyCnt2 < cck_base)) { - if (phyCnt1 < ofdm_base) { - ath_dbg(common, ANI, - "phyCnt1 0x%x, resetting counter value to 0x%x\n", - phyCnt1, ofdm_base); - REG_WRITE(ah, AR_PHY_ERR_1, ofdm_base); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < cck_base) { - ath_dbg(common, ANI, - "phyCnt2 0x%x, resetting counter value to 0x%x\n", - phyCnt2, cck_base); - REG_WRITE(ah, AR_PHY_ERR_2, cck_base); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return false; - } + ah->stats.ast_ani_ofdmerrs += phyCnt1 - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = phyCnt1; - ofdmPhyErrCnt = phyCnt1 - ofdm_base; - ah->stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + ah->stats.ast_ani_cckerrs += phyCnt2 - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = phyCnt2; - cckPhyErrCnt = phyCnt2 - cck_base; - ah->stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; return true; } @@ -716,21 +438,10 @@ void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan) if (aniState->listenTime > ah->aniperiod) { if (cckPhyErrRate < ah->config.cck_trig_low && - ((ofdmPhyErrRate < ah->config.ofdm_trig_low && - aniState->ofdmNoiseImmunityLevel < - ATH9K_ANI_OFDM_DEF_LEVEL) || - (ofdmPhyErrRate < ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI && - aniState->ofdmNoiseImmunityLevel >= - ATH9K_ANI_OFDM_DEF_LEVEL))) { + ofdmPhyErrRate < ah->config.ofdm_trig_low) { ath9k_hw_ani_lower_immunity(ah); aniState->ofdmsTurn = !aniState->ofdmsTurn; - } else if ((ofdmPhyErrRate > ah->config.ofdm_trig_high && - aniState->ofdmNoiseImmunityLevel >= - ATH9K_ANI_OFDM_DEF_LEVEL) || - (ofdmPhyErrRate > - ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI && - aniState->ofdmNoiseImmunityLevel < - ATH9K_ANI_OFDM_DEF_LEVEL)) { + } else if (ofdmPhyErrRate > ah->config.ofdm_trig_high) { ath9k_hw_ani_ofdm_err_trigger(ah); aniState->ofdmsTurn = false; } else if (cckPhyErrRate > ah->config.cck_trig_high) { @@ -778,49 +489,6 @@ void ath9k_hw_disable_mib_counters(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_disable_mib_counters); -/* - * Process a MIB interrupt. We may potentially be invoked because - * any of the MIB counters overflow/trigger so don't assume we're - * here because a PHY error counter triggered. - */ -void ath9k_hw_proc_mib_event(struct ath_hw *ah) -{ - u32 phyCnt1, phyCnt2; - - /* Reset these counters regardless */ - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) - REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); - - /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ah->ah_mibStats); - - if (!DO_ANI(ah)) { - /* - * We must always clear the interrupt cause by - * resetting the phy error regs. - */ - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - return; - } - - /* NB: these are not reset-on-read */ - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - - if (!use_new_ani(ah)) - ath9k_hw_ani_read_counters(ah); - - /* NB: always restart to insure the h/w counters are reset */ - ath9k_ani_restart(ah); - } -} -EXPORT_SYMBOL(ath9k_hw_proc_mib_event); - void ath9k_hw_ani_setup(struct ath_hw *ah) { int i; @@ -845,66 +513,37 @@ void ath9k_hw_ani_init(struct ath_hw *ah) ath_dbg(common, ANI, "Initialize ANI\n"); - if (use_new_ani(ah)) { - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_NEW; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_NEW; + ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH; + ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW; - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_NEW; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_NEW; - } else { - ah->config.ofdm_trig_high = ATH9K_ANI_OFDM_TRIG_HIGH_OLD; - ah->config.ofdm_trig_low = ATH9K_ANI_OFDM_TRIG_LOW_OLD; - - ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH_OLD; - ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW_OLD; - } + ah->config.cck_trig_high = ATH9K_ANI_CCK_TRIG_HIGH; + ah->config.cck_trig_low = ATH9K_ANI_CCK_TRIG_LOW; for (i = 0; i < ARRAY_SIZE(ah->channels); i++) { struct ath9k_channel *chan = &ah->channels[i]; struct ar5416AniState *ani = &chan->ani; - if (use_new_ani(ah)) { - ani->spurImmunityLevel = - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; + ani->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; + ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (AR_SREV_9300_20_OR_LATER(ah)) - ani->mrcCCKOff = - !ATH9K_ANI_ENABLE_MRC_CCK; - else - ani->mrcCCKOff = true; - - ani->ofdmsTurn = true; - } else { - ani->spurImmunityLevel = - ATH9K_ANI_SPUR_IMMUNE_LVL_OLD; - ani->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_OLD; - - ani->cckWeakSigThreshold = - ATH9K_ANI_CCK_WEAK_SIG_THR; - } + ani->mrcCCK = AR_SREV_9300_20_OR_LATER(ah) ? true : false; + + ani->ofdmsTurn = true; ani->rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; ani->rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ani->ofdmWeakSigDetectOff = - !ATH9K_ANI_USE_OFDM_WEAK_SIG; + ani->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL; ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL; - ani->update_ani = false; } /* * since we expect some ongoing maintenance on the tables, let's sanity * check here default level should not modify INI setting. */ - if (use_new_ani(ah)) { - ah->aniperiod = ATH9K_ANI_PERIOD_NEW; - ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_NEW; - } else { - ah->aniperiod = ATH9K_ANI_PERIOD_OLD; - ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL_OLD; - } + ah->aniperiod = ATH9K_ANI_PERIOD; + ah->config.ani_poll_interval = ATH9K_ANI_POLLINTERVAL; if (ah->config.enable_ani) ah->proc_phyerr |= HAL_PROCESS_ANI; diff --git a/drivers/net/wireless/ath/ath9k/ani.h b/drivers/net/wireless/ath/ath9k/ani.h index 72e2b874e179..1485bf5e3518 100644 --- a/drivers/net/wireless/ath/ath9k/ani.h +++ b/drivers/net/wireless/ath/ath9k/ani.h @@ -24,42 +24,34 @@ #define BEACON_RSSI(ahp) (ahp->stats.avgbrssi) /* units are errors per second */ -#define ATH9K_ANI_OFDM_TRIG_HIGH_OLD 500 -#define ATH9K_ANI_OFDM_TRIG_HIGH_NEW 3500 +#define ATH9K_ANI_OFDM_TRIG_HIGH 3500 #define ATH9K_ANI_OFDM_TRIG_HIGH_BELOW_INI 1000 /* units are errors per second */ -#define ATH9K_ANI_OFDM_TRIG_LOW_OLD 200 -#define ATH9K_ANI_OFDM_TRIG_LOW_NEW 400 +#define ATH9K_ANI_OFDM_TRIG_LOW 400 #define ATH9K_ANI_OFDM_TRIG_LOW_ABOVE_INI 900 /* units are errors per second */ -#define ATH9K_ANI_CCK_TRIG_HIGH_OLD 200 -#define ATH9K_ANI_CCK_TRIG_HIGH_NEW 600 +#define ATH9K_ANI_CCK_TRIG_HIGH 600 /* units are errors per second */ -#define ATH9K_ANI_CCK_TRIG_LOW_OLD 100 -#define ATH9K_ANI_CCK_TRIG_LOW_NEW 300 +#define ATH9K_ANI_CCK_TRIG_LOW 300 #define ATH9K_ANI_NOISE_IMMUNE_LVL 4 #define ATH9K_ANI_USE_OFDM_WEAK_SIG true #define ATH9K_ANI_CCK_WEAK_SIG_THR false -#define ATH9K_ANI_SPUR_IMMUNE_LVL_OLD 7 -#define ATH9K_ANI_SPUR_IMMUNE_LVL_NEW 3 +#define ATH9K_ANI_SPUR_IMMUNE_LVL 3 -#define ATH9K_ANI_FIRSTEP_LVL_OLD 0 -#define ATH9K_ANI_FIRSTEP_LVL_NEW 2 +#define ATH9K_ANI_FIRSTEP_LVL 2 #define ATH9K_ANI_RSSI_THR_HIGH 40 #define ATH9K_ANI_RSSI_THR_LOW 7 -#define ATH9K_ANI_PERIOD_OLD 100 -#define ATH9K_ANI_PERIOD_NEW 300 +#define ATH9K_ANI_PERIOD 300 /* in ms */ -#define ATH9K_ANI_POLLINTERVAL_OLD 100 -#define ATH9K_ANI_POLLINTERVAL_NEW 1000 +#define ATH9K_ANI_POLLINTERVAL 1000 #define HAL_NOISE_IMMUNE_MAX 4 #define HAL_SPUR_IMMUNE_MAX 7 @@ -70,8 +62,6 @@ #define ATH9K_SIG_SPUR_IMM_SETTING_MIN 0 #define ATH9K_SIG_SPUR_IMM_SETTING_MAX 22 -#define ATH9K_ANI_ENABLE_MRC_CCK true - /* values here are relative to the INI */ enum ath9k_ani_cmd { @@ -119,16 +109,14 @@ struct ar5416AniState { u8 ofdmNoiseImmunityLevel; u8 cckNoiseImmunityLevel; bool ofdmsTurn; - u8 mrcCCKOff; + u8 mrcCCK; u8 spurImmunityLevel; u8 firstepLevel; - u8 ofdmWeakSigDetectOff; + u8 ofdmWeakSigDetect; u8 cckWeakSigThreshold; - bool update_ani; u32 listenTime; int32_t rssiThrLow; int32_t rssiThrHigh; - u32 noiseFloor; u32 ofdmPhyErrCount; u32 cckPhyErrCount; int16_t pktRssi[2]; diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c index c7492c6a2519..874186bfda41 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c @@ -995,141 +995,6 @@ static u32 ar5008_hw_compute_pll_control(struct ath_hw *ah, return pll; } -static bool ar5008_hw_ani_control_old(struct ath_hw *ah, - enum ath9k_ani_cmd cmd, - int param) -{ - struct ar5416AniState *aniState = &ah->curchan->ani; - struct ath_common *common = ath9k_hw_common(ah); - - switch (cmd & ah->ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ah->totalSizeDesired)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", - level, ARRAY_SIZE(ah->totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ah->totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ah->coarse_low[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ah->coarse_high[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ah->firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ah->stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ah->stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - u32 on = param ? 1 : 0; - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ah->stats.ast_ani_ofdmon++; - else - ah->stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - static const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ah->stats.ast_ani_cckhigh++; - else - ah->stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - static const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", - level, ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ah->stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ah->stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - static const int cycpwrThr1[] = { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - ath_dbg(common, ANI, "level out of range (%u > %zu)\n", - level, ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ah->stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ah->stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - ath_dbg(common, ANI, "invalid cmd %u\n", cmd); - return false; - } - - ath_dbg(common, ANI, "ANI parameters:\n"); - ath_dbg(common, ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, - aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - ath_dbg(common, ANI, - "cckWeakSigThreshold=%d, firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, - aniState->firstepLevel, - aniState->listenTime); - ath_dbg(common, ANI, "ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - - return true; -} - static bool ar5008_hw_ani_control_new(struct ath_hw *ah, enum ath9k_ani_cmd cmd, int param) @@ -1206,18 +1071,18 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - if (!on != aniState->ofdmWeakSigDetectOff) { + if (on != aniState->ofdmWeakSigDetect) { ath_dbg(common, ANI, "** ch %d: ofdm weak signal: %s=>%s\n", chan->channel, - !aniState->ofdmWeakSigDetectOff ? + aniState->ofdmWeakSigDetect ? "on" : "off", on ? "on" : "off"); if (on) ah->stats.ast_ani_ofdmon++; else ah->stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; + aniState->ofdmWeakSigDetect = on; } break; } @@ -1236,7 +1101,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, * from INI file & cap value */ value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] + + firstep_table[ATH9K_ANI_FIRSTEP_LVL] + aniState->iniDef.firstep; if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) value = ATH9K_SIG_FIRSTEP_SETTING_MIN; @@ -1251,7 +1116,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, * from INI file & cap value */ value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] + + firstep_table[ATH9K_ANI_FIRSTEP_LVL] + aniState->iniDef.firstepLow; if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; @@ -1267,7 +1132,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, chan->channel, aniState->firstepLevel, level, - ATH9K_ANI_FIRSTEP_LVL_NEW, + ATH9K_ANI_FIRSTEP_LVL, value, aniState->iniDef.firstep); ath_dbg(common, ANI, @@ -1275,7 +1140,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, chan->channel, aniState->firstepLevel, level, - ATH9K_ANI_FIRSTEP_LVL_NEW, + ATH9K_ANI_FIRSTEP_LVL, value2, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) @@ -1300,7 +1165,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, * from INI file & cap value */ value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] + + cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + aniState->iniDef.cycpwrThr1; if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; @@ -1316,7 +1181,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, * from INI file & cap value */ value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] + + cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + aniState->iniDef.cycpwrThr1Ext; if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; @@ -1331,7 +1196,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, chan->channel, aniState->spurImmunityLevel, level, - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, + ATH9K_ANI_SPUR_IMMUNE_LVL, value, aniState->iniDef.cycpwrThr1); ath_dbg(common, ANI, @@ -1339,7 +1204,7 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, chan->channel, aniState->spurImmunityLevel, level, - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, + ATH9K_ANI_SPUR_IMMUNE_LVL, value2, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) @@ -1367,9 +1232,9 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, ath_dbg(common, ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff ? "on" : "off", + aniState->ofdmWeakSigDetect ? "on" : "off", aniState->firstepLevel, - !aniState->mrcCCKOff ? "on" : "off", + aniState->mrcCCK ? "on" : "off", aniState->listenTime, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); @@ -1454,10 +1319,10 @@ static void ar5008_hw_ani_cache_ini_regs(struct ath_hw *ah) AR_PHY_EXT_TIMING5_CYCPWR_THR1); /* these levels just got reset to defaults by the INI */ - aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; - aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; - aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; - aniState->mrcCCKOff = true; /* not available on pre AR9003 */ + aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; + aniState->mrcCCK = false; /* not available on pre AR9003 */ } static void ar5008_hw_set_nf_limits(struct ath_hw *ah) @@ -1545,11 +1410,8 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah) priv_ops->do_getnf = ar5008_hw_do_getnf; priv_ops->set_radar_params = ar5008_hw_set_radar_params; - if (modparam_force_new_ani) { - priv_ops->ani_control = ar5008_hw_ani_control_new; - priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs; - } else - priv_ops->ani_control = ar5008_hw_ani_control_old; + priv_ops->ani_control = ar5008_hw_ani_control_new; + priv_ops->ani_cache_ini_regs = ar5008_hw_ani_cache_ini_regs; if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) priv_ops->compute_pll_control = ar9160_hw_compute_pll_control; diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index d9a69fc470cd..edf21ea4fe93 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -21,10 +21,6 @@ #include "ar9002_initvals.h" #include "ar9002_phy.h" -int modparam_force_new_ani; -module_param_named(force_new_ani, modparam_force_new_ani, int, 0444); -MODULE_PARM_DESC(force_new_ani, "Force new ANI for AR5008, AR9001, AR9002"); - /* General hardware code for the A5008/AR9001/AR9002 hadware families */ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h index 952cb2b4656b..89bf94d4d8a1 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index d7deb8c9f299..84b558d126ca 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -159,14 +159,11 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah, } } - /* Do NF cal only at longer intervals */ - if (longcal) { - /* - * Get the value from the previous NF cal and update - * history buffer. - */ - ath9k_hw_getnf(ah, chan); - + /* + * Do NF cal only at longer intervals. Get the value from + * the previous NF cal and update history buffer. + */ + if (longcal && ath9k_hw_getnf(ah, chan)) { /* * Load the NF from history buffer of the current channel. * NF is slow time-variant, so it is OK to use a historical diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index 2cdf82bdb11d..25de6f9a9778 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -3509,7 +3509,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); - else if (AR_SREV_9462(ah)) + else if (AR_SREV_9462(ah) || AR_SREV_9550(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); else { REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias); @@ -3591,6 +3591,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) if (AR_SREV_9462(ah)) { REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_AR9462_ALL, value); + } else if (AR_SREV_9550(ah)) { + REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, + AR_SWITCH_TABLE_COM_AR9550_ALL, value); } else REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM, AR_SWITCH_TABLE_COM_ALL, value); @@ -3957,7 +3960,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, ar9003_hw_drive_strength_apply(ah); ar9003_hw_atten_apply(ah, chan); ar9003_hw_quick_drop_apply(ah, chan->channel); - if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah)) + if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) ar9003_hw_internal_regulator_apply(ah); if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) ar9003_hw_apply_tuning_caps(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index a0e3394b10dc..41e88c660e48 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -21,6 +21,7 @@ #include "ar9340_initvals.h" #include "ar9330_1p1_initvals.h" #include "ar9330_1p2_initvals.h" +#include "ar955x_1p0_initvals.h" #include "ar9580_1p0_initvals.h" #include "ar9462_2p0_initvals.h" @@ -327,7 +328,61 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ, ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2); + } else if (AR_SREV_9550(ah)) { + /* mac */ + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], + ar955x_1p0_mac_core, + ARRAY_SIZE(ar955x_1p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], + ar955x_1p0_mac_postamble, + ARRAY_SIZE(ar955x_1p0_mac_postamble), 5); + + /* bb */ + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], + ar955x_1p0_baseband_core, + ARRAY_SIZE(ar955x_1p0_baseband_core), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], + ar955x_1p0_baseband_postamble, + ARRAY_SIZE(ar955x_1p0_baseband_postamble), 5); + + /* radio */ + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], + ar955x_1p0_radio_core, + ARRAY_SIZE(ar955x_1p0_radio_core), 2); + INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], + ar955x_1p0_radio_postamble, + ARRAY_SIZE(ar955x_1p0_radio_postamble), 5); + + /* soc */ + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], + ar955x_1p0_soc_preamble, + ARRAY_SIZE(ar955x_1p0_soc_preamble), 2); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], + ar955x_1p0_soc_postamble, + ARRAY_SIZE(ar955x_1p0_soc_postamble), 5); + /* rx/tx gain */ + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar955x_1p0_common_wo_xlna_rx_gain_table, + ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), + 2); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + ar955x_1p0_common_wo_xlna_rx_gain_bounds, + ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), + 5); + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar955x_1p0_modes_xpa_tx_gain_table, + ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), + 9); + + /* Fast clock modal settings */ + INIT_INI_ARRAY(&ah->iniModesFastClock, + ar955x_1p0_modes_fast_clock, + ARRAY_SIZE(ar955x_1p0_modes_fast_clock), 3); } else if (AR_SREV_9580(ah)) { /* mac */ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); @@ -470,6 +525,11 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) ar9485_modes_lowest_ob_db_tx_gain_1_1, ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), 5); + else if (AR_SREV_9550(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar955x_1p0_modes_xpa_tx_gain_table, + ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), + 9); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9580_1p0_lowest_ob_db_tx_gain_table, @@ -514,6 +574,11 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) ar9580_1p0_high_ob_db_tx_gain_table, ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), 5); + else if (AR_SREV_9550(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar955x_1p0_modes_no_xpa_tx_gain_table, + ARRAY_SIZE(ar955x_1p0_modes_no_xpa_tx_gain_table), + 9); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, ar9462_modes_high_ob_db_tx_gain_table_2p0, @@ -635,7 +700,16 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) ar9485Common_wo_xlna_rx_gain_1_1, ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); - else if (AR_SREV_9580(ah)) + else if (AR_SREV_9550(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar955x_1p0_common_rx_gain_table, + ARRAY_SIZE(ar955x_1p0_common_rx_gain_table), + 2); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + ar955x_1p0_common_rx_gain_bounds, + ARRAY_SIZE(ar955x_1p0_common_rx_gain_bounds), + 5); + } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_rx_gain_table, ARRAY_SIZE(ar9580_1p0_rx_gain_table), @@ -679,7 +753,16 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) ar9462_common_wo_xlna_rx_gain_table_2p0, ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0), 2); - else if (AR_SREV_9580(ah)) + else if (AR_SREV_9550(ah)) { + INIT_INI_ARRAY(&ah->iniModesRxGain, + ar955x_1p0_common_wo_xlna_rx_gain_table, + ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), + 2); + INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, + ar955x_1p0_common_wo_xlna_rx_gain_bounds, + ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), + 5); + } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, ar9580_1p0_wo_xlna_rx_gain_table, ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table), diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mac.c b/drivers/net/wireless/ath/ath9k/ar9003_mac.c index d9e0824af093..78816b8b2173 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mac.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mac.c @@ -181,11 +181,14 @@ static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked) u32 mask2 = 0; struct ath9k_hw_capabilities *pCap = &ah->caps; struct ath_common *common = ath9k_hw_common(ah); - u32 sync_cause = 0, async_cause; + u32 sync_cause = 0, async_cause, async_mask = AR_INTR_MAC_IRQ; + + if (ath9k_hw_mci_is_enabled(ah)) + async_mask |= AR_INTR_ASYNC_MASK_MCI; async_cause = REG_READ(ah, AR_INTR_ASYNC_CAUSE); - if (async_cause & (AR_INTR_MAC_IRQ | AR_INTR_ASYNC_MASK_MCI)) { + if (async_cause & async_mask) { if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == AR_RTC_STATUS_ON) isr = REG_READ(ah, AR_ISR); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index b1ced2a76da3..9a34fcaae3ff 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -321,7 +321,7 @@ void ar9003_mci_set_full_sleep(struct ath_hw *ah) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) && + if (ar9003_mci_state(ah, MCI_STATE_ENABLE) && (mci->bt_state != MCI_BT_SLEEP) && !mci->halted_bt_gpm) { ar9003_mci_send_coex_halt_bt_gpm(ah, true, true); @@ -484,7 +484,7 @@ static void ar9003_mci_sync_bt_state(struct ath_hw *ah) struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; u32 cur_bt_state; - cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL); + cur_bt_state = ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP); if (mci->bt_state != cur_bt_state) mci->bt_state = cur_bt_state; @@ -593,8 +593,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, if (!time_out) break; - offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, - &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); if (offset == MCI_GPM_INVALID) continue; @@ -658,8 +657,7 @@ static u32 ar9003_mci_wait_for_gpm(struct ath_hw *ah, u8 gpm_type, time_out = 0; while (more_data == MCI_GPM_MORE) { - offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, - &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, false, &more_data); if (offset == MCI_GPM_INVALID) break; @@ -769,10 +767,6 @@ static void ar9003_mci_mute_bt(struct ath_hw *ah) { /* disable all MCI messages */ REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, 0xffff0000); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS0, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS1, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS2, 0xffffffff); - REG_WRITE(ah, AR_BTCOEX_WL_WEIGHTS3, 0xffffffff); REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); /* wait pending HW messages to flush out */ @@ -893,13 +887,16 @@ void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, udelay(100); } + /* Check pending GPM msg before MCI Reset Rx */ + ar9003_mci_check_gpm_offset(ah); + regval |= SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); udelay(1); regval &= ~SM(1, AR_MCI_COMMAND2_RESET_RX); REG_WRITE(ah, AR_MCI_COMMAND2, regval); - ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); + ar9003_mci_get_next_gpm_offset(ah, true, NULL); REG_WRITE(ah, AR_MCI_MSG_ATTRIBUTES_TABLE, (SM(0xe801, AR_MCI_MSG_ATTRIBUTES_TABLE_INVALID_HDR) | @@ -1010,11 +1007,11 @@ static void ar9003_mci_queue_unsent_gpm(struct ath_hw *ah, u8 header, } } -void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) +void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) { struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - if (!mci->update_2g5g) + if (!mci->update_2g5g && !force) return; if (mci->is_2g) { @@ -1028,8 +1025,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) - REG_SET_BIT(ah, AR_BTCOEX_CTRL, - AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + ar9003_mci_osla_setup(ah, true); } else { ar9003_mci_send_lna_take(ah, true); udelay(5); @@ -1038,9 +1034,8 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done) AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); - REG_CLR_BIT(ah, AR_BTCOEX_CTRL, - AR_BTCOEX_CTRL_ONE_STEP_LOOK_AHEAD_EN); + ar9003_mci_osla_setup(ah, false); ar9003_mci_send_2g5g_status(ah, true); } } @@ -1169,11 +1164,10 @@ void ar9003_mci_cleanup(struct ath_hw *ah) } EXPORT_SYMBOL(ar9003_mci_cleanup); -u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) +u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type) { - struct ath_common *common = ath9k_hw_common(ah); struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; - u32 value = 0, more_gpm = 0, gpm_ptr; + u32 value = 0; u8 query_type; switch (state_type) { @@ -1186,81 +1180,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) } value &= AR_BTCOEX_CTRL_MCI_MODE_EN; break; - case MCI_STATE_INIT_GPM_OFFSET: - value = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); - mci->gpm_idx = value; - break; - case MCI_STATE_NEXT_GPM_OFFSET: - case MCI_STATE_LAST_GPM_OFFSET: - /* - * This could be useful to avoid new GPM message interrupt which - * may lead to spurious interrupt after power sleep, or multiple - * entry of ath_mci_intr(). - * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can - * alleviate this effect, but clearing GPM RX interrupt bit is - * safe, because whether this is called from hw or driver code - * there must be an interrupt bit set/triggered initially - */ - REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, - AR_MCI_INTERRUPT_RX_MSG_GPM); - - gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); - value = gpm_ptr; - - if (value == 0) - value = mci->gpm_len - 1; - else if (value >= mci->gpm_len) { - if (value != 0xFFFF) - value = 0; - } else { - value--; - } - - if (value == 0xFFFF) { - value = MCI_GPM_INVALID; - more_gpm = MCI_GPM_NOMORE; - } else if (state_type == MCI_STATE_NEXT_GPM_OFFSET) { - if (gpm_ptr == mci->gpm_idx) { - value = MCI_GPM_INVALID; - more_gpm = MCI_GPM_NOMORE; - } else { - for (;;) { - u32 temp_index; - - /* skip reserved GPM if any */ - - if (value != mci->gpm_idx) - more_gpm = MCI_GPM_MORE; - else - more_gpm = MCI_GPM_NOMORE; - - temp_index = mci->gpm_idx; - mci->gpm_idx++; - - if (mci->gpm_idx >= - mci->gpm_len) - mci->gpm_idx = 0; - - if (ar9003_mci_is_gpm_valid(ah, - temp_index)) { - value = temp_index; - break; - } - - if (more_gpm == MCI_GPM_NOMORE) { - value = MCI_GPM_INVALID; - break; - } - } - } - if (p_data) - *p_data = more_gpm; - } - - if (value != MCI_GPM_INVALID) - value <<= 4; - - break; case MCI_STATE_LAST_SCHD_MSG_OFFSET: value = MS(REG_READ(ah, AR_MCI_RX_STATUS), AR_MCI_RX_LAST_SCHD_MSG_INDEX); @@ -1272,21 +1191,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) AR_MCI_RX_REMOTE_SLEEP) ? MCI_BT_SLEEP : MCI_BT_AWAKE; break; - case MCI_STATE_CONT_RSSI_POWER: - value = MS(mci->cont_status, AR_MCI_CONT_RSSI_POWER); - break; - case MCI_STATE_CONT_PRIORITY: - value = MS(mci->cont_status, AR_MCI_CONT_RRIORITY); - break; - case MCI_STATE_CONT_TXRX: - value = MS(mci->cont_status, AR_MCI_CONT_TXRX); - break; - case MCI_STATE_BT: - value = mci->bt_state; - break; - case MCI_STATE_SET_BT_SLEEP: - mci->bt_state = MCI_BT_SLEEP; - break; case MCI_STATE_SET_BT_AWAKE: mci->bt_state = MCI_BT_AWAKE; ar9003_mci_send_coex_version_query(ah, true); @@ -1295,7 +1199,7 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) if (mci->unhalt_bt_gpm) ar9003_mci_send_coex_halt_bt_gpm(ah, false, true); - ar9003_mci_2g5g_switch(ah, true); + ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_SET_BT_CAL_START: mci->bt_state = MCI_BT_CAL_START; @@ -1319,34 +1223,6 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) case MCI_STATE_SEND_WLAN_COEX_VERSION: ar9003_mci_send_coex_version_response(ah, true); break; - case MCI_STATE_SET_BT_COEX_VERSION: - if (!p_data) - ath_dbg(common, MCI, - "MCI Set BT Coex version with NULL data!!\n"); - else { - mci->bt_ver_major = (*p_data >> 8) & 0xff; - mci->bt_ver_minor = (*p_data) & 0xff; - mci->bt_version_known = true; - ath_dbg(common, MCI, "MCI BT version set: %d.%d\n", - mci->bt_ver_major, mci->bt_ver_minor); - } - break; - case MCI_STATE_SEND_WLAN_CHANNELS: - if (p_data) { - if (((mci->wlan_channels[1] & 0xffff0000) == - (*(p_data + 1) & 0xffff0000)) && - (mci->wlan_channels[2] == *(p_data + 2)) && - (mci->wlan_channels[3] == *(p_data + 3))) - break; - - mci->wlan_channels[0] = *p_data++; - mci->wlan_channels[1] = *p_data++; - mci->wlan_channels[2] = *p_data++; - mci->wlan_channels[3] = *p_data++; - } - mci->wlan_channels_update = true; - ar9003_mci_send_coex_wlan_channels(ah, true); - break; case MCI_STATE_SEND_VERSION_QUERY: ar9003_mci_send_coex_version_query(ah, true); break; @@ -1354,29 +1230,12 @@ u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data) query_type = MCI_GPM_COEX_QUERY_BT_TOPOLOGY; ar9003_mci_send_coex_bt_status_query(ah, true, query_type); break; - case MCI_STATE_NEED_FLUSH_BT_INFO: - /* - * btcoex_hw.mci.unhalt_bt_gpm means whether it's - * needed to send UNHALT message. It's set whenever - * there's a request to send HALT message. - * mci_halted_bt_gpm means whether HALT message is sent - * out successfully. - * - * Checking (mci_unhalt_bt_gpm == false) instead of - * checking (ah->mci_halted_bt_gpm == false) will make - * sure currently is in UNHALT-ed mode and BT can - * respond to status query. - */ - value = (!mci->unhalt_bt_gpm && mci->need_flush_btinfo) ? 1 : 0; - if (p_data) - mci->need_flush_btinfo = (*p_data != 0) ? true : false; - break; case MCI_STATE_RECOVER_RX: ar9003_mci_prep_interface(ah); mci->query_bt = true; mci->need_flush_btinfo = true; ar9003_mci_send_coex_wlan_channels(ah, true); - ar9003_mci_2g5g_switch(ah, true); + ar9003_mci_2g5g_switch(ah, false); break; case MCI_STATE_NEED_FTP_STOMP: value = !(mci->config & ATH_MCI_CONFIG_DISABLE_FTP_STOMP); @@ -1396,6 +1255,9 @@ void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) ath_dbg(common, MCI, "Give LNA and SPDT control to BT\n"); + ar9003_mci_send_lna_take(ah, true); + udelay(50); + REG_SET_BIT(ah, AR_PHY_GLB_CONTROL, AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); mci->is_2g = false; mci->update_2g5g = true; @@ -1404,3 +1266,154 @@ void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) /* Force another 2g5g update at next scanning */ mci->update_2g5g = true; } + +void ar9003_mci_set_power_awake(struct ath_hw *ah) +{ + u32 btcoex_ctrl2, diag_sw; + int i; + u8 lna_ctrl, bt_sleep; + + for (i = 0; i < AH_WAIT_TIMEOUT; i++) { + btcoex_ctrl2 = REG_READ(ah, AR_BTCOEX_CTRL2); + if (btcoex_ctrl2 != 0xdeadbeef) + break; + udelay(AH_TIME_QUANTUM); + } + REG_WRITE(ah, AR_BTCOEX_CTRL2, (btcoex_ctrl2 | BIT(23))); + + for (i = 0; i < AH_WAIT_TIMEOUT; i++) { + diag_sw = REG_READ(ah, AR_DIAG_SW); + if (diag_sw != 0xdeadbeef) + break; + udelay(AH_TIME_QUANTUM); + } + REG_WRITE(ah, AR_DIAG_SW, (diag_sw | BIT(27) | BIT(19) | BIT(18))); + lna_ctrl = REG_READ(ah, AR_OBS_BUS_CTRL) & 0x3; + bt_sleep = REG_READ(ah, AR_MCI_RX_STATUS) & AR_MCI_RX_REMOTE_SLEEP; + + REG_WRITE(ah, AR_BTCOEX_CTRL2, btcoex_ctrl2); + REG_WRITE(ah, AR_DIAG_SW, diag_sw); + + if (bt_sleep && (lna_ctrl == 2)) { + REG_SET_BIT(ah, AR_BTCOEX_RC, 0x1); + REG_CLR_BIT(ah, AR_BTCOEX_RC, 0x1); + udelay(50); + } +} + +void ar9003_mci_check_gpm_offset(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 offset; + + /* + * This should only be called before "MAC Warm Reset" or "MCI Reset Rx". + */ + offset = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + if (mci->gpm_idx == offset) + return; + ath_dbg(common, MCI, "GPM cached write pointer mismatch %d %d\n", + mci->gpm_idx, offset); + mci->query_bt = true; + mci->need_flush_btinfo = true; + mci->gpm_idx = 0; +} + +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + u32 offset, more_gpm = 0, gpm_ptr; + + if (first) { + gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + mci->gpm_idx = gpm_ptr; + return gpm_ptr; + } + + /* + * This could be useful to avoid new GPM message interrupt which + * may lead to spurious interrupt after power sleep, or multiple + * entry of ath_mci_intr(). + * Adding empty GPM check by returning HAL_MCI_GPM_INVALID can + * alleviate this effect, but clearing GPM RX interrupt bit is + * safe, because whether this is called from hw or driver code + * there must be an interrupt bit set/triggered initially + */ + REG_WRITE(ah, AR_MCI_INTERRUPT_RX_MSG_RAW, + AR_MCI_INTERRUPT_RX_MSG_GPM); + + gpm_ptr = MS(REG_READ(ah, AR_MCI_GPM_1), AR_MCI_GPM_WRITE_PTR); + offset = gpm_ptr; + + if (!offset) + offset = mci->gpm_len - 1; + else if (offset >= mci->gpm_len) { + if (offset != 0xFFFF) + offset = 0; + } else { + offset--; + } + + if ((offset == 0xFFFF) || (gpm_ptr == mci->gpm_idx)) { + offset = MCI_GPM_INVALID; + more_gpm = MCI_GPM_NOMORE; + goto out; + } + for (;;) { + u32 temp_index; + + /* skip reserved GPM if any */ + + if (offset != mci->gpm_idx) + more_gpm = MCI_GPM_MORE; + else + more_gpm = MCI_GPM_NOMORE; + + temp_index = mci->gpm_idx; + mci->gpm_idx++; + + if (mci->gpm_idx >= mci->gpm_len) + mci->gpm_idx = 0; + + if (ar9003_mci_is_gpm_valid(ah, temp_index)) { + offset = temp_index; + break; + } + + if (more_gpm == MCI_GPM_NOMORE) { + offset = MCI_GPM_INVALID; + break; + } + } + + if (offset != MCI_GPM_INVALID) + offset <<= 4; +out: + if (more) + *more = more_gpm; + + return offset; +} +EXPORT_SYMBOL(ar9003_mci_get_next_gpm_offset); + +void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + mci->bt_ver_major = major; + mci->bt_ver_minor = minor; + mci->bt_version_known = true; + ath_dbg(ath9k_hw_common(ah), MCI, "MCI BT version set: %d.%d\n", + mci->bt_ver_major, mci->bt_ver_minor); +} +EXPORT_SYMBOL(ar9003_mci_set_bt_version); + +void ar9003_mci_send_wlan_channels(struct ath_hw *ah) +{ + struct ath9k_hw_mci *mci = &ah->btcoex_hw.mci; + + mci->wlan_channels_update = true; + ar9003_mci_send_coex_wlan_channels(ah, true); +} +EXPORT_SYMBOL(ar9003_mci_send_wlan_channels); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.h b/drivers/net/wireless/ath/ath9k/ar9003_mci.h index 10282e2bcdc9..d33b8e128855 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.h @@ -189,26 +189,15 @@ enum mci_bt_state { /* Type of state query */ enum mci_state_type { MCI_STATE_ENABLE, - MCI_STATE_INIT_GPM_OFFSET, - MCI_STATE_NEXT_GPM_OFFSET, - MCI_STATE_LAST_GPM_OFFSET, - MCI_STATE_BT, - MCI_STATE_SET_BT_SLEEP, MCI_STATE_SET_BT_AWAKE, MCI_STATE_SET_BT_CAL_START, MCI_STATE_SET_BT_CAL, MCI_STATE_LAST_SCHD_MSG_OFFSET, MCI_STATE_REMOTE_SLEEP, - MCI_STATE_CONT_RSSI_POWER, - MCI_STATE_CONT_PRIORITY, - MCI_STATE_CONT_TXRX, MCI_STATE_RESET_REQ_WAKE, MCI_STATE_SEND_WLAN_COEX_VERSION, - MCI_STATE_SET_BT_COEX_VERSION, - MCI_STATE_SEND_WLAN_CHANNELS, MCI_STATE_SEND_VERSION_QUERY, MCI_STATE_SEND_STATUS_QUERY, - MCI_STATE_NEED_FLUSH_BT_INFO, MCI_STATE_SET_CONCUR_TX_PRI, MCI_STATE_RECOVER_RX, MCI_STATE_NEED_FTP_STOMP, @@ -259,14 +248,15 @@ enum mci_gpm_coex_opcode { bool ar9003_mci_send_message(struct ath_hw *ah, u8 header, u32 flag, u32 *payload, u8 len, bool wait_done, bool check_bt); -u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type, u32 *p_data); +u32 ar9003_mci_state(struct ath_hw *ah, u32 state_type); void ar9003_mci_setup(struct ath_hw *ah, u32 gpm_addr, void *gpm_buf, u16 len, u32 sched_addr); void ar9003_mci_cleanup(struct ath_hw *ah); void ar9003_mci_get_interrupt(struct ath_hw *ah, u32 *raw_intr, u32 *rx_msg_intr); -void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah); - +u32 ar9003_mci_get_next_gpm_offset(struct ath_hw *ah, bool first, u32 *more); +void ar9003_mci_set_bt_version(struct ath_hw *ah, u8 major, u8 minor); +void ar9003_mci_send_wlan_channels(struct ath_hw *ah); /* * These functions are used by ath9k_hw. */ @@ -277,7 +267,7 @@ void ar9003_mci_stop_bt(struct ath_hw *ah, bool save_fullsleep); void ar9003_mci_init_cal_req(struct ath_hw *ah, bool *is_reusable); void ar9003_mci_init_cal_done(struct ath_hw *ah); void ar9003_mci_set_full_sleep(struct ath_hw *ah); -void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool wait_done); +void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force); void ar9003_mci_check_bt(struct ath_hw *ah); bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan); int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, @@ -285,6 +275,9 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, bool is_full_sleep); void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked); +void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah); +void ar9003_mci_set_power_awake(struct ath_hw *ah); +void ar9003_mci_check_gpm_offset(struct ath_hw *ah); #else @@ -322,6 +315,15 @@ static inline void ar9003_mci_reset(struct ath_hw *ah, bool en_int, bool is_2g, static inline void ar9003_mci_get_isr(struct ath_hw *ah, enum ath9k_int *masked) { } +static inline void ar9003_mci_bt_gain_ctrl(struct ath_hw *ah) +{ +} +static inline void ar9003_mci_set_power_awake(struct ath_hw *ah) +{ +} +static inline void ar9003_mci_check_gpm_offset(struct ath_hw *ah) +{ +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ #endif diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 3d400e8d6535..2c9f7d7ed4cc 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c @@ -211,7 +211,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah) AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7); REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1); - if (AR_SREV_9485(ah) || AR_SREV_9462(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9550(ah)) REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3, AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP, -3); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index d6baf69cdc14..d2346dbad6cd 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -99,7 +99,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) channelSel = (freq * 4) / 120; chan_frac = (((freq * 4) % 120) * 0x20000) / 120; channelSel = (channelSel << 17) | chan_frac; - } else if (AR_SREV_9340(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { if (ah->is_clk_25mhz) { u32 chan_frac; @@ -113,7 +113,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) /* Set to 2G mode */ bMode = 1; } else { - if (AR_SREV_9340(ah) && ah->is_clk_25mhz) { + if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) && + ah->is_clk_25mhz) { u32 chan_frac; channelSel = (freq * 2) / 75; @@ -173,16 +174,15 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, int cur_bb_spur, negative = 0, cck_spur_freq; int i; int range, max_spur_cnts, synth_freq; - u8 *spur_fbin_ptr = NULL; + u8 *spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, IS_CHAN_2GHZ(chan)); /* * Need to verify range +/- 10 MHz in control channel, otherwise spur * is out-of-band and can be ignored. */ - if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) { - spur_fbin_ptr = ar9003_get_spur_chan_ptr(ah, - IS_CHAN_2GHZ(chan)); + if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || + AR_SREV_9550(ah)) { if (spur_fbin_ptr[0] == 0) /* No spur */ return; max_spur_cnts = 5; @@ -207,7 +207,8 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, if (AR_SREV_9462(ah) && (i == 0 || i == 3)) continue; negative = 0; - if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || + AR_SREV_9550(ah)) cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i], IS_CHAN_2GHZ(chan)); else @@ -620,6 +621,50 @@ static void ar9003_hw_prog_ini(struct ath_hw *ah, } } +static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah, + struct ath9k_channel *chan) +{ + int ret; + + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + if (chan->channel <= 5350) + ret = 1; + else if ((chan->channel > 5350) && (chan->channel <= 5600)) + ret = 3; + else + ret = 5; + break; + + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + if (chan->channel <= 5350) + ret = 2; + else if ((chan->channel > 5350) && (chan->channel <= 5600)) + ret = 4; + else + ret = 6; + break; + + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_B: + ret = 8; + break; + + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + ret = 7; + break; + + default: + ret = -EINVAL; + } + + return ret; +} + static int ar9003_hw_process_ini(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -661,7 +706,22 @@ static int ar9003_hw_process_ini(struct ath_hw *ah, } REG_WRITE_ARRAY(&ah->iniModesRxGain, 1, regWrites); - REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + if (AR_SREV_9550(ah)) + REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex, + regWrites); + + if (AR_SREV_9550(ah)) { + int modes_txgain_index; + + modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan); + if (modes_txgain_index < 0) + return -EINVAL; + + REG_WRITE_ARRAY(&ah->iniModesTxGain, modes_txgain_index, + regWrites); + } else { + REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites); + } /* * For 5GHz channels requiring Fast Clock, apply @@ -825,18 +885,18 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - if (!on != aniState->ofdmWeakSigDetectOff) { + if (on != aniState->ofdmWeakSigDetect) { ath_dbg(common, ANI, "** ch %d: ofdm weak signal: %s=>%s\n", chan->channel, - !aniState->ofdmWeakSigDetectOff ? + aniState->ofdmWeakSigDetect ? "on" : "off", on ? "on" : "off"); if (on) ah->stats.ast_ani_ofdmon++; else ah->stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; + aniState->ofdmWeakSigDetect = on; } break; } @@ -855,7 +915,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, * from INI file & cap value */ value = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] + + firstep_table[ATH9K_ANI_FIRSTEP_LVL] + aniState->iniDef.firstep; if (value < ATH9K_SIG_FIRSTEP_SETTING_MIN) value = ATH9K_SIG_FIRSTEP_SETTING_MIN; @@ -870,7 +930,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, * from INI file & cap value */ value2 = firstep_table[level] - - firstep_table[ATH9K_ANI_FIRSTEP_LVL_NEW] + + firstep_table[ATH9K_ANI_FIRSTEP_LVL] + aniState->iniDef.firstepLow; if (value2 < ATH9K_SIG_FIRSTEP_SETTING_MIN) value2 = ATH9K_SIG_FIRSTEP_SETTING_MIN; @@ -886,7 +946,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, chan->channel, aniState->firstepLevel, level, - ATH9K_ANI_FIRSTEP_LVL_NEW, + ATH9K_ANI_FIRSTEP_LVL, value, aniState->iniDef.firstep); ath_dbg(common, ANI, @@ -894,7 +954,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, chan->channel, aniState->firstepLevel, level, - ATH9K_ANI_FIRSTEP_LVL_NEW, + ATH9K_ANI_FIRSTEP_LVL, value2, aniState->iniDef.firstepLow); if (level > aniState->firstepLevel) @@ -919,7 +979,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, * from INI file & cap value */ value = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] + + cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + aniState->iniDef.cycpwrThr1; if (value < ATH9K_SIG_SPUR_IMM_SETTING_MIN) value = ATH9K_SIG_SPUR_IMM_SETTING_MIN; @@ -935,7 +995,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, * from INI file & cap value */ value2 = cycpwrThr1_table[level] - - cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL_NEW] + + cycpwrThr1_table[ATH9K_ANI_SPUR_IMMUNE_LVL] + aniState->iniDef.cycpwrThr1Ext; if (value2 < ATH9K_SIG_SPUR_IMM_SETTING_MIN) value2 = ATH9K_SIG_SPUR_IMM_SETTING_MIN; @@ -950,7 +1010,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, chan->channel, aniState->spurImmunityLevel, level, - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, + ATH9K_ANI_SPUR_IMMUNE_LVL, value, aniState->iniDef.cycpwrThr1); ath_dbg(common, ANI, @@ -958,7 +1018,7 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, chan->channel, aniState->spurImmunityLevel, level, - ATH9K_ANI_SPUR_IMMUNE_LVL_NEW, + ATH9K_ANI_SPUR_IMMUNE_LVL, value2, aniState->iniDef.cycpwrThr1Ext); if (level > aniState->spurImmunityLevel) @@ -979,16 +1039,16 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, AR_PHY_MRC_CCK_ENABLE, is_on); REG_RMW_FIELD(ah, AR_PHY_MRC_CCK_CTRL, AR_PHY_MRC_CCK_MUX_REG, is_on); - if (!is_on != aniState->mrcCCKOff) { + if (is_on != aniState->mrcCCK) { ath_dbg(common, ANI, "** ch %d: MRC CCK: %s=>%s\n", chan->channel, - !aniState->mrcCCKOff ? "on" : "off", + aniState->mrcCCK ? "on" : "off", is_on ? "on" : "off"); if (is_on) ah->stats.ast_ani_ccklow++; else ah->stats.ast_ani_cckhigh++; - aniState->mrcCCKOff = !is_on; + aniState->mrcCCK = is_on; } break; } @@ -1002,9 +1062,9 @@ static bool ar9003_hw_ani_control(struct ath_hw *ah, ath_dbg(common, ANI, "ANI parameters: SI=%d, ofdmWS=%s FS=%d MRCcck=%s listenTime=%d ofdmErrs=%d cckErrs=%d\n", aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff ? "on" : "off", + aniState->ofdmWeakSigDetect ? "on" : "off", aniState->firstepLevel, - !aniState->mrcCCKOff ? "on" : "off", + aniState->mrcCCK ? "on" : "off", aniState->listenTime, aniState->ofdmPhyErrCount, aniState->cckPhyErrCount); @@ -1111,10 +1171,10 @@ static void ar9003_hw_ani_cache_ini_regs(struct ath_hw *ah) AR_PHY_EXT_CYCPWR_THR1); /* these levels just got reset to defaults by the INI */ - aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL_NEW; - aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL_NEW; - aniState->ofdmWeakSigDetectOff = !ATH9K_ANI_USE_OFDM_WEAK_SIG; - aniState->mrcCCKOff = !ATH9K_ANI_ENABLE_MRC_CCK; + aniState->spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + aniState->firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + aniState->ofdmWeakSigDetect = ATH9K_ANI_USE_OFDM_WEAK_SIG; + aniState->mrcCCK = true; } static void ar9003_hw_set_radar_params(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index ed662c3bae5b..751c83b21493 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -636,8 +636,8 @@ #define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ ((AR_SREV_9462(ah) ? 0x1628c : 0x16280))) -#define AR_CH0_TOP_XPABIASLVL (0x300) -#define AR_CH0_TOP_XPABIASLVL_S (8) +#define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300) +#define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8) #define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \ ((AR_SREV_9485(ah) ? 0x1628c : 0x16294))) @@ -650,6 +650,8 @@ #define AR_SWITCH_TABLE_COM_ALL_S (0) #define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff) #define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0) +#define AR_SWITCH_TABLE_COM_AR9550_ALL (0xffffff) +#define AR_SWITCH_TABLE_COM_AR9550_ALL_S (0) #define AR_SWITCH_TABLE_COM_SPDT (0x00f00000) #define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0) #define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4) diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h index 1bd3a3d22101..6e1756bc3833 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p1_initvals.h @@ -337,12 +337,7 @@ static const u32 ar9331_modes_low_ob_db_tx_gain_1p1[][5] = { {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, }; -static const u32 ar9331_1p1_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; +#define ar9331_1p1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 static const u32 ar9331_1p1_xtal_25M[][2] = { /* Addr allmodes */ @@ -783,17 +778,7 @@ static const u32 ar9331_modes_high_power_tx_gain_1p1[][5] = { {0x00016284, 0x14d3f000, 0x14d3f000, 0x14d3f000, 0x14d3f000}, }; -static const u32 ar9331_1p1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; +#define ar9331_1p1_mac_postamble ar9300_2p2_mac_postamble static const u32 ar9331_1p1_soc_preamble[][2] = { /* Addr allmodes */ @@ -1112,38 +1097,4 @@ static const u32 ar9331_common_tx_gain_offset1_1[][1] = { {0x00000000}, }; -static const u32 ar9331_1p1_chansel_xtal_25M[] = { - 0x0101479e, - 0x0101d027, - 0x010258af, - 0x0102e138, - 0x010369c0, - 0x0103f249, - 0x01047ad1, - 0x0105035a, - 0x01058be2, - 0x0106146b, - 0x01069cf3, - 0x0107257c, - 0x0107ae04, - 0x0108f5b2, -}; - -static const u32 ar9331_1p1_chansel_xtal_40M[] = { - 0x00a0ccbe, - 0x00a12213, - 0x00a17769, - 0x00a1ccbe, - 0x00a22213, - 0x00a27769, - 0x00a2ccbe, - 0x00a32213, - 0x00a37769, - 0x00a3ccbe, - 0x00a42213, - 0x00a47769, - 0x00a4ccbe, - 0x00a5998b, -}; - #endif /* INITVALS_9330_1P1_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h index 0e6ca0834b34..57ed8a112173 100644 --- a/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9330_1p2_initvals.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,8 +18,8 @@ #ifndef INITVALS_9330_1P2_H #define INITVALS_9330_1P2_H -static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p2[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, @@ -102,8 +103,14 @@ static const u32 ar9331_modes_lowest_ob_db_tx_gain_1p2[][5] = { {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, }; +#define ar9331_modes_high_power_tx_gain_1p2 ar9331_modes_high_ob_db_tx_gain_1p2 + +#define ar9331_modes_low_ob_db_tx_gain_1p2 ar9331_modes_high_power_tx_gain_1p2 + +#define ar9331_modes_lowest_ob_db_tx_gain_1p2 ar9331_modes_low_ob_db_tx_gain_1p2 + static const u32 ar9331_1p2_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, @@ -147,191 +154,6 @@ static const u32 ar9331_1p2_baseband_postamble[][5] = { {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, }; -static const u32 ar9331_modes_high_ob_db_tx_gain_1p2[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, - {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, - {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, - {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, - {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, - {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, - {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, - {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, - {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, - {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, - {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, - {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, - {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, - {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, - {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, - {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, - {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, - {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, - {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, - {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, - {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, - {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, - {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, - {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, - {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03}, - {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, -}; - -static const u32 ar9331_modes_low_ob_db_tx_gain_1p2[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, - {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, - {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, - {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, - {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, - {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, - {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, - {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, - {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, - {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, - {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, - {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, - {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, - {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, - {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, - {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, - {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, - {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, - {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, - {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, - {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, - {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, - {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, - {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, - {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03}, - {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, -}; - -static const u32 ar9331_1p2_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9331_1p2_xtal_25M[][2] = { - /* Addr allmodes */ - {0x00007038, 0x000002f8}, - {0x00008244, 0x0010f3d7}, - {0x0000824c, 0x0001e7ae}, - {0x0001609c, 0x0f508f29}, -}; - static const u32 ar9331_1p2_radio_core[][2] = { /* Addr allmodes */ {0x00016000, 0x36db6db6}, @@ -397,684 +219,24 @@ static const u32 ar9331_1p2_radio_core[][2] = { {0x000163d4, 0x00000000}, }; -static const u32 ar9331_1p2_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000022, 0x00000022, 0x00000022, 0x00000022}, -}; +#define ar9331_1p2_baseband_core_txfir_coeff_japan_2484 ar9331_1p1_baseband_core_txfir_coeff_japan_2484 -static const u32 ar9331_common_wo_xlna_rx_gain_1p2[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00060005}, - {0x0000a004, 0x00810080}, - {0x0000a008, 0x00830082}, - {0x0000a00c, 0x00850084}, - {0x0000a010, 0x01820181}, - {0x0000a014, 0x01840183}, - {0x0000a018, 0x01880185}, - {0x0000a01c, 0x018a0189}, - {0x0000a020, 0x02850284}, - {0x0000a024, 0x02890288}, - {0x0000a028, 0x028b028a}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x24242428}, - {0x0000a098, 0x171e1e1e}, - {0x0000a09c, 0x02020b0b}, - {0x0000a0a0, 0x02020202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x22072208}, - {0x0000a0c4, 0x22052206}, - {0x0000a0c8, 0x22032204}, - {0x0000a0cc, 0x22012202}, - {0x0000a0d0, 0x221f2200}, - {0x0000a0d4, 0x221d221e}, - {0x0000a0d8, 0x33023303}, - {0x0000a0dc, 0x33003301}, - {0x0000a0e0, 0x331e331f}, - {0x0000a0e4, 0x4402331d}, - {0x0000a0e8, 0x44004401}, - {0x0000a0ec, 0x441e441f}, - {0x0000a0f0, 0x55025503}, - {0x0000a0f4, 0x55005501}, - {0x0000a0f8, 0x551e551f}, - {0x0000a0fc, 0x6602551d}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; +#define ar9331_1p2_xtal_25M ar9331_1p1_xtal_25M -static const u32 ar9331_1p2_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a8f6b}, - {0x0000980c, 0x04800000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x32840bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0x00000000}, - {0x00009c08, 0x03200000}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x1883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c00400}, - {0x00009d18, 0x00000000}, - {0x00009e08, 0x0038233c}, - {0x00009e24, 0x9927b515}, - {0x00009e28, 0x12ef0200}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009fc0, 0x803e4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x0000a20c, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x00000000}, - {0x0000a3a8, 0xaaaaaaaa}, - {0x0000a3ac, 0x3c466478}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739ce}, - {0x0000a418, 0x2d001dce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000000}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a458, 0x00000000}, - {0x0000a640, 0x00000000}, - {0x0000a644, 0x3fad9d74}, - {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00003c37}, - {0x0000a670, 0x03020100}, - {0x0000a674, 0x09080504}, - {0x0000a678, 0x0d0c0b0a}, - {0x0000a67c, 0x13121110}, - {0x0000a680, 0x31301514}, - {0x0000a684, 0x35343332}, - {0x0000a688, 0x00000036}, - {0x0000a690, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000001}, -}; +#define ar9331_1p2_xtal_40M ar9331_1p1_xtal_40M -static const u32 ar9331_modes_high_power_tx_gain_1p2[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a410, 0x000050d7, 0x000050d7, 0x000050d7, 0x000050d7}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x23000a00, 0x23000a00}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x27000a02, 0x27000a02}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2b000a04, 0x2b000a04}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x3f001620, 0x3f001620}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x41001621, 0x41001621}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x44001640, 0x44001640}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x46001641, 0x46001641}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x48001642, 0x48001642}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x4b001644, 0x4b001644}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4e001a81, 0x4e001a81}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x51001a83, 0x51001a83}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x54001c84, 0x54001c84}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x57001ce3, 0x57001ce3}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x5b001ce5, 0x5b001ce5}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5f001ce9, 0x5f001ce9}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x66001eec, 0x66001eec}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x66001eec, 0x66001eec}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x66001eec, 0x66001eec}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x66001eec, 0x66001eec}, - {0x0000a580, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a584, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a588, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a58c, 0x11062202, 0x11062202, 0x0b000200, 0x0b000200}, - {0x0000a590, 0x17022e00, 0x17022e00, 0x0f000202, 0x0f000202}, - {0x0000a594, 0x1d000ec2, 0x1d000ec2, 0x11000400, 0x11000400}, - {0x0000a598, 0x25020ec0, 0x25020ec0, 0x15000402, 0x15000402}, - {0x0000a59c, 0x2b020ec3, 0x2b020ec3, 0x19000404, 0x19000404}, - {0x0000a5a0, 0x2f001f04, 0x2f001f04, 0x1b000603, 0x1b000603}, - {0x0000a5a4, 0x35001fc4, 0x35001fc4, 0x1f000a02, 0x1f000a02}, - {0x0000a5a8, 0x3c022f04, 0x3c022f04, 0x23000a04, 0x23000a04}, - {0x0000a5ac, 0x41023e85, 0x41023e85, 0x26000a20, 0x26000a20}, - {0x0000a5b0, 0x48023ec6, 0x48023ec6, 0x2a000e20, 0x2a000e20}, - {0x0000a5b4, 0x4d023f01, 0x4d023f01, 0x2e000e22, 0x2e000e22}, - {0x0000a5b8, 0x53023f4b, 0x53023f4b, 0x31000e24, 0x31000e24}, - {0x0000a5bc, 0x5a027f09, 0x5a027f09, 0x34001640, 0x34001640}, - {0x0000a5c0, 0x5f027fc9, 0x5f027fc9, 0x38001660, 0x38001660}, - {0x0000a5c4, 0x6502feca, 0x6502feca, 0x3b001861, 0x3b001861}, - {0x0000a5c8, 0x6b02ff4a, 0x6b02ff4a, 0x3e001a81, 0x3e001a81}, - {0x0000a5cc, 0x7203feca, 0x7203feca, 0x42001a83, 0x42001a83}, - {0x0000a5d0, 0x7703ff0b, 0x7703ff0b, 0x44001c84, 0x44001c84}, - {0x0000a5d4, 0x7d06ffcb, 0x7d06ffcb, 0x48001ce3, 0x48001ce3}, - {0x0000a5d8, 0x8407ff0b, 0x8407ff0b, 0x4c001ce5, 0x4c001ce5}, - {0x0000a5dc, 0x8907ffcb, 0x8907ffcb, 0x50001ce9, 0x50001ce9}, - {0x0000a5e0, 0x900fff0b, 0x900fff0b, 0x54001ceb, 0x54001ceb}, - {0x0000a5e4, 0x960fffcb, 0x960fffcb, 0x56001eec, 0x56001eec}, - {0x0000a5e8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5ec, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f0, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f4, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5f8, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a5fc, 0x9c1fff0b, 0x9c1fff0b, 0x56001eec, 0x56001eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x02008501, 0x02008501, 0x02008501, 0x02008501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008802, 0x02008802}, - {0x0000a620, 0x0300c802, 0x0300c802, 0x0300c802, 0x0300c802}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x0300cc03, 0x0300cc03}, - {0x0000a628, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a62c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a630, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a634, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a638, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, - {0x0000a63c, 0x04011004, 0x04011004, 0x04011004, 0x04011004}, -}; +#define ar9331_1p2_baseband_core ar9331_1p1_baseband_core -static const u32 ar9331_1p2_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; +#define ar9331_1p2_soc_postamble ar9331_1p1_soc_postamble -static const u32 ar9331_1p2_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000002f8}, -}; +#define ar9331_1p2_mac_postamble ar9331_1p1_mac_postamble -static const u32 ar9331_1p2_xtal_40M[][2] = { - /* Addr allmodes */ - {0x00007038, 0x000004c2}, - {0x00008244, 0x0010f400}, - {0x0000824c, 0x0001e800}, - {0x0001609c, 0x0b283f31}, -}; +#define ar9331_1p2_soc_preamble ar9331_1p1_soc_preamble -static const u32 ar9331_1p2_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081c8, 0x00000000}, - {0x000081cc, 0x00000000}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008248, 0x00000800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x9d400010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xaa48105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; +#define ar9331_1p2_mac_core ar9331_1p1_mac_core -static const u32 ar9331_common_rx_gain_1p2[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x01800082}, - {0x0000a014, 0x01820181}, - {0x0000a018, 0x01840183}, - {0x0000a01c, 0x01880185}, - {0x0000a020, 0x018a0189}, - {0x0000a024, 0x02850284}, - {0x0000a028, 0x02890288}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x21212128}, - {0x0000a098, 0x171c1c1c}, - {0x0000a09c, 0x02020212}, - {0x0000a0a0, 0x00000202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x111f1100}, - {0x0000a0c8, 0x111d111e}, - {0x0000a0cc, 0x111b111c}, - {0x0000a0d0, 0x22032204}, - {0x0000a0d4, 0x22012202}, - {0x0000a0d8, 0x221f2200}, - {0x0000a0dc, 0x221d221e}, - {0x0000a0e0, 0x33013302}, - {0x0000a0e4, 0x331f3300}, - {0x0000a0e8, 0x4402331e}, - {0x0000a0ec, 0x44004401}, - {0x0000a0f0, 0x441e441f}, - {0x0000a0f4, 0x55015502}, - {0x0000a0f8, 0x551f5500}, - {0x0000a0fc, 0x6602551e}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, -}; +#define ar9331_common_wo_xlna_rx_gain_1p2 ar9331_common_wo_xlna_rx_gain_1p1 + +#define ar9331_common_rx_gain_1p2 ar9485_common_rx_gain_1_1 #endif /* INITVALS_9330_1P2_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h index 815a8af1beef..1d8235e19f0f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9340_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9340_initvals.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Atheros Communications Inc. + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -18,16 +19,16 @@ #define INITVALS_9340_H static const u32 ar9340_1p0_radio_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000160ac, 0xa4646800, 0xa4646800, 0xa4646800, 0xa4646800}, - {0x0001610c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x0001610c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016140, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, - {0x0001650c, 0x08000000, 0x08000000, 0x00000000, 0x00000000}, + {0x0001650c, 0x08000000, 0x00000000, 0x00000000, 0x00000000}, {0x00016540, 0x10804000, 0x10804000, 0x50804000, 0x50804000}, }; static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -99,21 +100,10 @@ static const u32 ar9340Modes_lowest_ob_db_tx_gain_table_1p0[][5] = { {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, }; -static const u32 ar9340Modes_fast_clock_1p0[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00001030, 0x00000268, 0x000004d0}, - {0x00001070, 0x0000018c, 0x00000318}, - {0x000010b0, 0x00000fd0, 0x00001fa0}, - {0x00008014, 0x044c044c, 0x08980898}, - {0x0000801c, 0x148ec02b, 0x148ec057}, - {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000000b, 0x00000016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; +#define ar9340Modes_fast_clock_1p0 ar9300Modes_fast_clock_2p2 static const u32 ar9340_1p0_radio_core[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00016000, 0x36db6db6}, {0x00016004, 0x6db6db40}, {0x00016008, 0x73f00000}, @@ -146,15 +136,13 @@ static const u32 ar9340_1p0_radio_core[][2] = { {0x00016100, 0x04cb0001}, {0x00016104, 0xfff80000}, {0x00016108, 0x00080010}, - {0x0001610c, 0x00000000}, {0x00016140, 0x50804008}, {0x00016144, 0x01884080}, {0x00016148, 0x000080c0}, {0x00016280, 0x01000015}, - {0x00016284, 0x05530000}, + {0x00016284, 0x15530000}, {0x00016288, 0x00318000}, {0x0001628c, 0x50000000}, - {0x00016290, 0x4080294f}, {0x00016380, 0x00000000}, {0x00016384, 0x00000000}, {0x00016388, 0x00800700}, @@ -219,52 +207,43 @@ static const u32 ar9340_1p0_radio_core[][2] = { }; static const u32 ar9340_1p0_radio_core_40M[][2] = { + /* Addr allmodes */ {0x0001609c, 0x02566f3a}, {0x000160ac, 0xa4647c00}, {0x000160b0, 0x01885f5a}, }; -static const u32 ar9340_1p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; +#define ar9340_1p0_mac_postamble ar9300_2p2_mac_postamble -static const u32 ar9340_1p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; +#define ar9340_1p0_soc_postamble ar9300_2p2_soc_postamble static const u32 ar9340_1p0_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, {0x00009820, 0x206a022e, 0x206a022e, 0x206a022e, 0x206a022e}, {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, - {0x00009c00, 0x00000044, 0x000000c4, 0x000000c4, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, {0x00009e44, 0x02321e27, 0x02321e27, 0x02291e27, 0x02291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x00003fc0, 0x00003fc4, 0x00003fc4, 0x00003fc0}, + {0x0000a204, 0x00003ec0, 0x00003ec4, 0x00003ec4, 0x00003ec0}, {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, @@ -277,11 +256,11 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = { {0x0000a288, 0x00000220, 0x00000220, 0x00000110, 0x00000110}, {0x0000a28c, 0x00011111, 0x00011111, 0x00022222, 0x00022222}, {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071981, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a2d0, 0x00041983, 0x00041983, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83a, 0x7999a83a, 0x7999a83a, 0x7999a83a}, {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, - {0x0000ae04, 0x00180000, 0x00180000, 0x00180000, 0x00180000}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, @@ -289,21 +268,21 @@ static const u32 ar9340_1p0_baseband_postamble[][5] = { }; static const u32 ar9340_1p0_baseband_core[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00009800, 0xafe68e30}, {0x00009804, 0xfd14e000}, {0x00009808, 0x9c0a9f6b}, {0x0000980c, 0x04900000}, - {0x00009814, 0xb280c00a}, + {0x00009814, 0x3280c00a}, {0x00009818, 0x00000000}, {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, + {0x00009834, 0x6400a190}, {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, + {0x0000983c, 0x14000600}, {0x00009880, 0x201fff00}, {0x00009884, 0x00001042}, {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, + {0x000098b0, 0x32840bbe}, {0x000098d0, 0x004b6a8e}, {0x000098d4, 0x00000820}, {0x000098dc, 0x00000000}, @@ -329,7 +308,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x00009e30, 0x06336f77}, {0x00009e34, 0x6af6532f}, {0x00009e38, 0x0cc80c00}, - {0x00009e3c, 0xcf946222}, {0x00009e40, 0x0d261820}, {0x00009e4c, 0x00001004}, {0x00009e50, 0x00ff03f1}, @@ -342,8 +320,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a220, 0x00000000}, {0x0000a224, 0x00000000}, {0x0000a228, 0x10002310}, - {0x0000a22c, 0x01036a1e}, - {0x0000a234, 0x10000fff}, {0x0000a23c, 0x00000000}, {0x0000a244, 0x0c000000}, {0x0000a2a0, 0x00000001}, @@ -351,10 +327,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a2c8, 0x00000000}, {0x0000a2cc, 0x18c43433}, {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, {0x0000a2ec, 0x00000000}, {0x0000a2f0, 0x00000000}, {0x0000a2f4, 0x00000000}, @@ -385,7 +357,7 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a3e8, 0x20202020}, {0x0000a3ec, 0x20202020}, {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000246}, + {0x0000a3f4, 0x00000000}, {0x0000a3f8, 0x0cdbd380}, {0x0000a3fc, 0x000f0f01}, {0x0000a400, 0x8fa91f01}, @@ -402,33 +374,17 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a430, 0x1ce739ce}, {0x0000a434, 0x00000000}, {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, + {0x0000a43c, 0x00100000}, {0x0000a440, 0x00000000}, {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000080}, + {0x0000a448, 0x05000080}, {0x0000a44c, 0x00000001}, {0x0000a450, 0x00010000}, {0x0000a458, 0x00000000}, - {0x0000a600, 0x00000000}, - {0x0000a604, 0x00000000}, - {0x0000a608, 0x00000000}, - {0x0000a60c, 0x00000000}, - {0x0000a610, 0x00000000}, - {0x0000a614, 0x00000000}, - {0x0000a618, 0x00000000}, - {0x0000a61c, 0x00000000}, - {0x0000a620, 0x00000000}, - {0x0000a624, 0x00000000}, - {0x0000a628, 0x00000000}, - {0x0000a62c, 0x00000000}, - {0x0000a630, 0x00000000}, - {0x0000a634, 0x00000000}, - {0x0000a638, 0x00000000}, - {0x0000a63c, 0x00000000}, {0x0000a640, 0x00000000}, {0x0000a644, 0x3fad9d74}, {0x0000a648, 0x0048060a}, - {0x0000a64c, 0x00000637}, + {0x0000a64c, 0x00003c37}, {0x0000a670, 0x03020100}, {0x0000a674, 0x09080504}, {0x0000a678, 0x0d0c0b0a}, @@ -451,10 +407,6 @@ static const u32 ar9340_1p0_baseband_core[][2] = { {0x0000a8f4, 0x00000000}, {0x0000b2d0, 0x00000080}, {0x0000b2d4, 0x00000000}, - {0x0000b2dc, 0x00000000}, - {0x0000b2e0, 0x00000000}, - {0x0000b2e4, 0x00000000}, - {0x0000b2e8, 0x00000000}, {0x0000b2ec, 0x00000000}, {0x0000b2f0, 0x00000000}, {0x0000b2f4, 0x00000000}, @@ -465,80 +417,108 @@ static const u32 ar9340_1p0_baseband_core[][2] = { }; static const u32 ar9340Modes_high_power_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, + {0x0000a504, 0x04002222, 0x04002222, 0x02000001, 0x02000001}, + {0x0000a508, 0x09002421, 0x09002421, 0x05000003, 0x05000003}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0a000005, 0x0a000005}, + {0x0000a510, 0x13004620, 0x13004620, 0x0e000201, 0x0e000201}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x11000203, 0x11000203}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x14000401, 0x14000401}, + {0x0000a51c, 0x21005420, 0x21005420, 0x18000403, 0x18000403}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000602, 0x1b000602}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000802, 0x1f000802}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x21000620, 0x21000620}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x25000820, 0x25000820}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x29000822, 0x29000822}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2d000824, 0x2d000824}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x30000828, 0x30000828}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x3400082a, 0x3400082a}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x38000849, 0x38000849}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b000a2c, 0x3b000a2c}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x3e000e2b, 0x3e000e2b}, + {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42000e2d, 0x42000e2d}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x4500124a, 0x4500124a}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x4900124c, 0x4900124c}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c00126c, 0x4c00126c}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x4f00128c, 0x4f00128c}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x52001290, 0x52001290}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001292, 0x56001292}, {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x0000a584, 0x04802222, 0x04802222, 0x02800001, 0x02800001}, + {0x0000a588, 0x09802421, 0x09802421, 0x05800003, 0x05800003}, + {0x0000a58c, 0x0d802621, 0x0d802621, 0x0a800005, 0x0a800005}, + {0x0000a590, 0x13804620, 0x13804620, 0x0e800201, 0x0e800201}, + {0x0000a594, 0x19804a20, 0x19804a20, 0x11800203, 0x11800203}, + {0x0000a598, 0x1d804e20, 0x1d804e20, 0x14800401, 0x14800401}, + {0x0000a59c, 0x21805420, 0x21805420, 0x18800403, 0x18800403}, + {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800602, 0x1b800602}, + {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800802, 0x1f800802}, + {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x21800620, 0x21800620}, + {0x0000a5ac, 0x33805e44, 0x33805e44, 0x25800820, 0x25800820}, + {0x0000a5b0, 0x38805e65, 0x38805e65, 0x29800822, 0x29800822}, + {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2d800824, 0x2d800824}, + {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x30800828, 0x30800828}, + {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x3480082a, 0x3480082a}, + {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38800849, 0x38800849}, + {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b800a2c, 0x3b800a2c}, + {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e800e2b, 0x3e800e2b}, + {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42800e2d, 0x42800e2d}, + {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x4580124a, 0x4580124a}, + {0x0000a5d4, 0x61827f12, 0x61827f12, 0x4980124c, 0x4980124c}, + {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c80126c, 0x4c80126c}, + {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x4f80128c, 0x4f80128c}, + {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x52801290, 0x52801290}, + {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801292, 0x56801292}, + {0x00016044, 0x056db2db, 0x056db2db, 0x022492db, 0x022492db}, {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, - {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, + {0x00016444, 0x056db2db, 0x056db2db, 0x022492db, 0x022492db}, {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, }; static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -559,7 +539,7 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb5, 0x59025eb5, 0x42001a83, 0x42001a83}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, @@ -604,13 +584,43 @@ static const u32 ar9340Modes_high_ob_db_tx_gain_table_1p0[][5] = { {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016048, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, + {0x00016048, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016448, 0x8e481266, 0x8e481266, 0x8e481266, 0x8e481266}, + {0x00016448, 0x8e481666, 0x8e481666, 0x8e481266, 0x8e481266}, }; + static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a00ae, 0x206a00ae}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec82d2e, 0x7ec82d2e}, + {0x0000a2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, + {0x0000a2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, + {0x0000a2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, + {0x0000a2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, @@ -676,15 +686,34 @@ static const u32 ar9340Modes_ub124_tx_gain_table_1p0[][5] = { {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x00016044, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, - {0x00016048, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, - {0x00016444, 0x036db2db, 0x036db2db, 0x036db2db, 0x036db2db}, - {0x00016448, 0x69b65266, 0x69b65266, 0x69b65266, 0x69b65266}, + {0x00016044, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016048, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, + {0x00016444, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4, 0x03b6d2e4}, + {0x00016448, 0x8e480086, 0x8e480086, 0x8e480086, 0x8e480086}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, + {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, + {0x0000b2dc, 0xfef5d402, 0xfef5d402, 0xfdab5b52, 0xfdab5b52}, + {0x0000b2e0, 0xfe896600, 0xfe896600, 0xfd339c84, 0xfd339c84}, + {0x0000b2e4, 0xff01f800, 0xff01f800, 0xfec3e000, 0xfec3e000}, + {0x0000b2e8, 0xfffe0000, 0xfffe0000, 0xfffc0000, 0xfffc0000}, }; - static const u32 ar9340Common_rx_gain_table_1p0[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, {0x0000a008, 0x00050004}, @@ -845,14 +874,14 @@ static const u32 ar9340Common_rx_gain_table_1p0[][2] = { {0x0000b074, 0x00000000}, {0x0000b078, 0x00000000}, {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, {0x0000b0a0, 0x00000000}, {0x0000b0a4, 0x00000000}, {0x0000b0a8, 0x00000000}, @@ -944,7 +973,11 @@ static const u32 ar9340Common_rx_gain_table_1p0[][2] = { }; static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -952,8 +985,8 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, @@ -965,19 +998,19 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x5d001eec, 0x5d001eec}, + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, @@ -1010,14 +1043,40 @@ static const u32 ar9340Modes_low_ob_db_tx_gain_table_1p0[][5] = { {0x0000a5f4, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, {0x0000a5f8, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, {0x0000a5fc, 0x778a308c, 0x778a308c, 0x5d801eec, 0x5d801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, - {0x00016048, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016048, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, + {0x00016288, 0xf0318000, 0xf0318000, 0xf0318000, 0xf0318000}, {0x00016444, 0x056db2db, 0x056db2db, 0x056db2db, 0x056db2db}, - {0x00016448, 0x24925266, 0x24925266, 0x24925266, 0x24925266}, + {0x00016448, 0x24925666, 0x24925666, 0x24925266, 0x24925266}, }; static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, @@ -1025,8 +1084,8 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, {0x0000a514, 0x1c000223, 0x1c000223, 0x11000400, 0x11000400}, - {0x0000a518, 0x21020220, 0x21020220, 0x15000402, 0x15000402}, - {0x0000a51c, 0x27020223, 0x27020223, 0x19000404, 0x19000404}, + {0x0000a518, 0x21002220, 0x21002220, 0x15000402, 0x15000402}, + {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, {0x0000a520, 0x2b022220, 0x2b022220, 0x1b000603, 0x1b000603}, {0x0000a524, 0x2f022222, 0x2f022222, 0x1f000a02, 0x1f000a02}, {0x0000a528, 0x34022225, 0x34022225, 0x23000a04, 0x23000a04}, @@ -1038,19 +1097,19 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { {0x0000a540, 0x4e02246c, 0x4e02246c, 0x38001660, 0x38001660}, {0x0000a544, 0x5302266c, 0x5302266c, 0x3b001861, 0x3b001861}, {0x0000a548, 0x5702286c, 0x5702286c, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x5c04286b, 0x5c04286b, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x61042a6c, 0x61042a6c, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x66062a6c, 0x66062a6c, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6b062e6c, 0x6b062e6c, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x7006308c, 0x7006308c, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x730a308a, 0x730a308a, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x770a308c, 0x770a308c, 0x56001eec, 0x56001eec}, + {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x42001a83, 0x42001a83}, + {0x0000a550, 0x61024a6c, 0x61024a6c, 0x44001c84, 0x44001c84}, + {0x0000a554, 0x66026a6c, 0x66026a6c, 0x48001ce3, 0x48001ce3}, + {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x4c001ce5, 0x4c001ce5}, + {0x0000a55c, 0x7002708c, 0x7002708c, 0x50001ce9, 0x50001ce9}, + {0x0000a560, 0x7302b08a, 0x7302b08a, 0x54001ceb, 0x54001ceb}, + {0x0000a564, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a568, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a570, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a574, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a578, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, + {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x56001eec, 0x56001eec}, {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, @@ -1083,14 +1142,36 @@ static const u32 ar9340Modes_mixed_ob_db_tx_gain_table_1p0[][5] = { {0x0000a5f4, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, {0x0000a5f8, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, {0x0000a5fc, 0x778a308c, 0x778a308c, 0x56801eec, 0x56801eec}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, + {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, + {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, + {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, + {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, + {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, + {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, + {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, + {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, + {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, + {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, {0x00016044, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016048, 0x24927266, 0x24927266, 0x8e483266, 0x8e483266}, + {0x00016048, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, + {0x00016280, 0x01000015, 0x01000015, 0x01001015, 0x01001015}, + {0x00016288, 0x30318000, 0x30318000, 0x00318000, 0x00318000}, {0x00016444, 0x056db2db, 0x056db2db, 0x03b6d2e4, 0x03b6d2e4}, - {0x00016448, 0x24927266, 0x24927266, 0x8e482266, 0x8e482266}, + {0x00016448, 0x24925666, 0x24925666, 0x8e481266, 0x8e481266}, }; static const u32 ar9340_1p0_mac_core[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00000008, 0x00000000}, {0x00000030, 0x00020085}, {0x00000034, 0x00000005}, @@ -1119,6 +1200,7 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x00008004, 0x00000000}, {0x00008008, 0x00000000}, {0x0000800c, 0x00000000}, + {0x00008010, 0x00080800}, {0x00008018, 0x00000000}, {0x00008020, 0x00000000}, {0x00008038, 0x00000000}, @@ -1146,7 +1228,7 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x000080bc, 0x00000000}, {0x000080c0, 0x2a800000}, {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c20}, + {0x000080c8, 0x13881c22}, {0x000080cc, 0x01f40000}, {0x000080d0, 0x00252500}, {0x000080d4, 0x00a00000}, @@ -1250,276 +1332,17 @@ static const u32 ar9340_1p0_mac_core[][2] = { {0x000083c4, 0x00000000}, {0x000083c8, 0x00000000}, {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, + {0x000083d0, 0x000101ff}, }; -static const u32 ar9340Common_wo_xlna_rx_gain_table_1p0[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; +#define ar9340Common_wo_xlna_rx_gain_table_1p0 ar9300Common_wo_xlna_rx_gain_table_2p2 static const u32 ar9340_1p0_soc_preamble[][2] = { - /* Addr allmodes */ - {0x000040a4, 0x00a0c1c9}, + /* Addr allmodes */ {0x00007008, 0x00000000}, {0x00007020, 0x00000000}, {0x00007034, 0x00000002}, {0x00007038, 0x000004c2}, }; -#endif +#endif /* INITVALS_9340_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h index 4a93e1534c1d..4ef7dcccaa2f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2010 Atheros Communications Inc. + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -52,7 +53,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000d8}, {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e}, - {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x33795d5e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3376605e, 0x32395d5e}, {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, @@ -61,7 +62,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = { {0x00009e44, 0x62321e27, 0x62321e27, 0xfe291e27, 0xfe291e27}, {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x013187c0, 0x013187c4, 0x013187c4, 0x013187c0}, + {0x0000a204, 0x01318fc0, 0x01318fc4, 0x01318fc4, 0x01318fc0}, {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, {0x0000a22c, 0x01026a2f, 0x01026a27, 0x01026a2f, 0x01026a2f}, {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, @@ -1007,7 +1008,7 @@ static const u32 ar9462_2p0_radio_core[][2] = { static const u32 ar9462_2p0_soc_preamble[][2] = { /* Addr allmodes */ - {0x000040a4 ,0x00a0c1c9}, + {0x000040a4, 0x00a0c1c9}, {0x00007020, 0x00000000}, {0x00007034, 0x00000002}, {0x00007038, 0x000004c2}, diff --git a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h index d16d029f81a9..fb4497fc7a3d 100644 --- a/drivers/net/wireless/ath/ath9k/ar9485_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9485_initvals.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -17,360 +18,151 @@ #ifndef INITVALS_9485_H #define INITVALS_9485_H -static const u32 ar9485_1_1_mac_core[][2] = { - /* Addr allmodes */ - {0x00000008, 0x00000000}, - {0x00000030, 0x00020085}, - {0x00000034, 0x00000005}, - {0x00000040, 0x00000000}, - {0x00000044, 0x00000000}, - {0x00000048, 0x00000008}, - {0x0000004c, 0x00000010}, - {0x00000050, 0x00000000}, - {0x00001040, 0x002ffc0f}, - {0x00001044, 0x002ffc0f}, - {0x00001048, 0x002ffc0f}, - {0x0000104c, 0x002ffc0f}, - {0x00001050, 0x002ffc0f}, - {0x00001054, 0x002ffc0f}, - {0x00001058, 0x002ffc0f}, - {0x0000105c, 0x002ffc0f}, - {0x00001060, 0x002ffc0f}, - {0x00001064, 0x002ffc0f}, - {0x000010f0, 0x00000100}, - {0x00001270, 0x00000000}, - {0x000012b0, 0x00000000}, - {0x000012f0, 0x00000000}, - {0x0000143c, 0x00000000}, - {0x0000147c, 0x00000000}, - {0x00008000, 0x00000000}, - {0x00008004, 0x00000000}, - {0x00008008, 0x00000000}, - {0x0000800c, 0x00000000}, - {0x00008018, 0x00000000}, - {0x00008020, 0x00000000}, - {0x00008038, 0x00000000}, - {0x0000803c, 0x00000000}, - {0x00008040, 0x00000000}, - {0x00008044, 0x00000000}, - {0x00008048, 0x00000000}, - {0x0000804c, 0xffffffff}, - {0x00008054, 0x00000000}, - {0x00008058, 0x00000000}, - {0x0000805c, 0x000fc78f}, - {0x00008060, 0x0000000f}, - {0x00008064, 0x00000000}, - {0x00008070, 0x00000310}, - {0x00008074, 0x00000020}, - {0x00008078, 0x00000000}, - {0x0000809c, 0x0000000f}, - {0x000080a0, 0x00000000}, - {0x000080a4, 0x02ff0000}, - {0x000080a8, 0x0e070605}, - {0x000080ac, 0x0000000d}, - {0x000080b0, 0x00000000}, - {0x000080b4, 0x00000000}, - {0x000080b8, 0x00000000}, - {0x000080bc, 0x00000000}, - {0x000080c0, 0x2a800000}, - {0x000080c4, 0x06900168}, - {0x000080c8, 0x13881c22}, - {0x000080cc, 0x01f40000}, - {0x000080d0, 0x00252500}, - {0x000080d4, 0x00a00000}, - {0x000080d8, 0x00400000}, - {0x000080dc, 0x00000000}, - {0x000080e0, 0xffffffff}, - {0x000080e4, 0x0000ffff}, - {0x000080e8, 0x3f3f3f3f}, - {0x000080ec, 0x00000000}, - {0x000080f0, 0x00000000}, - {0x000080f4, 0x00000000}, - {0x000080fc, 0x00020000}, - {0x00008100, 0x00000000}, - {0x00008108, 0x00000052}, - {0x0000810c, 0x00000000}, - {0x00008110, 0x00000000}, - {0x00008114, 0x000007ff}, - {0x00008118, 0x000000aa}, - {0x0000811c, 0x00003210}, - {0x00008124, 0x00000000}, - {0x00008128, 0x00000000}, - {0x0000812c, 0x00000000}, - {0x00008130, 0x00000000}, - {0x00008134, 0x00000000}, - {0x00008138, 0x00000000}, - {0x0000813c, 0x0000ffff}, - {0x00008144, 0xffffffff}, - {0x00008168, 0x00000000}, - {0x0000816c, 0x00000000}, - {0x00008170, 0x18486200}, - {0x00008174, 0x33332210}, - {0x00008178, 0x00000000}, - {0x0000817c, 0x00020000}, - {0x000081c0, 0x00000000}, - {0x000081c4, 0x33332210}, - {0x000081d4, 0x00000000}, - {0x000081ec, 0x00000000}, - {0x000081f0, 0x00000000}, - {0x000081f4, 0x00000000}, - {0x000081f8, 0x00000000}, - {0x000081fc, 0x00000000}, - {0x00008240, 0x00100000}, - {0x00008244, 0x0010f400}, - {0x00008248, 0x00000800}, - {0x0000824c, 0x0001e800}, - {0x00008250, 0x00000000}, - {0x00008254, 0x00000000}, - {0x00008258, 0x00000000}, - {0x0000825c, 0x40000000}, - {0x00008260, 0x00080922}, - {0x00008264, 0x9ca00010}, - {0x00008268, 0xffffffff}, - {0x0000826c, 0x0000ffff}, - {0x00008270, 0x00000000}, - {0x00008274, 0x40000000}, - {0x00008278, 0x003e4180}, - {0x0000827c, 0x00000004}, - {0x00008284, 0x0000002c}, - {0x00008288, 0x0000002c}, - {0x0000828c, 0x000000ff}, - {0x00008294, 0x00000000}, - {0x00008298, 0x00000000}, - {0x0000829c, 0x00000000}, - {0x00008300, 0x00000140}, - {0x00008314, 0x00000000}, - {0x0000831c, 0x0000010d}, - {0x00008328, 0x00000000}, - {0x0000832c, 0x00000007}, - {0x00008330, 0x00000302}, - {0x00008334, 0x00000700}, - {0x00008338, 0x00ff0000}, - {0x0000833c, 0x02400000}, - {0x00008340, 0x000107ff}, - {0x00008344, 0xa248105b}, - {0x00008348, 0x008f0000}, - {0x0000835c, 0x00000000}, - {0x00008360, 0xffffffff}, - {0x00008364, 0xffffffff}, - {0x00008368, 0x00000000}, - {0x00008370, 0x00000000}, - {0x00008374, 0x000000ff}, - {0x00008378, 0x00000000}, - {0x0000837c, 0x00000000}, - {0x00008380, 0xffffffff}, - {0x00008384, 0xffffffff}, - {0x00008390, 0xffffffff}, - {0x00008394, 0xffffffff}, - {0x00008398, 0x00000000}, - {0x0000839c, 0x00000000}, - {0x000083a0, 0x00000000}, - {0x000083a4, 0x0000fa14}, - {0x000083a8, 0x000f0c00}, - {0x000083ac, 0x33332210}, - {0x000083b0, 0x33332210}, - {0x000083b4, 0x33332210}, - {0x000083b8, 0x33332210}, - {0x000083bc, 0x00000000}, - {0x000083c0, 0x00000000}, - {0x000083c4, 0x00000000}, - {0x000083c8, 0x00000000}, - {0x000083cc, 0x00000200}, - {0x000083d0, 0x000301ff}, -}; +/* AR9485 1.0 */ -static const u32 ar9485_1_1_baseband_core[][2] = { - /* Addr allmodes */ - {0x00009800, 0xafe68e30}, - {0x00009804, 0xfd14e000}, - {0x00009808, 0x9c0a8f6b}, - {0x0000980c, 0x04800000}, - {0x00009814, 0x9280c00a}, - {0x00009818, 0x00000000}, - {0x0000981c, 0x00020028}, - {0x00009834, 0x5f3ca3de}, - {0x00009838, 0x0108ecff}, - {0x0000983c, 0x14750600}, - {0x00009880, 0x201fff00}, - {0x00009884, 0x00001042}, - {0x000098a4, 0x00200400}, - {0x000098b0, 0x52440bbe}, - {0x000098d0, 0x004b6a8e}, - {0x000098d4, 0x00000820}, - {0x000098dc, 0x00000000}, - {0x000098f0, 0x00000000}, - {0x000098f4, 0x00000000}, - {0x00009c04, 0x00000000}, - {0x00009c08, 0x03200000}, - {0x00009c0c, 0x00000000}, - {0x00009c10, 0x00000000}, - {0x00009c14, 0x00046384}, - {0x00009c18, 0x05b6b440}, - {0x00009c1c, 0x00b6b440}, - {0x00009d00, 0xc080a333}, - {0x00009d04, 0x40206c10}, - {0x00009d08, 0x009c4060}, - {0x00009d0c, 0x1883800a}, - {0x00009d10, 0x01834061}, - {0x00009d14, 0x00c00400}, - {0x00009d18, 0x00000000}, - {0x00009d1c, 0x00000000}, - {0x00009e08, 0x0038233c}, - {0x00009e24, 0x9927b515}, - {0x00009e28, 0x12ef0200}, - {0x00009e30, 0x06336f77}, - {0x00009e34, 0x6af6532f}, - {0x00009e38, 0x0cc80c00}, - {0x00009e40, 0x0d261820}, - {0x00009e4c, 0x00001004}, - {0x00009e50, 0x00ff03f1}, - {0x00009fc0, 0x80be4788}, - {0x00009fc4, 0x0001efb5}, - {0x00009fcc, 0x40000014}, - {0x0000a20c, 0x00000000}, - {0x0000a210, 0x00000000}, - {0x0000a220, 0x00000000}, - {0x0000a224, 0x00000000}, - {0x0000a228, 0x10002310}, - {0x0000a23c, 0x00000000}, - {0x0000a244, 0x0c000000}, - {0x0000a2a0, 0x00000001}, - {0x0000a2c0, 0x00000001}, - {0x0000a2c8, 0x00000000}, - {0x0000a2cc, 0x18c43433}, - {0x0000a2d4, 0x00000000}, - {0x0000a2dc, 0x00000000}, - {0x0000a2e0, 0x00000000}, - {0x0000a2e4, 0x00000000}, - {0x0000a2e8, 0x00000000}, - {0x0000a2ec, 0x00000000}, - {0x0000a2f0, 0x00000000}, - {0x0000a2f4, 0x00000000}, - {0x0000a2f8, 0x00000000}, - {0x0000a344, 0x00000000}, - {0x0000a34c, 0x00000000}, - {0x0000a350, 0x0000a000}, - {0x0000a364, 0x00000000}, - {0x0000a370, 0x00000000}, - {0x0000a390, 0x00000001}, - {0x0000a394, 0x00000444}, - {0x0000a398, 0x001f0e0f}, - {0x0000a39c, 0x0075393f}, - {0x0000a3a0, 0xb79f6427}, - {0x0000a3a4, 0x000000ff}, - {0x0000a3a8, 0x3b3b3b3b}, - {0x0000a3ac, 0x2f2f2f2f}, - {0x0000a3c0, 0x20202020}, - {0x0000a3c4, 0x22222220}, - {0x0000a3c8, 0x20200020}, - {0x0000a3cc, 0x20202020}, - {0x0000a3d0, 0x20202020}, - {0x0000a3d4, 0x20202020}, - {0x0000a3d8, 0x20202020}, - {0x0000a3dc, 0x20202020}, - {0x0000a3e0, 0x20202020}, - {0x0000a3e4, 0x20202020}, - {0x0000a3e8, 0x20202020}, - {0x0000a3ec, 0x20202020}, - {0x0000a3f0, 0x00000000}, - {0x0000a3f4, 0x00000006}, - {0x0000a3f8, 0x0cdbd380}, - {0x0000a3fc, 0x000f0f01}, - {0x0000a400, 0x8fa91f01}, - {0x0000a404, 0x00000000}, - {0x0000a408, 0x0e79e5c6}, - {0x0000a40c, 0x00820820}, - {0x0000a414, 0x1ce739cf}, - {0x0000a418, 0x2d0019ce}, - {0x0000a41c, 0x1ce739ce}, - {0x0000a420, 0x000001ce}, - {0x0000a424, 0x1ce739ce}, - {0x0000a428, 0x000001ce}, - {0x0000a42c, 0x1ce739ce}, - {0x0000a430, 0x1ce739ce}, - {0x0000a434, 0x00000000}, - {0x0000a438, 0x00001801}, - {0x0000a43c, 0x00000000}, - {0x0000a440, 0x00000000}, - {0x0000a444, 0x00000000}, - {0x0000a448, 0x04000000}, - {0x0000a44c, 0x00000001}, - {0x0000a450, 0x00010000}, - {0x0000a5c4, 0xbfad9d74}, - {0x0000a5c8, 0x0048060a}, - {0x0000a5cc, 0x00000637}, - {0x0000a760, 0x03020100}, - {0x0000a764, 0x09080504}, - {0x0000a768, 0x0d0c0b0a}, - {0x0000a76c, 0x13121110}, - {0x0000a770, 0x31301514}, - {0x0000a774, 0x35343332}, - {0x0000a778, 0x00000036}, - {0x0000a780, 0x00000838}, - {0x0000a7c0, 0x00000000}, - {0x0000a7c4, 0xfffffffc}, - {0x0000a7c8, 0x00000000}, - {0x0000a7cc, 0x00000000}, - {0x0000a7d0, 0x00000000}, - {0x0000a7d4, 0x00000004}, - {0x0000a7dc, 0x00000000}, -}; +#define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble -static const u32 ar9485Common_1_1[][2] = { - /* Addr allmodes */ - {0x00007010, 0x00000022}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, +static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18012e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000080c}, }; -static const u32 ar9485_1_1_baseband_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, - {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, - {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, - {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, - {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, - {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, - {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, - {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, - {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, - {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, - {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, - {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, - {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, - {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, - {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, - {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, - {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, - {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, - {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, - {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, - {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, - {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, - {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, - {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, - {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, - {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, - {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, - {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, - {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, - {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, - {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, - {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, - {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, - {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982}, - {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, - {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, - {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00060005}, + {0x0000a004, 0x00810080}, + {0x0000a008, 0x00830082}, + {0x0000a00c, 0x00850084}, + {0x0000a010, 0x01820181}, + {0x0000a014, 0x01840183}, + {0x0000a018, 0x01880185}, + {0x0000a01c, 0x018a0189}, + {0x0000a020, 0x02850284}, + {0x0000a024, 0x02890288}, + {0x0000a028, 0x028b028a}, + {0x0000a02c, 0x03850384}, + {0x0000a030, 0x03890388}, + {0x0000a034, 0x038b038a}, + {0x0000a038, 0x038d038c}, + {0x0000a03c, 0x03910390}, + {0x0000a040, 0x03930392}, + {0x0000a044, 0x03950394}, + {0x0000a048, 0x00000396}, + {0x0000a04c, 0x00000000}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x28282828}, + {0x0000a084, 0x28282828}, + {0x0000a088, 0x28282828}, + {0x0000a08c, 0x28282828}, + {0x0000a090, 0x28282828}, + {0x0000a094, 0x24242428}, + {0x0000a098, 0x171e1e1e}, + {0x0000a09c, 0x02020b0b}, + {0x0000a0a0, 0x02020202}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x22072208}, + {0x0000a0c4, 0x22052206}, + {0x0000a0c8, 0x22032204}, + {0x0000a0cc, 0x22012202}, + {0x0000a0d0, 0x221f2200}, + {0x0000a0d4, 0x221d221e}, + {0x0000a0d8, 0x33023303}, + {0x0000a0dc, 0x33003301}, + {0x0000a0e0, 0x331e331f}, + {0x0000a0e4, 0x4402331d}, + {0x0000a0e8, 0x44004401}, + {0x0000a0ec, 0x441e441f}, + {0x0000a0f0, 0x55025503}, + {0x0000a0f4, 0x55005501}, + {0x0000a0f8, 0x551e551f}, + {0x0000a0fc, 0x6602551d}, + {0x0000a100, 0x66006601}, + {0x0000a104, 0x661e661f}, + {0x0000a108, 0x7703661d}, + {0x0000a10c, 0x77017702}, + {0x0000a110, 0x00007700}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x111f1100}, + {0x0000a148, 0x111d111e}, + {0x0000a14c, 0x111b111c}, + {0x0000a150, 0x22032204}, + {0x0000a154, 0x22012202}, + {0x0000a158, 0x221f2200}, + {0x0000a15c, 0x221d221e}, + {0x0000a160, 0x33013302}, + {0x0000a164, 0x331f3300}, + {0x0000a168, 0x4402331e}, + {0x0000a16c, 0x44004401}, + {0x0000a170, 0x441e441f}, + {0x0000a174, 0x55015502}, + {0x0000a178, 0x551f5500}, + {0x0000a17c, 0x6602551e}, + {0x0000a180, 0x66006601}, + {0x0000a184, 0x661e661f}, + {0x0000a188, 0x7703661d}, + {0x0000a18c, 0x77017702}, + {0x0000a190, 0x00007700}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000296}, }; -static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ +static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, @@ -442,102 +234,34 @@ static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = { {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, }; -static const u32 ar9485_modes_lowest_ob_db_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, - {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, -}; +#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1 -static const u32 ar9485_1_1_radio_postamble[][2] = { - /* Addr allmodes */ - {0x0001609c, 0x0b283f31}, - {0x000160ac, 0x24611800}, - {0x000160b0, 0x03284f3e}, - {0x0001610c, 0x00170000}, - {0x00016140, 0x50804008}, -}; +#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1 -static const u32 ar9485_1_1_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +#define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1 + +static const u32 ar9485_1_1[][2] = { + /* Addr allmodes */ + {0x0000a580, 0x00000000}, + {0x0000a584, 0x00000000}, + {0x0000a588, 0x00000000}, + {0x0000a58c, 0x00000000}, + {0x0000a590, 0x00000000}, + {0x0000a594, 0x00000000}, + {0x0000a598, 0x00000000}, + {0x0000a59c, 0x00000000}, + {0x0000a5a0, 0x00000000}, + {0x0000a5a4, 0x00000000}, + {0x0000a5a8, 0x00000000}, + {0x0000a5ac, 0x00000000}, + {0x0000a5b0, 0x00000000}, + {0x0000a5b4, 0x00000000}, + {0x0000a5b8, 0x00000000}, + {0x0000a5bc, 0x00000000}, }; static const u32 ar9485_1_1_radio_core[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00016000, 0x36db6db6}, {0x00016004, 0x6db6db40}, {0x00016008, 0x73800000}, @@ -601,294 +325,145 @@ static const u32 ar9485_1_1_radio_core[][2] = { {0x00016c44, 0x12000000}, }; -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18052e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; - -static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, - {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, -}; - -static const u32 ar9485_1_1[][2] = { - /* Addr allmodes */ - {0x0000a580, 0x00000000}, - {0x0000a584, 0x00000000}, - {0x0000a588, 0x00000000}, - {0x0000a58c, 0x00000000}, - {0x0000a590, 0x00000000}, - {0x0000a594, 0x00000000}, - {0x0000a598, 0x00000000}, - {0x0000a59c, 0x00000000}, - {0x0000a5a0, 0x00000000}, - {0x0000a5a4, 0x00000000}, - {0x0000a5a8, 0x00000000}, - {0x0000a5ac, 0x00000000}, - {0x0000a5b0, 0x00000000}, - {0x0000a5b4, 0x00000000}, - {0x0000a5b8, 0x00000000}, - {0x0000a5bc, 0x00000000}, -}; - -static const u32 ar9485_modes_green_ob_db_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000003, 0x00000003, 0x00000003, 0x00000003}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a458, 0x80000000, 0x80000000, 0x80000000, 0x80000000}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000006, 0x00000006}, - {0x0000a504, 0x05062002, 0x05062002, 0x03000201, 0x03000201}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x06000203, 0x06000203}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0a000401, 0x0a000401}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x0e000403, 0x0e000403}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x12000405, 0x12000405}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x15000604, 0x15000604}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x18000605, 0x18000605}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x1c000a04, 0x1c000a04}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x21000a06, 0x21000a06}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x29000a24, 0x29000a24}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2f000e21, 0x2f000e21}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x31000e20, 0x31000e20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x33000e20, 0x33000e20}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000b500, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b504, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b508, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b50c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b510, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b514, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b518, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b51c, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b520, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b524, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b528, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a}, - {0x0000b52c, 0x0000002a, 0x0000002a, 0x0000002a, 0x0000002a}, - {0x0000b530, 0x0000003a, 0x0000003a, 0x0000003a, 0x0000003a}, - {0x0000b534, 0x0000004a, 0x0000004a, 0x0000004a, 0x0000004a}, - {0x0000b538, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b53c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b540, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b544, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b548, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b54c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b550, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b554, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b558, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b55c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b560, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b564, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b568, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b56c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b570, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b574, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b578, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x0000b57c, 0x0000005b, 0x0000005b, 0x0000005b, 0x0000005b}, - {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, - {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, -}; - -static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18013e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, -}; - -static const u32 ar9485_1_1_soc_preamble[][2] = { - /* Addr allmodes */ - {0x00004014, 0xba280400}, - {0x00004090, 0x00aa10aa}, - {0x000040a4, 0x00a0c9c9}, - {0x00007010, 0x00000022}, - {0x00007020, 0x00000000}, - {0x00007034, 0x00000002}, - {0x00007038, 0x000004c2}, - {0x00007048, 0x00000002}, -}; - -static const u32 ar9485_1_1_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; - -static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8}, - {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000}, - {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002}, - {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004}, - {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200}, - {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202}, - {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400}, - {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402}, - {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404}, - {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603}, - {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605}, - {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03}, - {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04}, - {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20}, - {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21}, - {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62}, - {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63}, - {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65}, - {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66}, - {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645}, - {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865}, - {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86}, - {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9}, - {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb}, - {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb}, - {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb}, - {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db}, - {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260}, -}; - -static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { - /* Addr 5G_HT2 5G_HT40 */ - {0x00009e00, 0x03721821, 0x03721821}, - {0x0000a230, 0x0000400b, 0x00004016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; - -static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = { - /* Addr allmodes */ - {0x00018c00, 0x18012e5e}, - {0x00018c04, 0x000801d8}, - {0x00018c08, 0x0000080c}, +static const u32 ar9485_1_1_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a8f6b}, + {0x0000980c, 0x04800000}, + {0x00009814, 0x9280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x5f3ca3de}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14750600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x52440bbe}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0x00000000}, + {0x00009c08, 0x03200000}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x1883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c00400}, + {0x00009d18, 0x00000000}, + {0x00009d1c, 0x00000000}, + {0x00009e08, 0x0038233c}, + {0x00009e24, 0x9927b515}, + {0x00009e28, 0x12ef0200}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x80be4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x0000a20c, 0x00000000}, + {0x0000a210, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a2a0, 0x00000001}, + {0x0000a2c0, 0x00000001}, + {0x0000a2c8, 0x00000000}, + {0x0000a2cc, 0x18c43433}, + {0x0000a2d4, 0x00000000}, + {0x0000a2dc, 0x00000000}, + {0x0000a2e0, 0x00000000}, + {0x0000a2e4, 0x00000000}, + {0x0000a2e8, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x001f0e0f}, + {0x0000a39c, 0x0075393f}, + {0x0000a3a0, 0xb79f6427}, + {0x0000a3a4, 0x000000ff}, + {0x0000a3a8, 0x3b3b3b3b}, + {0x0000a3ac, 0x2f2f2f2f}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000006}, + {0x0000a3f8, 0x0cdbd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739cf}, + {0x0000a418, 0x2d0019ce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00000000}, + {0x0000a440, 0x00000000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x04000000}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a5c4, 0xbfad9d74}, + {0x0000a5c8, 0x0048060a}, + {0x0000a5cc, 0x00000637}, + {0x0000a760, 0x03020100}, + {0x0000a764, 0x09080504}, + {0x0000a768, 0x0d0c0b0a}, + {0x0000a76c, 0x13121110}, + {0x0000a770, 0x31301514}, + {0x0000a774, 0x35343332}, + {0x0000a778, 0x00000036}, + {0x0000a780, 0x00000838}, + {0x0000a7c0, 0x00000000}, + {0x0000a7c4, 0xfffffffc}, + {0x0000a7c8, 0x00000000}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, }; static const u32 ar9485_common_rx_gain_1_1[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x0000a000, 0x00010000}, {0x0000a004, 0x00030002}, {0x0000a008, 0x00050004}, @@ -1019,143 +594,260 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = { {0x0000a1fc, 0x00000296}, }; +static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_enable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18052e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000080c}, +}; + static const u32 ar9485_1_1_pcie_phy_clkreq_enable_L1[][2] = { - /* Addr allmodes */ + /* Addr allmodes */ {0x00018c00, 0x18053e5e}, {0x00018c04, 0x000801d8}, {0x00018c08, 0x0000080c}, }; -static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00060005}, - {0x0000a004, 0x00810080}, - {0x0000a008, 0x00830082}, - {0x0000a00c, 0x00850084}, - {0x0000a010, 0x01820181}, - {0x0000a014, 0x01840183}, - {0x0000a018, 0x01880185}, - {0x0000a01c, 0x018a0189}, - {0x0000a020, 0x02850284}, - {0x0000a024, 0x02890288}, - {0x0000a028, 0x028b028a}, - {0x0000a02c, 0x03850384}, - {0x0000a030, 0x03890388}, - {0x0000a034, 0x038b038a}, - {0x0000a038, 0x038d038c}, - {0x0000a03c, 0x03910390}, - {0x0000a040, 0x03930392}, - {0x0000a044, 0x03950394}, - {0x0000a048, 0x00000396}, - {0x0000a04c, 0x00000000}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x28282828}, - {0x0000a084, 0x28282828}, - {0x0000a088, 0x28282828}, - {0x0000a08c, 0x28282828}, - {0x0000a090, 0x28282828}, - {0x0000a094, 0x24242428}, - {0x0000a098, 0x171e1e1e}, - {0x0000a09c, 0x02020b0b}, - {0x0000a0a0, 0x02020202}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x22072208}, - {0x0000a0c4, 0x22052206}, - {0x0000a0c8, 0x22032204}, - {0x0000a0cc, 0x22012202}, - {0x0000a0d0, 0x221f2200}, - {0x0000a0d4, 0x221d221e}, - {0x0000a0d8, 0x33023303}, - {0x0000a0dc, 0x33003301}, - {0x0000a0e0, 0x331e331f}, - {0x0000a0e4, 0x4402331d}, - {0x0000a0e8, 0x44004401}, - {0x0000a0ec, 0x441e441f}, - {0x0000a0f0, 0x55025503}, - {0x0000a0f4, 0x55005501}, - {0x0000a0f8, 0x551e551f}, - {0x0000a0fc, 0x6602551d}, - {0x0000a100, 0x66006601}, - {0x0000a104, 0x661e661f}, - {0x0000a108, 0x7703661d}, - {0x0000a10c, 0x77017702}, - {0x0000a110, 0x00007700}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x111f1100}, - {0x0000a148, 0x111d111e}, - {0x0000a14c, 0x111b111c}, - {0x0000a150, 0x22032204}, - {0x0000a154, 0x22012202}, - {0x0000a158, 0x221f2200}, - {0x0000a15c, 0x221d221e}, - {0x0000a160, 0x33013302}, - {0x0000a164, 0x331f3300}, - {0x0000a168, 0x4402331e}, - {0x0000a16c, 0x44004401}, - {0x0000a170, 0x441e441f}, - {0x0000a174, 0x55015502}, - {0x0000a178, 0x551f5500}, - {0x0000a17c, 0x6602551e}, - {0x0000a180, 0x66006601}, - {0x0000a184, 0x661e661f}, - {0x0000a188, 0x7703661d}, - {0x0000a18c, 0x77017702}, - {0x0000a190, 0x00007700}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000296}, +static const u32 ar9485_1_1_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00004014, 0xba280400}, + {0x00004090, 0x00aa10aa}, + {0x000040a4, 0x00a0c9c9}, + {0x00007010, 0x00000022}, + {0x00007020, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, + {0x00007048, 0x00000002}, +}; + +static const u32 ar9485_fast_clock_1_1_baseband_postamble[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00009e00, 0x03721821, 0x03721821}, + {0x0000a230, 0x0000400b, 0x00004016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +static const u32 ar9485_1_1_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8005, 0xd00a8005}, + {0x00009820, 0x206a002e, 0x206a002e, 0x206a002e, 0x206a002e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c}, + {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044}, + {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e}, + {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222}, + {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b}, + {0x0000a234, 0x10000fff, 0x10000fff, 0x10000fff, 0x10000fff}, + {0x0000a238, 0xffb81018, 0xffb81018, 0xffb81018, 0xffb81018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x3a021501, 0x3a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x000002a0, 0x000002a0}, + {0x0000a288, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a28c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2d0, 0x00071981, 0x00071981, 0x00071982, 0x00071982}, + {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0xf999a83a, 0xf999a83a}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be04, 0x00802020, 0x00802020, 0x00802020, 0x00802020}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, +}; + +static const u32 ar9485_1_1_pcie_phy_clkreq_disable_L1[][2] = { + /* Addr allmodes */ + {0x00018c00, 0x18013e5e}, + {0x00018c04, 0x000801d8}, + {0x00018c08, 0x0000080c}, +}; + +static const u32 ar9485_1_1_radio_postamble[][2] = { + /* Addr allmodes */ + {0x0001609c, 0x0b283f31}, + {0x000160ac, 0x24611800}, + {0x000160b0, 0x03284f3e}, + {0x0001610c, 0x00170000}, + {0x00016140, 0x50804008}, +}; + +static const u32 ar9485_1_1_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c22}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x00008170, 0x18486200}, + {0x00008174, 0x33332210}, + {0x00008178, 0x00000000}, + {0x0000817c, 0x00020000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081d4, 0x00000000}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9ca00010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00000140}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x00000007}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0x00ff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xa248105b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x000301ff}, }; -#endif +#endif /* INITVALS_9485_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h new file mode 100644 index 000000000000..df97f21c52dc --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h @@ -0,0 +1,1284 @@ +/* + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef INITVALS_955X_1P0_H +#define INITVALS_955X_1P0_H + +/* AR955X 1.0 */ + +static const u32 ar955x_1p0_radio_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xd28b3330, 0xd28b3330}, + {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x06345f2a, 0x06345f2a}, + {0x000160ac, 0xa4647c00, 0xa4647c00, 0xa4646800, 0xa4646800}, + {0x000160b0, 0x01885f52, 0x01885f52, 0x04accf3a, 0x04accf3a}, + {0x00016104, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x0001610c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, + {0x00016140, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, + {0x00016504, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x0001650c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, + {0x00016540, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, + {0x00016904, 0xb7a00001, 0xb7a00001, 0xb7a00001, 0xb7a00001}, + {0x0001690c, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000}, + {0x00016940, 0x10804008, 0x10804008, 0x10804008, 0x10804008}, +}; + +static const u32 ar955x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { + /* Addr allmodes */ + {0x0000a398, 0x00000000}, + {0x0000a39c, 0x6f7f0301}, + {0x0000a3a0, 0xca9228ee}, +}; + +static const u32 ar955x_1p0_baseband_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011}, + {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e}, + {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0}, + {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881}, + {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4}, + {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c}, + {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4}, + {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0}, + {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020}, + {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2}, + {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e}, + {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e}, + {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c}, + {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce}, + {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021}, + {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822}, + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, + {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000}, + {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0}, + {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004}, + {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f}, + {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b}, + {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff}, + {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018}, + {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108}, + {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898}, + {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002}, + {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01000e0e, 0x01000e0e}, + {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501}, + {0x0000a264, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e}, + {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b}, + {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110}, + {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222}, + {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18}, + {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33}, + {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982}, + {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b}, + {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, + {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000}, + {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c}, + {0x0000be20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce}, + {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010}, +}; + +static const u32 ar955x_1p0_radio_core[][2] = { + /* Addr allmodes */ + {0x00016000, 0x36db6db6}, + {0x00016004, 0x6db6db40}, + {0x00016008, 0x73f00000}, + {0x0001600c, 0x00000000}, + {0x00016040, 0x7f80fff8}, + {0x0001604c, 0x76d005b5}, + {0x00016050, 0x557cf031}, + {0x00016054, 0x13449440}, + {0x00016058, 0x0c51c92c}, + {0x0001605c, 0x3db7fffc}, + {0x00016060, 0xfffffffc}, + {0x00016064, 0x000f0278}, + {0x00016068, 0x6db6db6c}, + {0x0001606c, 0x6db60000}, + {0x00016080, 0x00080000}, + {0x00016084, 0x0e48048c}, + {0x00016088, 0x14214514}, + {0x0001608c, 0x119f101e}, + {0x00016090, 0x24926490}, + {0x00016094, 0x00000000}, + {0x000160a0, 0x0a108ffe}, + {0x000160a4, 0x812fc370}, + {0x000160a8, 0x423c8000}, + {0x000160b4, 0x92480080}, + {0x000160c0, 0x006db6d0}, + {0x000160c4, 0x6db6db60}, + {0x000160c8, 0x6db6db6c}, + {0x000160cc, 0x01e6c000}, + {0x00016100, 0x11999601}, + {0x00016108, 0x00080010}, + {0x00016144, 0x02084080}, + {0x00016148, 0x000080c0}, + {0x00016280, 0x01800804}, + {0x00016284, 0x00038dc5}, + {0x00016288, 0x00000000}, + {0x0001628c, 0x00000040}, + {0x00016380, 0x00000000}, + {0x00016384, 0x00000000}, + {0x00016388, 0x00400705}, + {0x0001638c, 0x00800700}, + {0x00016390, 0x00800700}, + {0x00016394, 0x00000000}, + {0x00016398, 0x00000000}, + {0x0001639c, 0x00000000}, + {0x000163a0, 0x00000001}, + {0x000163a4, 0x00000001}, + {0x000163a8, 0x00000000}, + {0x000163ac, 0x00000000}, + {0x000163b0, 0x00000000}, + {0x000163b4, 0x00000000}, + {0x000163b8, 0x00000000}, + {0x000163bc, 0x00000000}, + {0x000163c0, 0x000000a0}, + {0x000163c4, 0x000c0000}, + {0x000163c8, 0x14021402}, + {0x000163cc, 0x00001402}, + {0x000163d0, 0x00000000}, + {0x000163d4, 0x00000000}, + {0x00016400, 0x36db6db6}, + {0x00016404, 0x6db6db40}, + {0x00016408, 0x73f00000}, + {0x0001640c, 0x00000000}, + {0x00016440, 0x7f80fff8}, + {0x0001644c, 0x76d005b5}, + {0x00016450, 0x557cf031}, + {0x00016454, 0x13449440}, + {0x00016458, 0x0c51c92c}, + {0x0001645c, 0x3db7fffc}, + {0x00016460, 0xfffffffc}, + {0x00016464, 0x000f0278}, + {0x00016468, 0x6db6db6c}, + {0x0001646c, 0x6db60000}, + {0x00016500, 0x11999601}, + {0x00016508, 0x00080010}, + {0x00016544, 0x02084080}, + {0x00016548, 0x000080c0}, + {0x00016780, 0x00000000}, + {0x00016784, 0x00000000}, + {0x00016788, 0x00400705}, + {0x0001678c, 0x00800700}, + {0x00016790, 0x00800700}, + {0x00016794, 0x00000000}, + {0x00016798, 0x00000000}, + {0x0001679c, 0x00000000}, + {0x000167a0, 0x00000001}, + {0x000167a4, 0x00000001}, + {0x000167a8, 0x00000000}, + {0x000167ac, 0x00000000}, + {0x000167b0, 0x00000000}, + {0x000167b4, 0x00000000}, + {0x000167b8, 0x00000000}, + {0x000167bc, 0x00000000}, + {0x000167c0, 0x000000a0}, + {0x000167c4, 0x000c0000}, + {0x000167c8, 0x14021402}, + {0x000167cc, 0x00001402}, + {0x000167d0, 0x00000000}, + {0x000167d4, 0x00000000}, + {0x00016800, 0x36db6db6}, + {0x00016804, 0x6db6db40}, + {0x00016808, 0x73f00000}, + {0x0001680c, 0x00000000}, + {0x00016840, 0x7f80fff8}, + {0x0001684c, 0x76d005b5}, + {0x00016850, 0x557cf031}, + {0x00016854, 0x13449440}, + {0x00016858, 0x0c51c92c}, + {0x0001685c, 0x3db7fffc}, + {0x00016860, 0xfffffffc}, + {0x00016864, 0x000f0278}, + {0x00016868, 0x6db6db6c}, + {0x0001686c, 0x6db60000}, + {0x00016900, 0x11999601}, + {0x00016908, 0x00080010}, + {0x00016944, 0x02084080}, + {0x00016948, 0x000080c0}, + {0x00016b80, 0x00000000}, + {0x00016b84, 0x00000000}, + {0x00016b88, 0x00400705}, + {0x00016b8c, 0x00800700}, + {0x00016b90, 0x00800700}, + {0x00016b94, 0x00000000}, + {0x00016b98, 0x00000000}, + {0x00016b9c, 0x00000000}, + {0x00016ba0, 0x00000001}, + {0x00016ba4, 0x00000001}, + {0x00016ba8, 0x00000000}, + {0x00016bac, 0x00000000}, + {0x00016bb0, 0x00000000}, + {0x00016bb4, 0x00000000}, + {0x00016bb8, 0x00000000}, + {0x00016bbc, 0x00000000}, + {0x00016bc0, 0x000000a0}, + {0x00016bc4, 0x000c0000}, + {0x00016bc8, 0x14021402}, + {0x00016bcc, 0x00001402}, + {0x00016bd0, 0x00000000}, + {0x00016bd4, 0x00000000}, +}; + +static const u32 ar955x_1p0_modes_xpa_tx_gain_table[][9] = { + /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000a2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000a2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000a2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, + {0x0000a410, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050de, 0x000050da, 0x000050da}, + {0x0000a500, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000000, 0x00000000}, + {0x0000a504, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000005, 0x04000002, 0x04000002}, + {0x0000a508, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000009, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c00000b, 0x0c000006, 0x0c000006}, + {0x0000a510, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x1000000d, 0x0f00000a, 0x0f00000a}, + {0x0000a514, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x14000011, 0x1300000c, 0x1300000c}, + {0x0000a518, 0x19004008, 0x19004008, 0x19004008, 0x19004008, 0x18004008, 0x18004008, 0x1700000e, 0x1700000e}, + {0x0000a51c, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1d00400a, 0x1c00400a, 0x1c00400a, 0x1b000064, 0x1b000064}, + {0x0000a520, 0x230020a2, 0x230020a2, 0x210020a2, 0x210020a2, 0x200020a2, 0x200020a2, 0x1f000242, 0x1f000242}, + {0x0000a524, 0x2500006e, 0x2500006e, 0x2500006e, 0x2500006e, 0x2400006e, 0x2400006e, 0x23000229, 0x23000229}, + {0x0000a528, 0x29022221, 0x29022221, 0x28022221, 0x28022221, 0x27022221, 0x27022221, 0x270002a2, 0x270002a2}, + {0x0000a52c, 0x2d00062a, 0x2d00062a, 0x2c00062a, 0x2c00062a, 0x2a00062a, 0x2a00062a, 0x2c001203, 0x2c001203}, + {0x0000a530, 0x340220a5, 0x340220a5, 0x320220a5, 0x320220a5, 0x2f0220a5, 0x2f0220a5, 0x30001803, 0x30001803}, + {0x0000a534, 0x380022c5, 0x380022c5, 0x350022c5, 0x350022c5, 0x320022c5, 0x320022c5, 0x33000881, 0x33000881}, + {0x0000a538, 0x3b002486, 0x3b002486, 0x39002486, 0x39002486, 0x36002486, 0x36002486, 0x38001809, 0x38001809}, + {0x0000a53c, 0x3f00248a, 0x3f00248a, 0x3d00248a, 0x3d00248a, 0x3a00248a, 0x3a00248a, 0x3a000814, 0x3a000814}, + {0x0000a540, 0x4202242c, 0x4202242c, 0x4102242c, 0x4102242c, 0x3f02242c, 0x3f02242c, 0x3f001a0c, 0x3f001a0c}, + {0x0000a544, 0x490044c6, 0x490044c6, 0x460044c6, 0x460044c6, 0x420044c6, 0x420044c6, 0x43001a0e, 0x43001a0e}, + {0x0000a548, 0x4d024485, 0x4d024485, 0x4a024485, 0x4a024485, 0x46024485, 0x46024485, 0x46001812, 0x46001812}, + {0x0000a54c, 0x51044483, 0x51044483, 0x4e044483, 0x4e044483, 0x4a044483, 0x4a044483, 0x49001884, 0x49001884}, + {0x0000a550, 0x5404a40c, 0x5404a40c, 0x5204a40c, 0x5204a40c, 0x4d04a40c, 0x4d04a40c, 0x4d001e84, 0x4d001e84}, + {0x0000a554, 0x57024632, 0x57024632, 0x55024632, 0x55024632, 0x52024632, 0x52024632, 0x50001e69, 0x50001e69}, + {0x0000a558, 0x5c00a634, 0x5c00a634, 0x5900a634, 0x5900a634, 0x5600a634, 0x5600a634, 0x550006f4, 0x550006f4}, + {0x0000a55c, 0x5f026832, 0x5f026832, 0x5d026832, 0x5d026832, 0x5a026832, 0x5a026832, 0x59000ad3, 0x59000ad3}, + {0x0000a560, 0x6602b012, 0x6602b012, 0x6202b012, 0x6202b012, 0x5d02b012, 0x5d02b012, 0x5e000ad5, 0x5e000ad5}, + {0x0000a564, 0x6e02d0e1, 0x6e02d0e1, 0x6802d0e1, 0x6802d0e1, 0x6002d0e1, 0x6002d0e1, 0x61001ced, 0x61001ced}, + {0x0000a568, 0x7202b4c4, 0x7202b4c4, 0x6c02b4c4, 0x6c02b4c4, 0x6502b4c4, 0x6502b4c4, 0x660018d4, 0x660018d4}, + {0x0000a56c, 0x75007894, 0x75007894, 0x70007894, 0x70007894, 0x6b007894, 0x6b007894, 0x660018d4, 0x660018d4}, + {0x0000a570, 0x7b025c74, 0x7b025c74, 0x75025c74, 0x75025c74, 0x70025c74, 0x70025c74, 0x660018d4, 0x660018d4}, + {0x0000a574, 0x8300bcb5, 0x8300bcb5, 0x7a00bcb5, 0x7a00bcb5, 0x7600bcb5, 0x7600bcb5, 0x660018d4, 0x660018d4}, + {0x0000a578, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, + {0x0000a57c, 0x8a04dc74, 0x8a04dc74, 0x7f04dc74, 0x7f04dc74, 0x7c04dc74, 0x7c04dc74, 0x660018d4, 0x660018d4}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x03804000, 0x03804000}, + {0x0000a610, 0x04c08c01, 0x04c08c01, 0x04808b01, 0x04808b01, 0x04808a01, 0x04808a01, 0x0300ca02, 0x0300ca02}, + {0x0000a614, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00000e04, 0x00000e04}, + {0x0000a618, 0x04010c01, 0x04010c01, 0x03c10b01, 0x03c10b01, 0x03810a01, 0x03810a01, 0x03014000, 0x03014000}, + {0x0000a61c, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x00000000, 0x00000000}, + {0x0000a620, 0x04010303, 0x04010303, 0x03c10303, 0x03c10303, 0x03810303, 0x03810303, 0x00000000, 0x00000000}, + {0x0000a624, 0x03814e05, 0x03814e05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03414d05, 0x03014000, 0x03014000}, + {0x0000a628, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x00c0c000, 0x03804c05, 0x03804c05}, + {0x0000a62c, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x00c0c303, 0x0701de06, 0x0701de06}, + {0x0000a630, 0x03418000, 0x03418000, 0x03018000, 0x03018000, 0x02c18000, 0x02c18000, 0x07819c07, 0x07819c07}, + {0x0000a634, 0x03815004, 0x03815004, 0x03414f04, 0x03414f04, 0x03414e04, 0x03414e04, 0x0701dc07, 0x0701dc07}, + {0x0000a638, 0x03005302, 0x03005302, 0x02c05202, 0x02c05202, 0x02805202, 0x02805202, 0x0701dc07, 0x0701dc07}, + {0x0000a63c, 0x04c09302, 0x04c09302, 0x04809202, 0x04809202, 0x04809202, 0x04809202, 0x0701dc07, 0x0701dc07}, + {0x0000b2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000b2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000b2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000b2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, + {0x0000c2dc, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xffffaaaa, 0xfffd5aaa, 0xfffd5aaa}, + {0x0000c2e0, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xffffcccc, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000c2e4, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xfffff0f0, 0xffffe0f0, 0xffffe0f0}, + {0x0000c2e8, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xfffcff00, 0xfffcff00}, + {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, + {0x00016048, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, + {0x00016280, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01801e84, 0x01808e84, 0x01808e84}, + {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, + {0x00016448, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, + {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x010002d4, 0x010002d4}, + {0x00016848, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x62482401, 0x66482401, 0x66482401}, +}; + +static const u32 ar955x_1p0_mac_core[][2] = { + /* Addr allmodes */ + {0x00000008, 0x00000000}, + {0x00000030, 0x00020085}, + {0x00000034, 0x00000005}, + {0x00000040, 0x00000000}, + {0x00000044, 0x00000000}, + {0x00000048, 0x00000008}, + {0x0000004c, 0x00000010}, + {0x00000050, 0x00000000}, + {0x00001040, 0x002ffc0f}, + {0x00001044, 0x002ffc0f}, + {0x00001048, 0x002ffc0f}, + {0x0000104c, 0x002ffc0f}, + {0x00001050, 0x002ffc0f}, + {0x00001054, 0x002ffc0f}, + {0x00001058, 0x002ffc0f}, + {0x0000105c, 0x002ffc0f}, + {0x00001060, 0x002ffc0f}, + {0x00001064, 0x002ffc0f}, + {0x000010f0, 0x00000100}, + {0x00001270, 0x00000000}, + {0x000012b0, 0x00000000}, + {0x000012f0, 0x00000000}, + {0x0000143c, 0x00000000}, + {0x0000147c, 0x00000000}, + {0x00008000, 0x00000000}, + {0x00008004, 0x00000000}, + {0x00008008, 0x00000000}, + {0x0000800c, 0x00000000}, + {0x00008018, 0x00000000}, + {0x00008020, 0x00000000}, + {0x00008038, 0x00000000}, + {0x0000803c, 0x00000000}, + {0x00008040, 0x00000000}, + {0x00008044, 0x00000000}, + {0x00008048, 0x00000000}, + {0x0000804c, 0xffffffff}, + {0x00008054, 0x00000000}, + {0x00008058, 0x00000000}, + {0x0000805c, 0x000fc78f}, + {0x00008060, 0x0000000f}, + {0x00008064, 0x00000000}, + {0x00008070, 0x00000310}, + {0x00008074, 0x00000020}, + {0x00008078, 0x00000000}, + {0x0000809c, 0x0000000f}, + {0x000080a0, 0x00000000}, + {0x000080a4, 0x02ff0000}, + {0x000080a8, 0x0e070605}, + {0x000080ac, 0x0000000d}, + {0x000080b0, 0x00000000}, + {0x000080b4, 0x00000000}, + {0x000080b8, 0x00000000}, + {0x000080bc, 0x00000000}, + {0x000080c0, 0x2a800000}, + {0x000080c4, 0x06900168}, + {0x000080c8, 0x13881c22}, + {0x000080cc, 0x01f40000}, + {0x000080d0, 0x00252500}, + {0x000080d4, 0x00a00000}, + {0x000080d8, 0x00400000}, + {0x000080dc, 0x00000000}, + {0x000080e0, 0xffffffff}, + {0x000080e4, 0x0000ffff}, + {0x000080e8, 0x3f3f3f3f}, + {0x000080ec, 0x00000000}, + {0x000080f0, 0x00000000}, + {0x000080f4, 0x00000000}, + {0x000080fc, 0x00020000}, + {0x00008100, 0x00000000}, + {0x00008108, 0x00000052}, + {0x0000810c, 0x00000000}, + {0x00008110, 0x00000000}, + {0x00008114, 0x000007ff}, + {0x00008118, 0x000000aa}, + {0x0000811c, 0x00003210}, + {0x00008124, 0x00000000}, + {0x00008128, 0x00000000}, + {0x0000812c, 0x00000000}, + {0x00008130, 0x00000000}, + {0x00008134, 0x00000000}, + {0x00008138, 0x00000000}, + {0x0000813c, 0x0000ffff}, + {0x00008140, 0x000000fe}, + {0x00008144, 0xffffffff}, + {0x00008168, 0x00000000}, + {0x0000816c, 0x00000000}, + {0x000081c0, 0x00000000}, + {0x000081c4, 0x33332210}, + {0x000081ec, 0x00000000}, + {0x000081f0, 0x00000000}, + {0x000081f4, 0x00000000}, + {0x000081f8, 0x00000000}, + {0x000081fc, 0x00000000}, + {0x00008240, 0x00100000}, + {0x00008244, 0x0010f400}, + {0x00008248, 0x00000800}, + {0x0000824c, 0x0001e800}, + {0x00008250, 0x00000000}, + {0x00008254, 0x00000000}, + {0x00008258, 0x00000000}, + {0x0000825c, 0x40000000}, + {0x00008260, 0x00080922}, + {0x00008264, 0x9d400010}, + {0x00008268, 0xffffffff}, + {0x0000826c, 0x0000ffff}, + {0x00008270, 0x00000000}, + {0x00008274, 0x40000000}, + {0x00008278, 0x003e4180}, + {0x0000827c, 0x00000004}, + {0x00008284, 0x0000002c}, + {0x00008288, 0x0000002c}, + {0x0000828c, 0x000000ff}, + {0x00008294, 0x00000000}, + {0x00008298, 0x00000000}, + {0x0000829c, 0x00000000}, + {0x00008300, 0x00001d40}, + {0x00008314, 0x00000000}, + {0x0000831c, 0x0000010d}, + {0x00008328, 0x00000000}, + {0x0000832c, 0x0000001f}, + {0x00008330, 0x00000302}, + {0x00008334, 0x00000700}, + {0x00008338, 0xffff0000}, + {0x0000833c, 0x02400000}, + {0x00008340, 0x000107ff}, + {0x00008344, 0xaa48107b}, + {0x00008348, 0x008f0000}, + {0x0000835c, 0x00000000}, + {0x00008360, 0xffffffff}, + {0x00008364, 0xffffffff}, + {0x00008368, 0x00000000}, + {0x00008370, 0x00000000}, + {0x00008374, 0x000000ff}, + {0x00008378, 0x00000000}, + {0x0000837c, 0x00000000}, + {0x00008380, 0xffffffff}, + {0x00008384, 0xffffffff}, + {0x00008390, 0xffffffff}, + {0x00008394, 0xffffffff}, + {0x00008398, 0x00000000}, + {0x0000839c, 0x00000000}, + {0x000083a0, 0x00000000}, + {0x000083a4, 0x0000fa14}, + {0x000083a8, 0x000f0c00}, + {0x000083ac, 0x33332210}, + {0x000083b0, 0x33332210}, + {0x000083b4, 0x33332210}, + {0x000083b8, 0x33332210}, + {0x000083bc, 0x00000000}, + {0x000083c0, 0x00000000}, + {0x000083c4, 0x00000000}, + {0x000083c8, 0x00000000}, + {0x000083cc, 0x00000200}, + {0x000083d0, 0x8c7901ff}, +}; + +static const u32 ar955x_1p0_common_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x01910190}, + {0x0000a030, 0x01930192}, + {0x0000a034, 0x01950194}, + {0x0000a038, 0x038a0196}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x22222229}, + {0x0000a084, 0x1d1d1d1d}, + {0x0000a088, 0x1d1d1d1d}, + {0x0000a08c, 0x1d1d1d1d}, + {0x0000a090, 0x171d1d1d}, + {0x0000a094, 0x11111717}, + {0x0000a098, 0x00030311}, + {0x0000a09c, 0x00000000}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x23232323}, + {0x0000b084, 0x21232323}, + {0x0000b088, 0x19191c1e}, + {0x0000b08c, 0x12141417}, + {0x0000b090, 0x07070e0e}, + {0x0000b094, 0x03030305}, + {0x0000b098, 0x00000003}, + {0x0000b09c, 0x00000000}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar955x_1p0_baseband_core[][2] = { + /* Addr allmodes */ + {0x00009800, 0xafe68e30}, + {0x00009804, 0xfd14e000}, + {0x00009808, 0x9c0a9f6b}, + {0x0000980c, 0x04900000}, + {0x00009814, 0x0280c00a}, + {0x00009818, 0x00000000}, + {0x0000981c, 0x00020028}, + {0x00009834, 0x6400a190}, + {0x00009838, 0x0108ecff}, + {0x0000983c, 0x14000600}, + {0x00009880, 0x201fff00}, + {0x00009884, 0x00001042}, + {0x000098a4, 0x00200400}, + {0x000098b0, 0x32840bbe}, + {0x000098bc, 0x00000002}, + {0x000098d0, 0x004b6a8e}, + {0x000098d4, 0x00000820}, + {0x000098dc, 0x00000000}, + {0x000098f0, 0x00000000}, + {0x000098f4, 0x00000000}, + {0x00009c04, 0xff55ff55}, + {0x00009c08, 0x0320ff55}, + {0x00009c0c, 0x00000000}, + {0x00009c10, 0x00000000}, + {0x00009c14, 0x00046384}, + {0x00009c18, 0x05b6b440}, + {0x00009c1c, 0x00b6b440}, + {0x00009d00, 0xc080a333}, + {0x00009d04, 0x40206c10}, + {0x00009d08, 0x009c4060}, + {0x00009d0c, 0x9883800a}, + {0x00009d10, 0x01834061}, + {0x00009d14, 0x00c0040b}, + {0x00009d18, 0x00000000}, + {0x00009e08, 0x0038230c}, + {0x00009e24, 0x990bb515}, + {0x00009e28, 0x0c6f0000}, + {0x00009e30, 0x06336f77}, + {0x00009e34, 0x6af6532f}, + {0x00009e38, 0x0cc80c00}, + {0x00009e40, 0x0d261820}, + {0x00009e4c, 0x00001004}, + {0x00009e50, 0x00ff03f1}, + {0x00009fc0, 0x813e4788}, + {0x00009fc4, 0x0001efb5}, + {0x00009fcc, 0x40000014}, + {0x00009fd0, 0x01193b93}, + {0x0000a20c, 0x00000000}, + {0x0000a220, 0x00000000}, + {0x0000a224, 0x00000000}, + {0x0000a228, 0x10002310}, + {0x0000a23c, 0x00000000}, + {0x0000a244, 0x0c000000}, + {0x0000a248, 0x00000140}, + {0x0000a2a0, 0x00000007}, + {0x0000a2c0, 0x00000007}, + {0x0000a2c8, 0x00000000}, + {0x0000a2d4, 0x00000000}, + {0x0000a2ec, 0x00000000}, + {0x0000a2f0, 0x00000000}, + {0x0000a2f4, 0x00000000}, + {0x0000a2f8, 0x00000000}, + {0x0000a344, 0x00000000}, + {0x0000a34c, 0x00000000}, + {0x0000a350, 0x0000a000}, + {0x0000a364, 0x00000000}, + {0x0000a370, 0x00000000}, + {0x0000a390, 0x00000001}, + {0x0000a394, 0x00000444}, + {0x0000a398, 0x1f020503}, + {0x0000a39c, 0x29180c03}, + {0x0000a3a0, 0x9a8b6844}, + {0x0000a3a4, 0x00000000}, + {0x0000a3a8, 0xaaaaaaaa}, + {0x0000a3ac, 0x3c466478}, + {0x0000a3c0, 0x20202020}, + {0x0000a3c4, 0x22222220}, + {0x0000a3c8, 0x20200020}, + {0x0000a3cc, 0x20202020}, + {0x0000a3d0, 0x20202020}, + {0x0000a3d4, 0x20202020}, + {0x0000a3d8, 0x20202020}, + {0x0000a3dc, 0x20202020}, + {0x0000a3e0, 0x20202020}, + {0x0000a3e4, 0x20202020}, + {0x0000a3e8, 0x20202020}, + {0x0000a3ec, 0x20202020}, + {0x0000a3f0, 0x00000000}, + {0x0000a3f4, 0x00000000}, + {0x0000a3f8, 0x0c9bd380}, + {0x0000a3fc, 0x000f0f01}, + {0x0000a400, 0x8fa91f01}, + {0x0000a404, 0x00000000}, + {0x0000a408, 0x0e79e5c6}, + {0x0000a40c, 0x00820820}, + {0x0000a414, 0x1ce739ce}, + {0x0000a418, 0x2d001dce}, + {0x0000a41c, 0x1ce739ce}, + {0x0000a420, 0x000001ce}, + {0x0000a424, 0x1ce739ce}, + {0x0000a428, 0x000001ce}, + {0x0000a42c, 0x1ce739ce}, + {0x0000a430, 0x1ce739ce}, + {0x0000a434, 0x00000000}, + {0x0000a438, 0x00001801}, + {0x0000a43c, 0x00100000}, + {0x0000a444, 0x00000000}, + {0x0000a448, 0x05000080}, + {0x0000a44c, 0x00000001}, + {0x0000a450, 0x00010000}, + {0x0000a458, 0x00000000}, + {0x0000a644, 0x3fad9d74}, + {0x0000a648, 0x0048060a}, + {0x0000a64c, 0x00003c37}, + {0x0000a670, 0x03020100}, + {0x0000a674, 0x09080504}, + {0x0000a678, 0x0d0c0b0a}, + {0x0000a67c, 0x13121110}, + {0x0000a680, 0x31301514}, + {0x0000a684, 0x35343332}, + {0x0000a688, 0x00000036}, + {0x0000a690, 0x00000838}, + {0x0000a7cc, 0x00000000}, + {0x0000a7d0, 0x00000000}, + {0x0000a7d4, 0x00000004}, + {0x0000a7dc, 0x00000000}, + {0x0000a8d0, 0x004b6a8e}, + {0x0000a8d4, 0x00000820}, + {0x0000a8dc, 0x00000000}, + {0x0000a8f0, 0x00000000}, + {0x0000a8f4, 0x00000000}, + {0x0000b2d0, 0x00000080}, + {0x0000b2d4, 0x00000000}, + {0x0000b2ec, 0x00000000}, + {0x0000b2f0, 0x00000000}, + {0x0000b2f4, 0x00000000}, + {0x0000b2f8, 0x00000000}, + {0x0000b408, 0x0e79e5c0}, + {0x0000b40c, 0x00820820}, + {0x0000b420, 0x00000000}, + {0x0000b8d0, 0x004b6a8e}, + {0x0000b8d4, 0x00000820}, + {0x0000b8dc, 0x00000000}, + {0x0000b8f0, 0x00000000}, + {0x0000b8f4, 0x00000000}, + {0x0000c2d0, 0x00000080}, + {0x0000c2d4, 0x00000000}, + {0x0000c2ec, 0x00000000}, + {0x0000c2f0, 0x00000000}, + {0x0000c2f4, 0x00000000}, + {0x0000c2f8, 0x00000000}, + {0x0000c408, 0x0e79e5c0}, + {0x0000c40c, 0x00820820}, + {0x0000c420, 0x00000000}, +}; + +static const u32 ar955x_1p0_common_wo_xlna_rx_gain_table[][2] = { + /* Addr allmodes */ + {0x0000a000, 0x00010000}, + {0x0000a004, 0x00030002}, + {0x0000a008, 0x00050004}, + {0x0000a00c, 0x00810080}, + {0x0000a010, 0x00830082}, + {0x0000a014, 0x01810180}, + {0x0000a018, 0x01830182}, + {0x0000a01c, 0x01850184}, + {0x0000a020, 0x01890188}, + {0x0000a024, 0x018b018a}, + {0x0000a028, 0x018d018c}, + {0x0000a02c, 0x03820190}, + {0x0000a030, 0x03840383}, + {0x0000a034, 0x03880385}, + {0x0000a038, 0x038a0389}, + {0x0000a03c, 0x038c038b}, + {0x0000a040, 0x0390038d}, + {0x0000a044, 0x03920391}, + {0x0000a048, 0x03940393}, + {0x0000a04c, 0x03960395}, + {0x0000a050, 0x00000000}, + {0x0000a054, 0x00000000}, + {0x0000a058, 0x00000000}, + {0x0000a05c, 0x00000000}, + {0x0000a060, 0x00000000}, + {0x0000a064, 0x00000000}, + {0x0000a068, 0x00000000}, + {0x0000a06c, 0x00000000}, + {0x0000a070, 0x00000000}, + {0x0000a074, 0x00000000}, + {0x0000a078, 0x00000000}, + {0x0000a07c, 0x00000000}, + {0x0000a080, 0x29292929}, + {0x0000a084, 0x29292929}, + {0x0000a088, 0x29292929}, + {0x0000a08c, 0x29292929}, + {0x0000a090, 0x22292929}, + {0x0000a094, 0x1d1d2222}, + {0x0000a098, 0x0c111117}, + {0x0000a09c, 0x00030303}, + {0x0000a0a0, 0x00000000}, + {0x0000a0a4, 0x00000000}, + {0x0000a0a8, 0x00000000}, + {0x0000a0ac, 0x00000000}, + {0x0000a0b0, 0x00000000}, + {0x0000a0b4, 0x00000000}, + {0x0000a0b8, 0x00000000}, + {0x0000a0bc, 0x00000000}, + {0x0000a0c0, 0x001f0000}, + {0x0000a0c4, 0x01000101}, + {0x0000a0c8, 0x011e011f}, + {0x0000a0cc, 0x011c011d}, + {0x0000a0d0, 0x02030204}, + {0x0000a0d4, 0x02010202}, + {0x0000a0d8, 0x021f0200}, + {0x0000a0dc, 0x0302021e}, + {0x0000a0e0, 0x03000301}, + {0x0000a0e4, 0x031e031f}, + {0x0000a0e8, 0x0402031d}, + {0x0000a0ec, 0x04000401}, + {0x0000a0f0, 0x041e041f}, + {0x0000a0f4, 0x0502041d}, + {0x0000a0f8, 0x05000501}, + {0x0000a0fc, 0x051e051f}, + {0x0000a100, 0x06010602}, + {0x0000a104, 0x061f0600}, + {0x0000a108, 0x061d061e}, + {0x0000a10c, 0x07020703}, + {0x0000a110, 0x07000701}, + {0x0000a114, 0x00000000}, + {0x0000a118, 0x00000000}, + {0x0000a11c, 0x00000000}, + {0x0000a120, 0x00000000}, + {0x0000a124, 0x00000000}, + {0x0000a128, 0x00000000}, + {0x0000a12c, 0x00000000}, + {0x0000a130, 0x00000000}, + {0x0000a134, 0x00000000}, + {0x0000a138, 0x00000000}, + {0x0000a13c, 0x00000000}, + {0x0000a140, 0x001f0000}, + {0x0000a144, 0x01000101}, + {0x0000a148, 0x011e011f}, + {0x0000a14c, 0x011c011d}, + {0x0000a150, 0x02030204}, + {0x0000a154, 0x02010202}, + {0x0000a158, 0x021f0200}, + {0x0000a15c, 0x0302021e}, + {0x0000a160, 0x03000301}, + {0x0000a164, 0x031e031f}, + {0x0000a168, 0x0402031d}, + {0x0000a16c, 0x04000401}, + {0x0000a170, 0x041e041f}, + {0x0000a174, 0x0502041d}, + {0x0000a178, 0x05000501}, + {0x0000a17c, 0x051e051f}, + {0x0000a180, 0x06010602}, + {0x0000a184, 0x061f0600}, + {0x0000a188, 0x061d061e}, + {0x0000a18c, 0x07020703}, + {0x0000a190, 0x07000701}, + {0x0000a194, 0x00000000}, + {0x0000a198, 0x00000000}, + {0x0000a19c, 0x00000000}, + {0x0000a1a0, 0x00000000}, + {0x0000a1a4, 0x00000000}, + {0x0000a1a8, 0x00000000}, + {0x0000a1ac, 0x00000000}, + {0x0000a1b0, 0x00000000}, + {0x0000a1b4, 0x00000000}, + {0x0000a1b8, 0x00000000}, + {0x0000a1bc, 0x00000000}, + {0x0000a1c0, 0x00000000}, + {0x0000a1c4, 0x00000000}, + {0x0000a1c8, 0x00000000}, + {0x0000a1cc, 0x00000000}, + {0x0000a1d0, 0x00000000}, + {0x0000a1d4, 0x00000000}, + {0x0000a1d8, 0x00000000}, + {0x0000a1dc, 0x00000000}, + {0x0000a1e0, 0x00000000}, + {0x0000a1e4, 0x00000000}, + {0x0000a1e8, 0x00000000}, + {0x0000a1ec, 0x00000000}, + {0x0000a1f0, 0x00000396}, + {0x0000a1f4, 0x00000396}, + {0x0000a1f8, 0x00000396}, + {0x0000a1fc, 0x00000196}, + {0x0000b000, 0x00010000}, + {0x0000b004, 0x00030002}, + {0x0000b008, 0x00050004}, + {0x0000b00c, 0x00810080}, + {0x0000b010, 0x00830082}, + {0x0000b014, 0x01810180}, + {0x0000b018, 0x01830182}, + {0x0000b01c, 0x01850184}, + {0x0000b020, 0x02810280}, + {0x0000b024, 0x02830282}, + {0x0000b028, 0x02850284}, + {0x0000b02c, 0x02890288}, + {0x0000b030, 0x028b028a}, + {0x0000b034, 0x0388028c}, + {0x0000b038, 0x038a0389}, + {0x0000b03c, 0x038c038b}, + {0x0000b040, 0x0390038d}, + {0x0000b044, 0x03920391}, + {0x0000b048, 0x03940393}, + {0x0000b04c, 0x03960395}, + {0x0000b050, 0x00000000}, + {0x0000b054, 0x00000000}, + {0x0000b058, 0x00000000}, + {0x0000b05c, 0x00000000}, + {0x0000b060, 0x00000000}, + {0x0000b064, 0x00000000}, + {0x0000b068, 0x00000000}, + {0x0000b06c, 0x00000000}, + {0x0000b070, 0x00000000}, + {0x0000b074, 0x00000000}, + {0x0000b078, 0x00000000}, + {0x0000b07c, 0x00000000}, + {0x0000b080, 0x32323232}, + {0x0000b084, 0x2f2f3232}, + {0x0000b088, 0x23282a2d}, + {0x0000b08c, 0x1c1e2123}, + {0x0000b090, 0x14171919}, + {0x0000b094, 0x0e0e1214}, + {0x0000b098, 0x03050707}, + {0x0000b09c, 0x00030303}, + {0x0000b0a0, 0x00000000}, + {0x0000b0a4, 0x00000000}, + {0x0000b0a8, 0x00000000}, + {0x0000b0ac, 0x00000000}, + {0x0000b0b0, 0x00000000}, + {0x0000b0b4, 0x00000000}, + {0x0000b0b8, 0x00000000}, + {0x0000b0bc, 0x00000000}, + {0x0000b0c0, 0x003f0020}, + {0x0000b0c4, 0x00400041}, + {0x0000b0c8, 0x0140005f}, + {0x0000b0cc, 0x0160015f}, + {0x0000b0d0, 0x017e017f}, + {0x0000b0d4, 0x02410242}, + {0x0000b0d8, 0x025f0240}, + {0x0000b0dc, 0x027f0260}, + {0x0000b0e0, 0x0341027e}, + {0x0000b0e4, 0x035f0340}, + {0x0000b0e8, 0x037f0360}, + {0x0000b0ec, 0x04400441}, + {0x0000b0f0, 0x0460045f}, + {0x0000b0f4, 0x0541047f}, + {0x0000b0f8, 0x055f0540}, + {0x0000b0fc, 0x057f0560}, + {0x0000b100, 0x06400641}, + {0x0000b104, 0x0660065f}, + {0x0000b108, 0x067e067f}, + {0x0000b10c, 0x07410742}, + {0x0000b110, 0x075f0740}, + {0x0000b114, 0x077f0760}, + {0x0000b118, 0x07800781}, + {0x0000b11c, 0x07a0079f}, + {0x0000b120, 0x07c107bf}, + {0x0000b124, 0x000007c0}, + {0x0000b128, 0x00000000}, + {0x0000b12c, 0x00000000}, + {0x0000b130, 0x00000000}, + {0x0000b134, 0x00000000}, + {0x0000b138, 0x00000000}, + {0x0000b13c, 0x00000000}, + {0x0000b140, 0x003f0020}, + {0x0000b144, 0x00400041}, + {0x0000b148, 0x0140005f}, + {0x0000b14c, 0x0160015f}, + {0x0000b150, 0x017e017f}, + {0x0000b154, 0x02410242}, + {0x0000b158, 0x025f0240}, + {0x0000b15c, 0x027f0260}, + {0x0000b160, 0x0341027e}, + {0x0000b164, 0x035f0340}, + {0x0000b168, 0x037f0360}, + {0x0000b16c, 0x04400441}, + {0x0000b170, 0x0460045f}, + {0x0000b174, 0x0541047f}, + {0x0000b178, 0x055f0540}, + {0x0000b17c, 0x057f0560}, + {0x0000b180, 0x06400641}, + {0x0000b184, 0x0660065f}, + {0x0000b188, 0x067e067f}, + {0x0000b18c, 0x07410742}, + {0x0000b190, 0x075f0740}, + {0x0000b194, 0x077f0760}, + {0x0000b198, 0x07800781}, + {0x0000b19c, 0x07a0079f}, + {0x0000b1a0, 0x07c107bf}, + {0x0000b1a4, 0x000007c0}, + {0x0000b1a8, 0x00000000}, + {0x0000b1ac, 0x00000000}, + {0x0000b1b0, 0x00000000}, + {0x0000b1b4, 0x00000000}, + {0x0000b1b8, 0x00000000}, + {0x0000b1bc, 0x00000000}, + {0x0000b1c0, 0x00000000}, + {0x0000b1c4, 0x00000000}, + {0x0000b1c8, 0x00000000}, + {0x0000b1cc, 0x00000000}, + {0x0000b1d0, 0x00000000}, + {0x0000b1d4, 0x00000000}, + {0x0000b1d8, 0x00000000}, + {0x0000b1dc, 0x00000000}, + {0x0000b1e0, 0x00000000}, + {0x0000b1e4, 0x00000000}, + {0x0000b1e8, 0x00000000}, + {0x0000b1ec, 0x00000000}, + {0x0000b1f0, 0x00000396}, + {0x0000b1f4, 0x00000396}, + {0x0000b1f8, 0x00000396}, + {0x0000b1fc, 0x00000196}, +}; + +static const u32 ar955x_1p0_soc_preamble[][2] = { + /* Addr allmodes */ + {0x00007000, 0x00000000}, + {0x00007004, 0x00000000}, + {0x00007008, 0x00000000}, + {0x0000700c, 0x00000000}, + {0x0000701c, 0x00000000}, + {0x00007020, 0x00000000}, + {0x00007024, 0x00000000}, + {0x00007028, 0x00000000}, + {0x0000702c, 0x00000000}, + {0x00007030, 0x00000000}, + {0x00007034, 0x00000002}, + {0x00007038, 0x000004c2}, + {0x00007048, 0x00000000}, +}; + +static const u32 ar955x_1p0_common_wo_xlna_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012}, +}; + +static const u32 ar955x_1p0_mac_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, + {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, + {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, + {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, + {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, + {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, + {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, + {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, +}; + +static const u32 ar955x_1p0_common_rx_gain_bounds[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27}, + {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018}, +}; + +static const u32 ar955x_1p0_modes_no_xpa_tx_gain_table[][9] = { + /* Addr 5G_HT20_L 5G_HT40_L 5G_HT20_M 5G_HT40_M 5G_HT20_H 5G_HT40_H 2G_HT40 2G_HT20 */ + {0x0000a2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, + {0x0000a2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, + {0x0000a2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, + {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d8, 0x000050d7, 0x000050d7}, + {0x0000a500, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, + {0x0000a504, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, + {0x0000a508, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, + {0x0000a50c, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0d002621, 0x0b000006, 0x0b000006}, + {0x0000a510, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x13004620, 0x0f00000a, 0x0f00000a}, + {0x0000a514, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x19004a20, 0x1300000c, 0x1300000c}, + {0x0000a518, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1d004e20, 0x1700000e, 0x1700000e}, + {0x0000a51c, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x21005420, 0x1b000012, 0x1b000012}, + {0x0000a520, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x26005e20, 0x1f00004a, 0x1f00004a}, + {0x0000a524, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x2b005e40, 0x23000244, 0x23000244}, + {0x0000a528, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2f005e42, 0x2700022b, 0x2700022b}, + {0x0000a52c, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x33005e44, 0x2b000625, 0x2b000625}, + {0x0000a530, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x38005e65, 0x2f001006, 0x2f001006}, + {0x0000a534, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x3c005e69, 0x330008a0, 0x330008a0}, + {0x0000a538, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x40005e6b, 0x37000a2a, 0x37000a2a}, + {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x44005e6d, 0x3b001c23, 0x3b001c23}, + {0x0000a540, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x49005e72, 0x3f0014a0, 0x3f0014a0}, + {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x4e005eb2, 0x43001882, 0x43001882}, + {0x0000a548, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x53005f12, 0x47001ca2, 0x47001ca2}, + {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x59025eb2, 0x4b001ec3, 0x4b001ec3}, + {0x0000a550, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x5e025f12, 0x4f00148c, 0x4f00148c}, + {0x0000a554, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x61027f12, 0x53001c6e, 0x53001c6e}, + {0x0000a558, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x6702bf12, 0x57001c92, 0x57001c92}, + {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x6b02bf14, 0x5c001af6, 0x5c001af6}, + {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x6f02bf16, 0x5c001af6, 0x5c001af6}, + {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, + {0x0000a610, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x00804000, 0x04005001, 0x04005001}, + {0x0000a614, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x00804201, 0x03808e02, 0x03808e02}, + {0x0000a618, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0280c802, 0x0300c000, 0x0300c000}, + {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x0280ca03, 0x03808e02, 0x03808e02}, + {0x0000a620, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x04c15104, 0x03410c03, 0x03410c03}, + {0x0000a624, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04014c03, 0x04014c03}, + {0x0000a628, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x05818d04, 0x05818d04}, + {0x0000a62c, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801cd04, 0x0801cd04}, + {0x0000a630, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, + {0x0000a634, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, + {0x0000a638, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, + {0x0000a63c, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x04c15305, 0x0801e007, 0x0801e007}, + {0x0000b2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, + {0x0000b2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, + {0x0000b2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, + {0x0000c2dc, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0x01feee00, 0xfffe5aaa, 0xfffe5aaa}, + {0x0000c2e0, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0x0000f000, 0xfffe9ccc, 0xfffe9ccc}, + {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0x01ff0000, 0xffffe0f0, 0xffffe0f0}, + {0x0000c2e8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffef00, 0xffffef00}, + {0x00016044, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, + {0x00016048, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, + {0x00016444, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, + {0x00016448, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, + {0x00016844, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x056db2d4, 0x054922d4, 0x054922d4}, + {0x00016848, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401, 0x66482401}, +}; + +static const u32 ar955x_1p0_soc_postamble[][5] = { + /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ + {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, +}; + +static const u32 ar955x_1p0_modes_fast_clock[][3] = { + /* Addr 5G_HT20 5G_HT40 */ + {0x00001030, 0x00000268, 0x000004d0}, + {0x00001070, 0x0000018c, 0x00000318}, + {0x000010b0, 0x00000fd0, 0x00001fa0}, + {0x00008014, 0x044c044c, 0x08980898}, + {0x0000801c, 0x148ec02b, 0x148ec057}, + {0x00008318, 0x000044c0, 0x00008980}, + {0x00009e00, 0x0372131c, 0x0372131c}, + {0x0000a230, 0x0000000b, 0x00000016}, + {0x0000a254, 0x00000898, 0x00001130}, +}; + +#endif /* INITVALS_955X_1P0_H */ diff --git a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h index 06b3f0df9fad..6e1915aee712 100644 --- a/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9580_1p0_initvals.h @@ -1,5 +1,6 @@ /* - * Copyright (c) 2010 Atheros Communications Inc. + * Copyright (c) 2010-2011 Atheros Communications Inc. + * Copyright (c) 2011-2012 Qualcomm Atheros Inc. * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -19,18 +20,7 @@ /* AR9580 1.0 */ -static const u32 ar9580_1p0_modes_fast_clock[][3] = { - /* Addr 5G_HT20 5G_HT40 */ - {0x00001030, 0x00000268, 0x000004d0}, - {0x00001070, 0x0000018c, 0x00000318}, - {0x000010b0, 0x00000fd0, 0x00001fa0}, - {0x00008014, 0x044c044c, 0x08980898}, - {0x0000801c, 0x148ec02b, 0x148ec057}, - {0x00008318, 0x000044c0, 0x00008980}, - {0x00009e00, 0x0372131c, 0x0372131c}, - {0x0000a230, 0x0000000b, 0x00000016}, - {0x0000a254, 0x00000898, 0x00001130}, -}; +#define ar9580_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2 static const u32 ar9580_1p0_radio_postamble[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ @@ -208,17 +198,7 @@ static const u32 ar9580_1p0_baseband_core[][2] = { {0x0000c420, 0x00000000}, }; -static const u32 ar9580_1p0_mac_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, - {0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c}, - {0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38}, - {0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00}, - {0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b}, - {0x00008120, 0x08f04800, 0x08f04800, 0x08f04810, 0x08f04810}, - {0x000081d0, 0x00003210, 0x00003210, 0x0000320a, 0x0000320a}, - {0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440}, -}; +#define ar9580_1p0_mac_postamble ar9300_2p2_mac_postamble static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ @@ -326,111 +306,7 @@ static const u32 ar9580_1p0_low_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -static const u32 ar9580_1p0_high_power_tx_gain_table[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a504, 0x06000003, 0x06000003, 0x04000002, 0x04000002}, - {0x0000a508, 0x0a000020, 0x0a000020, 0x08000004, 0x08000004}, - {0x0000a50c, 0x10000023, 0x10000023, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x16000220, 0x16000220, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x1c000223, 0x1c000223, 0x12000400, 0x12000400}, - {0x0000a518, 0x21002220, 0x21002220, 0x16000402, 0x16000402}, - {0x0000a51c, 0x27002223, 0x27002223, 0x19000404, 0x19000404}, - {0x0000a520, 0x2b022220, 0x2b022220, 0x1c000603, 0x1c000603}, - {0x0000a524, 0x2f022222, 0x2f022222, 0x21000a02, 0x21000a02}, - {0x0000a528, 0x34022225, 0x34022225, 0x25000a04, 0x25000a04}, - {0x0000a52c, 0x3a02222a, 0x3a02222a, 0x28000a20, 0x28000a20}, - {0x0000a530, 0x3e02222c, 0x3e02222c, 0x2c000e20, 0x2c000e20}, - {0x0000a534, 0x4202242a, 0x4202242a, 0x30000e22, 0x30000e22}, - {0x0000a538, 0x4702244a, 0x4702244a, 0x34000e24, 0x34000e24}, - {0x0000a53c, 0x4b02244c, 0x4b02244c, 0x38001640, 0x38001640}, - {0x0000a540, 0x4e02246c, 0x4e02246c, 0x3c001660, 0x3c001660}, - {0x0000a544, 0x5302266c, 0x5302266c, 0x3f001861, 0x3f001861}, - {0x0000a548, 0x5702286c, 0x5702286c, 0x43001a81, 0x43001a81}, - {0x0000a54c, 0x5c02486b, 0x5c02486b, 0x47001a83, 0x47001a83}, - {0x0000a550, 0x61024a6c, 0x61024a6c, 0x4a001c84, 0x4a001c84}, - {0x0000a554, 0x66026a6c, 0x66026a6c, 0x4e001ce3, 0x4e001ce3}, - {0x0000a558, 0x6b026e6c, 0x6b026e6c, 0x52001ce5, 0x52001ce5}, - {0x0000a55c, 0x7002708c, 0x7002708c, 0x56001ce9, 0x56001ce9}, - {0x0000a560, 0x7302b08a, 0x7302b08a, 0x5a001ceb, 0x5a001ceb}, - {0x0000a564, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a568, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a56c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a570, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a574, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a578, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a57c, 0x7702b08c, 0x7702b08c, 0x5d001eec, 0x5d001eec}, - {0x0000a580, 0x00800000, 0x00800000, 0x00800000, 0x00800000}, - {0x0000a584, 0x06800003, 0x06800003, 0x04800002, 0x04800002}, - {0x0000a588, 0x0a800020, 0x0a800020, 0x08800004, 0x08800004}, - {0x0000a58c, 0x10800023, 0x10800023, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x16800220, 0x16800220, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x1c800223, 0x1c800223, 0x12800400, 0x12800400}, - {0x0000a598, 0x21802220, 0x21802220, 0x16800402, 0x16800402}, - {0x0000a59c, 0x27802223, 0x27802223, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x2b822220, 0x2b822220, 0x1c800603, 0x1c800603}, - {0x0000a5a4, 0x2f822222, 0x2f822222, 0x21800a02, 0x21800a02}, - {0x0000a5a8, 0x34822225, 0x34822225, 0x25800a04, 0x25800a04}, - {0x0000a5ac, 0x3a82222a, 0x3a82222a, 0x28800a20, 0x28800a20}, - {0x0000a5b0, 0x3e82222c, 0x3e82222c, 0x2c800e20, 0x2c800e20}, - {0x0000a5b4, 0x4282242a, 0x4282242a, 0x30800e22, 0x30800e22}, - {0x0000a5b8, 0x4782244a, 0x4782244a, 0x34800e24, 0x34800e24}, - {0x0000a5bc, 0x4b82244c, 0x4b82244c, 0x38801640, 0x38801640}, - {0x0000a5c0, 0x4e82246c, 0x4e82246c, 0x3c801660, 0x3c801660}, - {0x0000a5c4, 0x5382266c, 0x5382266c, 0x3f801861, 0x3f801861}, - {0x0000a5c8, 0x5782286c, 0x5782286c, 0x43801a81, 0x43801a81}, - {0x0000a5cc, 0x5c82486b, 0x5c82486b, 0x47801a83, 0x47801a83}, - {0x0000a5d0, 0x61824a6c, 0x61824a6c, 0x4a801c84, 0x4a801c84}, - {0x0000a5d4, 0x66826a6c, 0x66826a6c, 0x4e801ce3, 0x4e801ce3}, - {0x0000a5d8, 0x6b826e6c, 0x6b826e6c, 0x52801ce5, 0x52801ce5}, - {0x0000a5dc, 0x7082708c, 0x7082708c, 0x56801ce9, 0x56801ce9}, - {0x0000a5e0, 0x7382b08a, 0x7382b08a, 0x5a801ceb, 0x5a801ceb}, - {0x0000a5e4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5e8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5ec, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f0, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f4, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5f8, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a5fc, 0x7782b08c, 0x7782b08c, 0x5d801eec, 0x5d801eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a614, 0x01404000, 0x01404000, 0x01404000, 0x01404000}, - {0x0000a618, 0x01404501, 0x01404501, 0x01404501, 0x01404501}, - {0x0000a61c, 0x02008802, 0x02008802, 0x02008501, 0x02008501}, - {0x0000a620, 0x0300cc03, 0x0300cc03, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x0300cc03, 0x0300cc03, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x0300cc03, 0x0300cc03, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x03810c03, 0x03810c03, 0x04015005, 0x04015005}, - {0x0000a630, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a634, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a638, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000a63c, 0x03810e04, 0x03810e04, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x0380c7fc, 0x0380c7fc, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0000f800, 0x0000f800, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x03ff0000, 0x03ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016048, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, - {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016444, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016448, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, - {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016844, 0x012492d4, 0x012492d4, 0x012492d4, 0x012492d4}, - {0x00016848, 0x66480001, 0x66480001, 0x66480001, 0x66480001}, - {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -}; +#define ar9580_1p0_high_power_tx_gain_table ar9580_1p0_low_ob_db_tx_gain_table static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ @@ -538,12 +414,7 @@ static const u32 ar9580_1p0_lowest_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -static const u32 ar9580_1p0_baseband_core_txfir_coeff_japan_2484[][2] = { - /* Addr allmodes */ - {0x0000a398, 0x00000000}, - {0x0000a39c, 0x6f7f0301}, - {0x0000a3a0, 0xca9228ee}, -}; +#define ar9580_1p0_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484 static const u32 ar9580_1p0_mac_core[][2] = { /* Addr allmodes */ @@ -808,376 +679,11 @@ static const u32 ar9580_1p0_mixed_ob_db_tx_gain_table[][5] = { {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, }; -static const u32 ar9580_1p0_wo_xlna_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x03820190}, - {0x0000a030, 0x03840383}, - {0x0000a034, 0x03880385}, - {0x0000a038, 0x038a0389}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x29292929}, - {0x0000a084, 0x29292929}, - {0x0000a088, 0x29292929}, - {0x0000a08c, 0x29292929}, - {0x0000a090, 0x22292929}, - {0x0000a094, 0x1d1d2222}, - {0x0000a098, 0x0c111117}, - {0x0000a09c, 0x00030303}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x32323232}, - {0x0000b084, 0x2f2f3232}, - {0x0000b088, 0x23282a2d}, - {0x0000b08c, 0x1c1e2123}, - {0x0000b090, 0x14171919}, - {0x0000b094, 0x0e0e1214}, - {0x0000b098, 0x03050707}, - {0x0000b09c, 0x00030303}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; +#define ar9580_1p0_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2 -static const u32 ar9580_1p0_soc_postamble[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x00007010, 0x00000023, 0x00000023, 0x00000023, 0x00000023}, -}; +#define ar9580_1p0_soc_postamble ar9300_2p2_soc_postamble -static const u32 ar9580_1p0_high_ob_db_tx_gain_table[][5] = { - /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ - {0x0000a2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000a2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000a2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000a2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000a410, 0x000050d8, 0x000050d8, 0x000050d9, 0x000050d9}, - {0x0000a500, 0x00002220, 0x00002220, 0x00000000, 0x00000000}, - {0x0000a504, 0x04002222, 0x04002222, 0x04000002, 0x04000002}, - {0x0000a508, 0x09002421, 0x09002421, 0x08000004, 0x08000004}, - {0x0000a50c, 0x0d002621, 0x0d002621, 0x0b000200, 0x0b000200}, - {0x0000a510, 0x13004620, 0x13004620, 0x0f000202, 0x0f000202}, - {0x0000a514, 0x19004a20, 0x19004a20, 0x11000400, 0x11000400}, - {0x0000a518, 0x1d004e20, 0x1d004e20, 0x15000402, 0x15000402}, - {0x0000a51c, 0x21005420, 0x21005420, 0x19000404, 0x19000404}, - {0x0000a520, 0x26005e20, 0x26005e20, 0x1b000603, 0x1b000603}, - {0x0000a524, 0x2b005e40, 0x2b005e40, 0x1f000a02, 0x1f000a02}, - {0x0000a528, 0x2f005e42, 0x2f005e42, 0x23000a04, 0x23000a04}, - {0x0000a52c, 0x33005e44, 0x33005e44, 0x26000a20, 0x26000a20}, - {0x0000a530, 0x38005e65, 0x38005e65, 0x2a000e20, 0x2a000e20}, - {0x0000a534, 0x3c005e69, 0x3c005e69, 0x2e000e22, 0x2e000e22}, - {0x0000a538, 0x40005e6b, 0x40005e6b, 0x31000e24, 0x31000e24}, - {0x0000a53c, 0x44005e6d, 0x44005e6d, 0x34001640, 0x34001640}, - {0x0000a540, 0x49005e72, 0x49005e72, 0x38001660, 0x38001660}, - {0x0000a544, 0x4e005eb2, 0x4e005eb2, 0x3b001861, 0x3b001861}, - {0x0000a548, 0x53005f12, 0x53005f12, 0x3e001a81, 0x3e001a81}, - {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83}, - {0x0000a550, 0x5e025f12, 0x5e025f12, 0x44001c84, 0x44001c84}, - {0x0000a554, 0x61027f12, 0x61027f12, 0x48001ce3, 0x48001ce3}, - {0x0000a558, 0x6702bf12, 0x6702bf12, 0x4c001ce5, 0x4c001ce5}, - {0x0000a55c, 0x6b02bf14, 0x6b02bf14, 0x50001ce9, 0x50001ce9}, - {0x0000a560, 0x6f02bf16, 0x6f02bf16, 0x54001ceb, 0x54001ceb}, - {0x0000a564, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a568, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a56c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a570, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a574, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a578, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a57c, 0x6f02bf16, 0x6f02bf16, 0x56001eec, 0x56001eec}, - {0x0000a580, 0x00802220, 0x00802220, 0x00800000, 0x00800000}, - {0x0000a584, 0x04802222, 0x04802222, 0x04800002, 0x04800002}, - {0x0000a588, 0x09802421, 0x09802421, 0x08800004, 0x08800004}, - {0x0000a58c, 0x0d802621, 0x0d802621, 0x0b800200, 0x0b800200}, - {0x0000a590, 0x13804620, 0x13804620, 0x0f800202, 0x0f800202}, - {0x0000a594, 0x19804a20, 0x19804a20, 0x11800400, 0x11800400}, - {0x0000a598, 0x1d804e20, 0x1d804e20, 0x15800402, 0x15800402}, - {0x0000a59c, 0x21805420, 0x21805420, 0x19800404, 0x19800404}, - {0x0000a5a0, 0x26805e20, 0x26805e20, 0x1b800603, 0x1b800603}, - {0x0000a5a4, 0x2b805e40, 0x2b805e40, 0x1f800a02, 0x1f800a02}, - {0x0000a5a8, 0x2f805e42, 0x2f805e42, 0x23800a04, 0x23800a04}, - {0x0000a5ac, 0x33805e44, 0x33805e44, 0x26800a20, 0x26800a20}, - {0x0000a5b0, 0x38805e65, 0x38805e65, 0x2a800e20, 0x2a800e20}, - {0x0000a5b4, 0x3c805e69, 0x3c805e69, 0x2e800e22, 0x2e800e22}, - {0x0000a5b8, 0x40805e6b, 0x40805e6b, 0x31800e24, 0x31800e24}, - {0x0000a5bc, 0x44805e6d, 0x44805e6d, 0x34801640, 0x34801640}, - {0x0000a5c0, 0x49805e72, 0x49805e72, 0x38801660, 0x38801660}, - {0x0000a5c4, 0x4e805eb2, 0x4e805eb2, 0x3b801861, 0x3b801861}, - {0x0000a5c8, 0x53805f12, 0x53805f12, 0x3e801a81, 0x3e801a81}, - {0x0000a5cc, 0x59825eb2, 0x59825eb2, 0x42801a83, 0x42801a83}, - {0x0000a5d0, 0x5e825f12, 0x5e825f12, 0x44801c84, 0x44801c84}, - {0x0000a5d4, 0x61827f12, 0x61827f12, 0x48801ce3, 0x48801ce3}, - {0x0000a5d8, 0x6782bf12, 0x6782bf12, 0x4c801ce5, 0x4c801ce5}, - {0x0000a5dc, 0x6b82bf14, 0x6b82bf14, 0x50801ce9, 0x50801ce9}, - {0x0000a5e0, 0x6f82bf16, 0x6f82bf16, 0x54801ceb, 0x54801ceb}, - {0x0000a5e4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5e8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5ec, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f0, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f4, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5f8, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a5fc, 0x6f82bf16, 0x6f82bf16, 0x56801eec, 0x56801eec}, - {0x0000a600, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a604, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a608, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a60c, 0x00000000, 0x00000000, 0x00000000, 0x00000000}, - {0x0000a610, 0x00804000, 0x00804000, 0x00000000, 0x00000000}, - {0x0000a614, 0x00804201, 0x00804201, 0x01404000, 0x01404000}, - {0x0000a618, 0x0280c802, 0x0280c802, 0x01404501, 0x01404501}, - {0x0000a61c, 0x0280ca03, 0x0280ca03, 0x02008501, 0x02008501}, - {0x0000a620, 0x04c15104, 0x04c15104, 0x0280ca03, 0x0280ca03}, - {0x0000a624, 0x04c15305, 0x04c15305, 0x03010c04, 0x03010c04}, - {0x0000a628, 0x04c15305, 0x04c15305, 0x04014c04, 0x04014c04}, - {0x0000a62c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a630, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a634, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a638, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000a63c, 0x04c15305, 0x04c15305, 0x04015005, 0x04015005}, - {0x0000b2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000b2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000b2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000b2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x0000c2dc, 0x01feee00, 0x01feee00, 0x03aaa352, 0x03aaa352}, - {0x0000c2e0, 0x0000f000, 0x0000f000, 0x03ccc584, 0x03ccc584}, - {0x0000c2e4, 0x01ff0000, 0x01ff0000, 0x03f0f800, 0x03f0f800}, - {0x0000c2e8, 0x00000000, 0x00000000, 0x03ff0000, 0x03ff0000}, - {0x00016044, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016048, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016068, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016444, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016448, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016468, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, - {0x00016844, 0x056db2e4, 0x056db2e4, 0x056db2e4, 0x056db2e4}, - {0x00016848, 0x8e480001, 0x8e480001, 0x8e480001, 0x8e480001}, - {0x00016868, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c, 0x6db6db6c}, -}; +#define ar9580_1p0_high_ob_db_tx_gain_table ar9300Modes_high_ob_db_tx_gain_table_2p2 static const u32 ar9580_1p0_soc_preamble[][2] = { /* Addr allmodes */ @@ -1189,265 +695,7 @@ static const u32 ar9580_1p0_soc_preamble[][2] = { {0x00007048, 0x00000008}, }; -static const u32 ar9580_1p0_rx_gain_table[][2] = { - /* Addr allmodes */ - {0x0000a000, 0x00010000}, - {0x0000a004, 0x00030002}, - {0x0000a008, 0x00050004}, - {0x0000a00c, 0x00810080}, - {0x0000a010, 0x00830082}, - {0x0000a014, 0x01810180}, - {0x0000a018, 0x01830182}, - {0x0000a01c, 0x01850184}, - {0x0000a020, 0x01890188}, - {0x0000a024, 0x018b018a}, - {0x0000a028, 0x018d018c}, - {0x0000a02c, 0x01910190}, - {0x0000a030, 0x01930192}, - {0x0000a034, 0x01950194}, - {0x0000a038, 0x038a0196}, - {0x0000a03c, 0x038c038b}, - {0x0000a040, 0x0390038d}, - {0x0000a044, 0x03920391}, - {0x0000a048, 0x03940393}, - {0x0000a04c, 0x03960395}, - {0x0000a050, 0x00000000}, - {0x0000a054, 0x00000000}, - {0x0000a058, 0x00000000}, - {0x0000a05c, 0x00000000}, - {0x0000a060, 0x00000000}, - {0x0000a064, 0x00000000}, - {0x0000a068, 0x00000000}, - {0x0000a06c, 0x00000000}, - {0x0000a070, 0x00000000}, - {0x0000a074, 0x00000000}, - {0x0000a078, 0x00000000}, - {0x0000a07c, 0x00000000}, - {0x0000a080, 0x22222229}, - {0x0000a084, 0x1d1d1d1d}, - {0x0000a088, 0x1d1d1d1d}, - {0x0000a08c, 0x1d1d1d1d}, - {0x0000a090, 0x171d1d1d}, - {0x0000a094, 0x11111717}, - {0x0000a098, 0x00030311}, - {0x0000a09c, 0x00000000}, - {0x0000a0a0, 0x00000000}, - {0x0000a0a4, 0x00000000}, - {0x0000a0a8, 0x00000000}, - {0x0000a0ac, 0x00000000}, - {0x0000a0b0, 0x00000000}, - {0x0000a0b4, 0x00000000}, - {0x0000a0b8, 0x00000000}, - {0x0000a0bc, 0x00000000}, - {0x0000a0c0, 0x001f0000}, - {0x0000a0c4, 0x01000101}, - {0x0000a0c8, 0x011e011f}, - {0x0000a0cc, 0x011c011d}, - {0x0000a0d0, 0x02030204}, - {0x0000a0d4, 0x02010202}, - {0x0000a0d8, 0x021f0200}, - {0x0000a0dc, 0x0302021e}, - {0x0000a0e0, 0x03000301}, - {0x0000a0e4, 0x031e031f}, - {0x0000a0e8, 0x0402031d}, - {0x0000a0ec, 0x04000401}, - {0x0000a0f0, 0x041e041f}, - {0x0000a0f4, 0x0502041d}, - {0x0000a0f8, 0x05000501}, - {0x0000a0fc, 0x051e051f}, - {0x0000a100, 0x06010602}, - {0x0000a104, 0x061f0600}, - {0x0000a108, 0x061d061e}, - {0x0000a10c, 0x07020703}, - {0x0000a110, 0x07000701}, - {0x0000a114, 0x00000000}, - {0x0000a118, 0x00000000}, - {0x0000a11c, 0x00000000}, - {0x0000a120, 0x00000000}, - {0x0000a124, 0x00000000}, - {0x0000a128, 0x00000000}, - {0x0000a12c, 0x00000000}, - {0x0000a130, 0x00000000}, - {0x0000a134, 0x00000000}, - {0x0000a138, 0x00000000}, - {0x0000a13c, 0x00000000}, - {0x0000a140, 0x001f0000}, - {0x0000a144, 0x01000101}, - {0x0000a148, 0x011e011f}, - {0x0000a14c, 0x011c011d}, - {0x0000a150, 0x02030204}, - {0x0000a154, 0x02010202}, - {0x0000a158, 0x021f0200}, - {0x0000a15c, 0x0302021e}, - {0x0000a160, 0x03000301}, - {0x0000a164, 0x031e031f}, - {0x0000a168, 0x0402031d}, - {0x0000a16c, 0x04000401}, - {0x0000a170, 0x041e041f}, - {0x0000a174, 0x0502041d}, - {0x0000a178, 0x05000501}, - {0x0000a17c, 0x051e051f}, - {0x0000a180, 0x06010602}, - {0x0000a184, 0x061f0600}, - {0x0000a188, 0x061d061e}, - {0x0000a18c, 0x07020703}, - {0x0000a190, 0x07000701}, - {0x0000a194, 0x00000000}, - {0x0000a198, 0x00000000}, - {0x0000a19c, 0x00000000}, - {0x0000a1a0, 0x00000000}, - {0x0000a1a4, 0x00000000}, - {0x0000a1a8, 0x00000000}, - {0x0000a1ac, 0x00000000}, - {0x0000a1b0, 0x00000000}, - {0x0000a1b4, 0x00000000}, - {0x0000a1b8, 0x00000000}, - {0x0000a1bc, 0x00000000}, - {0x0000a1c0, 0x00000000}, - {0x0000a1c4, 0x00000000}, - {0x0000a1c8, 0x00000000}, - {0x0000a1cc, 0x00000000}, - {0x0000a1d0, 0x00000000}, - {0x0000a1d4, 0x00000000}, - {0x0000a1d8, 0x00000000}, - {0x0000a1dc, 0x00000000}, - {0x0000a1e0, 0x00000000}, - {0x0000a1e4, 0x00000000}, - {0x0000a1e8, 0x00000000}, - {0x0000a1ec, 0x00000000}, - {0x0000a1f0, 0x00000396}, - {0x0000a1f4, 0x00000396}, - {0x0000a1f8, 0x00000396}, - {0x0000a1fc, 0x00000196}, - {0x0000b000, 0x00010000}, - {0x0000b004, 0x00030002}, - {0x0000b008, 0x00050004}, - {0x0000b00c, 0x00810080}, - {0x0000b010, 0x00830082}, - {0x0000b014, 0x01810180}, - {0x0000b018, 0x01830182}, - {0x0000b01c, 0x01850184}, - {0x0000b020, 0x02810280}, - {0x0000b024, 0x02830282}, - {0x0000b028, 0x02850284}, - {0x0000b02c, 0x02890288}, - {0x0000b030, 0x028b028a}, - {0x0000b034, 0x0388028c}, - {0x0000b038, 0x038a0389}, - {0x0000b03c, 0x038c038b}, - {0x0000b040, 0x0390038d}, - {0x0000b044, 0x03920391}, - {0x0000b048, 0x03940393}, - {0x0000b04c, 0x03960395}, - {0x0000b050, 0x00000000}, - {0x0000b054, 0x00000000}, - {0x0000b058, 0x00000000}, - {0x0000b05c, 0x00000000}, - {0x0000b060, 0x00000000}, - {0x0000b064, 0x00000000}, - {0x0000b068, 0x00000000}, - {0x0000b06c, 0x00000000}, - {0x0000b070, 0x00000000}, - {0x0000b074, 0x00000000}, - {0x0000b078, 0x00000000}, - {0x0000b07c, 0x00000000}, - {0x0000b080, 0x2a2d2f32}, - {0x0000b084, 0x21232328}, - {0x0000b088, 0x19191c1e}, - {0x0000b08c, 0x12141417}, - {0x0000b090, 0x07070e0e}, - {0x0000b094, 0x03030305}, - {0x0000b098, 0x00000003}, - {0x0000b09c, 0x00000000}, - {0x0000b0a0, 0x00000000}, - {0x0000b0a4, 0x00000000}, - {0x0000b0a8, 0x00000000}, - {0x0000b0ac, 0x00000000}, - {0x0000b0b0, 0x00000000}, - {0x0000b0b4, 0x00000000}, - {0x0000b0b8, 0x00000000}, - {0x0000b0bc, 0x00000000}, - {0x0000b0c0, 0x003f0020}, - {0x0000b0c4, 0x00400041}, - {0x0000b0c8, 0x0140005f}, - {0x0000b0cc, 0x0160015f}, - {0x0000b0d0, 0x017e017f}, - {0x0000b0d4, 0x02410242}, - {0x0000b0d8, 0x025f0240}, - {0x0000b0dc, 0x027f0260}, - {0x0000b0e0, 0x0341027e}, - {0x0000b0e4, 0x035f0340}, - {0x0000b0e8, 0x037f0360}, - {0x0000b0ec, 0x04400441}, - {0x0000b0f0, 0x0460045f}, - {0x0000b0f4, 0x0541047f}, - {0x0000b0f8, 0x055f0540}, - {0x0000b0fc, 0x057f0560}, - {0x0000b100, 0x06400641}, - {0x0000b104, 0x0660065f}, - {0x0000b108, 0x067e067f}, - {0x0000b10c, 0x07410742}, - {0x0000b110, 0x075f0740}, - {0x0000b114, 0x077f0760}, - {0x0000b118, 0x07800781}, - {0x0000b11c, 0x07a0079f}, - {0x0000b120, 0x07c107bf}, - {0x0000b124, 0x000007c0}, - {0x0000b128, 0x00000000}, - {0x0000b12c, 0x00000000}, - {0x0000b130, 0x00000000}, - {0x0000b134, 0x00000000}, - {0x0000b138, 0x00000000}, - {0x0000b13c, 0x00000000}, - {0x0000b140, 0x003f0020}, - {0x0000b144, 0x00400041}, - {0x0000b148, 0x0140005f}, - {0x0000b14c, 0x0160015f}, - {0x0000b150, 0x017e017f}, - {0x0000b154, 0x02410242}, - {0x0000b158, 0x025f0240}, - {0x0000b15c, 0x027f0260}, - {0x0000b160, 0x0341027e}, - {0x0000b164, 0x035f0340}, - {0x0000b168, 0x037f0360}, - {0x0000b16c, 0x04400441}, - {0x0000b170, 0x0460045f}, - {0x0000b174, 0x0541047f}, - {0x0000b178, 0x055f0540}, - {0x0000b17c, 0x057f0560}, - {0x0000b180, 0x06400641}, - {0x0000b184, 0x0660065f}, - {0x0000b188, 0x067e067f}, - {0x0000b18c, 0x07410742}, - {0x0000b190, 0x075f0740}, - {0x0000b194, 0x077f0760}, - {0x0000b198, 0x07800781}, - {0x0000b19c, 0x07a0079f}, - {0x0000b1a0, 0x07c107bf}, - {0x0000b1a4, 0x000007c0}, - {0x0000b1a8, 0x00000000}, - {0x0000b1ac, 0x00000000}, - {0x0000b1b0, 0x00000000}, - {0x0000b1b4, 0x00000000}, - {0x0000b1b8, 0x00000000}, - {0x0000b1bc, 0x00000000}, - {0x0000b1c0, 0x00000000}, - {0x0000b1c4, 0x00000000}, - {0x0000b1c8, 0x00000000}, - {0x0000b1cc, 0x00000000}, - {0x0000b1d0, 0x00000000}, - {0x0000b1d4, 0x00000000}, - {0x0000b1d8, 0x00000000}, - {0x0000b1dc, 0x00000000}, - {0x0000b1e0, 0x00000000}, - {0x0000b1e4, 0x00000000}, - {0x0000b1e8, 0x00000000}, - {0x0000b1ec, 0x00000000}, - {0x0000b1f0, 0x00000396}, - {0x0000b1f4, 0x00000396}, - {0x0000b1f8, 0x00000396}, - {0x0000b1fc, 0x00000196}, -}; +#define ar9580_1p0_rx_gain_table ar9462_common_rx_gain_table_2p0 static const u32 ar9580_1p0_radio_core[][2] = { /* Addr allmodes */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 02fc1c1e5eeb..79840d6deef2 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -214,6 +214,7 @@ struct ath_frame_info { enum ath9k_key_type keytype; u8 keyix; u8 retries; + u8 rtscts_rate; }; struct ath_buf_state { @@ -480,6 +481,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc); void ath9k_btcoex_timer_pause(struct ath_softc *sc); void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status); u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen); +void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc); #else static inline int ath9k_init_btcoex(struct ath_softc *sc) { @@ -503,6 +505,9 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, { return 0; } +static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) +{ +} #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ /********************/ @@ -698,6 +703,7 @@ struct ath_softc { #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT struct ath_btcoex btcoex; struct ath_mci_coex mci_coex; + struct work_struct mci_work; #endif struct ath_descdma txsdma; @@ -720,6 +726,7 @@ extern int ath9k_modparam_nohwcrypt; extern int led_blink; extern bool is_ath9k_unloaded; +u8 ath9k_parse_mpdudensity(u8 mpdudensity); irqreturn_t ath_isr(int irq, void *dev); int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops); diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 2831258d9507..5c3192ffc196 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -348,8 +348,6 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) sc->debug.stats.istats.txok++; if (status & ATH9K_INT_TXURN) sc->debug.stats.istats.txurn++; - if (status & ATH9K_INT_MIB) - sc->debug.stats.istats.mib++; if (status & ATH9K_INT_RXPHY) sc->debug.stats.istats.rxphyerr++; if (status & ATH9K_INT_RXKCM) diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index af6d27350291..bacdb8fb4ef4 100644 --- a/drivers/net/wireless/ath/ath9k/gpio.c +++ b/drivers/net/wireless/ath/ath9k/gpio.c @@ -194,6 +194,14 @@ static void ath_btcoex_period_timer(unsigned long data) struct ath_mci_profile *mci = &btcoex->mci; u32 timer_period; bool is_btscan; + unsigned long flags; + + spin_lock_irqsave(&sc->sc_pm_lock, flags); + if (sc->sc_ah->power_mode == ATH9K_PM_NETWORK_SLEEP) { + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); + goto skip_hw_wakeup; + } + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); ath9k_ps_wakeup(sc); if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI)) @@ -202,7 +210,7 @@ static void ath_btcoex_period_timer(unsigned long data) btcoex->bt_wait_time += btcoex->btcoex_period; if (btcoex->bt_wait_time > ATH_BTCOEX_RX_WAIT_TIME) { - if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP, NULL) && + if (ar9003_mci_state(ah, MCI_STATE_NEED_FTP_STOMP) && (mci->num_pan || mci->num_other_acl)) ah->btcoex_hw.mci.stomp_ftp = (sc->rx.num_pkts < ATH_BTCOEX_STOMP_FTP_THRESH); @@ -232,7 +240,8 @@ static void ath_btcoex_period_timer(unsigned long data) } ath9k_ps_restore(sc); - timer_period = btcoex->btcoex_period / 1000; +skip_hw_wakeup: + timer_period = btcoex->btcoex_period; mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); } @@ -267,10 +276,10 @@ static int ath_init_btcoex_timer(struct ath_softc *sc) { struct ath_btcoex *btcoex = &sc->btcoex; - btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD * 1000; - btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * + btcoex->btcoex_period = ATH_BTCOEX_DEF_BT_PERIOD; + btcoex->btcoex_no_stomp = (100 - ATH_BTCOEX_DEF_DUTY_CYCLE) * 1000 * btcoex->btcoex_period / 100; - btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * + btcoex->btscan_no_stomp = (100 - ATH_BTCOEX_BTSCAN_DUTY_CYCLE) * 1000 * btcoex->btcoex_period / 100; setup_timer(&btcoex->period_timer, ath_btcoex_period_timer, @@ -305,7 +314,8 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc) btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; - btcoex->op_flags &= ~(BT_OP_PRIORITY_DETECTED | BT_OP_SCAN); + clear_bit(BT_OP_PRIORITY_DETECTED, &btcoex->op_flags); + clear_bit(BT_OP_SCAN, &btcoex->op_flags); mod_timer(&btcoex->period_timer, jiffies); } @@ -327,6 +337,13 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc) btcoex->hw_timer_enabled = false; } +void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) +{ + struct ath_btcoex *btcoex = &sc->btcoex; + + ath9k_gen_timer_stop(sc->sc_ah, btcoex->no_stomp_timer); +} + u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen) { struct ath_btcoex *btcoex = &sc->btcoex; @@ -376,9 +393,9 @@ void ath9k_stop_btcoex(struct ath_softc *sc) if (ah->btcoex_hw.enabled && ath9k_hw_get_btcoex_scheme(ah) != ATH_BTCOEX_CFG_NONE) { - ath9k_hw_btcoex_disable(ah); if (ath9k_hw_get_btcoex_scheme(ah) == ATH_BTCOEX_CFG_3WIRE) ath9k_btcoex_timer_pause(sc); + ath9k_hw_btcoex_disable(ah); if (AR_SREV_9462(ah)) ath_mci_flush_profile(&sc->btcoex.mci); } @@ -386,11 +403,13 @@ void ath9k_stop_btcoex(struct ath_softc *sc) void ath9k_deinit_btcoex(struct ath_softc *sc) { + struct ath_hw *ah = sc->sc_ah; + if ((sc->btcoex.no_stomp_timer) && ath9k_hw_get_btcoex_scheme(sc->sc_ah) == ATH_BTCOEX_CFG_3WIRE) ath_gen_timer_free(sc->sc_ah, sc->btcoex.no_stomp_timer); - if (AR_SREV_9462(sc->sc_ah)) + if (ath9k_hw_mci_is_enabled(ah)) ath_mci_cleanup(sc); } @@ -416,7 +435,7 @@ int ath9k_init_btcoex(struct ath_softc *sc) txq = sc->tx.txq_map[WME_AC_BE]; ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum); sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - if (AR_SREV_9462(ah)) { + if (ath9k_hw_mci_is_enabled(ah)) { sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; INIT_LIST_HEAD(&sc->btcoex.mci.info); diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h index 135795257d95..936e920fb88e 100644 --- a/drivers/net/wireless/ath/ath9k/htc.h +++ b/drivers/net/wireless/ath/ath9k/htc.h @@ -453,7 +453,6 @@ struct ath9k_htc_priv { u8 num_sta_assoc_vif; u8 num_ap_vif; - u16 op_flags; u16 curtxpow; u16 txpowlimit; u16 nvifs; @@ -461,6 +460,7 @@ struct ath9k_htc_priv { bool rearm_ani; bool reconfig_beacon; unsigned int rxfilter; + unsigned long op_flags; struct ath9k_hw_cal_data caldata; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; @@ -572,8 +572,6 @@ bool ath9k_htc_setpower(struct ath9k_htc_priv *priv, void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv); void ath9k_htc_rfkill_poll_state(struct ieee80211_hw *hw); -void ath9k_htc_radio_enable(struct ieee80211_hw *hw); -void ath9k_htc_radio_disable(struct ieee80211_hw *hw); #ifdef CONFIG_MAC80211_LEDS void ath9k_init_leds(struct ath9k_htc_priv *priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c index 2eadffb7971c..77d541feb910 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_beacon.c @@ -207,9 +207,9 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - if (priv->op_flags & OP_TSF_RESET) { + if (test_bit(OP_TSF_RESET, &priv->op_flags)) { ath9k_hw_reset_tsf(priv->ah); - priv->op_flags &= ~OP_TSF_RESET; + clear_bit(OP_TSF_RESET, &priv->op_flags); } else { /* * Pull nexttbtt forward to reflect the current TSF. @@ -221,7 +221,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv, } while (nexttbtt < tsftu); } - if (priv->op_flags & OP_ENABLE_BEACON) + if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, @@ -269,7 +269,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv, else priv->ah->config.sw_beacon_response_time = MIN_SWBA_RESPONSE; - if (priv->op_flags & OP_ENABLE_BEACON) + if (test_bit(OP_ENABLE_BEACON, &priv->op_flags)) imask |= ATH9K_INT_SWBA; ath_dbg(common, CONFIG, @@ -365,7 +365,7 @@ static void ath9k_htc_send_beacon(struct ath9k_htc_priv *priv, vif = priv->cur_beacon_conf.bslot[slot]; avp = (struct ath9k_htc_vif *)vif->drv_priv; - if (unlikely(priv->op_flags & OP_SCANNING)) { + if (unlikely(test_bit(OP_SCANNING, &priv->op_flags))) { spin_unlock_bh(&priv->beacon_lock); return; } diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c index 1c10e2e5c237..07df279c8d46 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c @@ -37,17 +37,18 @@ static void ath_detect_bt_priority(struct ath9k_htc_priv *priv) if (time_after(jiffies, btcoex->bt_priority_time + msecs_to_jiffies(ATH_BT_PRIORITY_TIME_THRESHOLD))) { - priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); + clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags); + clear_bit(OP_BT_SCAN, &priv->op_flags); /* Detect if colocated bt started scanning */ if (btcoex->bt_priority_cnt >= ATH_BT_CNT_SCAN_THRESHOLD) { ath_dbg(ath9k_hw_common(ah), BTCOEX, "BT scan detected\n"); - priv->op_flags |= (OP_BT_SCAN | - OP_BT_PRIORITY_DETECTED); + set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags); + set_bit(OP_BT_SCAN, &priv->op_flags); } else if (btcoex->bt_priority_cnt >= ATH_BT_CNT_THRESHOLD) { ath_dbg(ath9k_hw_common(ah), BTCOEX, "BT priority traffic detected\n"); - priv->op_flags |= OP_BT_PRIORITY_DETECTED; + set_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags); } btcoex->bt_priority_cnt = 0; @@ -67,26 +68,23 @@ static void ath_btcoex_period_work(struct work_struct *work) struct ath_btcoex *btcoex = &priv->btcoex; struct ath_common *common = ath9k_hw_common(priv->ah); u32 timer_period; - bool is_btscan; int ret; ath_detect_bt_priority(priv); - is_btscan = !!(priv->op_flags & OP_BT_SCAN); - ret = ath9k_htc_update_cap_target(priv, - !!(priv->op_flags & OP_BT_PRIORITY_DETECTED)); + test_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags)); if (ret) { ath_err(common, "Unable to set BTCOEX parameters\n"); return; } - ath9k_hw_btcoex_bt_stomp(priv->ah, is_btscan ? ATH_BTCOEX_STOMP_ALL : - btcoex->bt_stomp_type); + ath9k_hw_btcoex_bt_stomp(priv->ah, test_bit(OP_BT_SCAN, &priv->op_flags) ? + ATH_BTCOEX_STOMP_ALL : btcoex->bt_stomp_type); ath9k_hw_btcoex_enable(priv->ah); - timer_period = is_btscan ? btcoex->btscan_no_stomp : - btcoex->btcoex_no_stomp; + timer_period = test_bit(OP_BT_SCAN, &priv->op_flags) ? + btcoex->btscan_no_stomp : btcoex->btcoex_no_stomp; ieee80211_queue_delayed_work(priv->hw, &priv->duty_cycle_work, msecs_to_jiffies(timer_period)); ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, @@ -104,14 +102,15 @@ static void ath_btcoex_duty_cycle_work(struct work_struct *work) struct ath_hw *ah = priv->ah; struct ath_btcoex *btcoex = &priv->btcoex; struct ath_common *common = ath9k_hw_common(ah); - bool is_btscan = priv->op_flags & OP_BT_SCAN; ath_dbg(common, BTCOEX, "time slice work for bt and wlan\n"); - if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || is_btscan) + if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_LOW || + test_bit(OP_BT_SCAN, &priv->op_flags)) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE); else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL) ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW); + ath9k_hw_btcoex_enable(priv->ah); } @@ -141,7 +140,8 @@ static void ath_htc_resume_btcoex_work(struct ath9k_htc_priv *priv) btcoex->bt_priority_cnt = 0; btcoex->bt_priority_time = jiffies; - priv->op_flags &= ~(OP_BT_PRIORITY_DETECTED | OP_BT_SCAN); + clear_bit(OP_BT_PRIORITY_DETECTED, &priv->op_flags); + clear_bit(OP_BT_SCAN, &priv->op_flags); ieee80211_queue_delayed_work(priv->hw, &priv->coex_period_work, 0); } @@ -310,95 +310,3 @@ void ath9k_start_rfkill_poll(struct ath9k_htc_priv *priv) if (priv->ah->caps.hw_caps & ATH9K_HW_CAP_RFSILENT) wiphy_rfkill_start_polling(priv->hw->wiphy); } - -void ath9k_htc_radio_enable(struct ieee80211_hw *hw) -{ - struct ath9k_htc_priv *priv = hw->priv; - struct ath_hw *ah = priv->ah; - struct ath_common *common = ath9k_hw_common(ah); - int ret; - u8 cmd_rsp; - - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(hw, ah); - - /* Reset the HW */ - ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); - if (ret) { - ath_err(common, - "Unable to reset hardware; reset status %d (freq %u MHz)\n", - ret, ah->curchan->channel); - } - - ath9k_cmn_update_txpow(ah, priv->curtxpow, priv->txpowlimit, - &priv->curtxpow); - - /* Start RX */ - WMI_CMD(WMI_START_RECV_CMDID); - ath9k_host_rx_init(priv); - - /* Start TX */ - htc_start(priv->htc); - spin_lock_bh(&priv->tx.tx_lock); - priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; - spin_unlock_bh(&priv->tx.tx_lock); - ieee80211_wake_queues(hw); - - WMI_CMD(WMI_ENABLE_INTR_CMDID); - - /* Enable LED */ - ath9k_hw_cfg_output(ah, ah->led_pin, - AR_GPIO_OUTPUT_MUX_AS_OUTPUT); - ath9k_hw_set_gpio(ah, ah->led_pin, 0); -} - -void ath9k_htc_radio_disable(struct ieee80211_hw *hw) -{ - struct ath9k_htc_priv *priv = hw->priv; - struct ath_hw *ah = priv->ah; - struct ath_common *common = ath9k_hw_common(ah); - int ret; - u8 cmd_rsp; - - ath9k_htc_ps_wakeup(priv); - - /* Disable LED */ - ath9k_hw_set_gpio(ah, ah->led_pin, 1); - ath9k_hw_cfg_gpio_input(ah, ah->led_pin); - - WMI_CMD(WMI_DISABLE_INTR_CMDID); - - /* Stop TX */ - ieee80211_stop_queues(hw); - ath9k_htc_tx_drain(priv); - WMI_CMD(WMI_DRAIN_TXQ_ALL_CMDID); - - /* Stop RX */ - WMI_CMD(WMI_STOP_RECV_CMDID); - - /* Clear the WMI event queue */ - ath9k_wmi_event_drain(priv); - - /* - * The MIB counters have to be disabled here, - * since the target doesn't do it. - */ - ath9k_hw_disable_mib_counters(ah); - - if (!ah->curchan) - ah->curchan = ath9k_cmn_get_curchannel(hw, ah); - - /* Reset the HW */ - ret = ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); - if (ret) { - ath_err(common, - "Unable to reset hardware; reset status %d (freq %u MHz)\n", - ret, ah->curchan->channel); - } - - /* Disable the PHY */ - ath9k_hw_phy_disable(ah); - - ath9k_htc_ps_restore(priv); - ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); -} diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c index 25213d521bc2..a035a380d669 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c @@ -611,7 +611,7 @@ static int ath9k_init_priv(struct ath9k_htc_priv *priv, struct ath_common *common; int i, ret = 0, csz = 0; - priv->op_flags |= OP_INVALID; + set_bit(OP_INVALID, &priv->op_flags); ah = kzalloc(sizeof(struct ath_hw), GFP_KERNEL); if (!ah) @@ -718,7 +718,7 @@ static void ath9k_set_hw_capab(struct ath9k_htc_priv *priv, hw->queues = 4; hw->channel_change_time = 5000; - hw->max_listen_interval = 10; + hw->max_listen_interval = 1; hw->vif_data_size = sizeof(struct ath9k_htc_vif); hw->sta_data_size = sizeof(struct ath9k_htc_sta); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 2b8f61c210e1..374c32ed905a 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -75,14 +75,19 @@ unlock: void ath9k_htc_ps_restore(struct ath9k_htc_priv *priv) { + bool reset; + mutex_lock(&priv->htc_pm_lock); if (--priv->ps_usecount != 0) goto unlock; - if (priv->ps_idle) + if (priv->ps_idle) { + ath9k_hw_setrxabort(priv->ah, true); + ath9k_hw_stopdmarecv(priv->ah, &reset); ath9k_hw_setpower(priv->ah, ATH9K_PM_FULL_SLEEP); - else if (priv->ps_enabled) + } else if (priv->ps_enabled) { ath9k_hw_setpower(priv->ah, ATH9K_PM_NETWORK_SLEEP); + } unlock: mutex_unlock(&priv->htc_pm_lock); @@ -250,7 +255,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, u8 cmd_rsp; int ret; - if (priv->op_flags & OP_INVALID) + if (test_bit(OP_INVALID, &priv->op_flags)) return -EIO; fastcc = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); @@ -304,7 +309,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv, htc_start(priv->htc); - if (!(priv->op_flags & OP_SCANNING) && + if (!test_bit(OP_SCANNING, &priv->op_flags) && !(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) ath9k_htc_vif_reconfig(priv); @@ -750,7 +755,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; - priv->op_flags |= OP_ANI_RUNNING; + set_bit(OP_ANI_RUNNING, &priv->op_flags); ieee80211_queue_delayed_work(common->hw, &priv->ani_work, msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); @@ -759,7 +764,7 @@ void ath9k_htc_start_ani(struct ath9k_htc_priv *priv) void ath9k_htc_stop_ani(struct ath9k_htc_priv *priv) { cancel_delayed_work_sync(&priv->ani_work); - priv->op_flags &= ~OP_ANI_RUNNING; + clear_bit(OP_ANI_RUNNING, &priv->op_flags); } void ath9k_htc_ani_work(struct work_struct *work) @@ -944,7 +949,7 @@ static int ath9k_htc_start(struct ieee80211_hw *hw) ath_dbg(common, CONFIG, "Failed to update capability in target\n"); - priv->op_flags &= ~OP_INVALID; + clear_bit(OP_INVALID, &priv->op_flags); htc_start(priv->htc); spin_lock_bh(&priv->tx.tx_lock); @@ -973,7 +978,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); - if (priv->op_flags & OP_INVALID) { + if (test_bit(OP_INVALID, &priv->op_flags)) { ath_dbg(common, ANY, "Device not present\n"); mutex_unlock(&priv->mutex); return; @@ -1015,7 +1020,7 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw) ath9k_htc_ps_restore(priv); ath9k_htc_setpower(priv, ATH9K_PM_FULL_SLEEP); - priv->op_flags |= OP_INVALID; + set_bit(OP_INVALID, &priv->op_flags); ath_dbg(common, CONFIG, "Driver halt\n"); mutex_unlock(&priv->mutex); @@ -1105,7 +1110,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, ath9k_htc_set_opmode(priv); if ((priv->ah->opmode == NL80211_IFTYPE_AP) && - !(priv->op_flags & OP_ANI_RUNNING)) { + !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { ath9k_hw_set_tsfadjust(priv->ah, 1); ath9k_htc_start_ani(priv); } @@ -1178,24 +1183,20 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) struct ath9k_htc_priv *priv = hw->priv; struct ath_common *common = ath9k_hw_common(priv->ah); struct ieee80211_conf *conf = &hw->conf; + bool chip_reset = false; + int ret = 0; mutex_lock(&priv->mutex); + ath9k_htc_ps_wakeup(priv); if (changed & IEEE80211_CONF_CHANGE_IDLE) { - bool enable_radio = false; - bool idle = !!(conf->flags & IEEE80211_CONF_IDLE); - mutex_lock(&priv->htc_pm_lock); - if (!idle && priv->ps_idle) - enable_radio = true; - priv->ps_idle = idle; - mutex_unlock(&priv->htc_pm_lock); - if (enable_radio) { - ath_dbg(common, CONFIG, "not-idle: enabling radio\n"); - ath9k_htc_setpower(priv, ATH9K_PM_AWAKE); - ath9k_htc_radio_enable(hw); - } + priv->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); + if (priv->ps_idle) + chip_reset = true; + + mutex_unlock(&priv->htc_pm_lock); } /* @@ -1210,7 +1211,7 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) ath9k_htc_remove_monitor_interface(priv); } - if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || chip_reset) { struct ieee80211_channel *curchan = hw->conf.channel; int pos = curchan->hw_value; @@ -1223,8 +1224,8 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) if (ath9k_htc_set_channel(priv, hw, &priv->ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); - mutex_unlock(&priv->mutex); - return -EINVAL; + ret = -EINVAL; + goto out; } } @@ -1246,21 +1247,10 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed) priv->txpowlimit, &priv->curtxpow); } - if (changed & IEEE80211_CONF_CHANGE_IDLE) { - mutex_lock(&priv->htc_pm_lock); - if (!priv->ps_idle) { - mutex_unlock(&priv->htc_pm_lock); - goto out; - } - mutex_unlock(&priv->htc_pm_lock); - - ath_dbg(common, CONFIG, "idle: disabling radio\n"); - ath9k_htc_radio_disable(hw); - } - out: + ath9k_htc_ps_restore(priv); mutex_unlock(&priv->mutex); - return 0; + return ret; } #define SUPPORTED_FILTERS \ @@ -1285,7 +1275,7 @@ static void ath9k_htc_configure_filter(struct ieee80211_hw *hw, changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - if (priv->op_flags & OP_INVALID) { + if (test_bit(OP_INVALID, &priv->op_flags)) { ath_dbg(ath9k_hw_common(priv->ah), ANY, "Unable to configure filter on invalid state\n"); mutex_unlock(&priv->mutex); @@ -1496,6 +1486,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, priv->num_sta_assoc_vif++ : priv->num_sta_assoc_vif--; if (priv->ah->opmode == NL80211_IFTYPE_STATION) { + ath9k_htc_choose_set_bssid(priv); if (bss_conf->assoc && (priv->num_sta_assoc_vif == 1)) ath9k_htc_start_ani(priv); else if (priv->num_sta_assoc_vif == 0) @@ -1503,13 +1494,11 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, } } - if (changed & BSS_CHANGED_BSSID) { + if (changed & BSS_CHANGED_IBSS) { if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) { common->curaid = bss_conf->aid; memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); ath9k_htc_set_bssid(priv); - } else if (priv->ah->opmode == NL80211_IFTYPE_STATION) { - ath9k_htc_choose_set_bssid(priv); } } @@ -1517,7 +1506,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon enabled for BSS: %pM\n", bss_conf->bssid); ath9k_htc_set_tsfadjust(priv, vif); - priv->op_flags |= OP_ENABLE_BEACON; + set_bit(OP_ENABLE_BEACON, &priv->op_flags); ath9k_htc_beacon_config(priv, vif); } @@ -1530,7 +1519,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, ath_dbg(common, CONFIG, "Beacon disabled for BSS: %pM\n", bss_conf->bssid); - priv->op_flags &= ~OP_ENABLE_BEACON; + clear_bit(OP_ENABLE_BEACON, &priv->op_flags); ath9k_htc_beacon_config(priv, vif); } } @@ -1543,7 +1532,7 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw, (priv->nvifs == 1) && (priv->num_ap_vif == 1) && (vif->type == NL80211_IFTYPE_AP)) { - priv->op_flags |= OP_TSF_RESET; + set_bit(OP_TSF_RESET, &priv->op_flags); } ath_dbg(common, CONFIG, "Beacon interval changed for BSS: %pM\n", @@ -1655,7 +1644,7 @@ static void ath9k_htc_sw_scan_start(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - priv->op_flags |= OP_SCANNING; + set_bit(OP_SCANNING, &priv->op_flags); spin_unlock_bh(&priv->beacon_lock); cancel_work_sync(&priv->ps_work); ath9k_htc_stop_ani(priv); @@ -1668,7 +1657,7 @@ static void ath9k_htc_sw_scan_complete(struct ieee80211_hw *hw) mutex_lock(&priv->mutex); spin_lock_bh(&priv->beacon_lock); - priv->op_flags &= ~OP_SCANNING; + clear_bit(OP_SCANNING, &priv->op_flags); spin_unlock_bh(&priv->beacon_lock); ath9k_htc_ps_wakeup(priv); ath9k_htc_vif_reconfig(priv); diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c index 3e40a6461512..47e61d0da33b 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_txrx.c @@ -916,7 +916,7 @@ void ath9k_host_rx_init(struct ath9k_htc_priv *priv) { ath9k_hw_rxena(priv->ah); ath9k_htc_opmode_init(priv); - ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING)); + ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index 45e670087e1c..c1659d079513 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -342,6 +342,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah) val = REG_READ(ah, AR_SREV); ah->hw_version.macRev = MS(val, AR_SREV_REVISION2); return; + case AR9300_DEVID_QCA955X: + ah->hw_version.macVersion = AR_SREV_VERSION_9550; + return; } val = REG_READ(ah, AR_SREV) & AR_SREV_ID; @@ -614,7 +617,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) { if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI || - ((AR_SREV_9160(ah) || AR_SREV_9280(ah)) && + ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) && !ah->is_pciexpress)) { ah->config.serialize_regmode = SER_REG_MODE_ON; @@ -646,6 +649,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) case AR_SREV_VERSION_9485: case AR_SREV_VERSION_9340: case AR_SREV_VERSION_9462: + case AR_SREV_VERSION_9550: break; default: ath_err(common, @@ -655,7 +659,7 @@ static int __ath9k_hw_init(struct ath_hw *ah) } if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) || - AR_SREV_9330(ah)) + AR_SREV_9330(ah) || AR_SREV_9550(ah)) ah->is_pciexpress = false; ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID); @@ -727,6 +731,7 @@ int ath9k_hw_init(struct ath_hw *ah) case AR9300_DEVID_AR9485_PCIE: case AR9300_DEVID_AR9330: case AR9300_DEVID_AR9340: + case AR9300_DEVID_QCA955X: case AR9300_DEVID_AR9580: case AR9300_DEVID_AR9462: break; @@ -773,13 +778,25 @@ static void ath9k_hw_init_qos(struct ath_hw *ah) u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah) { + struct ath_common *common = ath9k_hw_common(ah); + int i = 0; + REG_CLR_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); udelay(100); REG_SET_BIT(ah, PLL3, PLL3_DO_MEAS_MASK); - while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) + while ((REG_READ(ah, PLL4) & PLL4_MEAS_DONE) == 0) { + udelay(100); + if (WARN_ON_ONCE(i >= 100)) { + ath_err(common, "PLL4 meaurement not done\n"); + break; + } + + i++; + } + return (REG_READ(ah, PLL3) & SQSUM_DVC_MASK) >> 3; } EXPORT_SYMBOL(ar9003_get_pll_sqsum_dvc); @@ -853,7 +870,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, /* program BB PLL phase_shift */ REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3, AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1); - } else if (AR_SREV_9340(ah)) { + } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { u32 regval, pll2_divint, pll2_divfrac, refdiv; REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c); @@ -867,9 +884,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, pll2_divfrac = 0x1eb85; refdiv = 3; } else { - pll2_divint = 88; - pll2_divfrac = 0; - refdiv = 5; + if (AR_SREV_9340(ah)) { + pll2_divint = 88; + pll2_divfrac = 0; + refdiv = 5; + } else { + pll2_divint = 0x11; + pll2_divfrac = 0x26666; + refdiv = 1; + } } regval = REG_READ(ah, AR_PHY_PLL_MODE); @@ -882,8 +905,12 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, udelay(100); regval = REG_READ(ah, AR_PHY_PLL_MODE); - regval = (regval & 0x80071fff) | (0x1 << 30) | (0x1 << 13) | - (0x4 << 26) | (0x18 << 19); + if (AR_SREV_9340(ah)) + regval = (regval & 0x80071fff) | (0x1 << 30) | + (0x1 << 13) | (0x4 << 26) | (0x18 << 19); + else + regval = (regval & 0x80071fff) | (0x3 << 30) | + (0x1 << 13) | (0x4 << 26) | (0x60 << 19); REG_WRITE(ah, AR_PHY_PLL_MODE, regval); REG_WRITE(ah, AR_PHY_PLL_MODE, REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff); @@ -894,7 +921,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_WRITE(ah, AR_RTC_PLL_CONTROL, pll); - if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah)) + if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) || + AR_SREV_9550(ah)) udelay(1000); /* Switch the core clock for ar9271 to 117Mhz */ @@ -907,7 +935,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah, REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); - if (AR_SREV_9340(ah)) { + if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) { if (ah->is_clk_25mhz) { REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1); REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7); @@ -931,7 +959,7 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah, AR_IMR_RXORN | AR_IMR_BCNMISC; - if (AR_SREV_9340(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; if (AR_SREV_9300_20_OR_LATER(ah)) { @@ -1348,6 +1376,9 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type) } } + if (ath9k_hw_mci_is_enabled(ah)) + ar9003_mci_check_gpm_offset(ah); + REG_WRITE(ah, AR_RTC_RC, rst_flags); REGWRITE_BUFFER_FLUSH(ah); @@ -1708,7 +1739,7 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) ath9k_hw_start_nfcal(ah, true); if (ath9k_hw_mci_is_enabled(ah)) - ar9003_mci_2g5g_switch(ah, true); + ar9003_mci_2g5g_switch(ah, false); if (AR_SREV_9271(ah)) ar9002_hw_load_ani_reg(ah, chan); @@ -1912,7 +1943,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, ath9k_hw_set_dma(ah); - REG_WRITE(ah, AR_OBS, 8); + if (!ath9k_hw_mci_is_enabled(ah)) + REG_WRITE(ah, AR_OBS, 8); if (ah->config.rx_intr_mitigation) { REG_RMW_FIELD(ah, AR_RIMT, AR_RIMT_LAST, 500); @@ -1933,9 +1965,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (!ath9k_hw_init_cal(ah, chan)) return -EIO; - ath9k_hw_loadnf(ah, chan); - ath9k_hw_start_nfcal(ah, true); - if (ath9k_hw_mci_is_enabled(ah) && ar9003_mci_end_reset(ah, chan, caldata)) return -EIO; @@ -1971,7 +2000,8 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); } #ifdef __BIG_ENDIAN - else if (AR_SREV_9330(ah) || AR_SREV_9340(ah)) + else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) || + AR_SREV_9550(ah)) REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0); else REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD); @@ -1984,6 +2014,9 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (ath9k_hw_mci_is_enabled(ah)) ar9003_mci_check_bt(ah); + ath9k_hw_loadnf(ah, chan); + ath9k_hw_start_nfcal(ah, true); + if (AR_SREV_9300_20_OR_LATER(ah)) { ar9003_hw_bb_watchdog_config(ah); @@ -2111,6 +2144,9 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah) AR_RTC_FORCE_WAKE_EN); udelay(50); + if (ath9k_hw_mci_is_enabled(ah)) + ar9003_mci_set_power_awake(ah); + for (i = POWER_UP_TIME / 50; i > 0; i--) { val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; if (val == AR_RTC_STATUS_ON) @@ -3118,6 +3154,7 @@ static struct { { AR_SREV_VERSION_9340, "9340" }, { AR_SREV_VERSION_9485, "9485" }, { AR_SREV_VERSION_9462, "9462" }, + { AR_SREV_VERSION_9550, "9550" }, }; /* For devices with external radios */ diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 03d590924c64..26da1732978d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -48,6 +48,7 @@ #define AR9300_DEVID_AR9580 0x0033 #define AR9300_DEVID_AR9462 0x0034 #define AR9300_DEVID_AR9330 0x0035 +#define AR9300_DEVID_QCA955X 0x0038 #define AR5416_AR9100_DEVID 0x000b @@ -818,6 +819,7 @@ struct ath_hw { struct ar5416IniArray iniModesFastClock; struct ar5416IniArray iniAdditional; struct ar5416IniArray iniModesRxGain; + struct ar5416IniArray ini_modes_rx_gain_bounds; struct ar5416IniArray iniModesTxGain; struct ar5416IniArray iniCckfirNormal; struct ar5416IniArray iniCckfirJapan2484; @@ -1019,16 +1021,8 @@ void ar9002_hw_attach_ops(struct ath_hw *ah); void ar9003_hw_attach_ops(struct ath_hw *ah); void ar9002_hw_load_ani_reg(struct ath_hw *ah, struct ath9k_channel *chan); -/* - * ANI work can be shared between all families but a next - * generation implementation of ANI will be used only for AR9003 only - * for now as the other families still need to be tested with the same - * next generation ANI. Feel free to start testing it though for the - * older families (AR5008, AR9001, AR9002) by using modparam_force_new_ani. - */ -extern int modparam_force_new_ani; + void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning); -void ath9k_hw_proc_mib_event(struct ath_hw *ah); void ath9k_hw_ani_monitor(struct ath_hw *ah, struct ath9k_channel *chan); #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT @@ -1038,7 +1032,8 @@ static inline bool ath9k_hw_btcoex_is_enabled(struct ath_hw *ah) } static inline bool ath9k_hw_mci_is_enabled(struct ath_hw *ah) { - return ah->btcoex_hw.enabled && (ah->caps.hw_caps & ATH9K_HW_CAP_MCI); + return ah->common.btcoex_enabled && + (ah->caps.hw_caps & ATH9K_HW_CAP_MCI); } void ath9k_hw_btcoex_enable(struct ath_hw *ah); diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 0cc4c70f7f0c..91650fe50461 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -136,6 +136,14 @@ void ath_hw_pll_work(struct work_struct *work) u32 pll_sqsum; struct ath_softc *sc = container_of(work, struct ath_softc, hw_pll_work.work); + /* + * ensure that the PLL WAR is executed only + * after the STA is associated (or) if the + * beaconing had started in interfaces that + * uses beacons. + */ + if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) + return; ath9k_ps_wakeup(sc); pll_sqsum = ar9003_get_pll_sqsum_dvc(sc->sc_ah); @@ -399,6 +407,7 @@ void ath_ani_calibrate(unsigned long data) longcal ? "long" : "", shortcal ? "short" : "", aniflag ? "ani" : "", common->ani.caldone ? "true" : "false"); + ath9k_debug_samp_bb_mac(sc); ath9k_ps_restore(sc); set_timer: @@ -407,7 +416,6 @@ set_timer: * The interval must be the shortest necessary to satisfy ANI, * short calibration and long calibration. */ - ath9k_debug_samp_bb_mac(sc); cal_interval = ATH_LONG_CALINTERVAL; if (sc->sc_ah->config.enable_ani) cal_interval = min(cal_interval, diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 04ef775ccee1..7990cd55599c 100644 --- a/drivers/net/wireless/ath/ath9k/mac.c +++ b/drivers/net/wireless/ath/ath9k/mac.c @@ -810,7 +810,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah) return; } - if (AR_SREV_9340(ah)) + if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) sync_default &= ~AR_INTR_SYNC_HOST1_FATAL; async_mask = AR_INTR_MAC_IRQ; diff --git a/drivers/net/wireless/ath/ath9k/mac.h b/drivers/net/wireless/ath/ath9k/mac.h index 21c955609e6c..0eba36dca6f8 100644 --- a/drivers/net/wireless/ath/ath9k/mac.h +++ b/drivers/net/wireless/ath/ath9k/mac.h @@ -646,6 +646,7 @@ enum ath9k_rx_filter { ATH9K_RX_FILTER_PHYRADAR = 0x00002000, ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000, ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000, + ATH9K_RX_FILTER_4ADDRESS = 0x00100000, }; #define ATH9K_RATESERIES_RTS_CTS 0x0001 diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index c0f478b0a9a2..248e5b24acfa 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -19,7 +19,7 @@ #include "ath9k.h" #include "btcoex.h" -static u8 parse_mpdudensity(u8 mpdudensity) +u8 ath9k_parse_mpdudensity(u8 mpdudensity) { /* * 802.11n D2.0 defined values for "Minimum MPDU Start Spacing": @@ -130,6 +130,8 @@ void ath9k_ps_restore(struct ath_softc *sc) PS_WAIT_FOR_PSPOLL_DATA | PS_WAIT_FOR_TX_ACK))) { mode = ATH9K_PM_NETWORK_SLEEP; + if (ath9k_hw_btcoex_is_enabled(sc->sc_ah)) + ath9k_btcoex_stop_gen_timer(sc); } else { goto unlock; } @@ -150,6 +152,11 @@ static void __ath_cancel_work(struct ath_softc *sc) cancel_work_sync(&sc->hw_check_work); cancel_delayed_work_sync(&sc->tx_complete_work); cancel_delayed_work_sync(&sc->hw_pll_work); + +#ifdef CONFIG_ATH9K_BTCOEX_SUPPORT + if (ath9k_hw_mci_is_enabled(sc->sc_ah)) + cancel_work_sync(&sc->mci_work); +#endif } static void ath_cancel_work(struct ath_softc *sc) @@ -164,7 +171,8 @@ static void ath_restart_work(struct ath_softc *sc) ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); - if (AR_SREV_9485(sc->sc_ah) || AR_SREV_9340(sc->sc_ah)) + if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || + AR_SREV_9550(sc->sc_ah)) ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); @@ -317,6 +325,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, struct ieee80211_vif *vif) { struct ath_node *an; + u8 density; an = (struct ath_node *)sta->drv_priv; #ifdef CONFIG_ATH9K_DEBUGFS @@ -331,7 +340,8 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, ath_tx_node_init(sc, an); an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + sta->ht_cap.ampdu_factor); - an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); + density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); + an->mpdudensity = density; } } @@ -513,24 +523,6 @@ irqreturn_t ath_isr(int irq, void *dev) ath9k_hw_set_interrupts(ah); } - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_disable_interrupts(ah); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - spin_lock(&common->cc_lock); - ath9k_hw_proc_mib_event(ah); - spin_unlock(&common->cc_lock); - ath9k_hw_enable_interrupts(ah); - } - if (!(ah->caps.hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) if (status & ATH9K_INT_TIM_TIMER) { if (ATH_DBG_WARN_ON_ONCE(sc->ps_idle)) @@ -677,8 +669,6 @@ static int ath9k_start(struct ieee80211_hw *hw) spin_unlock_bh(&sc->sc_pcu_lock); - ath9k_start_btcoex(sc); - if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en) common->bus_ops->extn_synch_en(common); @@ -785,8 +775,6 @@ static void ath9k_stop(struct ieee80211_hw *hw) /* Ensure HW is awake when we try to shut it down. */ ath9k_ps_wakeup(sc); - ath9k_stop_btcoex(sc); - spin_lock_bh(&sc->sc_pcu_lock); /* prevent tasklets to enable interrupts once we disable them */ @@ -956,14 +944,10 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, /* * Enable MIB interrupts when there are hardware phy counters. */ - if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) { - if (ah->config.enable_ani) - ah->imask |= ATH9K_INT_MIB; + if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) ah->imask |= ATH9K_INT_TSFOOR; - } else { - ah->imask &= ~ATH9K_INT_MIB; + else ah->imask &= ~ATH9K_INT_TSFOOR; - } ath9k_hw_set_interrupts(ah); @@ -1033,15 +1017,6 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, } } - if ((ah->opmode == NL80211_IFTYPE_ADHOC) || - ((vif->type == NL80211_IFTYPE_ADHOC) && - sc->nvifs > 0)) { - ath_err(common, "Cannot create ADHOC interface when other" - " interfaces already exist.\n"); - ret = -EINVAL; - goto out; - } - ath_dbg(common, CONFIG, "Attach a VIF of type: %d\n", vif->type); sc->nvifs++; @@ -1066,15 +1041,6 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); - /* See if new interface type is valid. */ - if ((new_type == NL80211_IFTYPE_ADHOC) && - (sc->nvifs > 1)) { - ath_err(common, "When using ADHOC, it must be the only" - " interface.\n"); - ret = -EINVAL; - goto out; - } - if (ath9k_uses_beacons(new_type) && !ath9k_uses_beacons(vif->type)) { if (sc->nbcnvifs >= ATH_BCBUF) { @@ -1172,14 +1138,17 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (changed & IEEE80211_CONF_CHANGE_IDLE) { sc->ps_idle = !!(conf->flags & IEEE80211_CONF_IDLE); - if (sc->ps_idle) + if (sc->ps_idle) { ath_cancel_work(sc); - else + ath9k_stop_btcoex(sc); + } else { + ath9k_start_btcoex(sc); /* * The chip needs a reset to properly wake up from * full sleep */ reset_channel = ah->chip_fullsleep; + } } /* @@ -1258,6 +1227,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { ath_err(common, "Unable to set channel\n"); mutex_unlock(&sc->mutex); + ath9k_ps_restore(sc); return -EINVAL; } diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 49137f477b05..87acff7fdaae 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -20,7 +20,7 @@ #include "ath9k.h" #include "mci.h" -static const u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 }; +static const u8 ath_mci_duty_cycle[] = { 55, 50, 60, 70, 80, 85, 90, 95, 98 }; static struct ath_mci_profile_info* ath_mci_find_profile(struct ath_mci_profile *mci, @@ -28,11 +28,14 @@ ath_mci_find_profile(struct ath_mci_profile *mci, { struct ath_mci_profile_info *entry; + if (list_empty(&mci->info)) + return NULL; + list_for_each_entry(entry, &mci->info, list) { if (entry->conn_handle == info->conn_handle) - break; + return entry; } - return entry; + return NULL; } static bool ath_mci_add_profile(struct ath_common *common, @@ -49,31 +52,21 @@ static bool ath_mci_add_profile(struct ath_common *common, (info->type != MCI_GPM_COEX_PROFILE_VOICE)) return false; - entry = ath_mci_find_profile(mci, info); - - if (entry) { - memcpy(entry, info, 10); - } else { - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return false; + entry = kzalloc(sizeof(*entry), GFP_ATOMIC); + if (!entry) + return false; - memcpy(entry, info, 10); - INC_PROF(mci, info); - list_add_tail(&info->list, &mci->info); - } + memcpy(entry, info, 10); + INC_PROF(mci, info); + list_add_tail(&entry->list, &mci->info); return true; } static void ath_mci_del_profile(struct ath_common *common, struct ath_mci_profile *mci, - struct ath_mci_profile_info *info) + struct ath_mci_profile_info *entry) { - struct ath_mci_profile_info *entry; - - entry = ath_mci_find_profile(mci, info); - if (!entry) return; @@ -86,12 +79,16 @@ void ath_mci_flush_profile(struct ath_mci_profile *mci) { struct ath_mci_profile_info *info, *tinfo; + mci->aggr_limit = 0; + + if (list_empty(&mci->info)) + return; + list_for_each_entry_safe(info, tinfo, &mci->info, list) { list_del(&info->list); DEC_PROF(mci, info); kfree(info); } - mci->aggr_limit = 0; } static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex) @@ -123,6 +120,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc) if (mci_hw->config & ATH_MCI_CONFIG_DISABLE_TUNING) goto skip_tuning; + btcoex->duty_cycle = ath_mci_duty_cycle[num_profile]; + if (num_profile == 1) { info = list_first_entry(&mci->info, struct ath_mci_profile_info, @@ -175,18 +174,17 @@ skip_tuning: btcoex->btcoex_period >>= 1; } - ath9k_hw_btcoex_disable(sc->sc_ah); ath9k_btcoex_timer_pause(sc); + ath9k_hw_btcoex_disable(sc->sc_ah); if (IS_CHAN_5GHZ(sc->sc_ah->curchan)) return; - btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0); + btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_BDR_DUTY_CYCLE : 0); if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE) btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE; - btcoex->btcoex_period *= 1000; - btcoex->btcoex_no_stomp = btcoex->btcoex_period * + btcoex->btcoex_no_stomp = btcoex->btcoex_period * 1000 * (100 - btcoex->duty_cycle) / 100; ath9k_hw_btcoex_enable(sc->sc_ah); @@ -197,20 +195,16 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 payload[4] = {0, 0, 0, 0}; switch (opcode) { case MCI_GPM_BT_CAL_REQ: - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { - ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START, NULL); + if (mci_hw->bt_state == MCI_BT_AWAKE) { + ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START); ieee80211_queue_work(sc->hw, &sc->hw_reset_work); - } else { - ath_dbg(common, MCI, "MCI State mismatch: %d\n", - ar9003_mci_state(ah, MCI_STATE_BT, NULL)); } - break; - case MCI_GPM_BT_CAL_DONE: - ar9003_mci_state(ah, MCI_STATE_BT, NULL); + ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state); break; case MCI_GPM_BT_CAL_GRANT: MCI_GPM_SET_CAL_TYPE(payload, MCI_GPM_WLAN_CAL_DONE); @@ -223,32 +217,55 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) } } +static void ath9k_mci_work(struct work_struct *work) +{ + struct ath_softc *sc = container_of(work, struct ath_softc, mci_work); + + ath_mci_update_scheme(sc); +} + static void ath_mci_process_profile(struct ath_softc *sc, struct ath_mci_profile_info *info) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_btcoex *btcoex = &sc->btcoex; struct ath_mci_profile *mci = &btcoex->mci; + struct ath_mci_profile_info *entry = NULL; + + entry = ath_mci_find_profile(mci, info); + if (entry) { + /* + * Two MCI interrupts are generated while connecting to + * headset and A2DP profile, but only one MCI interrupt + * is generated with last added profile type while disconnecting + * both profiles. + * So while adding second profile type decrement + * the first one. + */ + if (entry->type != info->type) { + DEC_PROF(mci, entry); + INC_PROF(mci, info); + } + memcpy(entry, info, 10); + } if (info->start) { - if (!ath_mci_add_profile(common, mci, info)) + if (!entry && !ath_mci_add_profile(common, mci, info)) return; } else - ath_mci_del_profile(common, mci, info); + ath_mci_del_profile(common, mci, entry); btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD; mci->aggr_limit = mci->num_sco ? 6 : 0; - if (NUM_PROF(mci)) { + btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; + if (NUM_PROF(mci)) btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW; - btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)]; - } else { + else btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL : ATH_BTCOEX_STOMP_LOW; - btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE; - } - ath_mci_update_scheme(sc); + ieee80211_queue_work(sc->hw, &sc->mci_work); } static void ath_mci_process_status(struct ath_softc *sc, @@ -263,8 +280,6 @@ static void ath_mci_process_status(struct ath_softc *sc, if (status->is_link) return; - memset(&info, 0, sizeof(struct ath_mci_profile_info)); - info.conn_handle = status->conn_handle; if (ath_mci_find_profile(mci, &info)) return; @@ -284,7 +299,7 @@ static void ath_mci_process_status(struct ath_softc *sc, } while (++i < ATH_MCI_MAX_PROFILE); if (old_num_mgmt != mci->num_mgmt) - ath_mci_update_scheme(sc); + ieee80211_queue_work(sc->hw, &sc->mci_work); } static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) @@ -293,25 +308,20 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) struct ath_mci_profile_info profile_info; struct ath_mci_profile_status profile_status; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - u32 version; - u8 major; - u8 minor; + u8 major, minor; u32 seq_num; switch (opcode) { case MCI_GPM_COEX_VERSION_QUERY: - version = ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION, - NULL); + ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_COEX_VERSION); break; case MCI_GPM_COEX_VERSION_RESPONSE: major = *(rx_payload + MCI_GPM_COEX_B_MAJOR_VERSION); minor = *(rx_payload + MCI_GPM_COEX_B_MINOR_VERSION); - version = (major << 8) + minor; - version = ar9003_mci_state(ah, MCI_STATE_SET_BT_COEX_VERSION, - &version); + ar9003_mci_set_bt_version(ah, major, minor); break; case MCI_GPM_COEX_STATUS_QUERY: - ar9003_mci_state(ah, MCI_STATE_SEND_WLAN_CHANNELS, NULL); + ar9003_mci_send_wlan_channels(ah); break; case MCI_GPM_COEX_BT_PROFILE_INFO: memcpy(&profile_info, @@ -338,7 +348,7 @@ static void ath_mci_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) seq_num = *((u32 *)(rx_payload + 12)); ath_dbg(common, MCI, - "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%d\n", + "BT_Status_Update: is_link=%d, linkId=%d, state=%d, SEQ=%u\n", profile_status.is_link, profile_status.conn_handle, profile_status.is_critical, seq_num); @@ -378,6 +388,7 @@ int ath_mci_setup(struct ath_softc *sc) mci->gpm_buf.bf_addr, (mci->gpm_buf.bf_len >> 4), mci->sched_buf.bf_paddr); + INIT_WORK(&sc->mci_work, ath9k_mci_work); ath_dbg(common, MCI, "MCI Initialized\n"); return 0; @@ -405,6 +416,7 @@ void ath_mci_intr(struct ath_softc *sc) struct ath_mci_coex *mci = &sc->mci_coex; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_mci *mci_hw = &ah->btcoex_hw.mci; u32 mci_int, mci_int_rxmsg; u32 offset, subtype, opcode; u32 *pgpm; @@ -413,8 +425,8 @@ void ath_mci_intr(struct ath_softc *sc) ar9003_mci_get_interrupt(sc->sc_ah, &mci_int, &mci_int_rxmsg); - if (ar9003_mci_state(ah, MCI_STATE_ENABLE, NULL) == 0) { - ar9003_mci_state(ah, MCI_STATE_INIT_GPM_OFFSET, NULL); + if (ar9003_mci_state(ah, MCI_STATE_ENABLE) == 0) { + ar9003_mci_get_next_gpm_offset(ah, true, NULL); return; } @@ -433,46 +445,41 @@ void ath_mci_intr(struct ath_softc *sc) NULL, 0, true, false); mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE; - ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE, NULL); + ar9003_mci_state(ah, MCI_STATE_RESET_REQ_WAKE); /* * always do this for recovery and 2G/5G toggling and LNA_TRANS */ - ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, NULL); + ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING; - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_SLEEP) { - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != - MCI_BT_SLEEP) - ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE, - NULL); - } + if ((mci_hw->bt_state == MCI_BT_SLEEP) && + (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) != + MCI_BT_SLEEP)) + ar9003_mci_state(ah, MCI_STATE_SET_BT_AWAKE); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING; - if (ar9003_mci_state(ah, MCI_STATE_BT, NULL) == MCI_BT_AWAKE) { - if (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP, NULL) != - MCI_BT_AWAKE) - ar9003_mci_state(ah, MCI_STATE_SET_BT_SLEEP, - NULL); - } + if ((mci_hw->bt_state == MCI_BT_AWAKE) && + (ar9003_mci_state(ah, MCI_STATE_REMOTE_SLEEP) != + MCI_BT_AWAKE)) + mci_hw->bt_state = MCI_BT_SLEEP; } if ((mci_int & AR_MCI_INTERRUPT_RX_INVALID_HDR) || (mci_int & AR_MCI_INTERRUPT_CONT_INFO_TIMEOUT)) { - ar9003_mci_state(ah, MCI_STATE_RECOVER_RX, NULL); + ar9003_mci_state(ah, MCI_STATE_RECOVER_RX); skip_gpm = true; } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO) { mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO; - offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET, - NULL); + offset = ar9003_mci_state(ah, MCI_STATE_LAST_SCHD_MSG_OFFSET); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_GPM) { @@ -481,8 +488,8 @@ void ath_mci_intr(struct ath_softc *sc) while (more_data == MCI_GPM_MORE) { pgpm = mci->gpm_buf.bf_addr; - offset = ar9003_mci_state(ah, MCI_STATE_NEXT_GPM_OFFSET, - &more_data); + offset = ar9003_mci_get_next_gpm_offset(ah, false, + &more_data); if (offset == MCI_GPM_INVALID) break; @@ -523,23 +530,17 @@ void ath_mci_intr(struct ath_softc *sc) mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_LNA_INFO; if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_INFO) { - int value_dbm = ar9003_mci_state(ah, - MCI_STATE_CONT_RSSI_POWER, NULL); + int value_dbm = MS(mci_hw->cont_status, + AR_MCI_CONT_RSSI_POWER); mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_CONT_INFO; - if (ar9003_mci_state(ah, MCI_STATE_CONT_TXRX, NULL)) - ath_dbg(common, MCI, - "MCI CONT_INFO: (tx) pri = %d, pwr = %d dBm\n", - ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), - value_dbm); - else - ath_dbg(common, MCI, - "MCI CONT_INFO: (rx) pri = %d,pwr = %d dBm\n", - ar9003_mci_state(ah, - MCI_STATE_CONT_PRIORITY, NULL), - value_dbm); + ath_dbg(common, MCI, + "MCI CONT_INFO: (%s) pri = %d pwr = %d dBm\n", + MS(mci_hw->cont_status, AR_MCI_CONT_TXRX) ? + "tx" : "rx", + MS(mci_hw->cont_status, AR_MCI_CONT_PRIORITY), + value_dbm); } if (mci_int_rxmsg & AR_MCI_INTERRUPT_RX_MSG_CONT_NACK) diff --git a/drivers/net/wireless/ath/ath9k/rc.c b/drivers/net/wireless/ath/ath9k/rc.c index 92a6c0a87f89..e034add9cd5a 100644 --- a/drivers/net/wireless/ath/ath9k/rc.c +++ b/drivers/net/wireless/ath/ath9k/rc.c @@ -770,7 +770,7 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, struct ieee80211_tx_rate *rates = tx_info->control.rates; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; __le16 fc = hdr->frame_control; - u8 try_per_rate, i = 0, rix, high_rix; + u8 try_per_rate, i = 0, rix; int is_probe = 0; if (rate_control_send_low(sta, priv_sta, txrc)) @@ -791,7 +791,6 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, rate_table = ath_rc_priv->rate_table; rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe, false); - high_rix = rix; /* * If we're in HT mode and both us and our peer supports LDPC. @@ -839,16 +838,16 @@ static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, try_per_rate = 8; /* - * Use a legacy rate as last retry to ensure that the frame - * is tried in both MCS and legacy rates. + * If the last rate in the rate series is MCS and has + * more than 80% of per thresh, then use a legacy rate + * as last retry to ensure that the frame is tried in both + * MCS and legacy rate. */ - if ((rates[2].flags & IEEE80211_TX_RC_MCS) && - (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU) || - (ath_rc_priv->per[high_rix] > 45))) + ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy) && + (ath_rc_priv->per[rix] > 45)) rix = ath_rc_get_highest_rix(sc, ath_rc_priv, rate_table, &is_probe, true); - else - ath_rc_get_lower_rix(rate_table, ath_rc_priv, rix, &rix); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, &rates[i], txrc, diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index fbdcc80437fe..11f3703a420a 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -430,6 +430,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc) rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; } + if (AR_SREV_9550(sc->sc_ah)) + rfilt |= ATH9K_RX_FILTER_4ADDRESS; + return rfilt; } @@ -658,9 +661,9 @@ static bool ath_edma_get_buffers(struct ath_softc *sc, __skb_unlink(skb, &rx_edma->rx_fifo); list_add_tail(&bf->list, &sc->rx.rxbuf); ath_rx_edma_buf_link(sc, qtype); - } else { - bf = NULL; } + + bf = NULL; } *dest = bf; @@ -785,7 +788,8 @@ static bool ath9k_rx_accept(struct ath_common *common, * descriptor does contain a valid key index. This has been observed * mostly with CCMP encryption. */ - if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID) + if (rx_stats->rs_keyix == ATH9K_RXKEYIX_INVALID || + !test_bit(rx_stats->rs_keyix, common->ccmp_keymap)) rx_stats->rs_status &= ~ATH9K_RXERR_KEYMISS; if (!rx_stats->rs_datalen) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 560d6effac7a..6592c07ac646 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -798,6 +798,7 @@ #define AR_SREV_REVISION_9580_10 4 /* AR9580 1.0 */ #define AR_SREV_VERSION_9462 0x280 #define AR_SREV_REVISION_9462_20 2 +#define AR_SREV_VERSION_9550 0x400 #define AR_SREV_5416(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \ @@ -905,6 +906,9 @@ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9462) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9462_20)) +#define AR_SREV_9550(_ah) \ + (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9550)) + #define AR_SREV_9580(_ah) \ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \ ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10)) @@ -1643,11 +1647,11 @@ enum { #define AR_TPC 0x80e8 #define AR_TPC_ACK 0x0000003f -#define AR_TPC_ACK_S 0x00 +#define AR_TPC_ACK_S 0 #define AR_TPC_CTS 0x00003f00 -#define AR_TPC_CTS_S 0x08 +#define AR_TPC_CTS_S 8 #define AR_TPC_CHIRP 0x003f0000 -#define AR_TPC_CHIRP_S 0x16 +#define AR_TPC_CHIRP_S 16 #define AR_QUIET1 0x80fc #define AR_QUIET1_NEXT_QUIET_S 0 @@ -2077,12 +2081,6 @@ enum { AR_MCI_INTERRUPT_RX_MSG_REMOTE_RESET| \ AR_MCI_INTERRUPT_RX_MSG_SYS_WAKING | \ AR_MCI_INTERRUPT_RX_MSG_SYS_SLEEPING| \ - AR_MCI_INTERRUPT_RX_MSG_SCHD_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_CONTROL | \ - AR_MCI_INTERRUPT_RX_MSG_LNA_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_NACK | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_INFO | \ - AR_MCI_INTERRUPT_RX_MSG_CONT_RST | \ AR_MCI_INTERRUPT_RX_MSG_REQ_WAKE) #define AR_MCI_CPU_INT 0x1840 @@ -2098,8 +2096,8 @@ enum { #define AR_MCI_CONT_STATUS 0x1848 #define AR_MCI_CONT_RSSI_POWER 0x000000FF #define AR_MCI_CONT_RSSI_POWER_S 0 -#define AR_MCI_CONT_RRIORITY 0x0000FF00 -#define AR_MCI_CONT_RRIORITY_S 8 +#define AR_MCI_CONT_PRIORITY 0x0000FF00 +#define AR_MCI_CONT_PRIORITY_S 8 #define AR_MCI_CONT_TXRX 0x00010000 #define AR_MCI_CONT_TXRX_S 16 @@ -2162,10 +2160,6 @@ enum { #define AR_BTCOEX_CTRL_SPDT_POLARITY 0x80000000 #define AR_BTCOEX_CTRL_SPDT_POLARITY_S 31 -#define AR_BTCOEX_WL_WEIGHTS0 0x18b0 -#define AR_BTCOEX_WL_WEIGHTS1 0x18b4 -#define AR_BTCOEX_WL_WEIGHTS2 0x18b8 -#define AR_BTCOEX_WL_WEIGHTS3 0x18bc #define AR_BTCOEX_MAX_TXPWR(_x) (0x18c0 + ((_x) << 2)) #define AR_BTCOEX_WL_LNA 0x1940 #define AR_BTCOEX_RFGAIN_CTRL 0x1944 diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index f777ddcd1172..cafb4a09729a 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -938,6 +938,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; const struct ieee80211_rate *rate; struct ieee80211_hdr *hdr; + struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu); int i; u8 rix = 0; @@ -948,18 +949,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, /* set dur_update_en for l-sig computation except for PS-Poll frames */ info->dur_update = !ieee80211_is_pspoll(hdr->frame_control); - - /* - * We check if Short Preamble is needed for the CTS rate by - * checking the BSS's global flag. - * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. - */ - rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info); - info->rtscts_rate = rate->hw_value; - - if (tx_info->control.vif && - tx_info->control.vif->bss_conf.use_short_preamble) - info->rtscts_rate |= rate->hw_value_short; + info->rtscts_rate = fi->rtscts_rate; for (i = 0; i < 4; i++) { bool is_40, is_sgi, is_sp; @@ -1001,13 +991,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, } /* legacy rates */ + rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; if ((tx_info->band == IEEE80211_BAND_2GHZ) && !(rate->flags & IEEE80211_RATE_ERP_G)) phy = WLAN_RC_PHY_CCK; else phy = WLAN_RC_PHY_OFDM; - rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx]; info->rates[i].Rate = rate->hw_value; if (rate->hw_value_short) { if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) @@ -1175,6 +1165,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, { struct ath_atx_tid *txtid; struct ath_node *an; + u8 density; an = (struct ath_node *)sta->drv_priv; txtid = ATH_AN_2_TID(an, tid); @@ -1182,6 +1173,17 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE)) return -EAGAIN; + /* update ampdu factor/density, they may have changed. This may happen + * in HT IBSS when a beacon with HT-info is received after the station + * has already been added. + */ + if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) { + an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density); + an->mpdudensity = density; + } + txtid->state |= AGGR_ADDBA_PROGRESS; txtid->paused = true; *ssn = txtid->seq_start = txtid->seq_next; @@ -1776,10 +1778,22 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, struct ieee80211_sta *sta = tx_info->control.sta; struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + const struct ieee80211_rate *rate; struct ath_frame_info *fi = get_frame_info(skb); struct ath_node *an = NULL; enum ath9k_key_type keytype; + bool short_preamble = false; + + /* + * We check if Short Preamble is needed for the CTS rate by + * checking the BSS's global flag. + * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used. + */ + if (tx_info->control.vif && + tx_info->control.vif->bss_conf.use_short_preamble) + short_preamble = true; + rate = ieee80211_get_rts_cts_rate(hw, tx_info); keytype = ath9k_cmn_get_hw_crypto_keytype(skb); if (sta) @@ -1794,6 +1808,9 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb, fi->keyix = ATH9K_TXKEYIX_INVALID; fi->keytype = keytype; fi->framelen = framelen; + fi->rtscts_rate = rate->hw_value; + if (short_preamble) + fi->rtscts_rate |= rate->hw_value_short; } u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate) diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 0cea20e3e250..376be11161c0 100644 --- a/drivers/net/wireless/ath/carl9170/carl9170.h +++ b/drivers/net/wireless/ath/carl9170/carl9170.h @@ -289,6 +289,7 @@ struct ar9170 { unsigned int mem_block_size; unsigned int rx_size; unsigned int tx_seq_table; + bool ba_filter; } fw; /* interface configuration combinations */ @@ -425,6 +426,10 @@ struct ar9170 { struct sk_buff *rx_failover; int rx_failover_missing; + /* FIFO for collecting outstanding BlockAckRequest */ + struct list_head bar_list[__AR9170_NUM_TXQ]; + spinlock_t bar_list_lock[__AR9170_NUM_TXQ]; + #ifdef CONFIG_CARL9170_WPC struct { bool pbc_state; @@ -468,6 +473,12 @@ enum carl9170_ps_off_override_reasons { PS_OFF_BCN = BIT(1), }; +struct carl9170_bar_list_entry { + struct list_head list; + struct rcu_head head; + struct sk_buff *skb; +}; + struct carl9170_ba_stats { u8 ampdu_len; u8 ampdu_ack_len; diff --git a/drivers/net/wireless/ath/carl9170/fw.c b/drivers/net/wireless/ath/carl9170/fw.c index 5c73c03872f3..c5ca6f1f5836 100644 --- a/drivers/net/wireless/ath/carl9170/fw.c +++ b/drivers/net/wireless/ath/carl9170/fw.c @@ -307,6 +307,9 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len) if (SUPP(CARL9170FW_WOL)) device_set_wakeup_enable(&ar->udev->dev, true); + if (SUPP(CARL9170FW_RX_BA_FILTER)) + ar->fw.ba_filter = true; + if_comb_types = BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_P2P_CLIENT); diff --git a/drivers/net/wireless/ath/carl9170/fwdesc.h b/drivers/net/wireless/ath/carl9170/fwdesc.h index 6d9c0891ce7f..66848d47c88e 100644 --- a/drivers/net/wireless/ath/carl9170/fwdesc.h +++ b/drivers/net/wireless/ath/carl9170/fwdesc.h @@ -78,6 +78,9 @@ enum carl9170fw_feature_list { /* HW (ANI, CCA, MIB) tally counters */ CARL9170FW_HW_COUNTERS, + /* Firmware will pass BA when BARs are queued */ + CARL9170FW_RX_BA_FILTER, + /* KEEP LAST */ __CARL9170FW_FEATURE_NUM }; diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c index 8d2523b3f722..858e58dfc4dc 100644 --- a/drivers/net/wireless/ath/carl9170/main.c +++ b/drivers/net/wireless/ath/carl9170/main.c @@ -949,6 +949,9 @@ static void carl9170_op_configure_filter(struct ieee80211_hw *hw, if (ar->fw.rx_filter && changed_flags & ar->rx_filter_caps) { u32 rx_filter = 0; + if (!ar->fw.ba_filter) + rx_filter |= CARL9170_RX_FILTER_CTL_OTHER; + if (!(*new_flags & (FIF_FCSFAIL | FIF_PLCPFAIL))) rx_filter |= CARL9170_RX_FILTER_BAD; @@ -1753,6 +1756,9 @@ void *carl9170_alloc(size_t priv_size) for (i = 0; i < ar->hw->queues; i++) { skb_queue_head_init(&ar->tx_status[i]); skb_queue_head_init(&ar->tx_pending[i]); + + INIT_LIST_HEAD(&ar->bar_list[i]); + spin_lock_init(&ar->bar_list_lock[i]); } INIT_WORK(&ar->ps_work, carl9170_ps_work); INIT_WORK(&ar->ping_work, carl9170_ping_work); diff --git a/drivers/net/wireless/ath/carl9170/rx.c b/drivers/net/wireless/ath/carl9170/rx.c index 84b22eec7abd..25910a14e79c 100644 --- a/drivers/net/wireless/ath/carl9170/rx.c +++ b/drivers/net/wireless/ath/carl9170/rx.c @@ -576,6 +576,53 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len) } } +static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len) +{ + struct ieee80211_bar *bar = (void *) data; + struct carl9170_bar_list_entry *entry; + unsigned int queue; + + if (likely(!ieee80211_is_back(bar->frame_control))) + return; + + if (len <= sizeof(*bar) + FCS_LEN) + return; + + queue = TID_TO_WME_AC(((le16_to_cpu(bar->control) & + IEEE80211_BAR_CTRL_TID_INFO_MASK) >> + IEEE80211_BAR_CTRL_TID_INFO_SHIFT) & 7); + + rcu_read_lock(); + list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) { + struct sk_buff *entry_skb = entry->skb; + struct _carl9170_tx_superframe *super = (void *)entry_skb->data; + struct ieee80211_bar *entry_bar = (void *)super->frame_data; + +#define TID_CHECK(a, b) ( \ + ((a) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK)) == \ + ((b) & cpu_to_le16(IEEE80211_BAR_CTRL_TID_INFO_MASK))) \ + + if (bar->start_seq_num == entry_bar->start_seq_num && + TID_CHECK(bar->control, entry_bar->control) && + compare_ether_addr(bar->ra, entry_bar->ta) == 0 && + compare_ether_addr(bar->ta, entry_bar->ra) == 0) { + struct ieee80211_tx_info *tx_info; + + tx_info = IEEE80211_SKB_CB(entry_skb); + tx_info->flags |= IEEE80211_TX_STAT_ACK; + + spin_lock_bh(&ar->bar_list_lock[queue]); + list_del_rcu(&entry->list); + spin_unlock_bh(&ar->bar_list_lock[queue]); + kfree_rcu(entry, head); + break; + } + } + rcu_read_unlock(); + +#undef TID_CHECK +} + static bool carl9170_ampdu_check(struct ar9170 *ar, u8 *buf, u8 ms) { __le16 fc; @@ -738,6 +785,8 @@ static void carl9170_handle_mpdu(struct ar9170 *ar, u8 *buf, int len) carl9170_ps_beacon(ar, buf, mpdu_len); + carl9170_ba_check(ar, buf, mpdu_len); + skb = carl9170_rx_copy_data(buf, mpdu_len); if (!skb) goto drop; diff --git a/drivers/net/wireless/ath/carl9170/tx.c b/drivers/net/wireless/ath/carl9170/tx.c index aed305177af6..6a8681407a1d 100644 --- a/drivers/net/wireless/ath/carl9170/tx.c +++ b/drivers/net/wireless/ath/carl9170/tx.c @@ -277,11 +277,11 @@ static void carl9170_tx_release(struct kref *ref) return; BUILD_BUG_ON( - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); - memset(&txinfo->status.ampdu_ack_len, 0, + memset(&txinfo->status.ack_signal, 0, sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + offsetof(struct ieee80211_tx_info, status.ack_signal)); if (atomic_read(&ar->tx_total_queued)) ar->tx_schedule = true; @@ -436,6 +436,45 @@ out_rcu: rcu_read_unlock(); } +static void carl9170_tx_bar_status(struct ar9170 *ar, struct sk_buff *skb, + struct ieee80211_tx_info *tx_info) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_bar *bar = (void *) super->frame_data; + + /* + * Unlike all other frames, the status report for BARs does + * not directly come from the hardware as it is incapable of + * matching a BA to a previously send BAR. + * Instead the RX-path will scan for incoming BAs and set the + * IEEE80211_TX_STAT_ACK if it sees one that was likely + * caused by a BAR from us. + */ + + if (unlikely(ieee80211_is_back_req(bar->frame_control)) && + !(tx_info->flags & IEEE80211_TX_STAT_ACK)) { + struct carl9170_bar_list_entry *entry; + int queue = skb_get_queue_mapping(skb); + + rcu_read_lock(); + list_for_each_entry_rcu(entry, &ar->bar_list[queue], list) { + if (entry->skb == skb) { + spin_lock_bh(&ar->bar_list_lock[queue]); + list_del_rcu(&entry->list); + spin_unlock_bh(&ar->bar_list_lock[queue]); + kfree_rcu(entry, head); + goto out; + } + } + + WARN(1, "bar not found in %d - ra:%pM ta:%pM c:%x ssn:%x\n", + queue, bar->ra, bar->ta, bar->control, + bar->start_seq_num); +out: + rcu_read_unlock(); + } +} + void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, const bool success) { @@ -445,6 +484,8 @@ void carl9170_tx_status(struct ar9170 *ar, struct sk_buff *skb, txinfo = IEEE80211_SKB_CB(skb); + carl9170_tx_bar_status(ar, skb, txinfo); + if (success) txinfo->flags |= IEEE80211_TX_STAT_ACK; else @@ -1265,6 +1306,26 @@ out_rcu: return false; } +static void carl9170_bar_check(struct ar9170 *ar, struct sk_buff *skb) +{ + struct _carl9170_tx_superframe *super = (void *) skb->data; + struct ieee80211_bar *bar = (void *) super->frame_data; + + if (unlikely(ieee80211_is_back_req(bar->frame_control)) && + skb->len >= sizeof(struct ieee80211_bar)) { + struct carl9170_bar_list_entry *entry; + unsigned int queue = skb_get_queue_mapping(skb); + + entry = kmalloc(sizeof(*entry), GFP_ATOMIC); + if (!WARN_ON_ONCE(!entry)) { + entry->skb = skb; + spin_lock_bh(&ar->bar_list_lock[queue]); + list_add_tail_rcu(&entry->list, &ar->bar_list[queue]); + spin_unlock_bh(&ar->bar_list_lock[queue]); + } + } +} + static void carl9170_tx(struct ar9170 *ar) { struct sk_buff *skb; @@ -1287,6 +1348,8 @@ static void carl9170_tx(struct ar9170 *ar) if (unlikely(carl9170_tx_ps_drop(ar, skb))) continue; + carl9170_bar_check(ar, skb); + atomic_inc(&ar->tx_total_pending); q = __carl9170_get_queue(ar, i); diff --git a/drivers/net/wireless/ath/carl9170/version.h b/drivers/net/wireless/ath/carl9170/version.h index e651db856344..2ec3e9191e4d 100644 --- a/drivers/net/wireless/ath/carl9170/version.h +++ b/drivers/net/wireless/ath/carl9170/version.h @@ -1,7 +1,7 @@ #ifndef __CARL9170_SHARED_VERSION_H #define __CARL9170_SHARED_VERSION_H -#define CARL9170FW_VERSION_YEAR 11 -#define CARL9170FW_VERSION_MONTH 8 -#define CARL9170FW_VERSION_DAY 15 -#define CARL9170FW_VERSION_GIT "1.9.4" +#define CARL9170FW_VERSION_YEAR 12 +#define CARL9170FW_VERSION_MONTH 7 +#define CARL9170FW_VERSION_DAY 7 +#define CARL9170FW_VERSION_GIT "1.9.6" #endif /* __CARL9170_SHARED_VERSION_H */ diff --git a/drivers/net/wireless/ath/key.c b/drivers/net/wireless/ath/key.c index 0e81904956cf..5c54aa43ca2d 100644 --- a/drivers/net/wireless/ath/key.c +++ b/drivers/net/wireless/ath/key.c @@ -556,6 +556,9 @@ int ath_key_config(struct ath_common *common, return -EIO; set_bit(idx, common->keymap); + if (key->cipher == WLAN_CIPHER_SUITE_CCMP) + set_bit(idx, common->ccmp_keymap); + if (key->cipher == WLAN_CIPHER_SUITE_TKIP) { set_bit(idx + 64, common->keymap); set_bit(idx, common->tkip_keymap); @@ -582,6 +585,7 @@ void ath_key_delete(struct ath_common *common, struct ieee80211_key_conf *key) return; clear_bit(key->hw_key_idx, common->keymap); + clear_bit(key->hw_key_idx, common->ccmp_keymap); if (key->cipher != WLAN_CIPHER_SUITE_TKIP) return; diff --git a/drivers/net/wireless/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 108118820b36..b92bb9c92ad1 100644 --- a/drivers/net/wireless/b43/phy_n.c +++ b/drivers/net/wireless/b43/phy_n.c @@ -1369,7 +1369,7 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) i << 2); b43_nphy_poll_rssi(dev, 2, results[i], 8); } - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i += 2) { s32 curr; s32 mind = 40; s32 minpoll = 249; @@ -1415,14 +1415,15 @@ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev) b43_nphy_scale_offset_rssi(dev, 0, 0, core + 1, 1, i); b43_nphy_poll_rssi(dev, i, poll_results, 8); for (j = 0; j < 4; j++) { - if (j / 2 == core) + if (j / 2 == core) { offset[j] = 232 - poll_results[j]; - if (offset[j] < 0) - offset[j] = -(abs(offset[j] + 4) / 8); - else - offset[j] = (offset[j] + 4) / 8; - b43_nphy_scale_offset_rssi(dev, 0, - offset[2 * core], core + 1, j % 2, i); + if (offset[j] < 0) + offset[j] = -(abs(offset[j] + 4) / 8); + else + offset[j] = (offset[j] + 4) / 8; + b43_nphy_scale_offset_rssi(dev, 0, + offset[2 * core], core + 1, j % 2, i); + } } } } diff --git a/drivers/net/wireless/brcm80211/brcmfmac/Makefile b/drivers/net/wireless/brcm80211/brcmfmac/Makefile index abb48032753b..9d5170b6df50 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmfmac/Makefile @@ -34,3 +34,5 @@ brcmfmac-$(CONFIG_BRCMFMAC_SDIO) += \ sdio_chip.o brcmfmac-$(CONFIG_BRCMFMAC_USB) += \ usb.o +brcmfmac-$(CONFIG_BRCMDBG) += \ + dhd_dbg.o
\ No newline at end of file diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index 82f51dbd0d66..49765d34b4e0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -44,6 +44,7 @@ #define SDIO_DEVICE_ID_BROADCOM_4329 0x4329 #define SDIO_DEVICE_ID_BROADCOM_4330 0x4330 +#define SDIO_DEVICE_ID_BROADCOM_4334 0x4334 #define SDIO_FUNC1_BLOCKSIZE 64 #define SDIO_FUNC2_BLOCKSIZE 512 @@ -52,6 +53,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)}, {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)}, + {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)}, { /* end: all zeroes */ }, }; MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h index 9f637014486e..a11fe54f5950 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd.h @@ -613,6 +613,9 @@ struct brcmf_pub { struct work_struct multicast_work; u8 macvalue[ETH_ALEN]; atomic_t pend_8021x_cnt; +#ifdef DEBUG + struct dentry *dbgfs_dir; +#endif }; struct brcmf_if_event { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h index 366916494be4..537f499cc5d2 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h @@ -36,6 +36,13 @@ struct dngl_stats { unsigned long multicast; /* multicast packets received */ }; +struct brcmf_bus_dcmd { + char *name; + char *param; + int param_len; + struct list_head list; +}; + /* interface structure between common and bus layer */ struct brcmf_bus { u8 type; /* bus type */ @@ -50,6 +57,7 @@ struct brcmf_bus { unsigned long tx_realloc; /* Tx packets realloced for headroom */ struct dngl_stats dstats; /* Stats for dongle-based data */ u8 align; /* bus alignment requirement */ + struct list_head dcmd_list; /* interface functions pointers */ /* Stop bus module: clear pending frames, disable data flow */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c index 236cb9fa460c..2621dd3d7dcd 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c @@ -800,13 +800,13 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) char iovbuf[BRCMF_EVENTING_MASK_LEN + 12]; /* Room for "event_msgs" + '\0' + bitvec */ char buf[128], *ptr; - u32 dongle_align = drvr->bus_if->align; - u32 glom = 0; u32 roaming = 1; uint bcn_timeout = 3; int scan_assoc_time = 40; int scan_unassoc_time = 40; int i; + struct brcmf_bus_dcmd *cmdlst; + struct list_head *cur, *q; mutex_lock(&drvr->proto_block); @@ -827,17 +827,6 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) /* Print fw version info */ brcmf_dbg(ERROR, "Firmware version = %s\n", buf); - /* Match Host and Dongle rx alignment */ - brcmf_c_mkiovar("bus:txglomalign", (char *)&dongle_align, 4, iovbuf, - sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - - /* disable glom option per default */ - brcmf_c_mkiovar("bus:txglom", (char *)&glom, 4, iovbuf, sizeof(iovbuf)); - brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, iovbuf, - sizeof(iovbuf)); - /* Setup timeout if Beacons are lost and roam is off to report link down */ brcmf_c_mkiovar("bcn_timeout", (char *)&bcn_timeout, 4, iovbuf, @@ -874,6 +863,20 @@ int brcmf_c_preinit_dcmds(struct brcmf_pub *drvr) 0, true); } + /* set bus specific command if there is any */ + list_for_each_safe(cur, q, &drvr->bus_if->dcmd_list) { + cmdlst = list_entry(cur, struct brcmf_bus_dcmd, list); + if (cmdlst->name && cmdlst->param && cmdlst->param_len) { + brcmf_c_mkiovar(cmdlst->name, cmdlst->param, + cmdlst->param_len, iovbuf, + sizeof(iovbuf)); + brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_SET_VAR, + iovbuf, sizeof(iovbuf)); + } + list_del(cur); + kfree(cmdlst); + } + mutex_unlock(&drvr->proto_block); return 0; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c new file mode 100644 index 000000000000..7f89540b56da --- /dev/null +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2012 Broadcom Corporation + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/debugfs.h> +#include <linux/if_ether.h> +#include <linux/if.h> +#include <linux/ieee80211.h> +#include <linux/module.h> + +#include <defs.h> +#include <brcmu_wifi.h> +#include <brcmu_utils.h> +#include "dhd.h" +#include "dhd_bus.h" +#include "dhd_dbg.h" + +static struct dentry *root_folder; + +void brcmf_debugfs_init(void) +{ + root_folder = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (IS_ERR(root_folder)) + root_folder = NULL; +} + +void brcmf_debugfs_exit(void) +{ + if (!root_folder) + return; + + debugfs_remove_recursive(root_folder); + root_folder = NULL; +} + +int brcmf_debugfs_attach(struct brcmf_pub *drvr) +{ + if (!root_folder) + return -ENODEV; + + drvr->dbgfs_dir = debugfs_create_dir(dev_name(drvr->dev), root_folder); + return PTR_RET(drvr->dbgfs_dir); +} + +void brcmf_debugfs_detach(struct brcmf_pub *drvr) +{ + if (!IS_ERR_OR_NULL(drvr->dbgfs_dir)) + debugfs_remove_recursive(drvr->dbgfs_dir); +} + +struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr) +{ + return drvr->dbgfs_dir; +} + +static +ssize_t brcmf_debugfs_sdio_counter_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + struct brcmf_sdio_count *sdcnt = f->private_data; + char buf[750]; + int res; + + /* only allow read from start */ + if (*ppos > 0) + return 0; + + res = scnprintf(buf, sizeof(buf), + "intrcount: %u\nlastintrs: %u\n" + "pollcnt: %u\nregfails: %u\n" + "tx_sderrs: %u\nfcqueued: %u\n" + "rxrtx: %u\nrx_toolong: %u\n" + "rxc_errors: %u\nrx_hdrfail: %u\n" + "rx_badhdr: %u\nrx_badseq: %u\n" + "fc_rcvd: %u\nfc_xoff: %u\n" + "fc_xon: %u\nrxglomfail: %u\n" + "rxglomframes: %u\nrxglompkts: %u\n" + "f2rxhdrs: %u\nf2rxdata: %u\n" + "f2txdata: %u\nf1regdata: %u\n" + "tickcnt: %u\ntx_ctlerrs: %lu\n" + "tx_ctlpkts: %lu\nrx_ctlerrs: %lu\n" + "rx_ctlpkts: %lu\nrx_readahead: %lu\n", + sdcnt->intrcount, sdcnt->lastintrs, + sdcnt->pollcnt, sdcnt->regfails, + sdcnt->tx_sderrs, sdcnt->fcqueued, + sdcnt->rxrtx, sdcnt->rx_toolong, + sdcnt->rxc_errors, sdcnt->rx_hdrfail, + sdcnt->rx_badhdr, sdcnt->rx_badseq, + sdcnt->fc_rcvd, sdcnt->fc_xoff, + sdcnt->fc_xon, sdcnt->rxglomfail, + sdcnt->rxglomframes, sdcnt->rxglompkts, + sdcnt->f2rxhdrs, sdcnt->f2rxdata, + sdcnt->f2txdata, sdcnt->f1regdata, + sdcnt->tickcnt, sdcnt->tx_ctlerrs, + sdcnt->tx_ctlpkts, sdcnt->rx_ctlerrs, + sdcnt->rx_ctlpkts, sdcnt->rx_readahead_cnt); + + return simple_read_from_buffer(data, count, ppos, buf, res); +} + +static const struct file_operations brcmf_debugfs_sdio_counter_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcmf_debugfs_sdio_counter_read +}; + +void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, + struct brcmf_sdio_count *sdcnt) +{ + struct dentry *dentry = drvr->dbgfs_dir; + + if (!IS_ERR_OR_NULL(dentry)) + debugfs_create_file("counters", S_IRUGO, dentry, + sdcnt, &brcmf_debugfs_sdio_counter_ops); +} diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h index a2c4576cf9ff..b784920532d3 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h @@ -76,4 +76,63 @@ do { \ extern int brcmf_msg_level; +/* + * hold counter variables used in brcmfmac sdio driver. + */ +struct brcmf_sdio_count { + uint intrcount; /* Count of device interrupt callbacks */ + uint lastintrs; /* Count as of last watchdog timer */ + uint pollcnt; /* Count of active polls */ + uint regfails; /* Count of R_REG failures */ + uint tx_sderrs; /* Count of tx attempts with sd errors */ + uint fcqueued; /* Tx packets that got queued */ + uint rxrtx; /* Count of rtx requests (NAK to dongle) */ + uint rx_toolong; /* Receive frames too long to receive */ + uint rxc_errors; /* SDIO errors when reading control frames */ + uint rx_hdrfail; /* SDIO errors on header reads */ + uint rx_badhdr; /* Bad received headers (roosync?) */ + uint rx_badseq; /* Mismatched rx sequence number */ + uint fc_rcvd; /* Number of flow-control events received */ + uint fc_xoff; /* Number which turned on flow-control */ + uint fc_xon; /* Number which turned off flow-control */ + uint rxglomfail; /* Failed deglom attempts */ + uint rxglomframes; /* Number of glom frames (superframes) */ + uint rxglompkts; /* Number of packets from glom frames */ + uint f2rxhdrs; /* Number of header reads */ + uint f2rxdata; /* Number of frame data reads */ + uint f2txdata; /* Number of f2 frame writes */ + uint f1regdata; /* Number of f1 register accesses */ + uint tickcnt; /* Number of watchdog been schedule */ + ulong tx_ctlerrs; /* Err of sending ctrl frames */ + ulong tx_ctlpkts; /* Ctrl frames sent to dongle */ + ulong rx_ctlerrs; /* Err of processing rx ctrl frames */ + ulong rx_ctlpkts; /* Ctrl frames processed from dongle */ + ulong rx_readahead_cnt; /* packets where header read-ahead was used */ +}; + +struct brcmf_pub; +#ifdef DEBUG +void brcmf_debugfs_init(void); +void brcmf_debugfs_exit(void); +int brcmf_debugfs_attach(struct brcmf_pub *drvr); +void brcmf_debugfs_detach(struct brcmf_pub *drvr); +struct dentry *brcmf_debugfs_get_devdir(struct brcmf_pub *drvr); +void brcmf_debugfs_create_sdio_count(struct brcmf_pub *drvr, + struct brcmf_sdio_count *sdcnt); +#else +static inline void brcmf_debugfs_init(void) +{ +} +static inline void brcmf_debugfs_exit(void) +{ +} +static inline int brcmf_debugfs_attach(struct brcmf_pub *drvr) +{ + return 0; +} +static inline void brcmf_debugfs_detach(struct brcmf_pub *drvr) +{ +} +#endif + #endif /* _BRCMF_DBG_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c index 8933f9b31a9a..57bf1d7ee80f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c @@ -1007,6 +1007,9 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) drvr->bus_if->drvr = drvr; drvr->dev = dev; + /* create device debugfs folder */ + brcmf_debugfs_attach(drvr); + /* Attach and link in the protocol */ ret = brcmf_proto_attach(drvr); if (ret != 0) { @@ -1017,6 +1020,8 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev) INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address); INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list); + INIT_LIST_HEAD(&drvr->bus_if->dcmd_list); + return ret; fail: @@ -1123,6 +1128,7 @@ void brcmf_detach(struct device *dev) brcmf_proto_detach(drvr); } + brcmf_debugfs_detach(drvr); bus_if->drvr = NULL; kfree(drvr); } @@ -1192,6 +1198,8 @@ exit: static void brcmf_driver_init(struct work_struct *work) { + brcmf_debugfs_init(); + #ifdef CONFIG_BRCMFMAC_SDIO brcmf_sdio_init(); #endif @@ -1219,6 +1227,7 @@ static void __exit brcmfmac_module_exit(void) #ifdef CONFIG_BRCMFMAC_USB brcmf_usb_exit(); #endif + brcmf_debugfs_exit(); } module_init(brcmfmac_module_init); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 1dbf2be478c8..5c868bac1c1c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -31,6 +31,8 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/bcma/bcma.h> +#include <linux/debugfs.h> +#include <linux/vmalloc.h> #include <asm/unaligned.h> #include <defs.h> #include <brcmu_wifi.h> @@ -48,6 +50,9 @@ #define CBUF_LEN (128) +/* Device console log buffer state */ +#define CONSOLE_BUFFER_MAX 2024 + struct rte_log_le { __le32 buf; /* Can't be pointer on (64-bit) hosts */ __le32 buf_size; @@ -281,7 +286,7 @@ struct rte_console { * Shared structure between dongle and the host. * The structure contains pointers to trap or assert information. */ -#define SDPCM_SHARED_VERSION 0x0002 +#define SDPCM_SHARED_VERSION 0x0003 #define SDPCM_SHARED_VERSION_MASK 0x00FF #define SDPCM_SHARED_ASSERT_BUILT 0x0100 #define SDPCM_SHARED_ASSERT 0x0200 @@ -428,6 +433,29 @@ struct brcmf_console { u8 *buf; /* Log buffer (host copy) */ uint last; /* Last buffer read index */ }; + +struct brcmf_trap_info { + __le32 type; + __le32 epc; + __le32 cpsr; + __le32 spsr; + __le32 r0; /* a1 */ + __le32 r1; /* a2 */ + __le32 r2; /* a3 */ + __le32 r3; /* a4 */ + __le32 r4; /* v1 */ + __le32 r5; /* v2 */ + __le32 r6; /* v3 */ + __le32 r7; /* v4 */ + __le32 r8; /* v5 */ + __le32 r9; /* sb/v6 */ + __le32 r10; /* sl/v7 */ + __le32 r11; /* fp/v8 */ + __le32 r12; /* ip */ + __le32 r13; /* sp */ + __le32 r14; /* lr */ + __le32 pc; /* r15 */ +}; #endif /* DEBUG */ struct sdpcm_shared { @@ -439,6 +467,7 @@ struct sdpcm_shared { u32 console_addr; /* Address of struct rte_console */ u32 msgtrace_addr; u8 tag[32]; + u32 brpt_addr; }; struct sdpcm_shared_le { @@ -450,6 +479,7 @@ struct sdpcm_shared_le { __le32 console_addr; /* Address of struct rte_console */ __le32 msgtrace_addr; u8 tag[32]; + __le32 brpt_addr; }; @@ -502,12 +532,9 @@ struct brcmf_sdio { bool intr; /* Use interrupts */ bool poll; /* Use polling */ bool ipend; /* Device interrupt is pending */ - uint intrcount; /* Count of device interrupt callbacks */ - uint lastintrs; /* Count as of last watchdog timer */ uint spurious; /* Count of spurious interrupts */ uint pollrate; /* Ticks between device polls */ uint polltick; /* Tick counter */ - uint pollcnt; /* Count of active polls */ #ifdef DEBUG uint console_interval; @@ -515,8 +542,6 @@ struct brcmf_sdio { uint console_addr; /* Console address from shared struct */ #endif /* DEBUG */ - uint regfails; /* Count of R_REG failures */ - uint clkstate; /* State of sd and backplane clock(s) */ bool activity; /* Activity flag for clock down */ s32 idletime; /* Control for activity timeout */ @@ -531,33 +556,6 @@ struct brcmf_sdio { /* Field to decide if rx of control frames happen in rxbuf or lb-pool */ bool usebufpool; - /* Some additional counters */ - uint tx_sderrs; /* Count of tx attempts with sd errors */ - uint fcqueued; /* Tx packets that got queued */ - uint rxrtx; /* Count of rtx requests (NAK to dongle) */ - uint rx_toolong; /* Receive frames too long to receive */ - uint rxc_errors; /* SDIO errors when reading control frames */ - uint rx_hdrfail; /* SDIO errors on header reads */ - uint rx_badhdr; /* Bad received headers (roosync?) */ - uint rx_badseq; /* Mismatched rx sequence number */ - uint fc_rcvd; /* Number of flow-control events received */ - uint fc_xoff; /* Number which turned on flow-control */ - uint fc_xon; /* Number which turned off flow-control */ - uint rxglomfail; /* Failed deglom attempts */ - uint rxglomframes; /* Number of glom frames (superframes) */ - uint rxglompkts; /* Number of packets from glom frames */ - uint f2rxhdrs; /* Number of header reads */ - uint f2rxdata; /* Number of frame data reads */ - uint f2txdata; /* Number of f2 frame writes */ - uint f1regdata; /* Number of f1 register accesses */ - uint tickcnt; /* Number of watchdog been schedule */ - unsigned long tx_ctlerrs; /* Err of sending ctrl frames */ - unsigned long tx_ctlpkts; /* Ctrl frames sent to dongle */ - unsigned long rx_ctlerrs; /* Err of processing rx ctrl frames */ - unsigned long rx_ctlpkts; /* Ctrl frames processed from dongle */ - unsigned long rx_readahead_cnt; /* Number of packets where header - * read-ahead was used. */ - u8 *ctrl_frame_buf; u32 ctrl_frame_len; bool ctrl_frame_stat; @@ -583,6 +581,7 @@ struct brcmf_sdio { u32 fw_ptr; bool txoff; /* Transmit flow-controlled */ + struct brcmf_sdio_count sdcnt; }; /* clkstate */ @@ -945,7 +944,7 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) if (ret == 0) w_sdreg32(bus, SMB_INT_ACK, offsetof(struct sdpcmd_regs, tosbmailbox)); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; /* Dongle recomposed rx frames, accept them again */ if (hmb_data & HMB_DATA_NAKHANDLED) { @@ -984,12 +983,12 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) HMB_DATA_FCDATA_SHIFT; if (fcbits & ~bus->flowcontrol) - bus->fc_xoff++; + bus->sdcnt.fc_xoff++; if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; + bus->sdcnt.fc_xon++; - bus->fc_rcvd++; + bus->sdcnt.fc_rcvd++; bus->flowcontrol = fcbits; } @@ -1021,7 +1020,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_RF_TERM, &err); - bus->f1regdata++; + bus->sdcnt.f1regdata++; /* Wait until the packet has been flushed (device/FIFO stable) */ for (lastrbc = retries = 0xffff; retries > 0; retries--) { @@ -1029,7 +1028,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) SBSDIO_FUNC1_RFRAMEBCHI, &err); lo = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_RFRAMEBCLO, &err); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; if ((hi == 0) && (lo == 0)) break; @@ -1047,11 +1046,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) brcmf_dbg(INFO, "flush took %d iterations\n", 0xffff - retries); if (rtx) { - bus->rxrtx++; + bus->sdcnt.rxrtx++; err = w_sdreg32(bus, SMB_NAK, offsetof(struct sdpcmd_regs, tosbmailbox)); - bus->f1regdata++; + bus->sdcnt.f1regdata++; if (err == 0) bus->rxskip = true; } @@ -1243,7 +1242,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) dlen); errcode = -1; } - bus->f2rxdata++; + bus->sdcnt.f2rxdata++; /* On failure, kill the superframe, allow a couple retries */ if (errcode < 0) { @@ -1256,7 +1255,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } else { bus->glomerr = 0; brcmf_sdbrcm_rxfail(bus, true, false); - bus->rxglomfail++; + bus->sdcnt.rxglomfail++; brcmf_sdbrcm_free_glom(bus); } return 0; @@ -1312,7 +1311,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (rxseq != seq) { brcmf_dbg(INFO, "(superframe) rx_seq %d, expected %d\n", seq, rxseq); - bus->rx_badseq++; + bus->sdcnt.rx_badseq++; rxseq = seq; } @@ -1376,7 +1375,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) } else { bus->glomerr = 0; brcmf_sdbrcm_rxfail(bus, true, false); - bus->rxglomfail++; + bus->sdcnt.rxglomfail++; brcmf_sdbrcm_free_glom(bus); } bus->nextlen = 0; @@ -1402,7 +1401,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) if (rxseq != seq) { brcmf_dbg(GLOM, "rx_seq %d, expected %d\n", seq, rxseq); - bus->rx_badseq++; + bus->sdcnt.rx_badseq++; rxseq = seq; } rxseq++; @@ -1441,8 +1440,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq) down(&bus->sdsem); } - bus->rxglomframes++; - bus->rxglompkts += bus->glom.qlen; + bus->sdcnt.rxglomframes++; + bus->sdcnt.rxglompkts += bus->glom.qlen; } return num; } @@ -1526,7 +1525,7 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) brcmf_dbg(ERROR, "%d-byte ctl frame (%d-byte ctl data) exceeds %d-byte limit\n", len, len - doff, bus->sdiodev->bus_if->maxctl); bus->sdiodev->bus_if->dstats.rx_errors++; - bus->rx_toolong++; + bus->sdcnt.rx_toolong++; brcmf_sdbrcm_rxfail(bus, false, false); goto done; } @@ -1536,13 +1535,13 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff) bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen); - bus->f2rxdata++; + bus->sdcnt.f2rxdata++; /* Control frame failures need retransmission */ if (sdret < 0) { brcmf_dbg(ERROR, "read %d control bytes failed: %d\n", rdlen, sdret); - bus->rxc_errors++; + bus->sdcnt.rxc_errors++; brcmf_sdbrcm_rxfail(bus, true, true); goto done; } @@ -1589,7 +1588,7 @@ brcmf_alloc_pkt_and_read(struct brcmf_sdio *bus, u16 rdlen, /* Read the entire frame */ sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, *pkt); - bus->f2rxdata++; + bus->sdcnt.f2rxdata++; if (sdret < 0) { brcmf_dbg(ERROR, "(nextlen): read %d bytes failed: %d\n", @@ -1630,7 +1629,7 @@ brcmf_check_rxbuf(struct brcmf_sdio *bus, struct sk_buff *pkt, u8 *rxbuf, if ((u16)~(*len ^ check)) { brcmf_dbg(ERROR, "(nextlen): HW hdr error: nextlen/len/check 0x%04x/0x%04x/0x%04x\n", nextlen, *len, check); - bus->rx_badhdr++; + bus->sdcnt.rx_badhdr++; brcmf_sdbrcm_rxfail(bus, false, false); goto fail; } @@ -1746,7 +1745,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) bus->nextlen = 0; } - bus->rx_readahead_cnt++; + bus->sdcnt.rx_readahead_cnt++; /* Handle Flow Control */ fcbits = SDPCM_FCMASK_VALUE( @@ -1754,12 +1753,12 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) if (bus->flowcontrol != fcbits) { if (~bus->flowcontrol & fcbits) - bus->fc_xoff++; + bus->sdcnt.fc_xoff++; if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; + bus->sdcnt.fc_xon++; - bus->fc_rcvd++; + bus->sdcnt.fc_rcvd++; bus->flowcontrol = fcbits; } @@ -1767,7 +1766,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) if (rxseq != seq) { brcmf_dbg(INFO, "(nextlen): rx_seq %d, expected %d\n", seq, rxseq); - bus->rx_badseq++; + bus->sdcnt.rx_badseq++; rxseq = seq; } @@ -1814,11 +1813,11 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) sdret = brcmf_sdcard_recv_buf(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, bus->rxhdr, BRCMF_FIRSTREAD); - bus->f2rxhdrs++; + bus->sdcnt.f2rxhdrs++; if (sdret < 0) { brcmf_dbg(ERROR, "RXHEADER FAILED: %d\n", sdret); - bus->rx_hdrfail++; + bus->sdcnt.rx_hdrfail++; brcmf_sdbrcm_rxfail(bus, true, true); continue; } @@ -1840,7 +1839,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) if ((u16) ~(len ^ check)) { brcmf_dbg(ERROR, "HW hdr err: len/check 0x%04x/0x%04x\n", len, check); - bus->rx_badhdr++; + bus->sdcnt.rx_badhdr++; brcmf_sdbrcm_rxfail(bus, false, false); continue; } @@ -1861,7 +1860,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) if ((doff < SDPCM_HDRLEN) || (doff > len)) { brcmf_dbg(ERROR, "Bad data offset %d: HW len %d, min %d seq %d\n", doff, len, SDPCM_HDRLEN, seq); - bus->rx_badhdr++; + bus->sdcnt.rx_badhdr++; brcmf_sdbrcm_rxfail(bus, false, false); continue; } @@ -1880,19 +1879,19 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) if (bus->flowcontrol != fcbits) { if (~bus->flowcontrol & fcbits) - bus->fc_xoff++; + bus->sdcnt.fc_xoff++; if (bus->flowcontrol & ~fcbits) - bus->fc_xon++; + bus->sdcnt.fc_xon++; - bus->fc_rcvd++; + bus->sdcnt.fc_rcvd++; bus->flowcontrol = fcbits; } /* Check and update sequence number */ if (rxseq != seq) { brcmf_dbg(INFO, "rx_seq %d, expected %d\n", seq, rxseq); - bus->rx_badseq++; + bus->sdcnt.rx_badseq++; rxseq = seq; } @@ -1937,7 +1936,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) brcmf_dbg(ERROR, "too long: len %d rdlen %d\n", len, rdlen); bus->sdiodev->bus_if->dstats.rx_errors++; - bus->rx_toolong++; + bus->sdcnt.rx_toolong++; brcmf_sdbrcm_rxfail(bus, false, false); continue; } @@ -1960,7 +1959,7 @@ brcmf_sdbrcm_readframes(struct brcmf_sdio *bus, uint maxframes, bool *finished) /* Read the remaining frame data */ sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); - bus->f2rxdata++; + bus->sdcnt.f2rxdata++; if (sdret < 0) { brcmf_dbg(ERROR, "read %d %s bytes failed: %d\n", rdlen, @@ -2147,18 +2146,18 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad, SDIO_FUNC_2, F2SYNC, pkt); - bus->f2txdata++; + bus->sdcnt.f2txdata++; if (ret < 0) { /* On failure, abort the command and terminate the frame */ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ret); - bus->tx_sderrs++; + bus->sdcnt.tx_sderrs++; brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); - bus->f1regdata++; + bus->sdcnt.f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; @@ -2166,7 +2165,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, SBSDIO_FUNC1_WFRAMEBCHI, NULL); lo = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; if ((hi == 0) && (lo == 0)) break; } @@ -2224,7 +2223,7 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) ret = r_sdreg32(bus, &intstatus, offsetof(struct sdpcmd_regs, intstatus)); - bus->f2txdata++; + bus->sdcnt.f2txdata++; if (ret != 0) break; if (intstatus & bus->hostintmask) @@ -2417,7 +2416,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) bus->ipend = false; err = r_sdreg32(bus, &newstatus, offsetof(struct sdpcmd_regs, intstatus)); - bus->f1regdata++; + bus->sdcnt.f1regdata++; if (err != 0) newstatus = 0; newstatus &= bus->hostintmask; @@ -2426,7 +2425,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) err = w_sdreg32(bus, newstatus, offsetof(struct sdpcmd_regs, intstatus)); - bus->f1regdata++; + bus->sdcnt.f1regdata++; } } @@ -2445,7 +2444,7 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) err = r_sdreg32(bus, &newstatus, offsetof(struct sdpcmd_regs, intstatus)); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); intstatus |= (newstatus & bus->hostintmask); @@ -2510,13 +2509,13 @@ clkwait: terminate the frame */ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ret); - bus->tx_sderrs++; + bus->sdcnt.tx_sderrs++; brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, &err); - bus->f1regdata++; + bus->sdcnt.f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; @@ -2526,7 +2525,7 @@ clkwait: lo = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, &err); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; if ((hi == 0) && (lo == 0)) break; } @@ -2657,7 +2656,7 @@ static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt) /* Check for existing queue, current flow-control, pending event, or pending clock */ brcmf_dbg(TRACE, "deferring pktq len %d\n", pktq_len(&bus->txq)); - bus->fcqueued++; + bus->sdcnt.fcqueued++; /* Priority based enq */ spin_lock_bh(&bus->txqlock); @@ -2845,13 +2844,13 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) /* On failure, abort the command and terminate the frame */ brcmf_dbg(INFO, "sdio error %d, abort command and terminate frame\n", ret); - bus->tx_sderrs++; + bus->sdcnt.tx_sderrs++; brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, NULL); - bus->f1regdata++; + bus->sdcnt.f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; @@ -2859,7 +2858,7 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) SBSDIO_FUNC1_WFRAMEBCHI, NULL); lo = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_WFRAMEBCLO, NULL); - bus->f1regdata += 2; + bus->sdcnt.f1regdata += 2; if (hi == 0 && lo == 0) break; } @@ -2976,13 +2975,324 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen) up(&bus->sdsem); if (ret) - bus->tx_ctlerrs++; + bus->sdcnt.tx_ctlerrs++; else - bus->tx_ctlpkts++; + bus->sdcnt.tx_ctlpkts++; return ret ? -EIO : 0; } +#ifdef DEBUG +static inline bool brcmf_sdio_valid_shared_address(u32 addr) +{ + return !(addr == 0 || ((~addr >> 16) & 0xffff) == (addr & 0xffff)); +} + +static int brcmf_sdio_readshared(struct brcmf_sdio *bus, + struct sdpcm_shared *sh) +{ + u32 addr; + int rv; + u32 shaddr = 0; + struct sdpcm_shared_le sh_le; + __le32 addr_le; + + shaddr = bus->ramsize - 4; + + /* + * Read last word in socram to determine + * address of sdpcm_shared structure + */ + rv = brcmf_sdbrcm_membytes(bus, false, shaddr, + (u8 *)&addr_le, 4); + if (rv < 0) + return rv; + + addr = le32_to_cpu(addr_le); + + brcmf_dbg(INFO, "sdpcm_shared address 0x%08X\n", addr); + + /* + * Check if addr is valid. + * NVRAM length at the end of memory should have been overwritten. + */ + if (!brcmf_sdio_valid_shared_address(addr)) { + brcmf_dbg(ERROR, "invalid sdpcm_shared address 0x%08X\n", + addr); + return -EINVAL; + } + + /* Read hndrte_shared structure */ + rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le, + sizeof(struct sdpcm_shared_le)); + if (rv < 0) + return rv; + + /* Endianness */ + sh->flags = le32_to_cpu(sh_le.flags); + sh->trap_addr = le32_to_cpu(sh_le.trap_addr); + sh->assert_exp_addr = le32_to_cpu(sh_le.assert_exp_addr); + sh->assert_file_addr = le32_to_cpu(sh_le.assert_file_addr); + sh->assert_line = le32_to_cpu(sh_le.assert_line); + sh->console_addr = le32_to_cpu(sh_le.console_addr); + sh->msgtrace_addr = le32_to_cpu(sh_le.msgtrace_addr); + + if ((sh->flags & SDPCM_SHARED_VERSION_MASK) != SDPCM_SHARED_VERSION) { + brcmf_dbg(ERROR, + "sdpcm_shared version mismatch: dhd %d dongle %d\n", + SDPCM_SHARED_VERSION, + sh->flags & SDPCM_SHARED_VERSION_MASK); + return -EPROTO; + } + + return 0; +} + +static int brcmf_sdio_dump_console(struct brcmf_sdio *bus, + struct sdpcm_shared *sh, char __user *data, + size_t count) +{ + u32 addr, console_ptr, console_size, console_index; + char *conbuf = NULL; + __le32 sh_val; + int rv; + loff_t pos = 0; + int nbytes = 0; + + /* obtain console information from device memory */ + addr = sh->console_addr + offsetof(struct rte_console, log_le); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_ptr = le32_to_cpu(sh_val); + + addr = sh->console_addr + offsetof(struct rte_console, log_le.buf_size); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_size = le32_to_cpu(sh_val); + + addr = sh->console_addr + offsetof(struct rte_console, log_le.idx); + rv = brcmf_sdbrcm_membytes(bus, false, addr, + (u8 *)&sh_val, sizeof(u32)); + if (rv < 0) + return rv; + console_index = le32_to_cpu(sh_val); + + /* allocate buffer for console data */ + if (console_size <= CONSOLE_BUFFER_MAX) + conbuf = vzalloc(console_size+1); + + if (!conbuf) + return -ENOMEM; + + /* obtain the console data from device */ + conbuf[console_size] = '\0'; + rv = brcmf_sdbrcm_membytes(bus, false, console_ptr, (u8 *)conbuf, + console_size); + if (rv < 0) + goto done; + + rv = simple_read_from_buffer(data, count, &pos, + conbuf + console_index, + console_size - console_index); + if (rv < 0) + goto done; + + nbytes = rv; + if (console_index > 0) { + pos = 0; + rv = simple_read_from_buffer(data+nbytes, count, &pos, + conbuf, console_index - 1); + if (rv < 0) + goto done; + rv += nbytes; + } +done: + vfree(conbuf); + return rv; +} + +static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh, + char __user *data, size_t count) +{ + int error, res; + char buf[350]; + struct brcmf_trap_info tr; + int nbytes; + loff_t pos = 0; + + if ((sh->flags & SDPCM_SHARED_TRAP) == 0) + return 0; + + error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr, + sizeof(struct brcmf_trap_info)); + if (error < 0) + return error; + + nbytes = brcmf_sdio_dump_console(bus, sh, data, count); + if (nbytes < 0) + return nbytes; + + res = scnprintf(buf, sizeof(buf), + "dongle trap info: type 0x%x @ epc 0x%08x\n" + " cpsr 0x%08x spsr 0x%08x sp 0x%08x\n" + " lr 0x%08x pc 0x%08x offset 0x%x\n" + " r0 0x%08x r1 0x%08x r2 0x%08x r3 0x%08x\n" + " r4 0x%08x r5 0x%08x r6 0x%08x r7 0x%08x\n", + le32_to_cpu(tr.type), le32_to_cpu(tr.epc), + le32_to_cpu(tr.cpsr), le32_to_cpu(tr.spsr), + le32_to_cpu(tr.r13), le32_to_cpu(tr.r14), + le32_to_cpu(tr.pc), sh->trap_addr, + le32_to_cpu(tr.r0), le32_to_cpu(tr.r1), + le32_to_cpu(tr.r2), le32_to_cpu(tr.r3), + le32_to_cpu(tr.r4), le32_to_cpu(tr.r5), + le32_to_cpu(tr.r6), le32_to_cpu(tr.r7)); + + error = simple_read_from_buffer(data+nbytes, count, &pos, buf, res); + if (error < 0) + return error; + + nbytes += error; + return nbytes; +} + +static int brcmf_sdio_assert_info(struct brcmf_sdio *bus, + struct sdpcm_shared *sh, char __user *data, + size_t count) +{ + int error = 0; + char buf[200]; + char file[80] = "?"; + char expr[80] = "<???>"; + int res; + loff_t pos = 0; + + if ((sh->flags & SDPCM_SHARED_ASSERT_BUILT) == 0) { + brcmf_dbg(INFO, "firmware not built with -assert\n"); + return 0; + } else if ((sh->flags & SDPCM_SHARED_ASSERT) == 0) { + brcmf_dbg(INFO, "no assert in dongle\n"); + return 0; + } + + if (sh->assert_file_addr != 0) { + error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr, + (u8 *)file, 80); + if (error < 0) + return error; + } + if (sh->assert_exp_addr != 0) { + error = brcmf_sdbrcm_membytes(bus, false, sh->assert_exp_addr, + (u8 *)expr, 80); + if (error < 0) + return error; + } + + res = scnprintf(buf, sizeof(buf), + "dongle assert: %s:%d: assert(%s)\n", + file, sh->assert_line, expr); + return simple_read_from_buffer(data, count, &pos, buf, res); +} + +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +{ + int error; + struct sdpcm_shared sh; + + down(&bus->sdsem); + error = brcmf_sdio_readshared(bus, &sh); + up(&bus->sdsem); + + if (error < 0) + return error; + + if ((sh.flags & SDPCM_SHARED_ASSERT_BUILT) == 0) + brcmf_dbg(INFO, "firmware not built with -assert\n"); + else if (sh.flags & SDPCM_SHARED_ASSERT) + brcmf_dbg(ERROR, "assertion in dongle\n"); + + if (sh.flags & SDPCM_SHARED_TRAP) + brcmf_dbg(ERROR, "firmware trap in dongle\n"); + + return 0; +} + +static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data, + size_t count, loff_t *ppos) +{ + int error = 0; + struct sdpcm_shared sh; + int nbytes = 0; + loff_t pos = *ppos; + + if (pos != 0) + return 0; + + down(&bus->sdsem); + error = brcmf_sdio_readshared(bus, &sh); + if (error < 0) + goto done; + + error = brcmf_sdio_assert_info(bus, &sh, data, count); + if (error < 0) + goto done; + + nbytes = error; + error = brcmf_sdio_trap_info(bus, &sh, data, count); + if (error < 0) + goto done; + + error += nbytes; + *ppos += error; +done: + up(&bus->sdsem); + return error; +} + +static ssize_t brcmf_sdio_forensic_read(struct file *f, char __user *data, + size_t count, loff_t *ppos) +{ + struct brcmf_sdio *bus = f->private_data; + int res; + + res = brcmf_sdbrcm_died_dump(bus, data, count, ppos); + if (res > 0) + *ppos += res; + return (ssize_t)res; +} + +static const struct file_operations brcmf_sdio_forensic_ops = { + .owner = THIS_MODULE, + .open = simple_open, + .read = brcmf_sdio_forensic_read +}; + +static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) +{ + struct brcmf_pub *drvr = bus->sdiodev->bus_if->drvr; + struct dentry *dentry = brcmf_debugfs_get_devdir(drvr); + + if (IS_ERR_OR_NULL(dentry)) + return; + + debugfs_create_file("forensics", S_IRUGO, dentry, bus, + &brcmf_sdio_forensic_ops); + brcmf_debugfs_create_sdio_count(drvr, &bus->sdcnt); +} +#else +static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus) +{ + return 0; +} + +static void brcmf_sdio_debugfs_create(struct brcmf_sdio *bus) +{ +} +#endif /* DEBUG */ + static int brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) { @@ -3009,60 +3319,27 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen) rxlen, msglen); } else if (timeleft == 0) { brcmf_dbg(ERROR, "resumed on timeout\n"); + brcmf_sdbrcm_checkdied(bus); } else if (pending) { brcmf_dbg(CTL, "cancelled\n"); return -ERESTARTSYS; } else { brcmf_dbg(CTL, "resumed for unknown reason?\n"); + brcmf_sdbrcm_checkdied(bus); } if (rxlen) - bus->rx_ctlpkts++; + bus->sdcnt.rx_ctlpkts++; else - bus->rx_ctlerrs++; + bus->sdcnt.rx_ctlerrs++; return rxlen ? (int)rxlen : -ETIMEDOUT; } -static int brcmf_sdbrcm_downloadvars(struct brcmf_sdio *bus, void *arg, int len) -{ - int bcmerror = 0; - - brcmf_dbg(TRACE, "Enter\n"); - - /* Basic sanity checks */ - if (bus->sdiodev->bus_if->drvr_up) { - bcmerror = -EISCONN; - goto err; - } - if (!len) { - bcmerror = -EOVERFLOW; - goto err; - } - - /* Free the old ones and replace with passed variables */ - kfree(bus->vars); - - bus->vars = kmalloc(len, GFP_ATOMIC); - bus->varsz = bus->vars ? len : 0; - if (bus->vars == NULL) { - bcmerror = -ENOMEM; - goto err; - } - - /* Copy the passed variables, which should include the - terminating double-null */ - memcpy(bus->vars, arg, bus->varsz); -err: - return bcmerror; -} - static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) { int bcmerror = 0; - u32 varsize; u32 varaddr; - u8 *vbuffer; u32 varsizew; __le32 varsizew_le; #ifdef DEBUG @@ -3071,56 +3348,44 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) /* Even if there are no vars are to be written, we still need to set the ramsize. */ - varsize = bus->varsz ? roundup(bus->varsz, 4) : 0; - varaddr = (bus->ramsize - 4) - varsize; + varaddr = (bus->ramsize - 4) - bus->varsz; if (bus->vars) { - vbuffer = kzalloc(varsize, GFP_ATOMIC); - if (!vbuffer) - return -ENOMEM; - - memcpy(vbuffer, bus->vars, bus->varsz); - /* Write the vars list */ - bcmerror = - brcmf_sdbrcm_membytes(bus, true, varaddr, vbuffer, varsize); + bcmerror = brcmf_sdbrcm_membytes(bus, true, varaddr, + bus->vars, bus->varsz); #ifdef DEBUG /* Verify NVRAM bytes */ - brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", varsize); - nvram_ularray = kmalloc(varsize, GFP_ATOMIC); - if (!nvram_ularray) { - kfree(vbuffer); + brcmf_dbg(INFO, "Compare NVRAM dl & ul; varsize=%d\n", + bus->varsz); + nvram_ularray = kmalloc(bus->varsz, GFP_ATOMIC); + if (!nvram_ularray) return -ENOMEM; - } /* Upload image to verify downloaded contents. */ - memset(nvram_ularray, 0xaa, varsize); + memset(nvram_ularray, 0xaa, bus->varsz); /* Read the vars list to temp buffer for comparison */ - bcmerror = - brcmf_sdbrcm_membytes(bus, false, varaddr, nvram_ularray, - varsize); + bcmerror = brcmf_sdbrcm_membytes(bus, false, varaddr, + nvram_ularray, bus->varsz); if (bcmerror) { brcmf_dbg(ERROR, "error %d on reading %d nvram bytes at 0x%08x\n", - bcmerror, varsize, varaddr); + bcmerror, bus->varsz, varaddr); } /* Compare the org NVRAM with the one read from RAM */ - if (memcmp(vbuffer, nvram_ularray, varsize)) + if (memcmp(bus->vars, nvram_ularray, bus->varsz)) brcmf_dbg(ERROR, "Downloaded NVRAM image is corrupted\n"); else brcmf_dbg(ERROR, "Download/Upload/Compare of NVRAM ok\n"); kfree(nvram_ularray); #endif /* DEBUG */ - - kfree(vbuffer); } /* adjust to the user specified RAM */ brcmf_dbg(INFO, "Physical memory size: %d\n", bus->ramsize); brcmf_dbg(INFO, "Vars are at %d, orig varsize is %d\n", - varaddr, varsize); - varsize = ((bus->ramsize - 4) - varaddr); + varaddr, bus->varsz); /* * Determine the length token: @@ -3131,13 +3396,13 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) varsizew = 0; varsizew_le = cpu_to_le32(0); } else { - varsizew = varsize / 4; + varsizew = bus->varsz / 4; varsizew = (~varsizew << 16) | (varsizew & 0x0000FFFF); varsizew_le = cpu_to_le32(varsizew); } brcmf_dbg(INFO, "New varsize is %d, length token=0x%08x\n", - varsize, varsizew); + bus->varsz, varsizew); /* Write the length token to the last word */ bcmerror = brcmf_sdbrcm_membytes(bus, true, (bus->ramsize - 4), @@ -3261,13 +3526,21 @@ err: * by two NULs. */ -static uint brcmf_process_nvram_vars(char *varbuf, uint len) +static int brcmf_process_nvram_vars(struct brcmf_sdio *bus) { + char *varbuf; char *dp; bool findNewline; int column; - uint buf_len, n; + int ret = 0; + uint buf_len, n, len; + len = bus->firmware->size; + varbuf = vmalloc(len); + if (!varbuf) + return -ENOMEM; + + memcpy(varbuf, bus->firmware->data, len); dp = varbuf; findNewline = false; @@ -3296,56 +3569,44 @@ static uint brcmf_process_nvram_vars(char *varbuf, uint len) column++; } buf_len = dp - varbuf; - while (dp < varbuf + n) *dp++ = 0; - return buf_len; + kfree(bus->vars); + /* roundup needed for download to device */ + bus->varsz = roundup(buf_len + 1, 4); + bus->vars = kmalloc(bus->varsz, GFP_KERNEL); + if (bus->vars == NULL) { + bus->varsz = 0; + ret = -ENOMEM; + goto err; + } + + /* copy the processed variables and add null termination */ + memcpy(bus->vars, varbuf, buf_len); + bus->vars[buf_len] = 0; +err: + vfree(varbuf); + return ret; } static int brcmf_sdbrcm_download_nvram(struct brcmf_sdio *bus) { - uint len; - char *memblock = NULL; - char *bufp; int ret; + if (bus->sdiodev->bus_if->drvr_up) + return -EISCONN; + ret = request_firmware(&bus->firmware, BRCMF_SDIO_NV_NAME, &bus->sdiodev->func[2]->dev); if (ret) { brcmf_dbg(ERROR, "Fail to request nvram %d\n", ret); return ret; } - bus->fw_ptr = 0; - - memblock = kmalloc(MEMBLOCK, GFP_ATOMIC); - if (memblock == NULL) { - ret = -ENOMEM; - goto err; - } - - len = brcmf_sdbrcm_get_image(memblock, MEMBLOCK, bus); - - if (len > 0 && len < MEMBLOCK) { - bufp = (char *)memblock; - bufp[len] = 0; - len = brcmf_process_nvram_vars(bufp, len); - bufp += len; - *bufp++ = 0; - if (len) - ret = brcmf_sdbrcm_downloadvars(bus, memblock, len + 1); - if (ret) - brcmf_dbg(ERROR, "error downloading vars: %d\n", ret); - } else { - brcmf_dbg(ERROR, "error reading nvram file: %d\n", len); - ret = -EIO; - } -err: - kfree(memblock); + ret = brcmf_process_nvram_vars(bus); release_firmware(bus->firmware); - bus->fw_ptr = 0; return ret; } @@ -3419,7 +3680,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) return 0; /* Start the watchdog timer */ - bus->tickcnt = 0; + bus->sdcnt.tickcnt = 0; brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS); down(&bus->sdsem); @@ -3512,7 +3773,7 @@ void brcmf_sdbrcm_isr(void *arg) return; } /* Count the interrupt call */ - bus->intrcount++; + bus->sdcnt.intrcount++; bus->ipend = true; /* Shouldn't get this interrupt if we're sleeping? */ @@ -3554,7 +3815,8 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) bus->polltick = 0; /* Check device if no interrupts */ - if (!bus->intr || (bus->intrcount == bus->lastintrs)) { + if (!bus->intr || + (bus->sdcnt.intrcount == bus->sdcnt.lastintrs)) { if (!bus->dpc_sched) { u8 devpend; @@ -3569,7 +3831,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) /* If there is something, make like the ISR and schedule the DPC */ if (intstatus) { - bus->pollcnt++; + bus->sdcnt.pollcnt++; bus->ipend = true; bus->dpc_sched = true; @@ -3581,7 +3843,7 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) } /* Update interrupt tracking */ - bus->lastintrs = bus->intrcount; + bus->sdcnt.lastintrs = bus->sdcnt.intrcount; } #ifdef DEBUG /* Poll for console output periodically */ @@ -3623,6 +3885,8 @@ static bool brcmf_sdbrcm_chipmatch(u16 chipid) return true; if (chipid == BCM4330_CHIP_ID) return true; + if (chipid == BCM4334_CHIP_ID) + return true; return false; } @@ -3793,7 +4057,7 @@ brcmf_sdbrcm_watchdog_thread(void *data) if (!wait_for_completion_interruptible(&bus->watchdog_wait)) { brcmf_sdbrcm_bus_watchdog(bus); /* Count the tick for reference */ - bus->tickcnt++; + bus->sdcnt.tickcnt++; } else break; } @@ -3856,6 +4120,10 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) { int ret; struct brcmf_sdio *bus; + struct brcmf_bus_dcmd *dlst; + u32 dngl_txglom; + u32 dngl_txglomalign; + u8 idx; brcmf_dbg(TRACE, "Enter\n"); @@ -3938,8 +4206,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev) goto fail; } + brcmf_sdio_debugfs_create(bus); brcmf_dbg(INFO, "completed!!\n"); + /* sdio bus core specific dcmd */ + idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); + dlst = kzalloc(sizeof(struct brcmf_bus_dcmd), GFP_KERNEL); + if (dlst) { + if (bus->ci->c_inf[idx].rev < 12) { + /* for sdio core rev < 12, disable txgloming */ + dngl_txglom = 0; + dlst->name = "bus:txglom"; + dlst->param = (char *)&dngl_txglom; + dlst->param_len = sizeof(u32); + } else { + /* otherwise, set txglomalign */ + dngl_txglomalign = bus->sdiodev->bus_if->align; + dlst->name = "bus:txglomalign"; + dlst->param = (char *)&dngl_txglomalign; + dlst->param_len = sizeof(u32); + } + list_add(&dlst->list, &bus->sdiodev->bus_if->dcmd_list); + } + /* if firmware path present try to download and bring up bus */ ret = brcmf_bus_start(bus->sdiodev->dev); if (ret != 0) { diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index f8e1f1c84d08..58155e23d220 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -403,6 +403,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, ci->c_inf[3].cib = 0x03004211; ci->ramsize = 0x48000; break; + case BCM4334_CHIP_ID: + ci->c_inf[0].wrapbase = 0x18100000; + ci->c_inf[0].cib = 0x29004211; + ci->c_inf[1].id = BCMA_CORE_SDIO_DEV; + ci->c_inf[1].base = 0x18002000; + ci->c_inf[1].wrapbase = 0x18102000; + ci->c_inf[1].cib = 0x0d004211; + ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM; + ci->c_inf[2].base = 0x18004000; + ci->c_inf[2].wrapbase = 0x18104000; + ci->c_inf[2].cib = 0x13080401; + ci->c_inf[3].id = BCMA_CORE_ARM_CM3; + ci->c_inf[3].base = 0x18003000; + ci->c_inf[3].wrapbase = 0x18103000; + ci->c_inf[3].cib = 0x07004211; + ci->ramsize = 0x80000; + break; default: brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip); return -ENODEV; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d13ae9c299f2..c6a10caec79f 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -691,9 +691,10 @@ scan_out: } static s32 -brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, +brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *ndev = request->wdev->netdev; s32 err = 0; WL_TRACE("Enter\n"); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index 3c6f9b1e8d05..8c9345dd37d2 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -318,10 +318,6 @@ #define IS_SIM(chippkg) \ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) -#define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID) - -#define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID)) - #ifdef DEBUG #define SI_MSG(fmt, ...) pr_debug(fmt, ##__VA_ARGS__) #else @@ -473,9 +469,6 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) sii->pub.pmurev = sii->pub.pmucaps & PCAP_REV_MASK; } - /* figure out buscore */ - sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0); - return true; } @@ -483,11 +476,7 @@ static struct si_info *ai_doattach(struct si_info *sii, struct bcma_bus *pbus) { struct si_pub *sih = &sii->pub; - u32 w, savewin; struct bcma_device *cc; - struct ssb_sprom *sprom = &pbus->sprom; - - savewin = 0; sii->icbus = pbus; sii->pcibus = pbus->host_pci; @@ -510,47 +499,7 @@ static struct si_info *ai_doattach(struct si_info *sii, /* PMU specific initializations */ if (ai_get_cccaps(sih) & CC_CAP_PMU) { - si_pmu_init(sih); (void)si_pmu_measure_alpclk(sih); - si_pmu_res_init(sih); - } - - /* setup the GPIO based LED powersave register */ - w = (sprom->leddc_on_time << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) | - (sprom->leddc_off_time << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT); - if (w == 0) - w = DEFAULT_GPIOTIMERVAL; - ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval), - ~0, w); - - if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) { - /* - * enable 12 mA drive strenth for 43224 and - * set chipControl register bit 15 - */ - if (ai_get_chiprev(sih) == 0) { - SI_MSG("Applying 43224A0 WARs\n"); - ai_cc_reg(sih, offsetof(struct chipcregs, chipcontrol), - CCTRL43224_GPIO_TOGGLE, - CCTRL43224_GPIO_TOGGLE); - si_pmu_chipcontrol(sih, 0, CCTRL_43224A0_12MA_LED_DRIVE, - CCTRL_43224A0_12MA_LED_DRIVE); - } - if (ai_get_chiprev(sih) >= 1) { - SI_MSG("Applying 43224B0+ WARs\n"); - si_pmu_chipcontrol(sih, 0, CCTRL_43224B0_12MA_LED_DRIVE, - CCTRL_43224B0_12MA_LED_DRIVE); - } - } - - if (ai_get_chip_id(sih) == BCM4313_CHIP_ID) { - /* - * enable 12 mA drive strenth for 4313 and - * set chipControl register bit 1 - */ - SI_MSG("Applying 4313 WARs\n"); - si_pmu_chipcontrol(sih, 0, CCTRL_4313_12MA_LED_DRIVE, - CCTRL_4313_12MA_LED_DRIVE); } return sii; @@ -589,7 +538,7 @@ void ai_detach(struct si_pub *sih) struct si_pub *si_local = NULL; memcpy(&si_local, &sih, sizeof(struct si_pub **)); - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); if (sii == NULL) return; @@ -597,27 +546,6 @@ void ai_detach(struct si_pub *sih) kfree(sii); } -/* return index of coreid or BADIDX if not found */ -struct bcma_device *ai_findcore(struct si_pub *sih, u16 coreid, u16 coreunit) -{ - struct bcma_device *core; - struct si_info *sii; - uint found; - - sii = (struct si_info *)sih; - - found = 0; - - list_for_each_entry(core, &sii->icbus->cores, list) - if (core->id.id == coreid) { - if (found == coreunit) - return core; - found++; - } - - return NULL; -} - /* * read/modify chipcommon core register. */ @@ -627,7 +555,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val) u32 w; struct si_info *sii; - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); cc = sii->icbus->drv_cc.core; /* mask and set */ @@ -693,12 +621,13 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc) /* initialize power control delay registers */ void ai_clkctl_init(struct si_pub *sih) { + struct si_info *sii = container_of(sih, struct si_info, pub); struct bcma_device *cc; if (!(ai_get_cccaps(sih) & CC_CAP_PWR_CTL)) return; - cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + cc = sii->icbus->drv_cc.core; if (cc == NULL) return; @@ -720,7 +649,7 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) uint slowminfreq; u16 fpdelay; - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); if (ai_get_cccaps(sih) & CC_CAP_PMU) { fpdelay = si_pmu_fast_pwrup_delay(sih); return fpdelay; @@ -730,7 +659,7 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) return 0; fpdelay = 0; - cc = ai_findcore(sih, CC_CORE_ID, 0); + cc = sii->icbus->drv_cc.core; if (cc) { slowminfreq = ai_slowclk_freq(sih, false, cc); fpdelay = (((bcma_read32(cc, CHIPCREGOFFS(pll_on_delay)) + 2) @@ -752,12 +681,9 @@ bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode) struct si_info *sii; struct bcma_device *cc; - sii = (struct si_info *)sih; - - if (PCI_FORCEHT(sih)) - return mode == BCMA_CLKMODE_FAST; + sii = container_of(sih, struct si_info, pub); - cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); + cc = sii->icbus->drv_cc.core; bcma_core_set_clockmode(cc, mode); return mode == BCMA_CLKMODE_FAST; } @@ -765,16 +691,10 @@ bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode) void ai_pci_up(struct si_pub *sih) { struct si_info *sii; - struct bcma_device *cc; - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); - if (PCI_FORCEHT(sih)) { - cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); - bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST); - } - - if (PCIE(sih)) + if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true); } @@ -782,26 +702,20 @@ void ai_pci_up(struct si_pub *sih) void ai_pci_down(struct si_pub *sih) { struct si_info *sii; - struct bcma_device *cc; - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); - /* release FORCEHT since chip is going to "down" state */ - if (PCI_FORCEHT(sih)) { - cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); - bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC); - } - - if (PCIE(sih)) + if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false); } /* Enable BT-COEX & Ex-PA for 4313 */ void ai_epa_4313war(struct si_pub *sih) { + struct si_info *sii = container_of(sih, struct si_info, pub); struct bcma_device *cc; - cc = ai_findcore(sih, CC_CORE_ID, 0); + cc = sii->icbus->drv_cc.core; /* EPA Fix */ bcma_set32(cc, CHIPCREGOFFS(gpiocontrol), GPIO_CTRL_EPA_EN_MASK); @@ -813,7 +727,7 @@ bool ai_deviceremoved(struct si_pub *sih) u32 w; struct si_info *sii; - sii = (struct si_info *)sih; + sii = container_of(sih, struct si_info, pub); if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI) return false; @@ -824,15 +738,3 @@ bool ai_deviceremoved(struct si_pub *sih) return false; } - -uint ai_get_buscoretype(struct si_pub *sih) -{ - struct si_info *sii = (struct si_info *)sih; - return sii->buscore->id.id; -} - -uint ai_get_buscorerev(struct si_pub *sih) -{ - struct si_info *sii = (struct si_info *)sih; - return sii->buscore->id.rev; -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index d6fa9829af9a..89562c1fbf49 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -88,16 +88,6 @@ #define CLKD_OTP 0x000f0000 #define CLKD_OTP_SHIFT 16 -/* Package IDs */ -#define BCM4717_PKG_ID 9 /* 4717 package id */ -#define BCM4718_PKG_ID 10 /* 4718 package id */ -#define BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ - -/* these are router chips */ -#define BCM4716_CHIP_ID 0x4716 /* 4716 chipcommon chipid */ -#define BCM47162_CHIP_ID 47162 /* 47162 chipcommon chipid */ -#define BCM4748_CHIP_ID 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ - /* dynamic clock control defines */ #define LPOMINFREQ 25000 /* low power oscillator min */ #define LPOMAXFREQ 43000 /* low power oscillator max */ @@ -168,7 +158,6 @@ struct si_info { struct si_pub pub; /* back plane public state (must be first) */ struct bcma_bus *icbus; /* handle to soc interconnect bus */ struct pci_dev *pcibus; /* handle to pci bus */ - struct bcma_device *buscore; u32 chipst; /* chip status */ }; @@ -183,8 +172,6 @@ struct si_info { /* AMBA Interconnect exported externs */ -extern struct bcma_device *ai_findcore(struct si_pub *sih, - u16 coreid, u16 coreunit); extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); /* === exported functions === */ @@ -202,9 +189,6 @@ extern void ai_pci_up(struct si_pub *sih); /* Enable Ex-PA for 4313 */ extern void ai_epa_4313war(struct si_pub *sih); -extern uint ai_get_buscoretype(struct si_pub *sih); -extern uint ai_get_buscorerev(struct si_pub *sih); - static inline u32 ai_get_cccaps(struct si_pub *sih) { return sih->cccaps; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 95b5902bc4b3..01b190a25d94 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -735,10 +735,8 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, * a candidate for aggregation */ p = pktq_ppeek(&qi->q, prec); - /* tx_info must be checked with current p */ - tx_info = IEEE80211_SKB_CB(p); - if (p) { + tx_info = IEEE80211_SKB_CB(p); if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && ((u8) (p->priority) == tid)) { plen = p->len + AMPDU_MAX_MPDU_OVERHEAD; @@ -759,6 +757,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, p = NULL; continue; } + /* next packet fit for aggregation so dequeue */ p = brcmu_pktq_pdeq(&qi->q, prec); } else { p = NULL; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index eb77ac3cfb6b..9a4c63f927cb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -15,7 +15,9 @@ */ #include <linux/types.h> +#include <net/cfg80211.h> #include <net/mac80211.h> +#include <net/regulatory.h> #include <defs.h> #include "pub.h" @@ -23,73 +25,17 @@ #include "main.h" #include "stf.h" #include "channel.h" +#include "mac80211_if.h" /* QDB() macro takes a dB value and converts to a quarter dB value */ #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR) -#define LOCALE_CHAN_01_11 (1<<0) -#define LOCALE_CHAN_12_13 (1<<1) -#define LOCALE_CHAN_14 (1<<2) -#define LOCALE_SET_5G_LOW_JP1 (1<<3) /* 34-48, step 2 */ -#define LOCALE_SET_5G_LOW_JP2 (1<<4) /* 34-46, step 4 */ -#define LOCALE_SET_5G_LOW1 (1<<5) /* 36-48, step 4 */ -#define LOCALE_SET_5G_LOW2 (1<<6) /* 52 */ -#define LOCALE_SET_5G_LOW3 (1<<7) /* 56-64, step 4 */ -#define LOCALE_SET_5G_MID1 (1<<8) /* 100-116, step 4 */ -#define LOCALE_SET_5G_MID2 (1<<9) /* 120-124, step 4 */ -#define LOCALE_SET_5G_MID3 (1<<10) /* 128 */ -#define LOCALE_SET_5G_HIGH1 (1<<11) /* 132-140, step 4 */ -#define LOCALE_SET_5G_HIGH2 (1<<12) /* 149-161, step 4 */ -#define LOCALE_SET_5G_HIGH3 (1<<13) /* 165 */ -#define LOCALE_CHAN_52_140_ALL (1<<14) -#define LOCALE_SET_5G_HIGH4 (1<<15) /* 184-216 */ - -#define LOCALE_CHAN_36_64 (LOCALE_SET_5G_LOW1 | \ - LOCALE_SET_5G_LOW2 | \ - LOCALE_SET_5G_LOW3) -#define LOCALE_CHAN_52_64 (LOCALE_SET_5G_LOW2 | LOCALE_SET_5G_LOW3) -#define LOCALE_CHAN_100_124 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2) -#define LOCALE_CHAN_100_140 (LOCALE_SET_5G_MID1 | LOCALE_SET_5G_MID2 | \ - LOCALE_SET_5G_MID3 | LOCALE_SET_5G_HIGH1) -#define LOCALE_CHAN_149_165 (LOCALE_SET_5G_HIGH2 | LOCALE_SET_5G_HIGH3) -#define LOCALE_CHAN_184_216 LOCALE_SET_5G_HIGH4 - -#define LOCALE_CHAN_01_14 (LOCALE_CHAN_01_11 | \ - LOCALE_CHAN_12_13 | \ - LOCALE_CHAN_14) - -#define LOCALE_RADAR_SET_NONE 0 -#define LOCALE_RADAR_SET_1 1 - -#define LOCALE_RESTRICTED_NONE 0 -#define LOCALE_RESTRICTED_SET_2G_SHORT 1 -#define LOCALE_RESTRICTED_CHAN_165 2 -#define LOCALE_CHAN_ALL_5G 3 -#define LOCALE_RESTRICTED_JAPAN_LEGACY 4 -#define LOCALE_RESTRICTED_11D_2G 5 -#define LOCALE_RESTRICTED_11D_5G 6 -#define LOCALE_RESTRICTED_LOW_HI 7 -#define LOCALE_RESTRICTED_12_13_14 8 - -#define LOCALE_2G_IDX_i 0 -#define LOCALE_5G_IDX_11 0 #define LOCALE_MIMO_IDX_bn 0 #define LOCALE_MIMO_IDX_11n 0 -/* max of BAND_5G_PWR_LVLS and 6 for 2.4 GHz */ -#define BRCMS_MAXPWR_TBL_SIZE 6 /* max of BAND_5G_PWR_LVLS and 14 for 2.4 GHz */ #define BRCMS_MAXPWR_MIMO_TBL_SIZE 14 -/* power level in group of 2.4GHz band channels: - * maxpwr[0] - CCK channels [1] - * maxpwr[1] - CCK channels [2-10] - * maxpwr[2] - CCK channels [11-14] - * maxpwr[3] - OFDM channels [1] - * maxpwr[4] - OFDM channels [2-10] - * maxpwr[5] - OFDM channels [11-14] - */ - /* maxpwr mapping to 5GHz band channels: * maxpwr[0] - channels [34-48] * maxpwr[1] - channels [52-60] @@ -101,16 +47,8 @@ #define LC(id) LOCALE_MIMO_IDX_ ## id -#define LC_2G(id) LOCALE_2G_IDX_ ## id - -#define LC_5G(id) LOCALE_5G_IDX_ ## id - -#define LOCALES(band2, band5, mimo2, mimo5) \ - {LC_2G(band2), LC_5G(band5), LC(mimo2), LC(mimo5)} - -/* macro to get 2.4 GHz channel group index for tx power */ -#define CHANNEL_POWER_IDX_2G_CCK(c) (((c) < 2) ? 0 : (((c) < 11) ? 1 : 2)) -#define CHANNEL_POWER_IDX_2G_OFDM(c) (((c) < 2) ? 3 : (((c) < 11) ? 4 : 5)) +#define LOCALES(mimo2, mimo5) \ + {LC(mimo2), LC(mimo5)} /* macro to get 5 GHz channel group index for tx power */ #define CHANNEL_POWER_IDX_5G(c) (((c) < 52) ? 0 : \ @@ -118,18 +56,37 @@ (((c) < 100) ? 2 : \ (((c) < 149) ? 3 : 4)))) -#define ISDFS_EU(fl) (((fl) & BRCMS_DFS_EU) == BRCMS_DFS_EU) - -struct brcms_cm_band { - /* struct locale_info flags */ - u8 locale_flags; - /* List of valid channels in the country */ - struct brcms_chanvec valid_channels; - /* List of restricted use channels */ - const struct brcms_chanvec *restricted_channels; - /* List of radar sensitive channels */ - const struct brcms_chanvec *radar_channels; - u8 PAD[8]; +#define BRCM_2GHZ_2412_2462 REG_RULE(2412-10, 2462+10, 40, 0, 19, 0) +#define BRCM_2GHZ_2467_2472 REG_RULE(2467-10, 2472+10, 20, 0, 19, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +#define BRCM_5GHZ_5180_5240 REG_RULE(5180-10, 5240+10, 40, 0, 21, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) +#define BRCM_5GHZ_5260_5320 REG_RULE(5260-10, 5320+10, 40, 0, 21, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_DFS | \ + NL80211_RRF_NO_IBSS) +#define BRCM_5GHZ_5500_5700 REG_RULE(5500-10, 5700+10, 40, 0, 21, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_DFS | \ + NL80211_RRF_NO_IBSS) +#define BRCM_5GHZ_5745_5825 REG_RULE(5745-10, 5825+10, 40, 0, 21, \ + NL80211_RRF_PASSIVE_SCAN | \ + NL80211_RRF_NO_IBSS) + +static const struct ieee80211_regdomain brcms_regdom_x2 = { + .n_reg_rules = 7, + .alpha2 = "X2", + .reg_rules = { + BRCM_2GHZ_2412_2462, + BRCM_2GHZ_2467_2472, + BRCM_5GHZ_5180_5240, + BRCM_5GHZ_5260_5320, + BRCM_5GHZ_5500_5700, + BRCM_5GHZ_5745_5825, + } }; /* locale per-channel tx power limits for MIMO frames @@ -141,337 +98,23 @@ struct locale_mimo_info { s8 maxpwr20[BRCMS_MAXPWR_MIMO_TBL_SIZE]; /* tx 40 MHz power limits, qdBm units */ s8 maxpwr40[BRCMS_MAXPWR_MIMO_TBL_SIZE]; - u8 flags; }; /* Country names and abbreviations with locale defined from ISO 3166 */ struct country_info { - const u8 locale_2G; /* 2.4G band locale */ - const u8 locale_5G; /* 5G band locale */ const u8 locale_mimo_2G; /* 2.4G mimo info */ const u8 locale_mimo_5G; /* 5G mimo info */ }; +struct brcms_regd { + struct country_info country; + const struct ieee80211_regdomain *regdomain; +}; + struct brcms_cm_info { struct brcms_pub *pub; struct brcms_c_info *wlc; - char srom_ccode[BRCM_CNTRY_BUF_SZ]; /* Country Code in SROM */ - uint srom_regrev; /* Regulatory Rev for the SROM ccode */ - const struct country_info *country; /* current country def */ - char ccode[BRCM_CNTRY_BUF_SZ]; /* current internal Country Code */ - uint regrev; /* current Regulatory Revision */ - char country_abbrev[BRCM_CNTRY_BUF_SZ]; /* current advertised ccode */ - /* per-band state (one per phy/radio) */ - struct brcms_cm_band bandstate[MAXBANDS]; - /* quiet channels currently for radar sensitivity or 11h support */ - /* channels on which we cannot transmit */ - struct brcms_chanvec quiet_channels; -}; - -/* locale channel and power info. */ -struct locale_info { - u32 valid_channels; - /* List of radar sensitive channels */ - u8 radar_channels; - /* List of channels used only if APs are detected */ - u8 restricted_channels; - /* Max tx pwr in qdBm for each sub-band */ - s8 maxpwr[BRCMS_MAXPWR_TBL_SIZE]; - /* Country IE advertised max tx pwr in dBm per sub-band */ - s8 pub_maxpwr[BAND_5G_PWR_LVLS]; - u8 flags; -}; - -/* Regulatory Matrix Spreadsheet (CLM) MIMO v3.7.9 */ - -/* - * Some common channel sets - */ - -/* No channels */ -static const struct brcms_chanvec chanvec_none = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* All 2.4 GHz HW channels */ -static const struct brcms_chanvec chanvec_all_2G = { - {0xfe, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* All 5 GHz HW channels */ -static const struct brcms_chanvec chanvec_all_5G = { - {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x11, 0x11, - 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x20, 0x22, 0x22, 0x00, 0x00, 0x11, - 0x11, 0x11, 0x11, 0x01} -}; - -/* - * Radar channel sets - */ - -/* Channels 52 - 64, 100 - 140 */ -static const struct brcms_chanvec radar_set1 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, /* 52 - 60 */ - 0x01, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x11, /* 64, 100 - 124 */ - 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 128 - 140 */ - 0x00, 0x00, 0x00, 0x00} -}; - -/* - * Restricted channel sets - */ - -/* Channels 34, 38, 42, 46 */ -static const struct brcms_chanvec restricted_set_japan_legacy = { - {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* Channels 12, 13 */ -static const struct brcms_chanvec restricted_set_2g_short = { - {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* Channel 165 */ -static const struct brcms_chanvec restricted_chan_165 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* Channels 36 - 48 & 149 - 165 */ -static const struct brcms_chanvec restricted_low_hi = { - {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x22, 0x22, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* Channels 12 - 14 */ -static const struct brcms_chanvec restricted_set_12_13_14 = { - {0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -/* global memory to provide working buffer for expanded locale */ - -static const struct brcms_chanvec *g_table_radar_set[] = { - &chanvec_none, - &radar_set1 -}; - -static const struct brcms_chanvec *g_table_restricted_chan[] = { - &chanvec_none, /* restricted_set_none */ - &restricted_set_2g_short, - &restricted_chan_165, - &chanvec_all_5G, - &restricted_set_japan_legacy, - &chanvec_all_2G, /* restricted_set_11d_2G */ - &chanvec_all_5G, /* restricted_set_11d_5G */ - &restricted_low_hi, - &restricted_set_12_13_14 -}; - -static const struct brcms_chanvec locale_2g_01_11 = { - {0xfe, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_2g_12_13 = { - {0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_2g_14 = { - {0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_LOW_JP1 = { - {0x00, 0x00, 0x00, 0x00, 0x54, 0x55, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_LOW_JP2 = { - {0x00, 0x00, 0x00, 0x00, 0x44, 0x44, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_LOW1 = { - {0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x01, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_LOW2 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_LOW3 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_MID1 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, 0x11, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_MID2 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_MID3 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_HIGH1 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_HIGH2 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x20, 0x22, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_HIGH3 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_52_140_ALL = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x11, - 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, - 0x11, 0x11, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00} -}; - -static const struct brcms_chanvec locale_5g_HIGH4 = { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, - 0x11, 0x11, 0x11, 0x11} -}; - -static const struct brcms_chanvec *g_table_locale_base[] = { - &locale_2g_01_11, - &locale_2g_12_13, - &locale_2g_14, - &locale_5g_LOW_JP1, - &locale_5g_LOW_JP2, - &locale_5g_LOW1, - &locale_5g_LOW2, - &locale_5g_LOW3, - &locale_5g_MID1, - &locale_5g_MID2, - &locale_5g_MID3, - &locale_5g_HIGH1, - &locale_5g_HIGH2, - &locale_5g_HIGH3, - &locale_5g_52_140_ALL, - &locale_5g_HIGH4 -}; - -static void brcms_c_locale_add_channels(struct brcms_chanvec *target, - const struct brcms_chanvec *channels) -{ - u8 i; - for (i = 0; i < sizeof(struct brcms_chanvec); i++) - target->vec[i] |= channels->vec[i]; -} - -static void brcms_c_locale_get_channels(const struct locale_info *locale, - struct brcms_chanvec *channels) -{ - u8 i; - - memset(channels, 0, sizeof(struct brcms_chanvec)); - - for (i = 0; i < ARRAY_SIZE(g_table_locale_base); i++) { - if (locale->valid_channels & (1 << i)) - brcms_c_locale_add_channels(channels, - g_table_locale_base[i]); - } -} - -/* - * Locale Definitions - 2.4 GHz - */ -static const struct locale_info locale_i = { /* locale i. channel 1 - 13 */ - LOCALE_CHAN_01_11 | LOCALE_CHAN_12_13, - LOCALE_RADAR_SET_NONE, - LOCALE_RESTRICTED_SET_2G_SHORT, - {QDB(19), QDB(19), QDB(19), - QDB(19), QDB(19), QDB(19)}, - {20, 20, 20, 0}, - BRCMS_EIRP -}; - -/* - * Locale Definitions - 5 GHz - */ -static const struct locale_info locale_11 = { - /* locale 11. channel 36 - 48, 52 - 64, 100 - 140, 149 - 165 */ - LOCALE_CHAN_36_64 | LOCALE_CHAN_100_140 | LOCALE_CHAN_149_165, - LOCALE_RADAR_SET_1, - LOCALE_RESTRICTED_NONE, - {QDB(21), QDB(21), QDB(21), QDB(21), QDB(21)}, - {23, 23, 23, 30, 30}, - BRCMS_EIRP | BRCMS_DFS_EU -}; - -static const struct locale_info *g_locale_2g_table[] = { - &locale_i -}; - -static const struct locale_info *g_locale_5g_table[] = { - &locale_11 + const struct brcms_regd *world_regd; }; /* @@ -484,7 +127,6 @@ static const struct locale_mimo_info locale_bn = { {0, 0, QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), QDB(13), 0, 0}, - 0 }; static const struct locale_mimo_info *g_mimo_2g_table[] = { @@ -497,114 +139,20 @@ static const struct locale_mimo_info *g_mimo_2g_table[] = { static const struct locale_mimo_info locale_11n = { { /* 12.5 dBm */ 50, 50, 50, QDB(15), QDB(15)}, {QDB(14), QDB(15), QDB(15), QDB(15), QDB(15)}, - 0 }; static const struct locale_mimo_info *g_mimo_5g_table[] = { &locale_11n }; -static const struct { - char abbrev[BRCM_CNTRY_BUF_SZ]; /* country abbreviation */ - struct country_info country; -} cntry_locales[] = { +static const struct brcms_regd cntry_locales[] = { + /* Worldwide RoW 2, must always be at index 0 */ { - "X2", LOCALES(i, 11, bn, 11n)}, /* Worldwide RoW 2 */ -}; - -#ifdef SUPPORT_40MHZ -/* 20MHz channel info for 40MHz pairing support */ -struct chan20_info { - u8 sb; - u8 adj_sbs; + .country = LOCALES(bn, 11n), + .regdomain = &brcms_regdom_x2, + }, }; -/* indicates adjacent channels that are allowed for a 40 Mhz channel and - * those that permitted by the HT - */ -struct chan20_info chan20_info[] = { - /* 11b/11g */ -/* 0 */ {1, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 1 */ {2, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 2 */ {3, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 3 */ {4, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 4 */ {5, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, -/* 5 */ {6, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, -/* 6 */ {7, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, -/* 7 */ {8, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, -/* 8 */ {9, (CH_UPPER_SB | CH_LOWER_SB | CH_EWA_VALID)}, -/* 9 */ {10, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 10 */ {11, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 11 */ {12, (CH_LOWER_SB)}, -/* 12 */ {13, (CH_LOWER_SB)}, -/* 13 */ {14, (CH_LOWER_SB)}, - -/* 11a japan high */ -/* 14 */ {34, (CH_UPPER_SB)}, -/* 15 */ {38, (CH_LOWER_SB)}, -/* 16 */ {42, (CH_LOWER_SB)}, -/* 17 */ {46, (CH_LOWER_SB)}, - -/* 11a usa low */ -/* 18 */ {36, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 19 */ {40, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 20 */ {44, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 21 */ {48, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 22 */ {52, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 23 */ {56, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 24 */ {60, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 25 */ {64, (CH_LOWER_SB | CH_EWA_VALID)}, - -/* 11a Europe */ -/* 26 */ {100, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 27 */ {104, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 28 */ {108, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 29 */ {112, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 30 */ {116, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 31 */ {120, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 32 */ {124, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 33 */ {128, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 34 */ {132, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 35 */ {136, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 36 */ {140, (CH_LOWER_SB)}, - -/* 11a usa high, ref5 only */ -/* The 0x80 bit in pdiv means these are REF5, other entries are REF20 */ -/* 37 */ {149, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 38 */ {153, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 39 */ {157, (CH_UPPER_SB | CH_EWA_VALID)}, -/* 40 */ {161, (CH_LOWER_SB | CH_EWA_VALID)}, -/* 41 */ {165, (CH_LOWER_SB)}, - -/* 11a japan */ -/* 42 */ {184, (CH_UPPER_SB)}, -/* 43 */ {188, (CH_LOWER_SB)}, -/* 44 */ {192, (CH_UPPER_SB)}, -/* 45 */ {196, (CH_LOWER_SB)}, -/* 46 */ {200, (CH_UPPER_SB)}, -/* 47 */ {204, (CH_LOWER_SB)}, -/* 48 */ {208, (CH_UPPER_SB)}, -/* 49 */ {212, (CH_LOWER_SB)}, -/* 50 */ {216, (CH_LOWER_SB)} -}; -#endif /* SUPPORT_40MHZ */ - -static const struct locale_info *brcms_c_get_locale_2g(u8 locale_idx) -{ - if (locale_idx >= ARRAY_SIZE(g_locale_2g_table)) - return NULL; /* error condition */ - - return g_locale_2g_table[locale_idx]; -} - -static const struct locale_info *brcms_c_get_locale_5g(u8 locale_idx) -{ - if (locale_idx >= ARRAY_SIZE(g_locale_5g_table)) - return NULL; /* error condition */ - - return g_locale_5g_table[locale_idx]; -} - static const struct locale_mimo_info *brcms_c_get_mimo_2g(u8 locale_idx) { if (locale_idx >= ARRAY_SIZE(g_mimo_2g_table)) @@ -621,13 +169,6 @@ static const struct locale_mimo_info *brcms_c_get_mimo_5g(u8 locale_idx) return g_mimo_5g_table[locale_idx]; } -static int -brcms_c_country_aggregate_map(struct brcms_cm_info *wlc_cm, const char *ccode, - char *mapped_ccode, uint *mapped_regrev) -{ - return false; -} - /* * Indicates whether the country provided is valid to pass * to cfg80211 or not. @@ -662,155 +203,24 @@ static bool brcms_c_country_valid(const char *ccode) return true; } -/* Lookup a country info structure from a null terminated country - * abbreviation and regrev directly with no translation. - */ -static const struct country_info * -brcms_c_country_lookup_direct(const char *ccode, uint regrev) +static const struct brcms_regd *brcms_world_regd(const char *regdom, int len) { - uint size, i; - - /* Should just return 0 for single locale driver. */ - /* Keep it this way in case we add more locales. (for now anyway) */ - - /* - * all other country def arrays are for regrev == 0, so if - * regrev is non-zero, fail - */ - if (regrev > 0) - return NULL; - - /* find matched table entry from country code */ - size = ARRAY_SIZE(cntry_locales); - for (i = 0; i < size; i++) { - if (strcmp(ccode, cntry_locales[i].abbrev) == 0) - return &cntry_locales[i].country; - } - return NULL; -} - -static const struct country_info * -brcms_c_countrycode_map(struct brcms_cm_info *wlc_cm, const char *ccode, - char *mapped_ccode, uint *mapped_regrev) -{ - struct brcms_c_info *wlc = wlc_cm->wlc; - const struct country_info *country; - uint srom_regrev = wlc_cm->srom_regrev; - const char *srom_ccode = wlc_cm->srom_ccode; - int mapped; - - /* check for currently supported ccode size */ - if (strlen(ccode) > (BRCM_CNTRY_BUF_SZ - 1)) { - wiphy_err(wlc->wiphy, "wl%d: %s: ccode \"%s\" too long for " - "match\n", wlc->pub->unit, __func__, ccode); - return NULL; - } - - /* default mapping is the given ccode and regrev 0 */ - strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); - *mapped_regrev = 0; - - /* If the desired country code matches the srom country code, - * then the mapped country is the srom regulatory rev. - * Otherwise look for an aggregate mapping. - */ - if (!strcmp(srom_ccode, ccode)) { - *mapped_regrev = srom_regrev; - mapped = 0; - wiphy_err(wlc->wiphy, "srom_code == ccode %s\n", __func__); - } else { - mapped = - brcms_c_country_aggregate_map(wlc_cm, ccode, mapped_ccode, - mapped_regrev); - } - - /* find the matching built-in country definition */ - country = brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); - - /* if there is not an exact rev match, default to rev zero */ - if (country == NULL && *mapped_regrev != 0) { - *mapped_regrev = 0; - country = - brcms_c_country_lookup_direct(mapped_ccode, *mapped_regrev); - } - - return country; -} - -/* Lookup a country info structure from a null terminated country code - * The lookup is case sensitive. - */ -static const struct country_info * -brcms_c_country_lookup(struct brcms_c_info *wlc, const char *ccode) -{ - const struct country_info *country; - char mapped_ccode[BRCM_CNTRY_BUF_SZ]; - uint mapped_regrev; - - /* - * map the country code to a built-in country code, regrev, and - * country_info struct - */ - country = brcms_c_countrycode_map(wlc->cmi, ccode, mapped_ccode, - &mapped_regrev); - - return country; -} - -/* - * reset the quiet channels vector to the union - * of the restricted and radar channel sets - */ -static void brcms_c_quiet_channels_reset(struct brcms_cm_info *wlc_cm) -{ - struct brcms_c_info *wlc = wlc_cm->wlc; - uint i, j; - struct brcms_band *band; - const struct brcms_chanvec *chanvec; - - memset(&wlc_cm->quiet_channels, 0, sizeof(struct brcms_chanvec)); - - band = wlc->band; - for (i = 0; i < wlc->pub->_nbands; - i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { - - /* initialize quiet channels for restricted channels */ - chanvec = wlc_cm->bandstate[band->bandunit].restricted_channels; - for (j = 0; j < sizeof(struct brcms_chanvec); j++) - wlc_cm->quiet_channels.vec[j] |= chanvec->vec[j]; + const struct brcms_regd *regd = NULL; + int i; + for (i = 0; i < ARRAY_SIZE(cntry_locales); i++) { + if (!strncmp(regdom, cntry_locales[i].regdomain->alpha2, len)) { + regd = &cntry_locales[i]; + break; + } } -} - -/* Is the channel valid for the current locale and current band? */ -static bool brcms_c_valid_channel20(struct brcms_cm_info *wlc_cm, uint val) -{ - struct brcms_c_info *wlc = wlc_cm->wlc; - return ((val < MAXCHANNEL) && - isset(wlc_cm->bandstate[wlc->band->bandunit].valid_channels.vec, - val)); + return regd; } -/* Is the channel valid for the current locale and specified band? */ -static bool brcms_c_valid_channel20_in_band(struct brcms_cm_info *wlc_cm, - uint bandunit, uint val) -{ - return ((val < MAXCHANNEL) - && isset(wlc_cm->bandstate[bandunit].valid_channels.vec, val)); -} - -/* Is the channel valid for the current locale? (but don't consider channels not - * available due to bandlocking) - */ -static bool brcms_c_valid_channel20_db(struct brcms_cm_info *wlc_cm, uint val) +static const struct brcms_regd *brcms_default_world_regd(void) { - struct brcms_c_info *wlc = wlc_cm->wlc; - - return brcms_c_valid_channel20(wlc->cmi, val) || - (!wlc->bandlocked - && brcms_c_valid_channel20_in_band(wlc->cmi, - OTHERBANDUNIT(wlc), val)); + return &cntry_locales[0]; } /* JP, J1 - J10 are Japan ccodes */ @@ -820,12 +230,6 @@ static bool brcms_c_japan_ccode(const char *ccode) (ccode[1] == 'P' || (ccode[1] >= '1' && ccode[1] <= '9'))); } -/* Returns true if currently set country is Japan or variant */ -static bool brcms_c_japan(struct brcms_c_info *wlc) -{ - return brcms_c_japan_ccode(wlc->cmi->country_abbrev); -} - static void brcms_c_channel_min_txpower_limits_with_local_constraint( struct brcms_cm_info *wlc_cm, struct txpwr_limits *txpwr, @@ -901,140 +305,16 @@ brcms_c_channel_min_txpower_limits_with_local_constraint( } -/* Update the radio state (enable/disable) and tx power targets - * based on a new set of channel/regulatory information - */ -static void brcms_c_channels_commit(struct brcms_cm_info *wlc_cm) -{ - struct brcms_c_info *wlc = wlc_cm->wlc; - uint chan; - struct txpwr_limits txpwr; - - /* search for the existence of any valid channel */ - for (chan = 0; chan < MAXCHANNEL; chan++) { - if (brcms_c_valid_channel20_db(wlc->cmi, chan)) - break; - } - if (chan == MAXCHANNEL) - chan = INVCHANNEL; - - /* - * based on the channel search above, set or - * clear WL_RADIO_COUNTRY_DISABLE. - */ - if (chan == INVCHANNEL) { - /* - * country/locale with no valid channels, set - * the radio disable bit - */ - mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); - wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\" " - "nbands %d bandlocked %d\n", wlc->pub->unit, - __func__, wlc_cm->country_abbrev, wlc->pub->_nbands, - wlc->bandlocked); - } else if (mboolisset(wlc->pub->radio_disabled, - WL_RADIO_COUNTRY_DISABLE)) { - /* - * country/locale with valid channel, clear - * the radio disable bit - */ - mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); - } - - /* - * Now that the country abbreviation is set, if the radio supports 2G, - * then set channel 14 restrictions based on the new locale. - */ - if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G) - wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi, - brcms_c_japan(wlc) ? true : - false); - - if (wlc->pub->up && chan != INVCHANNEL) { - brcms_c_channel_reg_limits(wlc_cm, wlc->chanspec, &txpwr); - brcms_c_channel_min_txpower_limits_with_local_constraint(wlc_cm, - &txpwr, BRCMS_TXPWR_MAX); - wlc_phy_txpower_limit_set(wlc->band->pi, &txpwr, wlc->chanspec); - } -} - -static int -brcms_c_channels_init(struct brcms_cm_info *wlc_cm, - const struct country_info *country) -{ - struct brcms_c_info *wlc = wlc_cm->wlc; - uint i, j; - struct brcms_band *band; - const struct locale_info *li; - struct brcms_chanvec sup_chan; - const struct locale_mimo_info *li_mimo; - - band = wlc->band; - for (i = 0; i < wlc->pub->_nbands; - i++, band = wlc->bandstate[OTHERBANDUNIT(wlc)]) { - - li = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_locale_5g(country->locale_5G) : - brcms_c_get_locale_2g(country->locale_2G); - wlc_cm->bandstate[band->bandunit].locale_flags = li->flags; - li_mimo = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_mimo_5g(country->locale_mimo_5G) : - brcms_c_get_mimo_2g(country->locale_mimo_2G); - - /* merge the mimo non-mimo locale flags */ - wlc_cm->bandstate[band->bandunit].locale_flags |= - li_mimo->flags; - - wlc_cm->bandstate[band->bandunit].restricted_channels = - g_table_restricted_chan[li->restricted_channels]; - wlc_cm->bandstate[band->bandunit].radar_channels = - g_table_radar_set[li->radar_channels]; - - /* - * set the channel availability, masking out the channels - * that may not be supported on this phy. - */ - wlc_phy_chanspec_band_validch(band->pi, band->bandtype, - &sup_chan); - brcms_c_locale_get_channels(li, - &wlc_cm->bandstate[band->bandunit]. - valid_channels); - for (j = 0; j < sizeof(struct brcms_chanvec); j++) - wlc_cm->bandstate[band->bandunit].valid_channels. - vec[j] &= sup_chan.vec[j]; - } - - brcms_c_quiet_channels_reset(wlc_cm); - brcms_c_channels_commit(wlc_cm); - - return 0; -} - /* * set the driver's current country and regulatory information * using a country code as the source. Look up built in country * information found with the country code. */ static void -brcms_c_set_country_common(struct brcms_cm_info *wlc_cm, - const char *country_abbrev, - const char *ccode, uint regrev, - const struct country_info *country) +brcms_c_set_country(struct brcms_cm_info *wlc_cm, + const struct brcms_regd *regd) { - const struct locale_info *locale; struct brcms_c_info *wlc = wlc_cm->wlc; - char prev_country_abbrev[BRCM_CNTRY_BUF_SZ]; - - /* save current country state */ - wlc_cm->country = country; - - memset(&prev_country_abbrev, 0, BRCM_CNTRY_BUF_SZ); - strncpy(prev_country_abbrev, wlc_cm->country_abbrev, - BRCM_CNTRY_BUF_SZ - 1); - - strncpy(wlc_cm->country_abbrev, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); - strncpy(wlc_cm->ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); - wlc_cm->regrev = regrev; if ((wlc->pub->_n_enab & SUPPORT_11N) != wlc->protection->nmode_user) @@ -1042,75 +322,19 @@ brcms_c_set_country_common(struct brcms_cm_info *wlc_cm, brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_2G_INDEX]); brcms_c_stf_ss_update(wlc, wlc->bandstate[BAND_5G_INDEX]); - /* set or restore gmode as required by regulatory */ - locale = brcms_c_get_locale_2g(country->locale_2G); - if (locale && (locale->flags & BRCMS_NO_OFDM)) - brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false); - else - brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); - brcms_c_channels_init(wlc_cm, country); + brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); return; } -static int -brcms_c_set_countrycode_rev(struct brcms_cm_info *wlc_cm, - const char *country_abbrev, - const char *ccode, int regrev) -{ - const struct country_info *country; - char mapped_ccode[BRCM_CNTRY_BUF_SZ]; - uint mapped_regrev; - - /* if regrev is -1, lookup the mapped country code, - * otherwise use the ccode and regrev directly - */ - if (regrev == -1) { - /* - * map the country code to a built-in country - * code, regrev, and country_info - */ - country = - brcms_c_countrycode_map(wlc_cm, ccode, mapped_ccode, - &mapped_regrev); - } else { - /* find the matching built-in country definition */ - country = brcms_c_country_lookup_direct(ccode, regrev); - strncpy(mapped_ccode, ccode, BRCM_CNTRY_BUF_SZ); - mapped_regrev = regrev; - } - - if (country == NULL) - return -EINVAL; - - /* set the driver state for the country */ - brcms_c_set_country_common(wlc_cm, country_abbrev, mapped_ccode, - mapped_regrev, country); - - return 0; -} - -/* - * set the driver's current country and regulatory information using - * a country code as the source. Lookup built in country information - * found with the country code. - */ -static int -brcms_c_set_countrycode(struct brcms_cm_info *wlc_cm, const char *ccode) -{ - char country_abbrev[BRCM_CNTRY_BUF_SZ]; - strncpy(country_abbrev, ccode, BRCM_CNTRY_BUF_SZ); - return brcms_c_set_countrycode_rev(wlc_cm, country_abbrev, ccode, -1); -} - struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) { struct brcms_cm_info *wlc_cm; - char country_abbrev[BRCM_CNTRY_BUF_SZ]; - const struct country_info *country; struct brcms_pub *pub = wlc->pub; struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; + const char *ccode = sprom->alpha2; + int ccode_len = sizeof(sprom->alpha2); BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); @@ -1122,24 +346,27 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) wlc->cmi = wlc_cm; /* store the country code for passing up as a regulatory hint */ - if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2)) - strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2)); + wlc_cm->world_regd = brcms_world_regd(ccode, ccode_len); + if (brcms_c_country_valid(ccode)) + strncpy(wlc->pub->srom_ccode, ccode, ccode_len); /* - * internal country information which must match - * regulatory constraints in firmware + * If no custom world domain is found in the SROM, use the + * default "X2" domain. */ - memset(country_abbrev, 0, BRCM_CNTRY_BUF_SZ); - strncpy(country_abbrev, "X2", sizeof(country_abbrev) - 1); - country = brcms_c_country_lookup(wlc, country_abbrev); + if (!wlc_cm->world_regd) { + wlc_cm->world_regd = brcms_default_world_regd(); + ccode = wlc_cm->world_regd->regdomain->alpha2; + ccode_len = BRCM_CNTRY_BUF_SZ - 1; + } /* save default country for exiting 11d regulatory mode */ - strncpy(wlc->country_default, country_abbrev, BRCM_CNTRY_BUF_SZ - 1); + strncpy(wlc->country_default, ccode, ccode_len); /* initialize autocountry_default to driver default */ - strncpy(wlc->autocountry_default, "X2", BRCM_CNTRY_BUF_SZ - 1); + strncpy(wlc->autocountry_default, ccode, ccode_len); - brcms_c_set_countrycode(wlc_cm, country_abbrev); + brcms_c_set_country(wlc_cm, wlc_cm->world_regd); return wlc_cm; } @@ -1149,31 +376,15 @@ void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm) kfree(wlc_cm); } -u8 -brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, - uint bandunit) -{ - return wlc_cm->bandstate[bandunit].locale_flags; -} - -static bool -brcms_c_quiet_chanspec(struct brcms_cm_info *wlc_cm, u16 chspec) -{ - return (wlc_cm->wlc->pub->_n_enab & SUPPORT_11N) && - CHSPEC_IS40(chspec) ? - (isset(wlc_cm->quiet_channels.vec, - lower_20_sb(CHSPEC_CHANNEL(chspec))) || - isset(wlc_cm->quiet_channels.vec, - upper_20_sb(CHSPEC_CHANNEL(chspec)))) : - isset(wlc_cm->quiet_channels.vec, CHSPEC_CHANNEL(chspec)); -} - void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, u8 local_constraint_qdbm) { struct brcms_c_info *wlc = wlc_cm->wlc; + struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; + const struct ieee80211_reg_rule *reg_rule; struct txpwr_limits txpwr; + int ret; brcms_c_channel_reg_limits(wlc_cm, chanspec, &txpwr); @@ -1181,8 +392,15 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, wlc_cm, &txpwr, local_constraint_qdbm ); + /* set or restore gmode as required by regulatory */ + ret = freq_reg_info(wlc->wiphy, ch->center_freq, 0, ®_rule); + if (!ret && (reg_rule->flags & NL80211_RRF_NO_OFDM)) + brcms_c_set_gmode(wlc, GMODE_LEGACY_B, false); + else + brcms_c_set_gmode(wlc, wlc->protection->gmode_user, false); + brcms_b_set_chanspec(wlc->hw, chanspec, - (brcms_c_quiet_chanspec(wlc_cm, chanspec) != 0), + !!(ch->flags & IEEE80211_CHAN_PASSIVE_SCAN), &txpwr); } @@ -1191,15 +409,14 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, struct txpwr_limits *txpwr) { struct brcms_c_info *wlc = wlc_cm->wlc; + struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; uint i; uint chan; int maxpwr; int delta; const struct country_info *country; struct brcms_band *band; - const struct locale_info *li; int conducted_max = BRCMS_TXPWR_MAX; - int conducted_ofdm_max = BRCMS_TXPWR_MAX; const struct locale_mimo_info *li_mimo; int maxpwr20, maxpwr40; int maxpwr_idx; @@ -1207,67 +424,35 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, memset(txpwr, 0, sizeof(struct txpwr_limits)); - if (!brcms_c_valid_chanspec_db(wlc_cm, chanspec)) { - country = brcms_c_country_lookup(wlc, wlc->autocountry_default); - if (country == NULL) - return; - } else { - country = wlc_cm->country; - } + if (WARN_ON(!ch)) + return; + + country = &wlc_cm->world_regd->country; chan = CHSPEC_CHANNEL(chanspec); band = wlc->bandstate[chspec_bandunit(chanspec)]; - li = (band->bandtype == BRCM_BAND_5G) ? - brcms_c_get_locale_5g(country->locale_5G) : - brcms_c_get_locale_2g(country->locale_2G); - li_mimo = (band->bandtype == BRCM_BAND_5G) ? brcms_c_get_mimo_5g(country->locale_mimo_5G) : brcms_c_get_mimo_2g(country->locale_mimo_2G); - if (li->flags & BRCMS_EIRP) { - delta = band->antgain; - } else { - delta = 0; - if (band->antgain > QDB(6)) - delta = band->antgain - QDB(6); /* Excess over 6 dB */ - } + delta = band->antgain; - if (li == &locale_i) { + if (band->bandtype == BRCM_BAND_2G) conducted_max = QDB(22); - conducted_ofdm_max = QDB(22); - } + + maxpwr = QDB(ch->max_power) - delta; + maxpwr = max(maxpwr, 0); + maxpwr = min(maxpwr, conducted_max); /* CCK txpwr limits for 2.4G band */ if (band->bandtype == BRCM_BAND_2G) { - maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_CCK(chan)]; - - maxpwr = maxpwr - delta; - maxpwr = max(maxpwr, 0); - maxpwr = min(maxpwr, conducted_max); - for (i = 0; i < BRCMS_NUM_RATES_CCK; i++) txpwr->cck[i] = (u8) maxpwr; } - /* OFDM txpwr limits for 2.4G or 5G bands */ - if (band->bandtype == BRCM_BAND_2G) - maxpwr = li->maxpwr[CHANNEL_POWER_IDX_2G_OFDM(chan)]; - else - maxpwr = li->maxpwr[CHANNEL_POWER_IDX_5G(chan)]; - - maxpwr = maxpwr - delta; - maxpwr = max(maxpwr, 0); - maxpwr = min(maxpwr, conducted_ofdm_max); - - /* Keep OFDM lmit below CCK limit */ - if (band->bandtype == BRCM_BAND_2G) - maxpwr = min_t(int, maxpwr, txpwr->cck[0]); - - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) + for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) { txpwr->ofdm[i] = (u8) maxpwr; - for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++) { /* * OFDM 40 MHz SISO has the same power as the corresponding * MCS0-7 rate unless overriden by the locale specific code. @@ -1282,14 +467,9 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec, txpwr->ofdm_40_cdd[i] = 0; } - /* MIMO/HT specific limits */ - if (li_mimo->flags & BRCMS_EIRP) { - delta = band->antgain; - } else { - delta = 0; - if (band->antgain > QDB(6)) - delta = band->antgain - QDB(6); /* Excess over 6 dB */ - } + delta = 0; + if (band->antgain > QDB(6)) + delta = band->antgain - QDB(6); /* Excess over 6 dB */ if (band->bandtype == BRCM_BAND_2G) maxpwr_idx = (chan - 1); @@ -1431,8 +611,7 @@ static bool brcms_c_chspec_malformed(u16 chanspec) * and they are also a legal HT combination */ static bool -brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec, - bool dualband) +brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec) { struct brcms_c_info *wlc = wlc_cm->wlc; u8 channel = CHSPEC_CHANNEL(chspec); @@ -1448,59 +627,163 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec, chspec_bandunit(chspec)) return false; - /* Check a 20Mhz channel */ - if (CHSPEC_IS20(chspec)) { - if (dualband) - return brcms_c_valid_channel20_db(wlc_cm->wlc->cmi, - channel); - else - return brcms_c_valid_channel20(wlc_cm->wlc->cmi, - channel); + return true; +} + +bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec) +{ + return brcms_c_valid_chanspec_ext(wlc_cm, chspec); +} + +static bool brcms_is_radar_freq(u16 center_freq) +{ + return center_freq >= 5260 && center_freq <= 5700; +} + +static void brcms_reg_apply_radar_flags(struct wiphy *wiphy) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int i; + + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + if (!sband) + return; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (!brcms_is_radar_freq(ch->center_freq)) + continue; + + /* + * All channels in this range should be passive and have + * DFS enabled. + */ + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch->flags |= IEEE80211_CHAN_RADAR | + IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN; } -#ifdef SUPPORT_40MHZ - /* - * We know we are now checking a 40MHZ channel, so we should - * only be here for NPHYS - */ - if (BRCMS_ISNPHY(wlc->band) || BRCMS_ISSSLPNPHY(wlc->band)) { - u8 upper_sideband = 0, idx; - u8 num_ch20_entries = - sizeof(chan20_info) / sizeof(struct chan20_info); - - if (!VALID_40CHANSPEC_IN_BAND(wlc, chspec_bandunit(chspec))) - return false; - - if (dualband) { - if (!brcms_c_valid_channel20_db(wlc->cmi, - lower_20_sb(channel)) || - !brcms_c_valid_channel20_db(wlc->cmi, - upper_20_sb(channel))) - return false; - } else { - if (!brcms_c_valid_channel20(wlc->cmi, - lower_20_sb(channel)) || - !brcms_c_valid_channel20(wlc->cmi, - upper_20_sb(channel))) - return false; +} + +static void +brcms_reg_apply_beaconing_flags(struct wiphy *wiphy, + enum nl80211_reg_initiator initiator) +{ + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + const struct ieee80211_reg_rule *rule; + int band, i, ret; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (ch->flags & + (IEEE80211_CHAN_DISABLED | IEEE80211_CHAN_RADAR)) + continue; + + if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) { + ret = freq_reg_info(wiphy, ch->center_freq, + 0, &rule); + if (ret) + continue; + + if (!(rule->flags & NL80211_RRF_NO_IBSS)) + ch->flags &= ~IEEE80211_CHAN_NO_IBSS; + if (!(rule->flags & NL80211_RRF_PASSIVE_SCAN)) + ch->flags &= + ~IEEE80211_CHAN_PASSIVE_SCAN; + } else if (ch->beacon_found) { + ch->flags &= ~(IEEE80211_CHAN_NO_IBSS | + IEEE80211_CHAN_PASSIVE_SCAN); + } } + } +} - /* find the lower sideband info in the sideband array */ - for (idx = 0; idx < num_ch20_entries; idx++) { - if (chan20_info[idx].sb == lower_20_sb(channel)) - upper_sideband = chan20_info[idx].adj_sbs; +static int brcms_reg_notifier(struct wiphy *wiphy, + struct regulatory_request *request) +{ + struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy); + struct brcms_info *wl = hw->priv; + struct brcms_c_info *wlc = wl->wlc; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + int band, i; + bool ch_found = false; + + brcms_reg_apply_radar_flags(wiphy); + + if (request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) + brcms_reg_apply_beaconing_flags(wiphy, request->initiator); + + /* Disable radio if all channels disallowed by regulatory */ + for (band = 0; !ch_found && band < IEEE80211_NUM_BANDS; band++) { + sband = wiphy->bands[band]; + if (!sband) + continue; + + for (i = 0; !ch_found && i < sband->n_channels; i++) { + ch = &sband->channels[i]; + + if (!(ch->flags & IEEE80211_CHAN_DISABLED)) + ch_found = true; } - /* check that the lower sideband allows an upper sideband */ - if ((upper_sideband & (CH_UPPER_SB | CH_EWA_VALID)) == - (CH_UPPER_SB | CH_EWA_VALID)) - return true; - return false; } -#endif /* 40 MHZ */ - return false; + if (ch_found) { + mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + } else { + mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE); + wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n", + wlc->pub->unit, __func__, request->alpha2); + } + + if (wlc->pub->_nbands > 1 || wlc->band->bandtype == BRCM_BAND_2G) + wlc_phy_chanspec_ch14_widefilter_set(wlc->band->pi, + brcms_c_japan_ccode(request->alpha2)); + + return 0; } -bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec) +void brcms_c_regd_init(struct brcms_c_info *wlc) { - return brcms_c_valid_chanspec_ext(wlc_cm, chspec, true); + struct wiphy *wiphy = wlc->wiphy; + const struct brcms_regd *regd = wlc->cmi->world_regd; + struct ieee80211_supported_band *sband; + struct ieee80211_channel *ch; + struct brcms_chanvec sup_chan; + struct brcms_band *band; + int band_idx, i; + + /* Disable any channels not supported by the phy */ + for (band_idx = 0; band_idx < wlc->pub->_nbands; band_idx++) { + band = wlc->bandstate[band_idx]; + + wlc_phy_chanspec_band_validch(band->pi, band->bandtype, + &sup_chan); + + if (band_idx == BAND_2G_INDEX) + sband = wiphy->bands[IEEE80211_BAND_2GHZ]; + else + sband = wiphy->bands[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < sband->n_channels; i++) { + ch = &sband->channels[i]; + if (!isset(sup_chan.vec, ch->hw_value)) + ch->flags |= IEEE80211_CHAN_DISABLED; + } + } + + wlc->wiphy->reg_notifier = brcms_reg_notifier; + wlc->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY | + WIPHY_FLAG_STRICT_REGULATORY; + wiphy_apply_custom_regulatory(wlc->wiphy, regd->regdomain); + brcms_reg_apply_beaconing_flags(wiphy, NL80211_REGDOM_SET_BY_DRIVER); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.h b/drivers/net/wireless/brcm80211/brcmsmac/channel.h index 808cb4fbfbe7..006483a0abe6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.h @@ -37,9 +37,6 @@ brcms_c_channel_mgr_attach(struct brcms_c_info *wlc); extern void brcms_c_channel_mgr_detach(struct brcms_cm_info *wlc_cm); -extern u8 brcms_c_channel_locale_flags_in_band(struct brcms_cm_info *wlc_cm, - uint bandunit); - extern bool brcms_c_valid_chanspec_db(struct brcms_cm_info *wlc_cm, u16 chspec); @@ -49,5 +46,6 @@ extern void brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, extern void brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec, u8 local_constraint_qdbm); +extern void brcms_c_regd_init(struct brcms_c_info *wlc); #endif /* _WLC_CHANNEL_H */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 11054ae9d4f6..f64c5cf3fccc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/dma.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/dma.c @@ -573,6 +573,7 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, struct dma_info *di; u8 rev = core->id.rev; uint size; + struct si_info *sii = container_of(sih, struct si_info, pub); /* allocate private info structure */ di = kzalloc(sizeof(struct dma_info), GFP_ATOMIC); @@ -633,16 +634,20 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih, */ di->ddoffsetlow = 0; di->dataoffsetlow = 0; - /* add offset for pcie with DMA64 bus */ - di->ddoffsetlow = 0; - di->ddoffsethigh = SI_PCIE_DMA_H32; + /* for pci bus, add offset */ + if (sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) { + /* add offset for pcie with DMA64 bus */ + di->ddoffsetlow = 0; + di->ddoffsethigh = SI_PCIE_DMA_H32; + } di->dataoffsetlow = di->ddoffsetlow; di->dataoffsethigh = di->ddoffsethigh; + /* WAR64450 : DMACtl.Addr ext fields are not supported in SDIOD core. */ - if ((core->id.id == SDIOD_CORE_ID) + if ((core->id.id == BCMA_CORE_SDIO_DEV) && ((rev > 0) && (rev <= 2))) di->addrext = false; - else if ((core->id.id == I2S_CORE_ID) && + else if ((core->id.id == BCMA_CORE_I2S) && ((rev == 0) || (rev == 1))) di->addrext = false; else diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 50f92a0b7c41..2b57f57a7927 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -319,8 +319,7 @@ static void brcms_ops_stop(struct ieee80211_hw *hw) return; spin_lock_bh(&wl->lock); - status = brcms_c_chipmatch(wl->wlc->hw->vendorid, - wl->wlc->hw->deviceid); + status = brcms_c_chipmatch(wl->wlc->hw->d11core); spin_unlock_bh(&wl->lock); if (!status) { wiphy_err(wl->wiphy, @@ -721,14 +720,6 @@ static const struct ieee80211_ops brcms_ops = { .flush = brcms_ops_flush, }; -/* - * is called in brcms_bcma_probe() context, therefore no locking required. - */ -static int brcms_set_hint(struct brcms_info *wl, char *abbrev) -{ - return regulatory_hint(wl->pub->ieee_hw->wiphy, abbrev); -} - void brcms_dpc(unsigned long data) { struct brcms_info *wl; @@ -1058,6 +1049,8 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) goto fail; } + brcms_c_regd_init(wl->wlc); + memcpy(perm, &wl->pub->cur_etheraddr, ETH_ALEN); if (WARN_ON(!is_valid_ether_addr(perm))) goto fail; @@ -1068,9 +1061,9 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) wiphy_err(wl->wiphy, "%s: ieee80211_register_hw failed, status" "%d\n", __func__, err); - if (wl->pub->srom_ccode[0] && brcms_set_hint(wl, wl->pub->srom_ccode)) - wiphy_err(wl->wiphy, "%s: regulatory_hint failed, status %d\n", - __func__, err); + if (wl->pub->srom_ccode[0] && + regulatory_hint(wl->wiphy, wl->pub->srom_ccode)) + wiphy_err(wl->wiphy, "%s: regulatory hint failed\n", __func__); n_adapters_found++; return wl; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index 19db4052c44c..d39f7d041e0b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -18,6 +18,7 @@ #include <linux/pci_ids.h> #include <linux/if_ether.h> +#include <net/cfg80211.h> #include <net/mac80211.h> #include <brcm_hw_ids.h> #include <aiutils.h> @@ -268,7 +269,7 @@ struct brcms_c_bit_desc { */ /* Starting corerev for the fifo size table */ -#define XMTFIFOTBL_STARTREV 20 +#define XMTFIFOTBL_STARTREV 17 struct d11init { __le16 addr; @@ -332,6 +333,12 @@ const u8 wlc_prio2prec_map[] = { }; static const u16 xmtfifo_sz[][NFIFO] = { + /* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */ + {20, 192, 192, 21, 17, 5}, + /* corerev 18: */ + {0, 0, 0, 0, 0, 0}, + /* corerev 19: */ + {0, 0, 0, 0, 0, 0}, /* corerev 20: 5120, 49152, 49152, 5376, 4352, 1280 */ {20, 192, 192, 21, 17, 5}, /* corerev 21: 2304, 14848, 5632, 3584, 3584, 1280 */ @@ -342,6 +349,14 @@ static const u16 xmtfifo_sz[][NFIFO] = { {20, 192, 192, 21, 17, 5}, /* corerev 24: 2304, 14848, 5632, 3584, 3584, 1280 */ {9, 58, 22, 14, 14, 5}, + /* corerev 25: */ + {0, 0, 0, 0, 0, 0}, + /* corerev 26: */ + {0, 0, 0, 0, 0, 0}, + /* corerev 27: */ + {0, 0, 0, 0, 0, 0}, + /* corerev 28: 2304, 14848, 5632, 3584, 3584, 1280 */ + {9, 58, 22, 14, 14, 5}, }; #ifdef DEBUG @@ -1941,7 +1956,8 @@ static bool brcms_b_radio_read_hwdisabled(struct brcms_hardware *wlc_hw) * accesses phyreg throughput mac. This can be skipped since * only mac reg is accessed below */ - flags |= SICF_PCLKE; + if (D11REV_GE(wlc_hw->corerev, 18)) + flags |= SICF_PCLKE; /* * TODO: test suspend/resume @@ -2022,7 +2038,8 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) * phyreg throughput mac, AND phy_reset is skipped at early stage when * band->pi is invalid. need to enable PHY CLK */ - flags |= SICF_PCLKE; + if (D11REV_GE(wlc_hw->corerev, 18)) + flags |= SICF_PCLKE; /* * reset the core @@ -2125,8 +2142,8 @@ void brcms_b_switch_macfreq(struct brcms_hardware *wlc_hw, u8 spurmode) { struct bcma_device *core = wlc_hw->d11core; - if ((ai_get_chip_id(wlc_hw->sih) == BCM43224_CHIP_ID) || - (ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) { + if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43224) || + (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) { if (spurmode == WL_SPURAVOID_ON2) { /* 126Mhz */ bcma_write16(core, D11REGOFFS(tsf_clk_frac_l), 0x2082); bcma_write16(core, D11REGOFFS(tsf_clk_frac_h), 0x8); @@ -2790,7 +2807,7 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on) tmp = 0; if (on) { - if ((ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { + if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) { bcma_set32(core, D11REGOFFS(clk_ctl_st), CCS_ERSRC_REQ_HT | CCS_ERSRC_REQ_D11PLL | @@ -3139,20 +3156,6 @@ void brcms_c_reset(struct brcms_c_info *wlc) brcms_b_reset(wlc->hw); } -/* Return the channel the driver should initialize during brcms_c_init. - * the channel may have to be changed from the currently configured channel - * if other configurations are in conflict (bandlocked, 11n mode disabled, - * invalid channel for current country, etc.) - */ -static u16 brcms_c_init_chanspec(struct brcms_c_info *wlc) -{ - u16 chanspec = - 1 | WL_CHANSPEC_BW_20 | WL_CHANSPEC_CTL_SB_NONE | - WL_CHANSPEC_BAND_2G; - - return chanspec; -} - void brcms_c_init_scb(struct scb *scb) { int i; @@ -4231,9 +4234,8 @@ static void brcms_c_radio_timer(void *arg) } /* common low-level watchdog code */ -static void brcms_b_watchdog(void *arg) +static void brcms_b_watchdog(struct brcms_c_info *wlc) { - struct brcms_c_info *wlc = (struct brcms_c_info *) arg; struct brcms_hardware *wlc_hw = wlc->hw; BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit); @@ -4254,10 +4256,8 @@ static void brcms_b_watchdog(void *arg) } /* common watchdog code */ -static void brcms_c_watchdog(void *arg) +static void brcms_c_watchdog(struct brcms_c_info *wlc) { - struct brcms_c_info *wlc = (struct brcms_c_info *) arg; - BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); if (!wlc->pub->up) @@ -4297,7 +4297,9 @@ static void brcms_c_watchdog(void *arg) static void brcms_c_watchdog_by_timer(void *arg) { - brcms_c_watchdog(arg); + struct brcms_c_info *wlc = (struct brcms_c_info *) arg; + + brcms_c_watchdog(wlc); } static bool brcms_c_timers_init(struct brcms_c_info *wlc, int unit) @@ -4467,11 +4469,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, } /* verify again the device is supported */ - if (core->bus->hosttype == BCMA_HOSTTYPE_PCI && - !brcms_c_chipmatch(pcidev->vendor, pcidev->device)) { - wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported " - "vendor/device (0x%x/0x%x)\n", - unit, pcidev->vendor, pcidev->device); + if (!brcms_c_chipmatch(core)) { + wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported device\n", + unit); err = 12; goto fail; } @@ -4541,7 +4541,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, else wlc_hw->_nbands = 1; - if ((ai_get_chip_id(wlc_hw->sih) == BCM43225_CHIP_ID)) + if ((ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM43225)) wlc_hw->_nbands = 1; /* BMAC_NOTE: remove init of pub values when brcms_c_attach() @@ -4608,8 +4608,12 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, wlc_hw->machwcap_backup = wlc_hw->machwcap; /* init tx fifo size */ + WARN_ON((wlc_hw->corerev - XMTFIFOTBL_STARTREV) < 0 || + (wlc_hw->corerev - XMTFIFOTBL_STARTREV) > + ARRAY_SIZE(xmtfifo_sz)); wlc_hw->xmtfifo_sz = xmtfifo_sz[(wlc_hw->corerev - XMTFIFOTBL_STARTREV)]; + WARN_ON(!wlc_hw->xmtfifo_sz[0]); /* Get a phy for this band */ wlc_hw->band->pi = @@ -5049,7 +5053,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) wlc_hw->wlc->pub->hw_up = true; if ((wlc_hw->boardflags & BFL_FEM) - && (ai_get_chip_id(wlc_hw->sih) == BCM4313_CHIP_ID)) { + && (ai_get_chip_id(wlc_hw->sih) == BCMA_CHIP_ID_BCM4313)) { if (! (wlc_hw->boardrev >= 0x1250 && (wlc_hw->boardflags & BFL_FEM_BT))) @@ -5129,6 +5133,8 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc) /* make interface operational */ int brcms_c_up(struct brcms_c_info *wlc) { + struct ieee80211_channel *ch; + BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); /* HW is turned off so don't try to access it */ @@ -5141,7 +5147,7 @@ int brcms_c_up(struct brcms_c_info *wlc) } if ((wlc->pub->boardflags & BFL_FEM) - && (ai_get_chip_id(wlc->hw->sih) == BCM4313_CHIP_ID)) { + && (ai_get_chip_id(wlc->hw->sih) == BCMA_CHIP_ID_BCM4313)) { if (wlc->pub->boardrev >= 0x1250 && (wlc->pub->boardflags & BFL_FEM_BT)) brcms_b_mhf(wlc->hw, MHF5, MHF5_4313_GPIOCTRL, @@ -5195,8 +5201,9 @@ int brcms_c_up(struct brcms_c_info *wlc) wlc->pub->up = true; if (wlc->bandinit_pending) { + ch = wlc->pub->ieee_hw->conf.channel; brcms_c_suspend_mac_and_wait(wlc); - brcms_c_set_chanspec(wlc, wlc->default_bss->chanspec); + brcms_c_set_chanspec(wlc, ch20mhz_chspec(ch->hw_value)); wlc->bandinit_pending = false; brcms_c_enable_mac(wlc); } @@ -5397,11 +5404,6 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config) else return -EINVAL; - /* Legacy or bust when no OFDM is supported by regulatory */ - if ((brcms_c_channel_locale_flags_in_band(wlc->cmi, band->bandunit) & - BRCMS_NO_OFDM) && (gmode != GMODE_LEGACY_B)) - return -EINVAL; - /* update configuration value */ if (config) brcms_c_protection_upd(wlc, BRCMS_PROT_G_USER, gmode); @@ -5782,8 +5784,12 @@ void brcms_c_print_txstatus(struct tx_status *txs) (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT); } -bool brcms_c_chipmatch(u16 vendor, u16 device) +static bool brcms_c_chipmatch_pci(struct bcma_device *core) { + struct pci_dev *pcidev = core->bus->host_pci; + u16 vendor = pcidev->vendor; + u16 device = pcidev->device; + if (vendor != PCI_VENDOR_ID_BROADCOM) { pr_err("unknown vendor id %04x\n", vendor); return false; @@ -5802,6 +5808,30 @@ bool brcms_c_chipmatch(u16 vendor, u16 device) return false; } +static bool brcms_c_chipmatch_soc(struct bcma_device *core) +{ + struct bcma_chipinfo *chipinfo = &core->bus->chipinfo; + + if (chipinfo->id == BCMA_CHIP_ID_BCM4716) + return true; + + pr_err("unknown chip id %04x\n", chipinfo->id); + return false; +} + +bool brcms_c_chipmatch(struct bcma_device *core) +{ + switch (core->bus->hosttype) { + case BCMA_HOSTTYPE_PCI: + return brcms_c_chipmatch_pci(core); + case BCMA_HOSTTYPE_SOC: + return brcms_c_chipmatch_soc(core); + default: + pr_err("unknown host type: %i\n", core->bus->hosttype); + return false; + } +} + #if defined(DEBUG) void brcms_c_print_txdesc(struct d11txh *txh) { @@ -8201,19 +8231,12 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded) void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx) { struct bcma_device *core = wlc->hw->d11core; + struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel; u16 chanspec; BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); - /* - * This will happen if a big-hammer was executed. In - * that case, we want to go back to the channel that - * we were on and not new channel - */ - if (wlc->pub->associated) - chanspec = wlc->home_chanspec; - else - chanspec = brcms_c_init_chanspec(wlc); + chanspec = ch20mhz_chspec(ch->hw_value); brcms_b_init(wlc->hw, chanspec); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 264f8c4c703d..91937c5025ce 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c @@ -198,6 +198,8 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr) void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) { + struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); + if ((D11REV_GE(pi->sh->corerev, 24)) || (D11REV_IS(pi->sh->corerev, 22) && (pi->pubpi.phy_type != PHY_TYPE_SSN))) { @@ -209,7 +211,8 @@ void write_radio_reg(struct brcms_phy *pi, u16 addr, u16 val) bcma_write16(pi->d11core, D11REGOFFS(phy4wdatalo), val); } - if (++pi->phy_wreg >= pi->phy_wreg_limit) { + if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) && + (++pi->phy_wreg >= pi->phy_wreg_limit)) { (void)bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); pi->phy_wreg = 0; } @@ -292,10 +295,13 @@ void write_phy_reg(struct brcms_phy *pi, u16 addr, u16 val) bcma_wflush16(pi->d11core, D11REGOFFS(phyregaddr), addr); bcma_write16(pi->d11core, D11REGOFFS(phyregdata), val); if (addr == 0x72) - (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); + (void)bcma_read16(pi->d11core, D11REGOFFS(phyregdata)); #else + struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); + bcma_write32(pi->d11core, D11REGOFFS(phyregaddr), addr | (val << 16)); - if (++pi->phy_wreg >= pi->phy_wreg_limit) { + if ((sii->icbus->hosttype == BCMA_HOSTTYPE_PCI) && + (++pi->phy_wreg >= pi->phy_wreg_limit)) { pi->phy_wreg = 0; (void)bcma_read16(pi->d11core, D11REGOFFS(phyversion)); } @@ -837,7 +843,7 @@ wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, pi->tbl_data_hi = tblDataHi; pi->tbl_data_lo = tblDataLo; - if (pi->sh->chip == BCM43224_CHIP_ID && + if (pi->sh->chip == BCMA_CHIP_ID_BCM43224 && pi->sh->chiprev == 1) { pi->tbl_addr = tblAddr; pi->tbl_save_id = tbl_id; @@ -847,7 +853,7 @@ wlc_phy_table_addr(struct brcms_phy *pi, uint tbl_id, uint tbl_offset, void wlc_phy_table_data_write(struct brcms_phy *pi, uint width, u32 val) { - if ((pi->sh->chip == BCM43224_CHIP_ID) && + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && (pi->sh->chiprev == 1) && (pi->tbl_save_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { read_phy_reg(pi, pi->tbl_data_lo); @@ -881,7 +887,7 @@ wlc_phy_write_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, for (idx = 0; idx < ptbl_info->tbl_len; idx++) { - if ((pi->sh->chip == BCM43224_CHIP_ID) && + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && (pi->sh->chiprev == 1) && (tbl_id == NPHY_TBL_ID_ANTSWCTRLLUT)) { read_phy_reg(pi, tblDataLo); @@ -918,7 +924,7 @@ wlc_phy_read_table(struct brcms_phy *pi, const struct phytbl_info *ptbl_info, for (idx = 0; idx < ptbl_info->tbl_len; idx++) { - if ((pi->sh->chip == BCM43224_CHIP_ID) && + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) && (pi->sh->chiprev == 1)) { (void)read_phy_reg(pi, tblDataLo); @@ -2894,7 +2900,7 @@ const u8 *wlc_phy_get_ofdm_rate_lookup(void) void wlc_lcnphy_epa_switch(struct brcms_phy *pi, bool mode) { - if ((pi->sh->chip == BCM4313_CHIP_ID) && + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4313) && (pi->sh->boardflags & BFL_FEM)) { if (mode) { u16 txant = 0; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 366718146418..65db9b7458dc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -17893,6 +17893,8 @@ static u32 *wlc_phy_get_ipa_gaintbl_nphy(struct brcms_phy *pi) nphy_tpc_txgain_ipa_2g_2057rev7; } else if (NREV_IS(pi->pubpi.phy_rev, 6)) { tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev6; + if (pi->sh->chip == BCMA_CHIP_ID_BCM47162) + tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { tx_pwrctrl_tbl = nphy_tpc_txgain_ipa_rev5; } else { @@ -19254,8 +19256,14 @@ static void wlc_phy_spurwar_nphy(struct brcms_phy *pi) case 38: case 102: case 118: - nphy_adj_tone_id_buf[0] = 0; - nphy_adj_noise_var_buf[0] = 0x0; + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) && + (pi->sh->chippkg == BCMA_PKG_ID_BCM4717)) { + nphy_adj_tone_id_buf[0] = 32; + nphy_adj_noise_var_buf[0] = 0x21f; + } else { + nphy_adj_tone_id_buf[0] = 0; + nphy_adj_noise_var_buf[0] = 0x0; + } break; case 134: nphy_adj_tone_id_buf[0] = 32; @@ -19309,8 +19317,8 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) pi->measure_hold |= PHY_HOLD_FOR_NOT_ASSOC; if ((ISNPHY(pi)) && (NREV_GE(pi->pubpi.phy_rev, 5)) && - ((pi->sh->chippkg == BCM4717_PKG_ID) || - (pi->sh->chippkg == BCM4718_PKG_ID))) { + ((pi->sh->chippkg == BCMA_PKG_ID_BCM4717) || + (pi->sh->chippkg == BCMA_PKG_ID_BCM4718))) { if ((pi->sh->boardflags & BFL_EXTLNA) && (CHSPEC_IS2G(pi->radio_chanspec))) ai_cc_reg(pi->sh->sih, @@ -19318,6 +19326,10 @@ void wlc_phy_init_nphy(struct brcms_phy *pi) 0x40, 0x40); } + if ((!PHY_IPA(pi)) && (pi->sh->chip == BCMA_CHIP_ID_BCM5357)) + si_pmu_chipcontrol(pi->sh->sih, 1, CCTRL5357_EXTPA, + CCTRL5357_EXTPA); + if ((pi->nphy_gband_spurwar2_en) && CHSPEC_IS2G(pi->radio_chanspec) && CHSPEC_IS40(pi->radio_chanspec)) { @@ -20695,12 +20707,22 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, write_radio_reg(pi, RADIO_2056_SYN_PLL_LOOPFILTER2 | RADIO_2056_SYN, 0x1f); - write_radio_reg(pi, - RADIO_2056_SYN_PLL_LOOPFILTER4 | - RADIO_2056_SYN, 0xb); - write_radio_reg(pi, - RADIO_2056_SYN_PLL_CP2 | - RADIO_2056_SYN, 0x14); + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || + (pi->sh->chip == BCMA_CHIP_ID_BCM47162)) { + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER4 | + RADIO_2056_SYN, 0x14); + write_radio_reg(pi, + RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, 0x00); + } else { + write_radio_reg(pi, + RADIO_2056_SYN_PLL_LOOPFILTER4 | + RADIO_2056_SYN, 0xb); + write_radio_reg(pi, + RADIO_2056_SYN_PLL_CP2 | + RADIO_2056_SYN, 0x14); + } } } @@ -20747,24 +20769,30 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, PADG_IDAC, 0xcc); - bias = 0x25; - cascbias = 0x20; + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || + (pi->sh->chip == BCMA_CHIP_ID_BCM47162)) { + bias = 0x40; + cascbias = 0x45; + pag_boost_tune = 0x5; + pgag_boost_tune = 0x33; + padg_boost_tune = 0x77; + mixg_boost_tune = 0x55; + } else { + bias = 0x25; + cascbias = 0x20; - if ((pi->sh->chip == - BCM43224_CHIP_ID) - || (pi->sh->chip == - BCM43225_CHIP_ID)) { - if (pi->sh->chippkg == - BCM43224_FAB_SMIC) { + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224 || + pi->sh->chip == BCMA_CHIP_ID_BCM43225) && + pi->sh->chippkg == BCMA_PKG_ID_BCM43224_FAB_SMIC) { bias = 0x2a; cascbias = 0x38; } - } - pag_boost_tune = 0x4; - pgag_boost_tune = 0x03; - padg_boost_tune = 0x77; - mixg_boost_tune = 0x65; + pag_boost_tune = 0x4; + pgag_boost_tune = 0x03; + padg_boost_tune = 0x77; + mixg_boost_tune = 0x65; + } WRITE_RADIO_REG2(pi, RADIO_2056, TX, core, INTPAG_IMAIN_STAT, bias); @@ -20863,11 +20891,10 @@ wlc_phy_chanspec_radio2056_setup(struct brcms_phy *pi, cascbias = 0x30; - if ((pi->sh->chip == BCM43224_CHIP_ID) || - (pi->sh->chip == BCM43225_CHIP_ID)) { - if (pi->sh->chippkg == BCM43224_FAB_SMIC) - cascbias = 0x35; - } + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224 || + pi->sh->chip == BCMA_CHIP_ID_BCM43225) && + pi->sh->chippkg == BCMA_PKG_ID_BCM43224_FAB_SMIC) + cascbias = 0x35; pabias = (pi->phy_pabias == 0) ? 0x30 : pi->phy_pabias; @@ -21106,6 +21133,7 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, const struct nphy_sfo_cfg *ci) { u16 val; + struct si_info *sii = container_of(pi->sh->sih, struct si_info, pub); val = read_phy_reg(pi, 0x09) & NPHY_BandControl_currentBand; if (CHSPEC_IS5G(chanspec) && !val) { @@ -21178,22 +21206,32 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, } else if (NREV_GE(pi->pubpi.phy_rev, 7)) { if (val == 54) spuravoid = 1; - } else { - if (pi->nphy_aband_spurwar_en && - ((val == 38) || (val == 102) - || (val == 118))) + } else if (pi->nphy_aband_spurwar_en && + ((val == 38) || (val == 102) || (val == 118))) { + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) + && (pi->sh->chippkg == BCMA_PKG_ID_BCM4717)) { + spuravoid = 0; + } else { spuravoid = 1; + } } if (pi->phy_spuravoid == SPURAVOID_FORCEON) spuravoid = 1; - wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); - si_pmu_spuravoid_pllupdate(pi->sh->sih, spuravoid); - wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); + if ((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || + (pi->sh->chip == BCMA_CHIP_ID_BCM43225)) { + bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc, + spuravoid); + } else { + wlapi_bmac_core_phypll_ctl(pi->sh->physhim, false); + bcma_pmu_spuravoid_pllupdate(&sii->icbus->drv_cc, + spuravoid); + wlapi_bmac_core_phypll_ctl(pi->sh->physhim, true); + } - if ((pi->sh->chip == BCM43224_CHIP_ID) || - (pi->sh->chip == BCM43225_CHIP_ID)) { + if ((pi->sh->chip == BCMA_CHIP_ID_BCM43224) || + (pi->sh->chip == BCMA_CHIP_ID_BCM43225)) { if (spuravoid == 1) { bcma_write16(pi->d11core, D11REGOFFS(tsf_clk_frac_l), @@ -21209,7 +21247,9 @@ wlc_phy_chanspec_nphy_setup(struct brcms_phy *pi, u16 chanspec, } } - wlapi_bmac_core_phypll_reset(pi->sh->physhim); + if (!((pi->sh->chip == BCMA_CHIP_ID_BCM4716) || + (pi->sh->chip == BCMA_CHIP_ID_BCM47162))) + wlapi_bmac_core_phypll_reset(pi->sh->physhim); mod_phy_reg(pi, 0x01, (0x1 << 15), ((spuravoid > 0) ? (0x1 << 15) : 0)); @@ -22171,9 +22211,15 @@ s16 wlc_phy_tempsense_nphy(struct brcms_phy *pi) wlc_phy_table_write_nphy(pi, NPHY_TBL_ID_AFECTRL, 1, 0x03, 16, &auxADC_rssi_ctrlH_save); - radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) - + 82 * (auxADC_Vl) - 28861 + - 128) / 256; + if (pi->sh->chip == BCMA_CHIP_ID_BCM5357) { + radio_temp[0] = (193 * (radio_temp[1] + radio_temp2[1]) + + 88 * (auxADC_Vl) - 27111 + + 128) / 256; + } else { + radio_temp[0] = (179 * (radio_temp[1] + radio_temp2[1]) + + 82 * (auxADC_Vl) - 28861 + + 128) / 256; + } offset = (s16) pi->phy_tempsense_offset; @@ -24923,14 +24969,16 @@ wlc_phy_a2_nphy(struct brcms_phy *pi, struct nphy_ipa_txcalgains *txgains, if (txgains->useindex) { phy_a4 = 15 - ((txgains->index) >> 3); if (CHSPEC_IS2G(pi->radio_chanspec)) { - if (NREV_GE(pi->pubpi.phy_rev, 6)) + if (NREV_GE(pi->pubpi.phy_rev, 6) && + pi->sh->chip == BCMA_CHIP_ID_BCM47162) { + phy_a5 = 0x10f7 | (phy_a4 << 8); + } else if (NREV_GE(pi->pubpi.phy_rev, 6)) { phy_a5 = 0x00f7 | (phy_a4 << 8); - - else - if (NREV_IS(pi->pubpi.phy_rev, 5)) + } else if (NREV_IS(pi->pubpi.phy_rev, 5)) { phy_a5 = 0x10f7 | (phy_a4 << 8); - else + } else { phy_a5 = 0x50f7 | (phy_a4 << 8); + } } else { phy_a5 = 0x70f7 | (phy_a4 << 8); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c index 4931d29d077b..7e9df566c733 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.c @@ -74,16 +74,6 @@ * PMU<rev>_PLL<num>_XX where <rev> is PMU corerev and <num> is an arbitrary * number to differentiate different PLLs controlled by the same PMU rev. */ -/* pllcontrol registers: - * ndiv_pwrdn, pwrdn_ch<x>, refcomp_pwrdn, dly_ch<x>, - * p1div, p2div, _bypass_sdmod - */ -#define PMU1_PLL0_PLLCTL0 0 -#define PMU1_PLL0_PLLCTL1 1 -#define PMU1_PLL0_PLLCTL2 2 -#define PMU1_PLL0_PLLCTL3 3 -#define PMU1_PLL0_PLLCTL4 4 -#define PMU1_PLL0_PLLCTL5 5 /* pmu XtalFreqRatio */ #define PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF @@ -108,118 +98,14 @@ #define RES4313_HT_AVAIL_RSRC 14 #define RES4313_MACPHY_CLK_AVAIL_RSRC 15 -/* Determine min/max rsrc masks. Value 0 leaves hardware at default. */ -static void si_pmu_res_masks(struct si_pub *sih, u32 * pmin, u32 * pmax) -{ - u32 min_mask = 0, max_mask = 0; - uint rsrcs; - - /* # resources */ - rsrcs = (ai_get_pmucaps(sih) & PCAP_RC_MASK) >> PCAP_RC_SHIFT; - - /* determine min/max rsrc masks */ - switch (ai_get_chip_id(sih)) { - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - /* ??? */ - break; - - case BCM4313_CHIP_ID: - min_mask = PMURES_BIT(RES4313_BB_PU_RSRC) | - PMURES_BIT(RES4313_XTAL_PU_RSRC) | - PMURES_BIT(RES4313_ALP_AVAIL_RSRC) | - PMURES_BIT(RES4313_BB_PLL_PWRSW_RSRC); - max_mask = 0xffff; - break; - default: - break; - } - - *pmin = min_mask; - *pmax = max_mask; -} - -void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid) -{ - u32 tmp = 0; - struct bcma_device *core; - - /* switch to chipc */ - core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - - switch (ai_get_chip_id(sih)) { - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - if (spuravoid == 1) { - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL0); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x11500010); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL1); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x000C0C06); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL2); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x0F600a08); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL3); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x00000000); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL4); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x2001E920); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL5); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x88888815); - } else { - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL0); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x11100010); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL1); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x000c0c06); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL2); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x03000a08); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL3); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x00000000); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL4); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x200005c0); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_addr), - PMU1_PLL0_PLLCTL5); - bcma_write32(core, CHIPCREGOFFS(pllcontrol_data), - 0x88888815); - } - tmp = 1 << 10; - break; - - default: - /* bail out */ - return; - } - - bcma_set32(core, CHIPCREGOFFS(pmucontrol), tmp); -} - u16 si_pmu_fast_pwrup_delay(struct si_pub *sih) { uint delay = PMU_MAX_TRANSITION_DLY; switch (ai_get_chip_id(sih)) { - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - case BCM4313_CHIP_ID: + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43225: + case BCMA_CHIP_ID_BCM4313: delay = 3700; break; default: @@ -270,9 +156,9 @@ u32 si_pmu_alp_clock(struct si_pub *sih) return clock; switch (ai_get_chip_id(sih)) { - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - case BCM4313_CHIP_ID: + case BCMA_CHIP_ID_BCM43224: + case BCMA_CHIP_ID_BCM43225: + case BCMA_CHIP_ID_BCM4313: /* always 20Mhz */ clock = 20000 * 1000; break; @@ -283,51 +169,9 @@ u32 si_pmu_alp_clock(struct si_pub *sih) return clock; } -/* initialize PMU */ -void si_pmu_init(struct si_pub *sih) -{ - struct bcma_device *core; - - /* select chipc */ - core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - - if (ai_get_pmurev(sih) == 1) - bcma_mask32(core, CHIPCREGOFFS(pmucontrol), - ~PCTL_NOILP_ON_WAIT); - else if (ai_get_pmurev(sih) >= 2) - bcma_set32(core, CHIPCREGOFFS(pmucontrol), PCTL_NOILP_ON_WAIT); -} - -/* initialize PMU resources */ -void si_pmu_res_init(struct si_pub *sih) -{ - struct bcma_device *core; - u32 min_mask = 0, max_mask = 0; - - /* select to chipc */ - core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - - /* Determine min/max rsrc masks */ - si_pmu_res_masks(sih, &min_mask, &max_mask); - - /* It is required to program max_mask first and then min_mask */ - - /* Program max resource mask */ - - if (max_mask) - bcma_write32(core, CHIPCREGOFFS(max_res_mask), max_mask); - - /* Program min resource mask */ - - if (min_mask) - bcma_write32(core, CHIPCREGOFFS(min_res_mask), min_mask); - - /* Add some delay; allow resources to come up and settle. */ - mdelay(2); -} - u32 si_pmu_measure_alpclk(struct si_pub *sih) { + struct si_info *sii = container_of(sih, struct si_info, pub); struct bcma_device *core; u32 alp_khz; @@ -335,7 +179,7 @@ u32 si_pmu_measure_alpclk(struct si_pub *sih) return 0; /* Remember original core before switch to chipc */ - core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); + core = sii->icbus->drv_cc.core; if (bcma_read32(core, CHIPCREGOFFS(pmustatus)) & PST_EXTLPOAVAIL) { u32 ilp_ctr, alp_hz; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h index 3e39c5e0f9ff..f7cff873578b 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pmu.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pmu.h @@ -26,10 +26,7 @@ extern u32 si_pmu_chipcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_regcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); extern u32 si_pmu_alp_clock(struct si_pub *sih); extern void si_pmu_pllupd(struct si_pub *sih); -extern void si_pmu_spuravoid_pllupdate(struct si_pub *sih, u8 spuravoid); extern u32 si_pmu_pllcontrol(struct si_pub *sih, uint reg, u32 mask, u32 val); -extern void si_pmu_init(struct si_pub *sih); -extern void si_pmu_res_init(struct si_pub *sih); extern u32 si_pmu_measure_alpclk(struct si_pub *sih); #endif /* _BRCM_PMU_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index aa5d67f8d874..5855f4fd16dc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -311,7 +311,7 @@ extern uint brcms_c_detach(struct brcms_c_info *wlc); extern int brcms_c_up(struct brcms_c_info *wlc); extern uint brcms_c_down(struct brcms_c_info *wlc); -extern bool brcms_c_chipmatch(u16 vendor, u16 device); +extern bool brcms_c_chipmatch(struct bcma_device *core); extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx); extern void brcms_c_reset(struct brcms_c_info *wlc); diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h index 333193f20e1c..bcc79b4e3267 100644 --- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h +++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h @@ -37,5 +37,6 @@ #define BCM4329_CHIP_ID 0x4329 #define BCM4330_CHIP_ID 0x4330 #define BCM4331_CHIP_ID 0x4331 +#define BCM4334_CHIP_ID 0x4334 #endif /* _BRCM_HW_IDS_H_ */ diff --git a/drivers/net/wireless/brcm80211/include/soc.h b/drivers/net/wireless/brcm80211/include/soc.h index 4e9b7e4827ea..123cfa854a0d 100644 --- a/drivers/net/wireless/brcm80211/include/soc.h +++ b/drivers/net/wireless/brcm80211/include/soc.h @@ -19,68 +19,6 @@ #define SI_ENUM_BASE 0x18000000 /* Enumeration space base */ -/* core codes */ -#define NODEV_CORE_ID 0x700 /* Invalid coreid */ -#define CC_CORE_ID 0x800 /* chipcommon core */ -#define ILINE20_CORE_ID 0x801 /* iline20 core */ -#define SRAM_CORE_ID 0x802 /* sram core */ -#define SDRAM_CORE_ID 0x803 /* sdram core */ -#define PCI_CORE_ID 0x804 /* pci core */ -#define MIPS_CORE_ID 0x805 /* mips core */ -#define ENET_CORE_ID 0x806 /* enet mac core */ -#define CODEC_CORE_ID 0x807 /* v90 codec core */ -#define USB_CORE_ID 0x808 /* usb 1.1 host/device core */ -#define ADSL_CORE_ID 0x809 /* ADSL core */ -#define ILINE100_CORE_ID 0x80a /* iline100 core */ -#define IPSEC_CORE_ID 0x80b /* ipsec core */ -#define UTOPIA_CORE_ID 0x80c /* utopia core */ -#define PCMCIA_CORE_ID 0x80d /* pcmcia core */ -#define SOCRAM_CORE_ID 0x80e /* internal memory core */ -#define MEMC_CORE_ID 0x80f /* memc sdram core */ -#define OFDM_CORE_ID 0x810 /* OFDM phy core */ -#define EXTIF_CORE_ID 0x811 /* external interface core */ -#define D11_CORE_ID 0x812 /* 802.11 MAC core */ -#define APHY_CORE_ID 0x813 /* 802.11a phy core */ -#define BPHY_CORE_ID 0x814 /* 802.11b phy core */ -#define GPHY_CORE_ID 0x815 /* 802.11g phy core */ -#define MIPS33_CORE_ID 0x816 /* mips3302 core */ -#define USB11H_CORE_ID 0x817 /* usb 1.1 host core */ -#define USB11D_CORE_ID 0x818 /* usb 1.1 device core */ -#define USB20H_CORE_ID 0x819 /* usb 2.0 host core */ -#define USB20D_CORE_ID 0x81a /* usb 2.0 device core */ -#define SDIOH_CORE_ID 0x81b /* sdio host core */ -#define ROBO_CORE_ID 0x81c /* roboswitch core */ -#define ATA100_CORE_ID 0x81d /* parallel ATA core */ -#define SATAXOR_CORE_ID 0x81e /* serial ATA & XOR DMA core */ -#define GIGETH_CORE_ID 0x81f /* gigabit ethernet core */ -#define PCIE_CORE_ID 0x820 /* pci express core */ -#define NPHY_CORE_ID 0x821 /* 802.11n 2x2 phy core */ -#define SRAMC_CORE_ID 0x822 /* SRAM controller core */ -#define MINIMAC_CORE_ID 0x823 /* MINI MAC/phy core */ -#define ARM11_CORE_ID 0x824 /* ARM 1176 core */ -#define ARM7S_CORE_ID 0x825 /* ARM7tdmi-s core */ -#define LPPHY_CORE_ID 0x826 /* 802.11a/b/g phy core */ -#define PMU_CORE_ID 0x827 /* PMU core */ -#define SSNPHY_CORE_ID 0x828 /* 802.11n single-stream phy core */ -#define SDIOD_CORE_ID 0x829 /* SDIO device core */ -#define ARMCM3_CORE_ID 0x82a /* ARM Cortex M3 core */ -#define HTPHY_CORE_ID 0x82b /* 802.11n 4x4 phy core */ -#define MIPS74K_CORE_ID 0x82c /* mips 74k core */ -#define GMAC_CORE_ID 0x82d /* Gigabit MAC core */ -#define DMEMC_CORE_ID 0x82e /* DDR1/2 memory controller core */ -#define PCIERC_CORE_ID 0x82f /* PCIE Root Complex core */ -#define OCP_CORE_ID 0x830 /* OCP2OCP bridge core */ -#define SC_CORE_ID 0x831 /* shared common core */ -#define AHB_CORE_ID 0x832 /* OCP2AHB bridge core */ -#define SPIH_CORE_ID 0x833 /* SPI host core */ -#define I2S_CORE_ID 0x834 /* I2S core */ -#define DMEMS_CORE_ID 0x835 /* SDR/DDR1 memory controller core */ -#define DEF_SHIM_COMP 0x837 /* SHIM component in ubus/6362 */ -#define OOB_ROUTER_CORE_ID 0x367 /* OOB router core ID */ -#define DEF_AI_COMP 0xfff /* Default component, in ai chips it - * maps all unused address ranges - */ - /* Common core control flags */ #define SICF_BIST_EN 0x8000 #define SICF_PME_EN 0x4000 diff --git a/drivers/net/wireless/iwlegacy/3945-rs.c b/drivers/net/wireless/iwlegacy/3945-rs.c index 4b10157d8686..d4fd29ad90dc 100644 --- a/drivers/net/wireless/iwlegacy/3945-rs.c +++ b/drivers/net/wireless/iwlegacy/3945-rs.c @@ -946,7 +946,7 @@ il3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) case IEEE80211_BAND_5GHZ: rs_sta->expected_tpt = il3945_expected_tpt_a; break; - case IEEE80211_NUM_BANDS: + default: BUG(); break; } diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c index d24eaf89ffb5..34f61a0581a2 100644 --- a/drivers/net/wireless/iwlegacy/4965-mac.c +++ b/drivers/net/wireless/iwlegacy/4965-mac.c @@ -3405,7 +3405,7 @@ il4965_remove_dynamic_key(struct il_priv *il, return 0; } - if (il->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET) { + if (il->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_INVALID) { IL_WARN("Removing wrong key %d 0x%x\n", keyconf->keyidx, key_flags); spin_unlock_irqrestore(&il->sta_lock, flags); @@ -3420,7 +3420,7 @@ il4965_remove_dynamic_key(struct il_priv *il, memset(&il->stations[sta_id].sta.key, 0, sizeof(struct il4965_keyinfo)); il->stations[sta_id].sta.key.key_flags = STA_KEY_FLG_NO_ENC | STA_KEY_FLG_INVALID; - il->stations[sta_id].sta.key.key_offset = WEP_INVALID_OFFSET; + il->stations[sta_id].sta.key.key_offset = keyconf->hw_key_idx; il->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; il->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index cbf2dc18341f..0370403fd0bd 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -4717,10 +4717,11 @@ il_check_stuck_queue(struct il_priv *il, int cnt) struct il_tx_queue *txq = &il->txq[cnt]; struct il_queue *q = &txq->q; unsigned long timeout; + unsigned long now = jiffies; int ret; if (q->read_ptr == q->write_ptr) { - txq->time_stamp = jiffies; + txq->time_stamp = now; return 0; } @@ -4728,9 +4729,9 @@ il_check_stuck_queue(struct il_priv *il, int cnt) txq->time_stamp + msecs_to_jiffies(il->cfg->wd_timeout); - if (time_after(jiffies, timeout)) { + if (time_after(now, timeout)) { IL_ERR("Queue %d stuck for %u ms.\n", q->id, - il->cfg->wd_timeout); + jiffies_to_msecs(now - txq->time_stamp)); ret = il_force_reset(il, false); return (ret == -EAGAIN) ? 0 : 1; } @@ -4767,14 +4768,12 @@ il_bg_watchdog(unsigned long data) return; /* monitor and check for other stuck queues */ - if (il_is_any_associated(il)) { - for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { - /* skip as we already checked the command queue */ - if (cnt == il->cmd_queue) - continue; - if (il_check_stuck_queue(il, cnt)) - return; - } + for (cnt = 0; cnt < il->hw_params.max_txq_num; cnt++) { + /* skip as we already checked the command queue */ + if (cnt == il->cmd_queue) + continue; + if (il_check_stuck_queue(il, cnt)) + return; } mod_timer(&il->watchdog, @@ -5360,7 +5359,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_ASSOC) { D_MAC80211("ASSOC %d\n", bss_conf->assoc); if (bss_conf->assoc) { - il->timestamp = bss_conf->last_tsf; + il->timestamp = bss_conf->sync_tsf; if (!il_is_rfkill(il)) il->ops->post_associate(il); diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index b0f125c985cd..46782f1102ac 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -2228,6 +2228,7 @@ static ssize_t iwl_dbgfs_echo_test_write(struct file *file, return count; } +#ifdef CONFIG_IWLWIFI_DEBUG static ssize_t iwl_dbgfs_log_event_read(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) @@ -2269,6 +2270,7 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, return count; } +#endif static ssize_t iwl_dbgfs_calib_disabled_read(struct file *file, char __user *user_buf, @@ -2338,7 +2340,9 @@ DEBUGFS_READ_FILE_OPS(bt_traffic); DEBUGFS_READ_WRITE_FILE_OPS(protection_mode); DEBUGFS_READ_FILE_OPS(reply_tx_error); DEBUGFS_WRITE_FILE_OPS(echo_test); +#ifdef CONFIG_IWLWIFI_DEBUG DEBUGFS_READ_WRITE_FILE_OPS(log_event); +#endif DEBUGFS_READ_WRITE_FILE_OPS(calib_disabled); /* @@ -2398,7 +2402,9 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(rxon_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(rxon_filter_flags, dir_debug, S_IWUSR); DEBUGFS_ADD_FILE(echo_test, dir_debug, S_IWUSR); +#ifdef CONFIG_IWLWIFI_DEBUG DEBUGFS_ADD_FILE(log_event, dir_debug, S_IWUSR | S_IRUSR); +#endif if (iwl_advanced_bt_coexist(priv)) DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR); diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c index b83ca358eb18..a5f7bce96325 100644 --- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c @@ -801,6 +801,18 @@ static int iwlagn_mac_sta_state(struct ieee80211_hw *hw, switch (op) { case ADD: ret = iwlagn_mac_sta_add(hw, vif, sta); + if (ret) + break; + /* + * Clear the in-progress flag, the AP station entry was added + * but we'll initialize LQ only when we've associated (which + * would also clear the in-progress flag). This is necessary + * in case we never initialize LQ because association fails. + */ + spin_lock_bh(&priv->sta_lock); + priv->stations[iwl_sta_id(sta)].used &= + ~IWL_STA_UCODE_INPROGRESS; + spin_unlock_bh(&priv->sta_lock); break; case REMOVE: ret = iwlagn_mac_sta_remove(hw, vif, sta); diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 6ee940f497f9..10896393e5a0 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1447,7 +1447,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - priv->timestamp = bss_conf->last_tsf; + priv->timestamp = bss_conf->sync_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { /* diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index 6322e2a692cc..cc41cfaedfbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -911,8 +911,10 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context) const struct iwl_op_mode_ops *ops = op->ops; drv->op_mode = ops->start(drv->trans, drv->cfg, &drv->fw); - if (!drv->op_mode) + if (!drv->op_mode) { + mutex_unlock(&iwlwifi_opmode_table_mtx); goto out_unbind; + } } else { load_module = true; } diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig deleted file mode 100644 index 7107ce53d4d4..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/Kconfig +++ /dev/null @@ -1,39 +0,0 @@ -config IWM - tristate "Intel Wireless Multicomm 3200 WiFi driver (EXPERIMENTAL)" - depends on MMC && EXPERIMENTAL - depends on CFG80211 - select FW_LOADER - select IWMC3200TOP - help - The Intel Wireless Multicomm 3200 hardware is a combo - card with GPS, Bluetooth, WiMax and 802.11 radios. It - runs over SDIO and is typically found on Moorestown - based platform. This driver takes care of the 802.11 - part, which is a fullmac one. - - If you choose to build it as a module, it'll be called - iwmc3200wifi.ko. - -config IWM_DEBUG - bool "Enable full debugging output in iwmc3200wifi" - depends on IWM && DEBUG_FS - help - This option will enable debug tracing and setting for iwm - - You can set the debug level and module through debugfs. By - default all modules are set to the IWL_DL_ERR level. - To see the list of debug modules and levels, see iwm/debug.h - - For example, if you want the full MLME debug output: - echo 0xff > /sys/kernel/debug/iwm/phyN/debug/mlme - - Or, if you want the full debug, for all modules: - echo 0xff > /sys/kernel/debug/iwm/phyN/debug/level - echo 0xff > /sys/kernel/debug/iwm/phyN/debug/modules - -config IWM_TRACING - bool "Enable event tracing for iwmc3200wifi" - depends on IWM && EVENT_TRACING - help - Say Y here to trace all the commands and responses between - the driver and firmware (including TX/RX frames) with ftrace. diff --git a/drivers/net/wireless/iwmc3200wifi/Makefile b/drivers/net/wireless/iwmc3200wifi/Makefile deleted file mode 100644 index cdc7e07ba113..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -obj-$(CONFIG_IWM) := iwmc3200wifi.o -iwmc3200wifi-objs += main.o netdev.o rx.o tx.o sdio.o hal.o fw.o -iwmc3200wifi-objs += commands.o cfg80211.o eeprom.o - -iwmc3200wifi-$(CONFIG_IWM_DEBUG) += debugfs.o -iwmc3200wifi-$(CONFIG_IWM_TRACING) += trace.o - -CFLAGS_trace.o := -I$(src) - -ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/net/wireless/iwmc3200wifi/bus.h b/drivers/net/wireless/iwmc3200wifi/bus.h deleted file mode 100644 index 62edd5888a7b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/bus.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IWM_BUS_H__ -#define __IWM_BUS_H__ - -#include "iwm.h" - -struct iwm_if_ops { - int (*enable)(struct iwm_priv *iwm); - int (*disable)(struct iwm_priv *iwm); - int (*send_chunk)(struct iwm_priv *iwm, u8* buf, int count); - - void (*debugfs_init)(struct iwm_priv *iwm, struct dentry *parent_dir); - void (*debugfs_exit)(struct iwm_priv *iwm); - - const char *umac_name; - const char *calib_lmac_name; - const char *lmac_name; -}; - -static inline int iwm_bus_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) -{ - return iwm->bus_ops->send_chunk(iwm, buf, count); -} - -static inline int iwm_bus_enable(struct iwm_priv *iwm) -{ - return iwm->bus_ops->enable(iwm); -} - -static inline int iwm_bus_disable(struct iwm_priv *iwm) -{ - return iwm->bus_ops->disable(iwm); -} - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.c b/drivers/net/wireless/iwmc3200wifi/cfg80211.c deleted file mode 100644 index 48e8218fd23b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.c +++ /dev/null @@ -1,882 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/sched.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> -#include <linux/ieee80211.h> -#include <linux/slab.h> -#include <net/cfg80211.h> - -#include "iwm.h" -#include "commands.h" -#include "cfg80211.h" -#include "debug.h" - -#define RATETAB_ENT(_rate, _rateid, _flags) \ - { \ - .bitrate = (_rate), \ - .hw_value = (_rateid), \ - .flags = (_flags), \ - } - -#define CHAN2G(_channel, _freq, _flags) { \ - .band = IEEE80211_BAND_2GHZ, \ - .center_freq = (_freq), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -#define CHAN5G(_channel, _flags) { \ - .band = IEEE80211_BAND_5GHZ, \ - .center_freq = 5000 + (5 * (_channel)), \ - .hw_value = (_channel), \ - .flags = (_flags), \ - .max_antenna_gain = 0, \ - .max_power = 30, \ -} - -static struct ieee80211_rate iwm_rates[] = { - RATETAB_ENT(10, 0x1, 0), - RATETAB_ENT(20, 0x2, 0), - RATETAB_ENT(55, 0x4, 0), - RATETAB_ENT(110, 0x8, 0), - RATETAB_ENT(60, 0x10, 0), - RATETAB_ENT(90, 0x20, 0), - RATETAB_ENT(120, 0x40, 0), - RATETAB_ENT(180, 0x80, 0), - RATETAB_ENT(240, 0x100, 0), - RATETAB_ENT(360, 0x200, 0), - RATETAB_ENT(480, 0x400, 0), - RATETAB_ENT(540, 0x800, 0), -}; - -#define iwm_a_rates (iwm_rates + 4) -#define iwm_a_rates_size 8 -#define iwm_g_rates (iwm_rates + 0) -#define iwm_g_rates_size 12 - -static struct ieee80211_channel iwm_2ghz_channels[] = { - CHAN2G(1, 2412, 0), - CHAN2G(2, 2417, 0), - CHAN2G(3, 2422, 0), - CHAN2G(4, 2427, 0), - CHAN2G(5, 2432, 0), - CHAN2G(6, 2437, 0), - CHAN2G(7, 2442, 0), - CHAN2G(8, 2447, 0), - CHAN2G(9, 2452, 0), - CHAN2G(10, 2457, 0), - CHAN2G(11, 2462, 0), - CHAN2G(12, 2467, 0), - CHAN2G(13, 2472, 0), - CHAN2G(14, 2484, 0), -}; - -static struct ieee80211_channel iwm_5ghz_a_channels[] = { - CHAN5G(34, 0), CHAN5G(36, 0), - CHAN5G(38, 0), CHAN5G(40, 0), - CHAN5G(42, 0), CHAN5G(44, 0), - CHAN5G(46, 0), CHAN5G(48, 0), - CHAN5G(52, 0), CHAN5G(56, 0), - CHAN5G(60, 0), CHAN5G(64, 0), - CHAN5G(100, 0), CHAN5G(104, 0), - CHAN5G(108, 0), CHAN5G(112, 0), - CHAN5G(116, 0), CHAN5G(120, 0), - CHAN5G(124, 0), CHAN5G(128, 0), - CHAN5G(132, 0), CHAN5G(136, 0), - CHAN5G(140, 0), CHAN5G(149, 0), - CHAN5G(153, 0), CHAN5G(157, 0), - CHAN5G(161, 0), CHAN5G(165, 0), - CHAN5G(184, 0), CHAN5G(188, 0), - CHAN5G(192, 0), CHAN5G(196, 0), - CHAN5G(200, 0), CHAN5G(204, 0), - CHAN5G(208, 0), CHAN5G(212, 0), - CHAN5G(216, 0), -}; - -static struct ieee80211_supported_band iwm_band_2ghz = { - .channels = iwm_2ghz_channels, - .n_channels = ARRAY_SIZE(iwm_2ghz_channels), - .bitrates = iwm_g_rates, - .n_bitrates = iwm_g_rates_size, -}; - -static struct ieee80211_supported_band iwm_band_5ghz = { - .channels = iwm_5ghz_a_channels, - .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels), - .bitrates = iwm_a_rates, - .n_bitrates = iwm_a_rates_size, -}; - -static int iwm_key_init(struct iwm_key *key, u8 key_index, - const u8 *mac_addr, struct key_params *params) -{ - key->hdr.key_idx = key_index; - if (!mac_addr || is_broadcast_ether_addr(mac_addr)) { - key->hdr.multicast = 1; - memset(key->hdr.mac, 0xff, ETH_ALEN); - } else { - key->hdr.multicast = 0; - memcpy(key->hdr.mac, mac_addr, ETH_ALEN); - } - - if (params) { - if (params->key_len > WLAN_MAX_KEY_LEN || - params->seq_len > IW_ENCODE_SEQ_MAX_SIZE) - return -EINVAL; - - key->cipher = params->cipher; - key->key_len = params->key_len; - key->seq_len = params->seq_len; - memcpy(key->key, params->key, key->key_len); - memcpy(key->seq, params->seq, key->seq_len); - } - - return 0; -} - -static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, bool pairwise, const u8 *mac_addr, - struct key_params *params) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - struct iwm_key *key; - int ret; - - IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr); - - if (key_index >= IWM_NUM_KEYS) - return -ENOENT; - - key = &iwm->keys[key_index]; - memset(key, 0, sizeof(struct iwm_key)); - ret = iwm_key_init(key, key_index, mac_addr, params); - if (ret < 0) { - IWM_ERR(iwm, "Invalid key_params\n"); - return ret; - } - - return iwm_set_key(iwm, 0, key); -} - -static int iwm_cfg80211_get_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, bool pairwise, const u8 *mac_addr, - void *cookie, - void (*callback)(void *cookie, - struct key_params*)) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - struct iwm_key *key; - struct key_params params; - - IWM_DBG_WEXT(iwm, DBG, "Getting key %d\n", key_index); - - if (key_index >= IWM_NUM_KEYS) - return -ENOENT; - - memset(¶ms, 0, sizeof(params)); - - key = &iwm->keys[key_index]; - params.cipher = key->cipher; - params.key_len = key->key_len; - params.seq_len = key->seq_len; - params.seq = key->seq; - params.key = key->key; - - callback(cookie, ¶ms); - - return key->key_len ? 0 : -ENOENT; -} - - -static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev, - u8 key_index, bool pairwise, const u8 *mac_addr) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - struct iwm_key *key; - - if (key_index >= IWM_NUM_KEYS) - return -ENOENT; - - key = &iwm->keys[key_index]; - if (!iwm->keys[key_index].key_len) { - IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index); - return 0; - } - - if (key_index == iwm->default_key) - iwm->default_key = -1; - - return iwm_set_key(iwm, 1, key); -} - -static int iwm_cfg80211_set_default_key(struct wiphy *wiphy, - struct net_device *ndev, - u8 key_index, bool unicast, - bool multicast) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - - IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index); - - if (key_index >= IWM_NUM_KEYS) - return -ENOENT; - - if (!iwm->keys[key_index].key_len) { - IWM_ERR(iwm, "Key %d not used\n", key_index); - return -EINVAL; - } - - iwm->default_key = key_index; - - return iwm_set_tx_key(iwm, key_index); -} - -static int iwm_cfg80211_get_station(struct wiphy *wiphy, - struct net_device *ndev, - u8 *mac, struct station_info *sinfo) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - - if (memcmp(mac, iwm->bssid, ETH_ALEN)) - return -ENOENT; - - sinfo->filled |= STATION_INFO_TX_BITRATE; - sinfo->txrate.legacy = iwm->rate * 10; - - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - sinfo->filled |= STATION_INFO_SIGNAL; - sinfo->signal = iwm->wstats.qual.level; - } - - return 0; -} - - -int iwm_cfg80211_inform_bss(struct iwm_priv *iwm) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct iwm_bss_info *bss; - struct iwm_umac_notif_bss_info *umac_bss; - struct ieee80211_mgmt *mgmt; - struct ieee80211_channel *channel; - struct ieee80211_supported_band *band; - s32 signal; - int freq; - - list_for_each_entry(bss, &iwm->bss_list, node) { - umac_bss = bss->bss; - mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); - - if (umac_bss->band == UMAC_BAND_2GHZ) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else if (umac_bss->band == UMAC_BAND_5GHZ) - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - else { - IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); - return -EINVAL; - } - - freq = ieee80211_channel_to_frequency(umac_bss->channel, - band->band); - channel = ieee80211_get_channel(wiphy, freq); - signal = umac_bss->rssi * 100; - - if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt, - le16_to_cpu(umac_bss->frame_len), - signal, GFP_KERNEL)) - return -EINVAL; - } - - return 0; -} - -static int iwm_cfg80211_change_iface(struct wiphy *wiphy, - struct net_device *ndev, - enum nl80211_iftype type, u32 *flags, - struct vif_params *params) -{ - struct wireless_dev *wdev; - struct iwm_priv *iwm; - u32 old_mode; - - wdev = ndev->ieee80211_ptr; - iwm = ndev_to_iwm(ndev); - old_mode = iwm->conf.mode; - - switch (type) { - case NL80211_IFTYPE_STATION: - iwm->conf.mode = UMAC_MODE_BSS; - break; - case NL80211_IFTYPE_ADHOC: - iwm->conf.mode = UMAC_MODE_IBSS; - break; - default: - return -EOPNOTSUPP; - } - - wdev->iftype = type; - - if ((old_mode == iwm->conf.mode) || !iwm->umac_profile) - return 0; - - iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode); - - if (iwm->umac_profile_active) - iwm_invalidate_mlme_profile(iwm); - - return 0; -} - -static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, - struct cfg80211_scan_request *request) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - int ret; - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) { - IWM_ERR(iwm, "Scan while device is not ready\n"); - return -EIO; - } - - if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) { - IWM_ERR(iwm, "Scanning already\n"); - return -EAGAIN; - } - - if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) { - IWM_ERR(iwm, "Scanning being aborted\n"); - return -EAGAIN; - } - - set_bit(IWM_STATUS_SCANNING, &iwm->status); - - ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids); - if (ret) { - clear_bit(IWM_STATUS_SCANNING, &iwm->status); - return ret; - } - - iwm->scan_request = request; - return 0; -} - -static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - if (changed & WIPHY_PARAM_RTS_THRESHOLD && - (iwm->conf.rts_threshold != wiphy->rts_threshold)) { - int ret; - - iwm->conf.rts_threshold = wiphy->rts_threshold; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_RTS_THRESHOLD, - iwm->conf.rts_threshold); - if (ret < 0) - return ret; - } - - if (changed & WIPHY_PARAM_FRAG_THRESHOLD && - (iwm->conf.frag_threshold != wiphy->frag_threshold)) { - int ret; - - iwm->conf.frag_threshold = wiphy->frag_threshold; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, - CFG_FRAG_THRESHOLD, - iwm->conf.frag_threshold); - if (ret < 0) - return ret; - } - - return 0; -} - -static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_ibss_params *params) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - struct ieee80211_channel *chan = params->channel; - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - /* UMAC doesn't support creating or joining an IBSS network - * with specified bssid. */ - if (params->bssid) - return -EOPNOTSUPP; - - iwm->channel = ieee80211_frequency_to_channel(chan->center_freq); - iwm->umac_profile->ibss.band = chan->band; - iwm->umac_profile->ibss.channel = iwm->channel; - iwm->umac_profile->ssid.ssid_len = params->ssid_len; - memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len); - - return iwm_send_mlme_profile(iwm); -} - -static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - if (iwm->umac_profile_active) - return iwm_invalidate_mlme_profile(iwm); - - return 0; -} - -static int iwm_set_auth_type(struct iwm_priv *iwm, - enum nl80211_auth_type sme_auth_type) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - switch (sme_auth_type) { - case NL80211_AUTHTYPE_AUTOMATIC: - case NL80211_AUTHTYPE_OPEN_SYSTEM: - IWM_DBG_WEXT(iwm, DBG, "OPEN auth\n"); - *auth_type = UMAC_AUTH_TYPE_OPEN; - break; - case NL80211_AUTHTYPE_SHARED_KEY: - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) { - IWM_DBG_WEXT(iwm, DBG, "WPA auth alg\n"); - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - } else { - IWM_DBG_WEXT(iwm, DBG, "WEP shared key auth alg\n"); - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } - - break; - default: - IWM_ERR(iwm, "Unsupported auth alg: 0x%x\n", sme_auth_type); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_set_wpa_version(struct iwm_priv *iwm, u32 wpa_version) -{ - IWM_DBG_WEXT(iwm, DBG, "wpa_version: %d\n", wpa_version); - - if (!wpa_version) { - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; - return 0; - } - - if (wpa_version & NL80211_WPA_VERSION_1) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WPA_ON_MSK; - - if (wpa_version & NL80211_WPA_VERSION_2) - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_RSNA_ON_MSK; - - return 0; -} - -static int iwm_set_cipher(struct iwm_priv *iwm, u32 cipher, bool ucast) -{ - u8 *profile_cipher = ucast ? &iwm->umac_profile->sec.ucast_cipher : - &iwm->umac_profile->sec.mcast_cipher; - - if (!cipher) { - *profile_cipher = UMAC_CIPHER_TYPE_NONE; - return 0; - } - - IWM_DBG_WEXT(iwm, DBG, "%ccast cipher is 0x%x\n", ucast ? 'u' : 'm', - cipher); - - switch (cipher) { - case IW_AUTH_CIPHER_NONE: - *profile_cipher = UMAC_CIPHER_TYPE_NONE; - break; - case WLAN_CIPHER_SUITE_WEP40: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_40; - break; - case WLAN_CIPHER_SUITE_WEP104: - *profile_cipher = UMAC_CIPHER_TYPE_WEP_104; - break; - case WLAN_CIPHER_SUITE_TKIP: - *profile_cipher = UMAC_CIPHER_TYPE_TKIP; - break; - case WLAN_CIPHER_SUITE_CCMP: - *profile_cipher = UMAC_CIPHER_TYPE_CCMP; - break; - default: - IWM_ERR(iwm, "Unsupported cipher: 0x%x\n", cipher); - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_set_key_mgt(struct iwm_priv *iwm, u32 key_mgt) -{ - u8 *auth_type = &iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "key_mgt: 0x%x\n", key_mgt); - - if (key_mgt == WLAN_AKM_SUITE_8021X) - *auth_type = UMAC_AUTH_TYPE_8021X; - else if (key_mgt == WLAN_AKM_SUITE_PSK) { - if (iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) - *auth_type = UMAC_AUTH_TYPE_RSNA_PSK; - else - *auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - } else { - IWM_ERR(iwm, "Invalid key mgt: 0x%x\n", key_mgt); - return -EINVAL; - } - - return 0; -} - - -static int iwm_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, - struct cfg80211_connect_params *sme) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - struct ieee80211_channel *chan = sme->channel; - struct key_params key_param; - int ret; - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return -EIO; - - if (!sme->ssid) - return -EINVAL; - - if (iwm->umac_profile_active) { - ret = iwm_invalidate_mlme_profile(iwm); - if (ret) { - IWM_ERR(iwm, "Couldn't invalidate profile\n"); - return ret; - } - } - - if (chan) - iwm->channel = - ieee80211_frequency_to_channel(chan->center_freq); - - iwm->umac_profile->ssid.ssid_len = sme->ssid_len; - memcpy(iwm->umac_profile->ssid.ssid, sme->ssid, sme->ssid_len); - - if (sme->bssid) { - IWM_DBG_WEXT(iwm, DBG, "BSSID: %pM\n", sme->bssid); - memcpy(&iwm->umac_profile->bssid[0], sme->bssid, ETH_ALEN); - iwm->umac_profile->bss_num = 1; - } else { - memset(&iwm->umac_profile->bssid[0], 0, ETH_ALEN); - iwm->umac_profile->bss_num = 0; - } - - ret = iwm_set_wpa_version(iwm, sme->crypto.wpa_versions); - if (ret < 0) - return ret; - - ret = iwm_set_auth_type(iwm, sme->auth_type); - if (ret < 0) - return ret; - - if (sme->crypto.n_ciphers_pairwise) { - ret = iwm_set_cipher(iwm, sme->crypto.ciphers_pairwise[0], - true); - if (ret < 0) - return ret; - } - - ret = iwm_set_cipher(iwm, sme->crypto.cipher_group, false); - if (ret < 0) - return ret; - - if (sme->crypto.n_akm_suites) { - ret = iwm_set_key_mgt(iwm, sme->crypto.akm_suites[0]); - if (ret < 0) - return ret; - } - - /* - * We save the WEP key in case we want to do shared authentication. - * We have to do it so because UMAC will assert whenever it gets a - * key before a profile. - */ - if (sme->key) { - key_param.key = kmemdup(sme->key, sme->key_len, GFP_KERNEL); - if (key_param.key == NULL) - return -ENOMEM; - key_param.key_len = sme->key_len; - key_param.seq_len = 0; - key_param.cipher = sme->crypto.ciphers_pairwise[0]; - - ret = iwm_key_init(&iwm->keys[sme->key_idx], sme->key_idx, - NULL, &key_param); - kfree(key_param.key); - if (ret < 0) { - IWM_ERR(iwm, "Invalid key_params\n"); - return ret; - } - - iwm->default_key = sme->key_idx; - } - - /* WPA and open AUTH type from wpa_s means WPS (a.k.a. WSC) */ - if ((iwm->umac_profile->sec.flags & - (UMAC_SEC_FLG_WPA_ON_MSK | UMAC_SEC_FLG_RSNA_ON_MSK)) && - iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN) { - iwm->umac_profile->sec.flags = UMAC_SEC_FLG_WSC_ON_MSK; - } - - ret = iwm_send_mlme_profile(iwm); - - if (iwm->umac_profile->sec.auth_type != UMAC_AUTH_TYPE_LEGACY_PSK || - sme->key == NULL) - return ret; - - /* - * We want to do shared auth. - * We need to actually set the key we previously cached, - * and then tell the UMAC it's the default one. - * That will trigger the auth+assoc UMAC machinery, and again, - * this must be done after setting the profile. - */ - ret = iwm_set_key(iwm, 0, &iwm->keys[sme->key_idx]); - if (ret < 0) - return ret; - - return iwm_set_tx_key(iwm, iwm->default_key); -} - -static int iwm_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *dev, - u16 reason_code) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - IWM_DBG_WEXT(iwm, DBG, "Active: %d\n", iwm->umac_profile_active); - - if (iwm->umac_profile_active) - iwm_invalidate_mlme_profile(iwm); - - return 0; -} - -static int iwm_cfg80211_set_txpower(struct wiphy *wiphy, - enum nl80211_tx_power_setting type, int mbm) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - int ret; - - switch (type) { - case NL80211_TX_POWER_AUTOMATIC: - return 0; - case NL80211_TX_POWER_FIXED: - if (mbm < 0 || (mbm % 100)) - return -EOPNOTSUPP; - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_TX_PWR_LIMIT_USR, - MBM_TO_DBM(mbm) * 2); - if (ret < 0) - return ret; - - return iwm_tx_power_trigger(iwm); - default: - IWM_ERR(iwm, "Unsupported power type: %d\n", type); - return -EOPNOTSUPP; - } - - return 0; -} - -static int iwm_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - *dbm = iwm->txpower >> 1; - - return 0; -} - -static int iwm_cfg80211_set_power_mgmt(struct wiphy *wiphy, - struct net_device *dev, - bool enabled, int timeout) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - u32 power_index; - - if (enabled) - power_index = IWM_POWER_INDEX_DEFAULT; - else - power_index = IWM_POWER_INDEX_MIN; - - if (power_index == iwm->conf.power_index) - return 0; - - iwm->conf.power_index = power_index; - - return iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_POWER_INDEX, iwm->conf.power_index); -} - -static int iwm_cfg80211_set_pmksa(struct wiphy *wiphy, - struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_ADD); -} - -static int iwm_cfg80211_del_pmksa(struct wiphy *wiphy, - struct net_device *netdev, - struct cfg80211_pmksa *pmksa) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - - return iwm_send_pmkid_update(iwm, pmksa, IWM_CMD_PMKID_DEL); -} - -static int iwm_cfg80211_flush_pmksa(struct wiphy *wiphy, - struct net_device *netdev) -{ - struct iwm_priv *iwm = wiphy_to_iwm(wiphy); - struct cfg80211_pmksa pmksa; - - memset(&pmksa, 0, sizeof(struct cfg80211_pmksa)); - - return iwm_send_pmkid_update(iwm, &pmksa, IWM_CMD_PMKID_FLUSH); -} - - -static struct cfg80211_ops iwm_cfg80211_ops = { - .change_virtual_intf = iwm_cfg80211_change_iface, - .add_key = iwm_cfg80211_add_key, - .get_key = iwm_cfg80211_get_key, - .del_key = iwm_cfg80211_del_key, - .set_default_key = iwm_cfg80211_set_default_key, - .get_station = iwm_cfg80211_get_station, - .scan = iwm_cfg80211_scan, - .set_wiphy_params = iwm_cfg80211_set_wiphy_params, - .connect = iwm_cfg80211_connect, - .disconnect = iwm_cfg80211_disconnect, - .join_ibss = iwm_cfg80211_join_ibss, - .leave_ibss = iwm_cfg80211_leave_ibss, - .set_tx_power = iwm_cfg80211_set_txpower, - .get_tx_power = iwm_cfg80211_get_txpower, - .set_power_mgmt = iwm_cfg80211_set_power_mgmt, - .set_pmksa = iwm_cfg80211_set_pmksa, - .del_pmksa = iwm_cfg80211_del_pmksa, - .flush_pmksa = iwm_cfg80211_flush_pmksa, -}; - -static const u32 cipher_suites[] = { - WLAN_CIPHER_SUITE_WEP40, - WLAN_CIPHER_SUITE_WEP104, - WLAN_CIPHER_SUITE_TKIP, - WLAN_CIPHER_SUITE_CCMP, -}; - -struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev) -{ - int ret = 0; - struct wireless_dev *wdev; - - /* - * We're trying to have the following memory - * layout: - * - * +-------------------------+ - * | struct wiphy | - * +-------------------------+ - * | struct iwm_priv | - * +-------------------------+ - * | bus private data | - * | (e.g. iwm_priv_sdio) | - * +-------------------------+ - * - */ - - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) { - dev_err(dev, "Couldn't allocate wireless device\n"); - return ERR_PTR(-ENOMEM); - } - - wdev->wiphy = wiphy_new(&iwm_cfg80211_ops, - sizeof(struct iwm_priv) + sizeof_bus); - if (!wdev->wiphy) { - dev_err(dev, "Couldn't allocate wiphy device\n"); - ret = -ENOMEM; - goto out_err_new; - } - - set_wiphy_dev(wdev->wiphy, dev); - wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX; - wdev->wiphy->max_num_pmkids = UMAC_MAX_NUM_PMKIDS; - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz; - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz; - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - - wdev->wiphy->cipher_suites = cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites); - - ret = wiphy_register(wdev->wiphy); - if (ret < 0) { - dev_err(dev, "Couldn't register wiphy device\n"); - goto out_err_register; - } - - return wdev; - - out_err_register: - wiphy_free(wdev->wiphy); - - out_err_new: - kfree(wdev); - - return ERR_PTR(ret); -} - -void iwm_wdev_free(struct iwm_priv *iwm) -{ - struct wireless_dev *wdev = iwm_to_wdev(iwm); - - if (!wdev) - return; - - wiphy_unregister(wdev->wiphy); - wiphy_free(wdev->wiphy); - kfree(wdev); -} diff --git a/drivers/net/wireless/iwmc3200wifi/cfg80211.h b/drivers/net/wireless/iwmc3200wifi/cfg80211.h deleted file mode 100644 index 56a34145acbf..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/cfg80211.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IWM_CFG80211_H__ -#define __IWM_CFG80211_H__ - -int iwm_cfg80211_inform_bss(struct iwm_priv *iwm); -struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev); -void iwm_wdev_free(struct iwm_priv *iwm); - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/commands.c b/drivers/net/wireless/iwmc3200wifi/commands.c deleted file mode 100644 index bd75078c454b..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/commands.c +++ /dev/null @@ -1,1002 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#include <linux/kernel.h> -#include <linux/wireless.h> -#include <linux/etherdevice.h> -#include <linux/ieee80211.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/moduleparam.h> - -#include "iwm.h" -#include "bus.h" -#include "hal.h" -#include "umac.h" -#include "commands.h" -#include "debug.h" - -static int iwm_send_lmac_ptrough_cmd(struct iwm_priv *iwm, - u8 lmac_cmd_id, - const void *lmac_payload, - u16 lmac_payload_size, - u8 resp) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_LMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_lmac_cmd lmac_cmd; - - lmac_cmd.id = lmac_cmd_id; - - umac_cmd.id = UMAC_CMD_OPCODE_WIFI_PASS_THROUGH; - umac_cmd.resp = resp; - - return iwm_hal_send_host_cmd(iwm, &udma_cmd, &umac_cmd, &lmac_cmd, - lmac_payload, lmac_payload_size); -} - -int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, - bool resp) -{ - struct iwm_umac_wifi_if *hdr = (struct iwm_umac_wifi_if *)payload; - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - int ret; - u8 oid = hdr->oid; - - if (!test_bit(IWM_STATUS_READY, &iwm->status)) { - IWM_ERR(iwm, "Interface is not ready yet"); - return -EAGAIN; - } - - umac_cmd.id = UMAC_CMD_OPCODE_WIFI_IF_WRAPPER; - umac_cmd.resp = resp; - - ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, - payload, payload_size); - - if (resp) { - ret = wait_event_interruptible_timeout(iwm->wifi_ntfy_queue, - test_and_clear_bit(oid, &iwm->wifi_ntfy[0]), - 3 * HZ); - - return ret ? 0 : -EBUSY; - } - - return ret; -} - -static int modparam_wiwi = COEX_MODE_CM; -module_param_named(wiwi, modparam_wiwi, int, 0644); -MODULE_PARM_DESC(wiwi, "Wifi-WiMAX coexistence: 1=SA, 2=XOR, 3=CM (default)"); - -static struct coex_event iwm_sta_xor_prio_tbl[COEX_EVENTS_NUM] = -{ - {4, 3, 0, COEX_UNASSOC_IDLE_FLAGS}, - {4, 3, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, - {4, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, - {4, 3, 0, COEX_CALIBRATION_FLAGS}, - {4, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, - {4, 3, 0, COEX_CONNECTION_ESTAB_FLAGS}, - {4, 3, 0, COEX_ASSOCIATED_IDLE_FLAGS}, - {4, 3, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, - {4, 3, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, - {4, 3, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, - {6, 3, 0, COEX_XOR_RF_ON_FLAGS}, - {4, 3, 0, COEX_RF_OFF_FLAGS}, - {6, 6, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, - {4, 3, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, - {4, 3, 0, COEX_RSRVD1_FLAGS}, - {4, 3, 0, COEX_RSRVD2_FLAGS} -}; - -static struct coex_event iwm_sta_cm_prio_tbl[COEX_EVENTS_NUM] = -{ - {1, 1, 0, COEX_UNASSOC_IDLE_FLAGS}, - {4, 4, 0, COEX_UNASSOC_MANUAL_SCAN_FLAGS}, - {3, 3, 0, COEX_UNASSOC_AUTO_SCAN_FLAGS}, - {6, 6, 0, COEX_CALIBRATION_FLAGS}, - {3, 3, 0, COEX_PERIODIC_CALIBRATION_FLAGS}, - {6, 5, 0, COEX_CONNECTION_ESTAB_FLAGS}, - {4, 4, 0, COEX_ASSOCIATED_IDLE_FLAGS}, - {4, 4, 0, COEX_ASSOC_MANUAL_SCAN_FLAGS}, - {4, 4, 0, COEX_ASSOC_AUTO_SCAN_FLAGS}, - {4, 4, 0, COEX_ASSOC_ACTIVE_LEVEL_FLAGS}, - {1, 1, 0, COEX_RF_ON_FLAGS}, - {1, 1, 0, COEX_RF_OFF_FLAGS}, - {7, 7, 0, COEX_STAND_ALONE_DEBUG_FLAGS}, - {5, 4, 0, COEX_IPAN_ASSOC_LEVEL_FLAGS}, - {1, 1, 0, COEX_RSRVD1_FLAGS}, - {1, 1, 0, COEX_RSRVD2_FLAGS} -}; - -int iwm_send_prio_table(struct iwm_priv *iwm) -{ - struct iwm_coex_prio_table_cmd coex_table_cmd; - u32 coex_enabled, mode_enabled; - - memset(&coex_table_cmd, 0, sizeof(struct iwm_coex_prio_table_cmd)); - - coex_table_cmd.flags = COEX_FLAGS_STA_TABLE_VALID_MSK; - - switch (modparam_wiwi) { - case COEX_MODE_XOR: - case COEX_MODE_CM: - coex_enabled = 1; - break; - default: - coex_enabled = 0; - break; - } - - switch (iwm->conf.mode) { - case UMAC_MODE_BSS: - case UMAC_MODE_IBSS: - mode_enabled = 1; - break; - default: - mode_enabled = 0; - break; - } - - if (coex_enabled && mode_enabled) { - coex_table_cmd.flags |= COEX_FLAGS_COEX_ENABLE_MSK | - COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK | - COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK; - - switch (modparam_wiwi) { - case COEX_MODE_XOR: - memcpy(coex_table_cmd.sta_prio, iwm_sta_xor_prio_tbl, - sizeof(iwm_sta_xor_prio_tbl)); - break; - case COEX_MODE_CM: - memcpy(coex_table_cmd.sta_prio, iwm_sta_cm_prio_tbl, - sizeof(iwm_sta_cm_prio_tbl)); - break; - default: - IWM_ERR(iwm, "Invalid coex_mode 0x%x\n", - modparam_wiwi); - break; - } - } else - IWM_WARN(iwm, "coexistense disabled\n"); - - return iwm_send_lmac_ptrough_cmd(iwm, COEX_PRIORITY_TABLE_CMD, - &coex_table_cmd, - sizeof(struct iwm_coex_prio_table_cmd), 0); -} - -int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) -{ - struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; - - memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); - - cal_cfg_cmd.ucode_cfg.init.enable = cpu_to_le32(calib_requested); - cal_cfg_cmd.ucode_cfg.init.start = cpu_to_le32(calib_requested); - cal_cfg_cmd.ucode_cfg.init.send_res = cpu_to_le32(calib_requested); - cal_cfg_cmd.ucode_cfg.flags = - cpu_to_le32(CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK); - - return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, - sizeof(struct iwm_lmac_cal_cfg_cmd), 1); -} - -int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested) -{ - struct iwm_lmac_cal_cfg_cmd cal_cfg_cmd; - - memset(&cal_cfg_cmd, 0, sizeof(struct iwm_lmac_cal_cfg_cmd)); - - cal_cfg_cmd.ucode_cfg.periodic.enable = cpu_to_le32(calib_requested); - cal_cfg_cmd.ucode_cfg.periodic.start = cpu_to_le32(calib_requested); - - return iwm_send_lmac_ptrough_cmd(iwm, CALIBRATION_CFG_CMD, &cal_cfg_cmd, - sizeof(struct iwm_lmac_cal_cfg_cmd), 0); -} - -int iwm_store_rxiq_calib_result(struct iwm_priv *iwm) -{ - struct iwm_calib_rxiq *rxiq; - u8 *eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); - int grplen = sizeof(struct iwm_calib_rxiq_group); - - rxiq = kzalloc(sizeof(struct iwm_calib_rxiq), GFP_KERNEL); - if (!rxiq) { - IWM_ERR(iwm, "Couldn't alloc memory for RX IQ\n"); - return -ENOMEM; - } - - eeprom_rxiq = iwm_eeprom_access(iwm, IWM_EEPROM_CALIB_RXIQ); - if (IS_ERR(eeprom_rxiq)) { - IWM_ERR(iwm, "Couldn't access EEPROM RX IQ entry\n"); - kfree(rxiq); - return PTR_ERR(eeprom_rxiq); - } - - iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].buf = (u8 *)rxiq; - iwm->calib_res[SHILOH_PHY_CALIBRATE_RX_IQ_CMD].size = sizeof(*rxiq); - - rxiq->hdr.opcode = SHILOH_PHY_CALIBRATE_RX_IQ_CMD; - rxiq->hdr.first_grp = 0; - rxiq->hdr.grp_num = 1; - rxiq->hdr.all_data_valid = 1; - - memcpy(&rxiq->group[0], eeprom_rxiq, 4 * grplen); - memcpy(&rxiq->group[4], eeprom_rxiq + 6 * grplen, grplen); - - return 0; -} - -int iwm_send_calib_results(struct iwm_priv *iwm) -{ - int i, ret = 0; - - for (i = PHY_CALIBRATE_OPCODES_NUM; i < CALIBRATION_CMD_NUM; i++) { - if (test_bit(i - PHY_CALIBRATE_OPCODES_NUM, - &iwm->calib_done_map)) { - IWM_DBG_CMD(iwm, DBG, - "Send calibration %d result\n", i); - ret |= iwm_send_lmac_ptrough_cmd(iwm, - REPLY_PHY_CALIBRATION_CMD, - iwm->calib_res[i].buf, - iwm->calib_res[i].size, 0); - - kfree(iwm->calib_res[i].buf); - iwm->calib_res[i].buf = NULL; - iwm->calib_res[i].size = 0; - } - } - - return ret; -} - -int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit) -{ - struct iwm_ct_kill_cfg_cmd cmd; - - cmd.entry_threshold = entry; - cmd.exit_threshold = exit; - - return iwm_send_lmac_ptrough_cmd(iwm, REPLY_CT_KILL_CONFIG_CMD, &cmd, - sizeof(struct iwm_ct_kill_cfg_cmd), 0); -} - -int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_reset reset; - - reset.flags = reset_flags; - - umac_cmd.id = UMAC_CMD_OPCODE_RESET; - umac_cmd.resp = resp; - - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &reset, - sizeof(struct iwm_umac_cmd_reset)); -} - -int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_set_param_fix param; - - if ((tbl != UMAC_PARAM_TBL_CFG_FIX) && - (tbl != UMAC_PARAM_TBL_FA_CFG_FIX)) - return -EINVAL; - - umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_FIX; - umac_cmd.resp = 0; - - param.tbl = cpu_to_le16(tbl); - param.key = cpu_to_le16(key); - param.value = cpu_to_le32(value); - - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ¶m, - sizeof(struct iwm_umac_cmd_set_param_fix)); -} - -int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, - void *payload, u16 payload_size) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_set_param_var *param_hdr; - u8 *param; - int ret; - - param = kzalloc(payload_size + - sizeof(struct iwm_umac_cmd_set_param_var), GFP_KERNEL); - if (!param) { - IWM_ERR(iwm, "Couldn't allocate param\n"); - return -ENOMEM; - } - - param_hdr = (struct iwm_umac_cmd_set_param_var *)param; - - umac_cmd.id = UMAC_CMD_OPCODE_SET_PARAM_VAR; - umac_cmd.resp = 0; - - param_hdr->tbl = cpu_to_le16(UMAC_PARAM_TBL_CFG_VAR); - param_hdr->key = cpu_to_le16(key); - param_hdr->len = cpu_to_le16(payload_size); - memcpy(param + sizeof(struct iwm_umac_cmd_set_param_var), - payload, payload_size); - - ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, param, - sizeof(struct iwm_umac_cmd_set_param_var) + - payload_size); - kfree(param); - - return ret; -} - -int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags) -{ - int ret; - - /* Use UMAC default values */ - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_POWER_INDEX, iwm->conf.power_index); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX, - CFG_FRAG_THRESHOLD, - iwm->conf.frag_threshold); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_RTS_THRESHOLD, - iwm->conf.rts_threshold); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_CTS_TO_SELF, iwm->conf.cts_to_self); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_WIRELESS_MODE, - iwm->conf.wireless_mode); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_COEX_MODE, modparam_wiwi); - if (ret < 0) - return ret; - - /* - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_ASSOCIATION_TIMEOUT, - iwm->conf.assoc_timeout); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_ROAM_TIMEOUT, - iwm->conf.roam_timeout); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_WIRELESS_MODE, - WIRELESS_MODE_11A | WIRELESS_MODE_11G); - if (ret < 0) - return ret; - */ - - ret = iwm_umac_set_config_var(iwm, CFG_NET_ADDR, - iwm_to_ndev(iwm)->dev_addr, ETH_ALEN); - if (ret < 0) - return ret; - - /* UMAC PM static configurations */ - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_LEGACY_RX_TIMEOUT, 0x12C); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_LEGACY_TX_TIMEOUT, 0x15E); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_CTRL_FLAGS, 0x1); - if (ret < 0) - return ret; - - ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX, - CFG_PM_KEEP_ALIVE_IN_BEACONS, 0x80); - if (ret < 0) - return ret; - - /* reset UMAC */ - ret = iwm_send_umac_reset(iwm, reset_flags, 1); - if (ret < 0) - return ret; - - ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, - WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); - return ret; - } - - return ret; -} - -int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id) -{ - struct iwm_udma_wifi_cmd udma_cmd; - struct iwm_umac_cmd umac_cmd; - struct iwm_tx_info *tx_info = skb_to_tx_info(skb); - - udma_cmd.eop = 1; /* always set eop for non-concatenated Tx */ - udma_cmd.credit_group = pool_id; - udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; - udma_cmd.lmac_offset = 0; - - umac_cmd.id = REPLY_TX; - umac_cmd.color = tx_info->color; - umac_cmd.resp = 0; - - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, - skb->data, skb->len); -} - -static int iwm_target_read(struct iwm_priv *iwm, __le32 address, - u8 *response, u32 resp_size) -{ - struct iwm_udma_nonwifi_cmd target_cmd; - struct iwm_nonwifi_cmd *cmd; - u16 seq_num; - int ret = 0; - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ; - target_cmd.addr = address; - target_cmd.op1_sz = cpu_to_le32(resp_size); - target_cmd.op2 = 0; - target_cmd.handle_by_hw = 0; - target_cmd.resp = 1; - target_cmd.eop = 1; - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't send READ command\n"); - return ret; - } - - /* When succeeding, the send_target routine returns the seq number */ - seq_num = ret; - - ret = wait_event_interruptible_timeout(iwm->nonwifi_queue, - (cmd = iwm_get_pending_nonwifi_cmd(iwm, seq_num, - UMAC_HDI_OUT_OPCODE_READ)) != NULL, - 2 * HZ); - - if (!ret) { - IWM_ERR(iwm, "Didn't receive a target READ answer\n"); - return ret; - } - - memcpy(response, cmd->buf.hdr + sizeof(struct iwm_udma_in_hdr), - resp_size); - - kfree(cmd); - - return 0; -} - -int iwm_read_mac(struct iwm_priv *iwm, u8 *mac) -{ - int ret; - u8 mac_align[ALIGN(ETH_ALEN, 8)]; - - ret = iwm_target_read(iwm, cpu_to_le32(WICO_MAC_ADDRESS_ADDR), - mac_align, sizeof(mac_align)); - if (ret) - return ret; - - if (is_valid_ether_addr(mac_align)) - memcpy(mac, mac_align, ETH_ALEN); - else { - IWM_ERR(iwm, "Invalid EEPROM MAC\n"); - memcpy(mac, iwm->conf.mac_addr, ETH_ALEN); - get_random_bytes(&mac[3], 3); - } - - return 0; -} - -static int iwm_check_profile(struct iwm_priv *iwm) -{ - if (!iwm->umac_profile_active) - return -EAGAIN; - - if (iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && - iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104 && - iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_TKIP && - iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_CCMP) { - IWM_ERR(iwm, "Wrong unicast cipher: 0x%x\n", - iwm->umac_profile->sec.ucast_cipher); - return -EAGAIN; - } - - if (iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_40 && - iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_WEP_104 && - iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_TKIP && - iwm->umac_profile->sec.mcast_cipher != UMAC_CIPHER_TYPE_CCMP) { - IWM_ERR(iwm, "Wrong multicast cipher: 0x%x\n", - iwm->umac_profile->sec.mcast_cipher); - return -EAGAIN; - } - - if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || - iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && - (iwm->umac_profile->sec.ucast_cipher != - iwm->umac_profile->sec.mcast_cipher)) { - IWM_ERR(iwm, "Unicast and multicast ciphers differ for WEP\n"); - } - - return 0; -} - -int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx) -{ - struct iwm_umac_tx_key_id tx_key_id; - int ret; - - ret = iwm_check_profile(iwm); - if (ret < 0) - return ret; - - /* UMAC only allows to set default key for WEP and auth type is - * NOT 802.1X or RSNA. */ - if ((iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_40 && - iwm->umac_profile->sec.ucast_cipher != UMAC_CIPHER_TYPE_WEP_104) || - iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_8021X || - iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_RSNA_PSK) - return 0; - - tx_key_id.hdr.oid = UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID; - tx_key_id.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_tx_key_id) - - sizeof(struct iwm_umac_wifi_if)); - - tx_key_id.key_idx = key_idx; - - return iwm_send_wifi_if_cmd(iwm, &tx_key_id, sizeof(tx_key_id), 1); -} - -int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key) -{ - int ret = 0; - u8 cmd[64], *sta_addr, *key_data, key_len; - s8 key_idx; - u16 cmd_size = 0; - struct iwm_umac_key_hdr *key_hdr = &key->hdr; - struct iwm_umac_key_wep40 *wep40 = (struct iwm_umac_key_wep40 *)cmd; - struct iwm_umac_key_wep104 *wep104 = (struct iwm_umac_key_wep104 *)cmd; - struct iwm_umac_key_tkip *tkip = (struct iwm_umac_key_tkip *)cmd; - struct iwm_umac_key_ccmp *ccmp = (struct iwm_umac_key_ccmp *)cmd; - - if (!remove) { - ret = iwm_check_profile(iwm); - if (ret < 0) - return ret; - } - - sta_addr = key->hdr.mac; - key_data = key->key; - key_len = key->key_len; - key_idx = key->hdr.key_idx; - - if (!remove) { - u8 auth_type = iwm->umac_profile->sec.auth_type; - - IWM_DBG_WEXT(iwm, DBG, "key_idx:%d\n", key_idx); - IWM_DBG_WEXT(iwm, DBG, "key_len:%d\n", key_len); - IWM_DBG_WEXT(iwm, DBG, "MAC:%pM, idx:%d, multicast:%d\n", - key_hdr->mac, key_hdr->key_idx, key_hdr->multicast); - - IWM_DBG_WEXT(iwm, DBG, "profile: mcast:0x%x, ucast:0x%x\n", - iwm->umac_profile->sec.mcast_cipher, - iwm->umac_profile->sec.ucast_cipher); - IWM_DBG_WEXT(iwm, DBG, "profile: auth_type:0x%x, flags:0x%x\n", - iwm->umac_profile->sec.auth_type, - iwm->umac_profile->sec.flags); - - switch (key->cipher) { - case WLAN_CIPHER_SUITE_WEP40: - wep40->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP40_KEY; - wep40->hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_key_wep40) - - sizeof(struct iwm_umac_wifi_if)); - - memcpy(&wep40->key_hdr, key_hdr, - sizeof(struct iwm_umac_key_hdr)); - memcpy(wep40->key, key_data, key_len); - wep40->static_key = - !!((auth_type != UMAC_AUTH_TYPE_8021X) && - (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); - - cmd_size = sizeof(struct iwm_umac_key_wep40); - break; - - case WLAN_CIPHER_SUITE_WEP104: - wep104->hdr.oid = UMAC_WIFI_IF_CMD_ADD_WEP104_KEY; - wep104->hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_key_wep104) - - sizeof(struct iwm_umac_wifi_if)); - - memcpy(&wep104->key_hdr, key_hdr, - sizeof(struct iwm_umac_key_hdr)); - memcpy(wep104->key, key_data, key_len); - wep104->static_key = - !!((auth_type != UMAC_AUTH_TYPE_8021X) && - (auth_type != UMAC_AUTH_TYPE_RSNA_PSK)); - - cmd_size = sizeof(struct iwm_umac_key_wep104); - break; - - case WLAN_CIPHER_SUITE_CCMP: - key_hdr->key_idx++; - ccmp->hdr.oid = UMAC_WIFI_IF_CMD_ADD_CCMP_KEY; - ccmp->hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_key_ccmp) - - sizeof(struct iwm_umac_wifi_if)); - - memcpy(&ccmp->key_hdr, key_hdr, - sizeof(struct iwm_umac_key_hdr)); - - memcpy(ccmp->key, key_data, key_len); - - if (key->seq_len) - memcpy(ccmp->iv_count, key->seq, key->seq_len); - - cmd_size = sizeof(struct iwm_umac_key_ccmp); - break; - - case WLAN_CIPHER_SUITE_TKIP: - key_hdr->key_idx++; - tkip->hdr.oid = UMAC_WIFI_IF_CMD_ADD_TKIP_KEY; - tkip->hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_key_tkip) - - sizeof(struct iwm_umac_wifi_if)); - - memcpy(&tkip->key_hdr, key_hdr, - sizeof(struct iwm_umac_key_hdr)); - - memcpy(tkip->tkip_key, key_data, IWM_TKIP_KEY_SIZE); - memcpy(tkip->mic_tx_key, key_data + IWM_TKIP_KEY_SIZE, - IWM_TKIP_MIC_SIZE); - memcpy(tkip->mic_rx_key, - key_data + IWM_TKIP_KEY_SIZE + IWM_TKIP_MIC_SIZE, - IWM_TKIP_MIC_SIZE); - - if (key->seq_len) - memcpy(ccmp->iv_count, key->seq, key->seq_len); - - cmd_size = sizeof(struct iwm_umac_key_tkip); - break; - - default: - return -ENOTSUPP; - } - - if ((key->cipher == WLAN_CIPHER_SUITE_TKIP) || - (key->cipher == WLAN_CIPHER_SUITE_CCMP)) - /* - * UGLY_UGLY_UGLY - * Copied HACK from the MWG driver. - * Without it, the key is set before the second - * EAPOL frame is sent, and the latter is thus - * encrypted. - */ - schedule_timeout_interruptible(usecs_to_jiffies(300)); - - ret = iwm_send_wifi_if_cmd(iwm, cmd, cmd_size, 1); - } else { - struct iwm_umac_key_remove key_remove; - - IWM_DBG_WEXT(iwm, ERR, "Removing key_idx:%d\n", key_idx); - - key_remove.hdr.oid = UMAC_WIFI_IF_CMD_REMOVE_KEY; - key_remove.hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_key_remove) - - sizeof(struct iwm_umac_wifi_if)); - memcpy(&key_remove.key_hdr, key_hdr, - sizeof(struct iwm_umac_key_hdr)); - - ret = iwm_send_wifi_if_cmd(iwm, &key_remove, - sizeof(struct iwm_umac_key_remove), - 1); - if (ret) - return ret; - - iwm->keys[key_idx].key_len = 0; - } - - return ret; -} - - -int iwm_send_mlme_profile(struct iwm_priv *iwm) -{ - int ret; - struct iwm_umac_profile profile; - - memcpy(&profile, iwm->umac_profile, sizeof(profile)); - - profile.hdr.oid = UMAC_WIFI_IF_CMD_SET_PROFILE; - profile.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_profile) - - sizeof(struct iwm_umac_wifi_if)); - - ret = iwm_send_wifi_if_cmd(iwm, &profile, sizeof(profile), 1); - if (ret) { - IWM_ERR(iwm, "Send profile command failed\n"); - return ret; - } - - set_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); - return 0; -} - -int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm) -{ - struct iwm_umac_invalidate_profile invalid; - - invalid.hdr.oid = UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE; - invalid.hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_invalidate_profile) - - sizeof(struct iwm_umac_wifi_if)); - - invalid.reason = WLAN_REASON_UNSPECIFIED; - - return iwm_send_wifi_if_cmd(iwm, &invalid, sizeof(invalid), 1); -} - -int iwm_invalidate_mlme_profile(struct iwm_priv *iwm) -{ - int ret; - - ret = __iwm_invalidate_mlme_profile(iwm); - if (ret) - return ret; - - ret = wait_event_interruptible_timeout(iwm->mlme_queue, - (iwm->umac_profile_active == 0), 5 * HZ); - - return ret ? 0 : -EBUSY; -} - -int iwm_tx_power_trigger(struct iwm_priv *iwm) -{ - struct iwm_umac_pwr_trigger pwr_trigger; - - pwr_trigger.hdr.oid = UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER; - pwr_trigger.hdr.buf_size = - cpu_to_le16(sizeof(struct iwm_umac_pwr_trigger) - - sizeof(struct iwm_umac_wifi_if)); - - - return iwm_send_wifi_if_cmd(iwm, &pwr_trigger, sizeof(pwr_trigger), 1); -} - -int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_stats_req stats_req; - - stats_req.flags = cpu_to_le32(flags); - - umac_cmd.id = UMAC_CMD_OPCODE_STATISTIC_REQUEST; - umac_cmd.resp = 0; - - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stats_req, - sizeof(struct iwm_umac_cmd_stats_req)); -} - -int iwm_send_umac_channel_list(struct iwm_priv *iwm) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_get_channel_list *ch_list; - int size = sizeof(struct iwm_umac_cmd_get_channel_list) + - sizeof(struct iwm_umac_channel_info) * 4; - int ret; - - ch_list = kzalloc(size, GFP_KERNEL); - if (!ch_list) { - IWM_ERR(iwm, "Couldn't allocate channel list cmd\n"); - return -ENOMEM; - } - - ch_list->ch[0].band = UMAC_BAND_2GHZ; - ch_list->ch[0].type = UMAC_CHANNEL_WIDTH_20MHZ; - ch_list->ch[0].flags = UMAC_CHANNEL_FLAG_VALID; - - ch_list->ch[1].band = UMAC_BAND_5GHZ; - ch_list->ch[1].type = UMAC_CHANNEL_WIDTH_20MHZ; - ch_list->ch[1].flags = UMAC_CHANNEL_FLAG_VALID; - - ch_list->ch[2].band = UMAC_BAND_2GHZ; - ch_list->ch[2].type = UMAC_CHANNEL_WIDTH_20MHZ; - ch_list->ch[2].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; - - ch_list->ch[3].band = UMAC_BAND_5GHZ; - ch_list->ch[3].type = UMAC_CHANNEL_WIDTH_20MHZ; - ch_list->ch[3].flags = UMAC_CHANNEL_FLAG_VALID | UMAC_CHANNEL_FLAG_IBSS; - - ch_list->count = cpu_to_le16(4); - - umac_cmd.id = UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST; - umac_cmd.resp = 1; - - ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, ch_list, size); - - kfree(ch_list); - - return ret; -} - -int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, - int ssid_num) -{ - struct iwm_umac_cmd_scan_request req; - int i, ret; - - memset(&req, 0, sizeof(struct iwm_umac_cmd_scan_request)); - - req.hdr.oid = UMAC_WIFI_IF_CMD_SCAN_REQUEST; - req.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_cmd_scan_request) - - sizeof(struct iwm_umac_wifi_if)); - req.type = UMAC_WIFI_IF_SCAN_TYPE_USER; - req.timeout = 2; - req.seq_num = iwm->scan_id; - req.ssid_num = min(ssid_num, UMAC_WIFI_IF_PROBE_OPTION_MAX); - - for (i = 0; i < req.ssid_num; i++) { - memcpy(req.ssids[i].ssid, ssids[i].ssid, ssids[i].ssid_len); - req.ssids[i].ssid_len = ssids[i].ssid_len; - } - - ret = iwm_send_wifi_if_cmd(iwm, &req, sizeof(req), 0); - if (ret) { - IWM_ERR(iwm, "Couldn't send scan request\n"); - return ret; - } - - iwm->scan_id = (iwm->scan_id + 1) % IWM_SCAN_ID_MAX; - - return 0; -} - -int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len) -{ - struct cfg80211_ssid one_ssid; - - if (test_and_set_bit(IWM_STATUS_SCANNING, &iwm->status)) - return 0; - - one_ssid.ssid_len = min(ssid_len, IEEE80211_MAX_SSID_LEN); - memcpy(&one_ssid.ssid, ssid, one_ssid.ssid_len); - - return iwm_scan_ssids(iwm, &one_ssid, 1); -} - -int iwm_target_reset(struct iwm_priv *iwm) -{ - struct iwm_udma_nonwifi_cmd target_cmd; - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_REBOOT; - target_cmd.addr = 0; - target_cmd.op1_sz = 0; - target_cmd.op2 = 0; - target_cmd.handle_by_hw = 0; - target_cmd.resp = 0; - target_cmd.eop = 1; - - return iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); -} - -int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, - struct iwm_umac_notif_stop_resume_tx *ntf) -{ - struct iwm_udma_wifi_cmd udma_cmd = UDMA_UMAC_INIT; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_stop_resume_tx stp_res_cmd; - struct iwm_sta_info *sta_info; - u8 sta_id = STA_ID_N_COLOR_ID(ntf->sta_id); - int i; - - sta_info = &iwm->sta_table[sta_id]; - if (!sta_info->valid) { - IWM_ERR(iwm, "Invalid STA: %d\n", sta_id); - return -EINVAL; - } - - umac_cmd.id = UMAC_CMD_OPCODE_STOP_RESUME_STA_TX; - umac_cmd.resp = 0; - - stp_res_cmd.flags = ntf->flags; - stp_res_cmd.sta_id = ntf->sta_id; - stp_res_cmd.stop_resume_tid_msk = ntf->stop_resume_tid_msk; - for (i = 0; i < IWM_UMAC_TID_NR; i++) - stp_res_cmd.last_seq_num[i] = - sta_info->tid_info[i].last_seq_num; - - return iwm_hal_send_umac_cmd(iwm, &udma_cmd, &umac_cmd, &stp_res_cmd, - sizeof(struct iwm_umac_cmd_stop_resume_tx)); - -} - -int iwm_send_pmkid_update(struct iwm_priv *iwm, - struct cfg80211_pmksa *pmksa, u32 command) -{ - struct iwm_umac_pmkid_update update; - int ret; - - memset(&update, 0, sizeof(struct iwm_umac_pmkid_update)); - - update.hdr.oid = UMAC_WIFI_IF_CMD_PMKID_UPDATE; - update.hdr.buf_size = cpu_to_le16(sizeof(struct iwm_umac_pmkid_update) - - sizeof(struct iwm_umac_wifi_if)); - - update.command = cpu_to_le32(command); - if (pmksa->bssid) - memcpy(&update.bssid, pmksa->bssid, ETH_ALEN); - if (pmksa->pmkid) - memcpy(&update.pmkid, pmksa->pmkid, WLAN_PMKID_LEN); - - ret = iwm_send_wifi_if_cmd(iwm, &update, - sizeof(struct iwm_umac_pmkid_update), 0); - if (ret) { - IWM_ERR(iwm, "PMKID update command failed\n"); - return ret; - } - - return 0; -} diff --git a/drivers/net/wireless/iwmc3200wifi/commands.h b/drivers/net/wireless/iwmc3200wifi/commands.h deleted file mode 100644 index 6421689f5e8e..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/commands.h +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_COMMANDS_H__ -#define __IWM_COMMANDS_H__ - -#include <linux/ieee80211.h> - -#define IWM_BARKER_REBOOT_NOTIFICATION 0xF -#define IWM_ACK_BARKER_NOTIFICATION 0x10 - -/* UMAC commands */ -#define UMAC_RST_CTRL_FLG_LARC_CLK_EN 0x0001 -#define UMAC_RST_CTRL_FLG_LARC_RESET 0x0002 -#define UMAC_RST_CTRL_FLG_FUNC_RESET 0x0004 -#define UMAC_RST_CTRL_FLG_DEV_RESET 0x0008 -#define UMAC_RST_CTRL_FLG_WIFI_CORE_EN 0x0010 -#define UMAC_RST_CTRL_FLG_WIFI_LINK_EN 0x0040 -#define UMAC_RST_CTRL_FLG_WIFI_MLME_EN 0x0080 -#define UMAC_RST_CTRL_FLG_NVM_RELOAD 0x0100 - -struct iwm_umac_cmd_reset { - __le32 flags; -} __packed; - -#define UMAC_PARAM_TBL_ORD_FIX 0x0 -#define UMAC_PARAM_TBL_ORD_VAR 0x1 -#define UMAC_PARAM_TBL_CFG_FIX 0x2 -#define UMAC_PARAM_TBL_CFG_VAR 0x3 -#define UMAC_PARAM_TBL_BSS_TRK 0x4 -#define UMAC_PARAM_TBL_FA_CFG_FIX 0x5 -#define UMAC_PARAM_TBL_STA 0x6 -#define UMAC_PARAM_TBL_CHN 0x7 -#define UMAC_PARAM_TBL_STATISTICS 0x8 - -/* fast access table */ -enum { - CFG_FRAG_THRESHOLD = 0, - CFG_FRAME_RETRY_LIMIT, - CFG_OS_QUEUE_UTIL_TH, - CFG_RX_FILTER, - /* <-- LAST --> */ - FAST_ACCESS_CFG_TBL_FIX_LAST -}; - -/* fixed size table */ -enum { - CFG_POWER_INDEX = 0, - CFG_PM_LEGACY_RX_TIMEOUT, - CFG_PM_LEGACY_TX_TIMEOUT, - CFG_PM_CTRL_FLAGS, - CFG_PM_KEEP_ALIVE_IN_BEACONS, - CFG_BT_ON_THRESHOLD, - CFG_RTS_THRESHOLD, - CFG_CTS_TO_SELF, - CFG_COEX_MODE, - CFG_WIRELESS_MODE, - CFG_ASSOCIATION_TIMEOUT, - CFG_ROAM_TIMEOUT, - CFG_CAPABILITY_SUPPORTED_RATES, - CFG_SCAN_ALLOWED_UNASSOC_FLAGS, - CFG_SCAN_ALLOWED_MAIN_ASSOC_FLAGS, - CFG_SCAN_ALLOWED_PAN_ASSOC_FLAGS, - CFG_SCAN_INTERNAL_PERIODIC_ENABLED, - CFG_SCAN_IMM_INTERNAL_PERIODIC_SCAN_ON_INIT, - CFG_SCAN_DEFAULT_PERIODIC_FREQ_SEC, - CFG_SCAN_NUM_PASSIVE_CHAN_PER_PARTIAL_SCAN, - CFG_TLC_SUPPORTED_TX_HT_RATES, - CFG_TLC_SUPPORTED_TX_RATES, - CFG_TLC_SPATIAL_STREAM_SUPPORTED, - CFG_TLC_RETRY_PER_RATE, - CFG_TLC_RETRY_PER_HT_RATE, - CFG_TLC_FIXED_MCS, - CFG_TLC_CONTROL_FLAGS, - CFG_TLC_SR_MIN_FAIL, - CFG_TLC_SR_MIN_PASS, - CFG_TLC_HT_STAY_IN_COL_PASS_THRESH, - CFG_TLC_HT_STAY_IN_COL_FAIL_THRESH, - CFG_TLC_LEGACY_STAY_IN_COL_PASS_THRESH, - CFG_TLC_LEGACY_STAY_IN_COL_FAIL_THRESH, - CFG_TLC_HT_FLUSH_STATS_PACKETS, - CFG_TLC_LEGACY_FLUSH_STATS_PACKETS, - CFG_TLC_LEGACY_FLUSH_STATS_MS, - CFG_TLC_HT_FLUSH_STATS_MS, - CFG_TLC_STAY_IN_COL_TIME_OUT, - CFG_TLC_AGG_SHORT_LIM, - CFG_TLC_AGG_LONG_LIM, - CFG_TLC_HT_SR_NO_DECREASE, - CFG_TLC_LEGACY_SR_NO_DECREASE, - CFG_TLC_SR_FORCE_DECREASE, - CFG_TLC_SR_ALLOW_INCREASE, - CFG_TLC_AGG_SET_LONG, - CFG_TLC_AUTO_AGGREGATION, - CFG_TLC_AGG_THRESHOLD, - CFG_TLC_TID_LOAD_THRESHOLD, - CFG_TLC_BLOCK_ACK_TIMEOUT, - CFG_TLC_NO_BA_COUNTED_AS_ONE, - CFG_TLC_NUM_BA_STREAMS_ALLOWED, - CFG_TLC_NUM_BA_STREAMS_PRESENT, - CFG_TLC_RENEW_ADDBA_DELAY, - CFG_TLC_NUM_OF_MULTISEC_TO_COUN_LOAD, - CFG_TLC_IS_STABLE_IN_HT, - CFG_TLC_SR_SIC_1ST_FAIL, - CFG_TLC_SR_SIC_1ST_PASS, - CFG_TLC_SR_SIC_TOTAL_FAIL, - CFG_TLC_SR_SIC_TOTAL_PASS, - CFG_RLC_CHAIN_CTRL, - CFG_TRK_TABLE_OP_MODE, - CFG_TRK_TABLE_RSSI_THRESHOLD, - CFG_TX_PWR_TARGET, /* Used By xVT */ - CFG_TX_PWR_LIMIT_USR, - CFG_TX_PWR_LIMIT_BSS, /* 11d limit */ - CFG_TX_PWR_LIMIT_BSS_CONSTRAINT, /* 11h constraint */ - CFG_TX_PWR_MODE, - CFG_MLME_DBG_NOTIF_BLOCK, - CFG_BT_OFF_BECONS_INTERVALS, - CFG_BT_FRAG_DURATION, - CFG_ACTIVE_CHAINS, - CFG_CALIB_CTRL, - CFG_CAPABILITY_SUPPORTED_HT_RATES, - CFG_HT_MAC_PARAM_INFO, - CFG_MIMO_PS_MODE, - CFG_HT_DEFAULT_CAPABILIES_INFO, - CFG_LED_SC_RESOLUTION_FACTOR, - CFG_PTAM_ENERGY_CCK_DET_DEFAULT, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_DEFAULT, - CFG_PTAM_CORR40_4_TH_ADD_MIN_DEFAULT, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_DEFAULT, - CFG_PTAM_CORR32_4_TH_ADD_MIN_DEFAULT, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_DEFAULT, - CFG_PTAM_CORR32_1_TH_ADD_MIN_DEFAULT, - CFG_PTAM_ENERGY_CCK_DET_MIN_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MIN_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MIN_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MIN_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MIN_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MIN_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MIN_VAL, - CFG_PTAM_ENERGY_CCK_DET_MAX_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_MAX_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MAX_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_MAX_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MAX_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_MAX_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MAX_VAL, - CFG_PTAM_ENERGY_CCK_DET_STEP_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_MRC_STEP_VAL, - CFG_PTAM_CORR40_4_TH_ADD_MIN_STEP_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_MRC_STEP_VAL, - CFG_PTAM_CORR32_4_TH_ADD_MIN_STEP_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_MRC_STEP_VAL, - CFG_PTAM_CORR32_1_TH_ADD_MIN_STEP_VAL, - CFG_PTAM_LINK_SENS_FA_OFDM_MAX, - CFG_PTAM_LINK_SENS_FA_OFDM_MIN, - CFG_PTAM_LINK_SENS_FA_CCK_MAX, - CFG_PTAM_LINK_SENS_FA_CCK_MIN, - CFG_PTAM_LINK_SENS_NRG_DIFF, - CFG_PTAM_LINK_SENS_NRG_MARGIN, - CFG_PTAM_LINK_SENS_MAX_NUMBER_OF_TIMES_IN_CCK_NO_FA, - CFG_PTAM_LINK_SENS_AUTO_CORR_MAX_TH_CCK, - CFG_AGG_MGG_TID_LOAD_ADDBA_THRESHOLD, - CFG_AGG_MGG_TID_LOAD_DELBA_THRESHOLD, - CFG_AGG_MGG_ADDBA_BUF_SIZE, - CFG_AGG_MGG_ADDBA_INACTIVE_TIMEOUT, - CFG_AGG_MGG_ADDBA_DEBUG_FLAGS, - CFG_SCAN_PERIODIC_RSSI_HIGH_THRESHOLD, - CFG_SCAN_PERIODIC_COEF_RSSI_HIGH, - CFG_11D_ENABLED, - CFG_11H_FEATURE_FLAGS, - - /* <-- LAST --> */ - CFG_TBL_FIX_LAST -}; - -/* variable size table */ -enum { - CFG_NET_ADDR = 0, - CFG_LED_PATTERN_TABLE, - - /* <-- LAST --> */ - CFG_TBL_VAR_LAST -}; - -struct iwm_umac_cmd_set_param_fix { - __le16 tbl; - __le16 key; - __le32 value; -} __packed; - -struct iwm_umac_cmd_set_param_var { - __le16 tbl; - __le16 key; - __le16 len; - __le16 reserved; -} __packed; - -struct iwm_umac_cmd_get_param { - __le16 tbl; - __le16 key; -} __packed; - -struct iwm_umac_cmd_get_param_resp { - __le16 tbl; - __le16 key; - __le16 len; - __le16 reserved; -} __packed; - -struct iwm_umac_cmd_eeprom_proxy_hdr { - __le32 type; - __le32 offset; - __le32 len; -} __packed; - -struct iwm_umac_cmd_eeprom_proxy { - struct iwm_umac_cmd_eeprom_proxy_hdr hdr; - u8 buf[0]; -} __packed; - -#define IWM_UMAC_CMD_EEPROM_TYPE_READ 0x1 -#define IWM_UMAC_CMD_EEPROM_TYPE_WRITE 0x2 - -#define UMAC_CHANNEL_FLAG_VALID BIT(0) -#define UMAC_CHANNEL_FLAG_IBSS BIT(1) -#define UMAC_CHANNEL_FLAG_ACTIVE BIT(3) -#define UMAC_CHANNEL_FLAG_RADAR BIT(4) -#define UMAC_CHANNEL_FLAG_DFS BIT(7) - -struct iwm_umac_channel_info { - u8 band; - u8 type; - u8 reserved; - u8 flags; - __le32 channels_mask; -} __packed; - -struct iwm_umac_cmd_get_channel_list { - __le16 count; - __le16 reserved; - struct iwm_umac_channel_info ch[0]; -} __packed; - - -/* UMAC WiFi interface commands */ - -/* Coexistence mode */ -#define COEX_MODE_SA 0x1 -#define COEX_MODE_XOR 0x2 -#define COEX_MODE_CM 0x3 -#define COEX_MODE_MAX 0x4 - -/* Wireless mode */ -#define WIRELESS_MODE_11A 0x1 -#define WIRELESS_MODE_11G 0x2 -#define WIRELESS_MODE_11N 0x4 - -#define UMAC_PROFILE_EX_IE_REQUIRED 0x1 -#define UMAC_PROFILE_QOS_ALLOWED 0x2 - -/* Scanning */ -#define UMAC_WIFI_IF_PROBE_OPTION_MAX 10 - -#define UMAC_WIFI_IF_SCAN_TYPE_USER 0x0 -#define UMAC_WIFI_IF_SCAN_TYPE_UMAC_RESERVED 0x1 -#define UMAC_WIFI_IF_SCAN_TYPE_HOST_PERIODIC 0x2 -#define UMAC_WIFI_IF_SCAN_TYPE_MAX 0x3 - -struct iwm_umac_ssid { - u8 ssid_len; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - u8 reserved[3]; -} __packed; - -struct iwm_umac_cmd_scan_request { - struct iwm_umac_wifi_if hdr; - __le32 type; /* UMAC_WIFI_IF_SCAN_TYPE_* */ - u8 ssid_num; - u8 seq_num; - u8 timeout; /* In seconds */ - u8 reserved; - struct iwm_umac_ssid ssids[UMAC_WIFI_IF_PROBE_OPTION_MAX]; -} __packed; - -#define UMAC_CIPHER_TYPE_NONE 0xFF -#define UMAC_CIPHER_TYPE_USE_GROUPCAST 0x00 -#define UMAC_CIPHER_TYPE_WEP_40 0x01 -#define UMAC_CIPHER_TYPE_WEP_104 0x02 -#define UMAC_CIPHER_TYPE_TKIP 0x04 -#define UMAC_CIPHER_TYPE_CCMP 0x08 - -/* Supported authentication types - bitmap */ -#define UMAC_AUTH_TYPE_OPEN 0x00 -#define UMAC_AUTH_TYPE_LEGACY_PSK 0x01 -#define UMAC_AUTH_TYPE_8021X 0x02 -#define UMAC_AUTH_TYPE_RSNA_PSK 0x04 - -/* iwm_umac_security.flag is WPA supported -- bits[0:0] */ -#define UMAC_SEC_FLG_WPA_ON_POS 0 -#define UMAC_SEC_FLG_WPA_ON_SEED 1 -#define UMAC_SEC_FLG_WPA_ON_MSK (UMAC_SEC_FLG_WPA_ON_SEED << \ - UMAC_SEC_FLG_WPA_ON_POS) - -/* iwm_umac_security.flag is WPA2 supported -- bits [1:1] */ -#define UMAC_SEC_FLG_RSNA_ON_POS 1 -#define UMAC_SEC_FLG_RSNA_ON_SEED 1 -#define UMAC_SEC_FLG_RSNA_ON_MSK (UMAC_SEC_FLG_RSNA_ON_SEED << \ - UMAC_SEC_FLG_RSNA_ON_POS) - -/* iwm_umac_security.flag is WSC mode on -- bits [2:2] */ -#define UMAC_SEC_FLG_WSC_ON_POS 2 -#define UMAC_SEC_FLG_WSC_ON_SEED 1 -#define UMAC_SEC_FLG_WSC_ON_MSK (UMAC_SEC_FLG_WSC_ON_SEED << \ - UMAC_SEC_FLG_WSC_ON_POS) - - -/* Legacy profile can use only WEP40 and WEP104 for encryption and - * OPEN or PSK for authentication */ -#define UMAC_SEC_FLG_LEGACY_PROFILE 0 - -struct iwm_umac_security { - u8 auth_type; - u8 ucast_cipher; - u8 mcast_cipher; - u8 flags; -} __packed; - -struct iwm_umac_ibss { - u8 beacon_interval; /* in millisecond */ - u8 atim; /* in millisecond */ - s8 join_only; - u8 band; - u8 channel; - u8 reserved[3]; -} __packed; - -#define UMAC_MODE_BSS 0 -#define UMAC_MODE_IBSS 1 - -#define UMAC_BSSID_MAX 4 - -struct iwm_umac_profile { - struct iwm_umac_wifi_if hdr; - __le32 mode; - struct iwm_umac_ssid ssid; - u8 bssid[UMAC_BSSID_MAX][ETH_ALEN]; - struct iwm_umac_security sec; - struct iwm_umac_ibss ibss; - __le32 channel_2ghz; - __le32 channel_5ghz; - __le16 flags; - u8 wireless_mode; - u8 bss_num; -} __packed; - -struct iwm_umac_invalidate_profile { - struct iwm_umac_wifi_if hdr; - u8 reason; - u8 reserved[3]; -} __packed; - -/* Encryption key commands */ -struct iwm_umac_key_wep40 { - struct iwm_umac_wifi_if hdr; - struct iwm_umac_key_hdr key_hdr; - u8 key[WLAN_KEY_LEN_WEP40]; - u8 static_key; - u8 reserved[2]; -} __packed; - -struct iwm_umac_key_wep104 { - struct iwm_umac_wifi_if hdr; - struct iwm_umac_key_hdr key_hdr; - u8 key[WLAN_KEY_LEN_WEP104]; - u8 static_key; - u8 reserved[2]; -} __packed; - -#define IWM_TKIP_KEY_SIZE 16 -#define IWM_TKIP_MIC_SIZE 8 -struct iwm_umac_key_tkip { - struct iwm_umac_wifi_if hdr; - struct iwm_umac_key_hdr key_hdr; - u8 iv_count[6]; - u8 reserved[2]; - u8 tkip_key[IWM_TKIP_KEY_SIZE]; - u8 mic_rx_key[IWM_TKIP_MIC_SIZE]; - u8 mic_tx_key[IWM_TKIP_MIC_SIZE]; -} __packed; - -struct iwm_umac_key_ccmp { - struct iwm_umac_wifi_if hdr; - struct iwm_umac_key_hdr key_hdr; - u8 iv_count[6]; - u8 reserved[2]; - u8 key[WLAN_KEY_LEN_CCMP]; -} __packed; - -struct iwm_umac_key_remove { - struct iwm_umac_wifi_if hdr; - struct iwm_umac_key_hdr key_hdr; -} __packed; - -struct iwm_umac_tx_key_id { - struct iwm_umac_wifi_if hdr; - u8 key_idx; - u8 reserved[3]; -} __packed; - -struct iwm_umac_pwr_trigger { - struct iwm_umac_wifi_if hdr; - __le32 reseved; -} __packed; - -struct iwm_umac_cmd_stats_req { - __le32 flags; -} __packed; - -struct iwm_umac_cmd_stop_resume_tx { - u8 flags; - u8 sta_id; - __le16 stop_resume_tid_msk; - __le16 last_seq_num[IWM_UMAC_TID_NR]; - u16 reserved; -} __packed; - -#define IWM_CMD_PMKID_ADD 1 -#define IWM_CMD_PMKID_DEL 2 -#define IWM_CMD_PMKID_FLUSH 3 - -struct iwm_umac_pmkid_update { - struct iwm_umac_wifi_if hdr; - __le32 command; - u8 bssid[ETH_ALEN]; - __le16 reserved; - u8 pmkid[WLAN_PMKID_LEN]; -} __packed; - -/* LMAC commands */ -int iwm_read_mac(struct iwm_priv *iwm, u8 *mac); -int iwm_send_prio_table(struct iwm_priv *iwm); -int iwm_send_init_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); -int iwm_send_periodic_calib_cfg(struct iwm_priv *iwm, u8 calib_requested); -int iwm_send_calib_results(struct iwm_priv *iwm); -int iwm_store_rxiq_calib_result(struct iwm_priv *iwm); -int iwm_send_ct_kill_cfg(struct iwm_priv *iwm, u8 entry, u8 exit); - -/* UMAC commands */ -int iwm_send_wifi_if_cmd(struct iwm_priv *iwm, void *payload, u16 payload_size, - bool resp); -int iwm_send_umac_reset(struct iwm_priv *iwm, __le32 reset_flags, bool resp); -int iwm_umac_set_config_fix(struct iwm_priv *iwm, u16 tbl, u16 key, u32 value); -int iwm_umac_set_config_var(struct iwm_priv *iwm, u16 key, - void *payload, u16 payload_size); -int iwm_send_umac_config(struct iwm_priv *iwm, __le32 reset_flags); -int iwm_send_mlme_profile(struct iwm_priv *iwm); -int __iwm_invalidate_mlme_profile(struct iwm_priv *iwm); -int iwm_invalidate_mlme_profile(struct iwm_priv *iwm); -int iwm_send_packet(struct iwm_priv *iwm, struct sk_buff *skb, int pool_id); -int iwm_set_tx_key(struct iwm_priv *iwm, u8 key_idx); -int iwm_set_key(struct iwm_priv *iwm, bool remove, struct iwm_key *key); -int iwm_tx_power_trigger(struct iwm_priv *iwm); -int iwm_send_umac_stats_req(struct iwm_priv *iwm, u32 flags); -int iwm_send_umac_channel_list(struct iwm_priv *iwm); -int iwm_scan_ssids(struct iwm_priv *iwm, struct cfg80211_ssid *ssids, - int ssid_num); -int iwm_scan_one_ssid(struct iwm_priv *iwm, u8 *ssid, int ssid_len); -int iwm_send_umac_stop_resume_tx(struct iwm_priv *iwm, - struct iwm_umac_notif_stop_resume_tx *ntf); -int iwm_send_pmkid_update(struct iwm_priv *iwm, - struct cfg80211_pmksa *pmksa, u32 command); - -/* UDMA commands */ -int iwm_target_reset(struct iwm_priv *iwm); -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debug.h b/drivers/net/wireless/iwmc3200wifi/debug.h deleted file mode 100644 index a0c13a49ab3c..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/debug.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#ifndef __IWM_DEBUG_H__ -#define __IWM_DEBUG_H__ - -#define IWM_ERR(p, f, a...) dev_err(iwm_to_dev(p), f, ## a) -#define IWM_WARN(p, f, a...) dev_warn(iwm_to_dev(p), f, ## a) -#define IWM_INFO(p, f, a...) dev_info(iwm_to_dev(p), f, ## a) -#define IWM_CRIT(p, f, a...) dev_crit(iwm_to_dev(p), f, ## a) - -#ifdef CONFIG_IWM_DEBUG - -#define IWM_DEBUG_MODULE(i, level, module, f, a...) \ -do { \ - if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ - dev_printk(KERN_INFO, (iwm_to_dev(i)), \ - "%s " f, __func__ , ## a); \ -} while (0) - -#define IWM_HEXDUMP(i, level, module, pref, buf, len) \ -do { \ - if (unlikely(i->dbg.dbg_module[IWM_DM_##module] >= (IWM_DL_##level)))\ - print_hex_dump(KERN_INFO, pref, DUMP_PREFIX_OFFSET, \ - 16, 1, buf, len, 1); \ -} while (0) - -#else - -#define IWM_DEBUG_MODULE(i, level, module, f, a...) -#define IWM_HEXDUMP(i, level, module, pref, buf, len) - -#endif /* CONFIG_IWM_DEBUG */ - -/* Debug modules */ -enum iwm_debug_module_id { - IWM_DM_BOOT = 0, - IWM_DM_FW, - IWM_DM_SDIO, - IWM_DM_NTF, - IWM_DM_RX, - IWM_DM_TX, - IWM_DM_MLME, - IWM_DM_CMD, - IWM_DM_WEXT, - __IWM_DM_NR, -}; -#define IWM_DM_DEFAULT 0 - -#define IWM_DBG_BOOT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, BOOT, f, ## a) -#define IWM_DBG_FW(i, l, f, a...) IWM_DEBUG_MODULE(i, l, FW, f, ## a) -#define IWM_DBG_SDIO(i, l, f, a...) IWM_DEBUG_MODULE(i, l, SDIO, f, ## a) -#define IWM_DBG_NTF(i, l, f, a...) IWM_DEBUG_MODULE(i, l, NTF, f, ## a) -#define IWM_DBG_RX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, RX, f, ## a) -#define IWM_DBG_TX(i, l, f, a...) IWM_DEBUG_MODULE(i, l, TX, f, ## a) -#define IWM_DBG_MLME(i, l, f, a...) IWM_DEBUG_MODULE(i, l, MLME, f, ## a) -#define IWM_DBG_CMD(i, l, f, a...) IWM_DEBUG_MODULE(i, l, CMD, f, ## a) -#define IWM_DBG_WEXT(i, l, f, a...) IWM_DEBUG_MODULE(i, l, WEXT, f, ## a) - -/* Debug levels */ -enum iwm_debug_level { - IWM_DL_NONE = 0, - IWM_DL_ERR, - IWM_DL_WARN, - IWM_DL_INFO, - IWM_DL_DBG, -}; -#define IWM_DL_DEFAULT IWM_DL_ERR - -struct iwm_debugfs { - struct iwm_priv *iwm; - struct dentry *rootdir; - struct dentry *devdir; - struct dentry *dbgdir; - struct dentry *txdir; - struct dentry *rxdir; - struct dentry *busdir; - - u32 dbg_level; - struct dentry *dbg_level_dentry; - - unsigned long dbg_modules; - struct dentry *dbg_modules_dentry; - - u8 dbg_module[__IWM_DM_NR]; - struct dentry *dbg_module_dentries[__IWM_DM_NR]; - - struct dentry *txq_dentry; - struct dentry *tx_credit_dentry; - struct dentry *rx_ticket_dentry; - - struct dentry *fw_err_dentry; -}; - -#ifdef CONFIG_IWM_DEBUG -void iwm_debugfs_init(struct iwm_priv *iwm); -void iwm_debugfs_exit(struct iwm_priv *iwm); -#else -static inline void iwm_debugfs_init(struct iwm_priv *iwm) {} -static inline void iwm_debugfs_exit(struct iwm_priv *iwm) {} -#endif - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/debugfs.c b/drivers/net/wireless/iwmc3200wifi/debugfs.c deleted file mode 100644 index b6199d124bb9..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/debugfs.c +++ /dev/null @@ -1,488 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -#include <linux/slab.h> -#include <linux/kernel.h> -#include <linux/bitops.h> -#include <linux/debugfs.h> -#include <linux/export.h> - -#include "iwm.h" -#include "bus.h" -#include "rx.h" -#include "debug.h" - -static struct { - u8 id; - char *name; -} iwm_debug_module[__IWM_DM_NR] = { - {IWM_DM_BOOT, "boot"}, - {IWM_DM_FW, "fw"}, - {IWM_DM_SDIO, "sdio"}, - {IWM_DM_NTF, "ntf"}, - {IWM_DM_RX, "rx"}, - {IWM_DM_TX, "tx"}, - {IWM_DM_MLME, "mlme"}, - {IWM_DM_CMD, "cmd"}, - {IWM_DM_WEXT, "wext"}, -}; - -#define add_dbg_module(dbg, name, id, initlevel) \ -do { \ - dbg.dbg_module[id] = (initlevel); \ - dbg.dbg_module_dentries[id] = \ - debugfs_create_x8(name, 0600, \ - dbg.dbgdir, \ - &(dbg.dbg_module[id])); \ -} while (0) - -static int iwm_debugfs_u32_read(void *data, u64 *val) -{ - struct iwm_priv *iwm = data; - - *val = iwm->dbg.dbg_level; - return 0; -} - -static int iwm_debugfs_dbg_level_write(void *data, u64 val) -{ - struct iwm_priv *iwm = data; - int i; - - iwm->dbg.dbg_level = val; - - for (i = 0; i < __IWM_DM_NR; i++) - iwm->dbg.dbg_module[i] = val; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_level, - iwm_debugfs_u32_read, iwm_debugfs_dbg_level_write, - "%llu\n"); - -static int iwm_debugfs_dbg_modules_write(void *data, u64 val) -{ - struct iwm_priv *iwm = data; - int i, bit; - - iwm->dbg.dbg_modules = val; - - for (i = 0; i < __IWM_DM_NR; i++) - iwm->dbg.dbg_module[i] = 0; - - for_each_set_bit(bit, &iwm->dbg.dbg_modules, __IWM_DM_NR) - iwm->dbg.dbg_module[bit] = iwm->dbg.dbg_level; - - return 0; -} -DEFINE_SIMPLE_ATTRIBUTE(fops_iwm_dbg_modules, - iwm_debugfs_u32_read, iwm_debugfs_dbg_modules_write, - "%llu\n"); - - -static ssize_t iwm_debugfs_txq_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct iwm_priv *iwm = filp->private_data; - char *buf; - int i, buf_len = 4096; - size_t len = 0; - ssize_t ret; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - - buf = kzalloc(buf_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - for (i = 0; i < IWM_TX_QUEUES; i++) { - struct iwm_tx_queue *txq = &iwm->txq[i]; - struct sk_buff *skb; - int j; - unsigned long flags; - - spin_lock_irqsave(&txq->queue.lock, flags); - - skb = (struct sk_buff *)&txq->queue; - - len += snprintf(buf + len, buf_len - len, "TXQ #%d\n", i); - len += snprintf(buf + len, buf_len - len, "\tStopped: %d\n", - __netif_subqueue_stopped(iwm_to_ndev(iwm), - txq->id)); - len += snprintf(buf + len, buf_len - len, "\tConcat count:%d\n", - txq->concat_count); - len += snprintf(buf + len, buf_len - len, "\tQueue len: %d\n", - skb_queue_len(&txq->queue)); - for (j = 0; j < skb_queue_len(&txq->queue); j++) { - struct iwm_tx_info *tx_info; - - skb = skb->next; - tx_info = skb_to_tx_info(skb); - - len += snprintf(buf + len, buf_len - len, - "\tSKB #%d\n", j); - len += snprintf(buf + len, buf_len - len, - "\t\tsta: %d\n", tx_info->sta); - len += snprintf(buf + len, buf_len - len, - "\t\tcolor: %d\n", tx_info->color); - len += snprintf(buf + len, buf_len - len, - "\t\ttid: %d\n", tx_info->tid); - } - - spin_unlock_irqrestore(&txq->queue.lock, flags); - - spin_lock_irqsave(&txq->stopped_queue.lock, flags); - - len += snprintf(buf + len, buf_len - len, - "\tStopped Queue len: %d\n", - skb_queue_len(&txq->stopped_queue)); - for (j = 0; j < skb_queue_len(&txq->stopped_queue); j++) { - struct iwm_tx_info *tx_info; - - skb = skb->next; - tx_info = skb_to_tx_info(skb); - - len += snprintf(buf + len, buf_len - len, - "\tSKB #%d\n", j); - len += snprintf(buf + len, buf_len - len, - "\t\tsta: %d\n", tx_info->sta); - len += snprintf(buf + len, buf_len - len, - "\t\tcolor: %d\n", tx_info->color); - len += snprintf(buf + len, buf_len - len, - "\t\ttid: %d\n", tx_info->tid); - } - - spin_unlock_irqrestore(&txq->stopped_queue.lock, flags); - } - - ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); - kfree(buf); - - return ret; -} - -static ssize_t iwm_debugfs_tx_credit_read(struct file *filp, - char __user *buffer, - size_t count, loff_t *ppos) -{ - struct iwm_priv *iwm = filp->private_data; - struct iwm_tx_credit *credit = &iwm->tx_credit; - char *buf; - int i, buf_len = 4096; - size_t len = 0; - ssize_t ret; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - - buf = kzalloc(buf_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - len += snprintf(buf + len, buf_len - len, - "NR pools: %d\n", credit->pool_nr); - len += snprintf(buf + len, buf_len - len, - "pools map: 0x%lx\n", credit->full_pools_map); - - len += snprintf(buf + len, buf_len - len, "\n### POOLS ###\n"); - for (i = 0; i < IWM_MACS_OUT_GROUPS; i++) { - len += snprintf(buf + len, buf_len - len, - "pools entry #%d\n", i); - len += snprintf(buf + len, buf_len - len, - "\tid: %d\n", - credit->pools[i].id); - len += snprintf(buf + len, buf_len - len, - "\tsid: %d\n", - credit->pools[i].sid); - len += snprintf(buf + len, buf_len - len, - "\tmin_pages: %d\n", - credit->pools[i].min_pages); - len += snprintf(buf + len, buf_len - len, - "\tmax_pages: %d\n", - credit->pools[i].max_pages); - len += snprintf(buf + len, buf_len - len, - "\talloc_pages: %d\n", - credit->pools[i].alloc_pages); - len += snprintf(buf + len, buf_len - len, - "\tfreed_pages: %d\n", - credit->pools[i].total_freed_pages); - } - - len += snprintf(buf + len, buf_len - len, "\n### SPOOLS ###\n"); - for (i = 0; i < IWM_MACS_OUT_SGROUPS; i++) { - len += snprintf(buf + len, buf_len - len, - "spools entry #%d\n", i); - len += snprintf(buf + len, buf_len - len, - "\tid: %d\n", - credit->spools[i].id); - len += snprintf(buf + len, buf_len - len, - "\tmax_pages: %d\n", - credit->spools[i].max_pages); - len += snprintf(buf + len, buf_len - len, - "\talloc_pages: %d\n", - credit->spools[i].alloc_pages); - - } - - ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); - kfree(buf); - - return ret; -} - -static ssize_t iwm_debugfs_rx_ticket_read(struct file *filp, - char __user *buffer, - size_t count, loff_t *ppos) -{ - struct iwm_priv *iwm = filp->private_data; - struct iwm_rx_ticket_node *ticket; - char *buf; - int buf_len = 4096, i; - size_t len = 0; - ssize_t ret; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - - buf = kzalloc(buf_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - spin_lock(&iwm->ticket_lock); - list_for_each_entry(ticket, &iwm->rx_tickets, node) { - len += snprintf(buf + len, buf_len - len, "Ticket #%d\n", - ticket->ticket->id); - len += snprintf(buf + len, buf_len - len, "\taction: 0x%x\n", - ticket->ticket->action); - len += snprintf(buf + len, buf_len - len, "\tflags: 0x%x\n", - ticket->ticket->flags); - } - spin_unlock(&iwm->ticket_lock); - - for (i = 0; i < IWM_RX_ID_HASH; i++) { - struct iwm_rx_packet *packet; - struct list_head *pkt_list = &iwm->rx_packets[i]; - - if (!list_empty(pkt_list)) { - len += snprintf(buf + len, buf_len - len, - "Packet hash #%d\n", i); - spin_lock(&iwm->packet_lock[i]); - list_for_each_entry(packet, pkt_list, node) { - len += snprintf(buf + len, buf_len - len, - "\tPacket id: %d\n", - packet->id); - len += snprintf(buf + len, buf_len - len, - "\tPacket length: %lu\n", - packet->pkt_size); - } - spin_unlock(&iwm->packet_lock[i]); - } - } - - ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); - kfree(buf); - - return ret; -} - -static ssize_t iwm_debugfs_fw_err_read(struct file *filp, - char __user *buffer, - size_t count, loff_t *ppos) -{ - - struct iwm_priv *iwm = filp->private_data; - char buf[512]; - int buf_len = 512; - size_t len = 0; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - - if (!iwm->last_fw_err) - return -ENOMEM; - - if (iwm->last_fw_err->line_num == 0) - goto out; - - len += snprintf(buf + len, buf_len - len, "%cMAC FW ERROR:\n", - (le32_to_cpu(iwm->last_fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) - ? 'L' : 'U'); - len += snprintf(buf + len, buf_len - len, - "\tCategory: %d\n", - le32_to_cpu(iwm->last_fw_err->category)); - - len += snprintf(buf + len, buf_len - len, - "\tStatus: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->status)); - - len += snprintf(buf + len, buf_len - len, - "\tPC: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->pc)); - - len += snprintf(buf + len, buf_len - len, - "\tblink1: %d\n", - le32_to_cpu(iwm->last_fw_err->blink1)); - - len += snprintf(buf + len, buf_len - len, - "\tblink2: %d\n", - le32_to_cpu(iwm->last_fw_err->blink2)); - - len += snprintf(buf + len, buf_len - len, - "\tilink1: %d\n", - le32_to_cpu(iwm->last_fw_err->ilink1)); - - len += snprintf(buf + len, buf_len - len, - "\tilink2: %d\n", - le32_to_cpu(iwm->last_fw_err->ilink2)); - - len += snprintf(buf + len, buf_len - len, - "\tData1: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->data1)); - - len += snprintf(buf + len, buf_len - len, - "\tData2: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->data2)); - - len += snprintf(buf + len, buf_len - len, - "\tLine number: %d\n", - le32_to_cpu(iwm->last_fw_err->line_num)); - - len += snprintf(buf + len, buf_len - len, - "\tUMAC status: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->umac_status)); - - len += snprintf(buf + len, buf_len - len, - "\tLMAC status: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->lmac_status)); - - len += snprintf(buf + len, buf_len - len, - "\tSDIO status: 0x%x\n", - le32_to_cpu(iwm->last_fw_err->sdio_status)); - -out: - - return simple_read_from_buffer(buffer, len, ppos, buf, buf_len); -} - -static const struct file_operations iwm_debugfs_txq_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = iwm_debugfs_txq_read, - .llseek = default_llseek, -}; - -static const struct file_operations iwm_debugfs_tx_credit_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = iwm_debugfs_tx_credit_read, - .llseek = default_llseek, -}; - -static const struct file_operations iwm_debugfs_rx_ticket_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = iwm_debugfs_rx_ticket_read, - .llseek = default_llseek, -}; - -static const struct file_operations iwm_debugfs_fw_err_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = iwm_debugfs_fw_err_read, - .llseek = default_llseek, -}; - -void iwm_debugfs_init(struct iwm_priv *iwm) -{ - int i; - - iwm->dbg.rootdir = debugfs_create_dir(KBUILD_MODNAME, NULL); - iwm->dbg.devdir = debugfs_create_dir(wiphy_name(iwm_to_wiphy(iwm)), - iwm->dbg.rootdir); - iwm->dbg.dbgdir = debugfs_create_dir("debug", iwm->dbg.devdir); - iwm->dbg.rxdir = debugfs_create_dir("rx", iwm->dbg.devdir); - iwm->dbg.txdir = debugfs_create_dir("tx", iwm->dbg.devdir); - iwm->dbg.busdir = debugfs_create_dir("bus", iwm->dbg.devdir); - if (iwm->bus_ops->debugfs_init) - iwm->bus_ops->debugfs_init(iwm, iwm->dbg.busdir); - - iwm->dbg.dbg_level = IWM_DL_NONE; - iwm->dbg.dbg_level_dentry = - debugfs_create_file("level", 0200, iwm->dbg.dbgdir, iwm, - &fops_iwm_dbg_level); - - iwm->dbg.dbg_modules = IWM_DM_DEFAULT; - iwm->dbg.dbg_modules_dentry = - debugfs_create_file("modules", 0200, iwm->dbg.dbgdir, iwm, - &fops_iwm_dbg_modules); - - for (i = 0; i < __IWM_DM_NR; i++) - add_dbg_module(iwm->dbg, iwm_debug_module[i].name, - iwm_debug_module[i].id, IWM_DL_DEFAULT); - - iwm->dbg.txq_dentry = debugfs_create_file("queues", 0200, - iwm->dbg.txdir, iwm, - &iwm_debugfs_txq_fops); - iwm->dbg.tx_credit_dentry = debugfs_create_file("credits", 0200, - iwm->dbg.txdir, iwm, - &iwm_debugfs_tx_credit_fops); - iwm->dbg.rx_ticket_dentry = debugfs_create_file("tickets", 0200, - iwm->dbg.rxdir, iwm, - &iwm_debugfs_rx_ticket_fops); - iwm->dbg.fw_err_dentry = debugfs_create_file("last_fw_err", 0200, - iwm->dbg.dbgdir, iwm, - &iwm_debugfs_fw_err_fops); -} - -void iwm_debugfs_exit(struct iwm_priv *iwm) -{ - int i; - - for (i = 0; i < __IWM_DM_NR; i++) - debugfs_remove(iwm->dbg.dbg_module_dentries[i]); - - debugfs_remove(iwm->dbg.dbg_modules_dentry); - debugfs_remove(iwm->dbg.dbg_level_dentry); - debugfs_remove(iwm->dbg.txq_dentry); - debugfs_remove(iwm->dbg.tx_credit_dentry); - debugfs_remove(iwm->dbg.rx_ticket_dentry); - debugfs_remove(iwm->dbg.fw_err_dentry); - if (iwm->bus_ops->debugfs_exit) - iwm->bus_ops->debugfs_exit(iwm); - - debugfs_remove(iwm->dbg.busdir); - debugfs_remove(iwm->dbg.dbgdir); - debugfs_remove(iwm->dbg.txdir); - debugfs_remove(iwm->dbg.rxdir); - debugfs_remove(iwm->dbg.devdir); - debugfs_remove(iwm->dbg.rootdir); -} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.c b/drivers/net/wireless/iwmc3200wifi/eeprom.c deleted file mode 100644 index e80e776b74f7..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#include <linux/kernel.h> -#include <linux/slab.h> - -#include "iwm.h" -#include "umac.h" -#include "commands.h" -#include "eeprom.h" - -static struct iwm_eeprom_entry eeprom_map[] = { - [IWM_EEPROM_SIG] = - {"Signature", IWM_EEPROM_SIG_OFF, IWM_EEPROM_SIG_LEN}, - - [IWM_EEPROM_VERSION] = - {"Version", IWM_EEPROM_VERSION_OFF, IWM_EEPROM_VERSION_LEN}, - - [IWM_EEPROM_OEM_HW_VERSION] = - {"OEM HW version", IWM_EEPROM_OEM_HW_VERSION_OFF, - IWM_EEPROM_OEM_HW_VERSION_LEN}, - - [IWM_EEPROM_MAC_VERSION] = - {"MAC version", IWM_EEPROM_MAC_VERSION_OFF, IWM_EEPROM_MAC_VERSION_LEN}, - - [IWM_EEPROM_CARD_ID] = - {"Card ID", IWM_EEPROM_CARD_ID_OFF, IWM_EEPROM_CARD_ID_LEN}, - - [IWM_EEPROM_RADIO_CONF] = - {"Radio config", IWM_EEPROM_RADIO_CONF_OFF, IWM_EEPROM_RADIO_CONF_LEN}, - - [IWM_EEPROM_SKU_CAP] = - {"SKU capabilities", IWM_EEPROM_SKU_CAP_OFF, IWM_EEPROM_SKU_CAP_LEN}, - - [IWM_EEPROM_FAT_CHANNELS_CAP] = - {"HT channels capabilities", IWM_EEPROM_FAT_CHANNELS_CAP_OFF, - IWM_EEPROM_FAT_CHANNELS_CAP_LEN}, - - [IWM_EEPROM_CALIB_RXIQ_OFFSET] = - {"RX IQ offset", IWM_EEPROM_CALIB_RXIQ_OFF, IWM_EEPROM_INDIRECT_LEN}, - - [IWM_EEPROM_CALIB_RXIQ] = - {"Calib RX IQ", 0, IWM_EEPROM_CALIB_RXIQ_LEN}, -}; - - -static int iwm_eeprom_read(struct iwm_priv *iwm, u8 eeprom_id) -{ - int ret; - u32 entry_size, chunk_size, data_offset = 0, addr_offset = 0; - u32 addr; - struct iwm_udma_wifi_cmd udma_cmd; - struct iwm_umac_cmd umac_cmd; - struct iwm_umac_cmd_eeprom_proxy eeprom_cmd; - - if (eeprom_id > (IWM_EEPROM_LAST - 1)) - return -EINVAL; - - entry_size = eeprom_map[eeprom_id].length; - - if (eeprom_id >= IWM_EEPROM_INDIRECT_DATA) { - /* indirect data */ - u32 off_id = eeprom_id - IWM_EEPROM_INDIRECT_DATA + - IWM_EEPROM_INDIRECT_OFFSET; - - eeprom_map[eeprom_id].offset = - *(u16 *)(iwm->eeprom + eeprom_map[off_id].offset) << 1; - } - - addr = eeprom_map[eeprom_id].offset; - - udma_cmd.eop = 1; - udma_cmd.credit_group = 0x4; - udma_cmd.ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD; - udma_cmd.lmac_offset = 0; - - umac_cmd.id = UMAC_CMD_OPCODE_EEPROM_PROXY; - umac_cmd.resp = 1; - - while (entry_size > 0) { - chunk_size = min_t(u32, entry_size, IWM_MAX_EEPROM_DATA_LEN); - - eeprom_cmd.hdr.type = - cpu_to_le32(IWM_UMAC_CMD_EEPROM_TYPE_READ); - eeprom_cmd.hdr.offset = cpu_to_le32(addr + addr_offset); - eeprom_cmd.hdr.len = cpu_to_le32(chunk_size); - - ret = iwm_hal_send_umac_cmd(iwm, &udma_cmd, - &umac_cmd, &eeprom_cmd, - sizeof(struct iwm_umac_cmd_eeprom_proxy)); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't read eeprom\n"); - return ret; - } - - ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_EEPROM_PROXY, - IWM_SRC_UMAC, 2*HZ); - if (ret < 0) { - IWM_ERR(iwm, "Did not get any eeprom answer\n"); - return ret; - } - - data_offset += chunk_size; - addr_offset += chunk_size; - entry_size -= chunk_size; - } - - return 0; -} - -u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id) -{ - if (!iwm->eeprom) - return ERR_PTR(-ENODEV); - - return iwm->eeprom + eeprom_map[eeprom_id].offset; -} - -int iwm_eeprom_fat_channels(struct iwm_priv *iwm) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct ieee80211_supported_band *band; - u16 *channels, i; - - channels = (u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_FAT_CHANNELS_CAP); - if (IS_ERR(channels)) - return PTR_ERR(channels); - - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - band->ht_cap.ht_supported = true; - - for (i = 0; i < IWM_EEPROM_FAT_CHANNELS_24; i++) - if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) - band->ht_cap.ht_supported = false; - - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - band->ht_cap.ht_supported = true; - for (i = IWM_EEPROM_FAT_CHANNELS_24; i < IWM_EEPROM_FAT_CHANNELS; i++) - if (!(channels[i] & IWM_EEPROM_FAT_CHANNEL_ENABLED)) - band->ht_cap.ht_supported = false; - - return 0; -} - -u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm) -{ - u16 sku_cap; - u32 wireless_mode = 0; - - sku_cap = *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP)); - - if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_24GHZ) - wireless_mode |= WIRELESS_MODE_11G; - - if (sku_cap & IWM_EEPROM_SKU_CAP_BAND_52GHZ) - wireless_mode |= WIRELESS_MODE_11A; - - if (sku_cap & IWM_EEPROM_SKU_CAP_11N_ENABLE) - wireless_mode |= WIRELESS_MODE_11N; - - return wireless_mode; -} - - -int iwm_eeprom_init(struct iwm_priv *iwm) -{ - int i, ret = 0; - char name[32]; - - iwm->eeprom = kzalloc(IWM_EEPROM_LEN, GFP_KERNEL); - if (!iwm->eeprom) - return -ENOMEM; - - for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { - ret = iwm_eeprom_read(iwm, i); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't read eeprom entry #%d: %s\n", - i, eeprom_map[i].name); - break; - } - } - - IWM_DBG_BOOT(iwm, DBG, "EEPROM dump:\n"); - for (i = IWM_EEPROM_FIRST; i < IWM_EEPROM_LAST; i++) { - memset(name, 0, 32); - sprintf(name, "%s: ", eeprom_map[i].name); - - IWM_HEXDUMP(iwm, DBG, BOOT, name, - iwm->eeprom + eeprom_map[i].offset, - eeprom_map[i].length); - } - - return ret; -} - -void iwm_eeprom_exit(struct iwm_priv *iwm) -{ - kfree(iwm->eeprom); -} diff --git a/drivers/net/wireless/iwmc3200wifi/eeprom.h b/drivers/net/wireless/iwmc3200wifi/eeprom.h deleted file mode 100644 index 4e3a3fdab0d3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/eeprom.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_EEPROM_H__ -#define __IWM_EEPROM_H__ - -enum { - IWM_EEPROM_SIG = 0, - IWM_EEPROM_FIRST = IWM_EEPROM_SIG, - IWM_EEPROM_VERSION, - IWM_EEPROM_OEM_HW_VERSION, - IWM_EEPROM_MAC_VERSION, - IWM_EEPROM_CARD_ID, - IWM_EEPROM_RADIO_CONF, - IWM_EEPROM_SKU_CAP, - IWM_EEPROM_FAT_CHANNELS_CAP, - - IWM_EEPROM_INDIRECT_OFFSET, - IWM_EEPROM_CALIB_RXIQ_OFFSET = IWM_EEPROM_INDIRECT_OFFSET, - - IWM_EEPROM_INDIRECT_DATA, - IWM_EEPROM_CALIB_RXIQ = IWM_EEPROM_INDIRECT_DATA, - - IWM_EEPROM_LAST, -}; - -#define IWM_EEPROM_SIG_OFF 0x00 -#define IWM_EEPROM_VERSION_OFF (0x54 << 1) -#define IWM_EEPROM_OEM_HW_VERSION_OFF (0x56 << 1) -#define IWM_EEPROM_MAC_VERSION_OFF (0x30 << 1) -#define IWM_EEPROM_CARD_ID_OFF (0x5d << 1) -#define IWM_EEPROM_RADIO_CONF_OFF (0x58 << 1) -#define IWM_EEPROM_SKU_CAP_OFF (0x55 << 1) -#define IWM_EEPROM_CALIB_CONFIG_OFF (0x7c << 1) -#define IWM_EEPROM_FAT_CHANNELS_CAP_OFF (0xde << 1) - -#define IWM_EEPROM_SIG_LEN 4 -#define IWM_EEPROM_VERSION_LEN 2 -#define IWM_EEPROM_OEM_HW_VERSION_LEN 2 -#define IWM_EEPROM_MAC_VERSION_LEN 1 -#define IWM_EEPROM_CARD_ID_LEN 2 -#define IWM_EEPROM_RADIO_CONF_LEN 2 -#define IWM_EEPROM_SKU_CAP_LEN 2 -#define IWM_EEPROM_FAT_CHANNELS_CAP_LEN 40 -#define IWM_EEPROM_INDIRECT_LEN 2 - -#define IWM_MAX_EEPROM_DATA_LEN 240 -#define IWM_EEPROM_LEN 0x800 - -#define IWM_EEPROM_MIN_ALLOWED_VERSION 0x0610 -#define IWM_EEPROM_MAX_ALLOWED_VERSION 0x0700 -#define IWM_EEPROM_CURRENT_VERSION 0x0612 - -#define IWM_EEPROM_SKU_CAP_BAND_24GHZ (1 << 4) -#define IWM_EEPROM_SKU_CAP_BAND_52GHZ (1 << 5) -#define IWM_EEPROM_SKU_CAP_11N_ENABLE (1 << 6) - -#define IWM_EEPROM_FAT_CHANNELS 20 -/* 2.4 gHz FAT primary channels: 1, 2, 3, 4, 5, 6, 7, 8, 9 */ -#define IWM_EEPROM_FAT_CHANNELS_24 9 -/* 5.2 gHz FAT primary channels: 36,44,52,60,100,108,116,124,132,149,157 */ -#define IWM_EEPROM_FAT_CHANNELS_52 11 - -#define IWM_EEPROM_FAT_CHANNEL_ENABLED (1 << 0) - -enum { - IWM_EEPROM_CALIB_CAL_HDR, - IWM_EEPROM_CALIB_TX_POWER, - IWM_EEPROM_CALIB_XTAL, - IWM_EEPROM_CALIB_TEMPERATURE, - IWM_EEPROM_CALIB_RX_BB_FILTER, - IWM_EEPROM_CALIB_RX_IQ, - IWM_EEPROM_CALIB_MAX, -}; - -#define IWM_EEPROM_CALIB_RXIQ_OFF (IWM_EEPROM_CALIB_CONFIG_OFF + \ - (IWM_EEPROM_CALIB_RX_IQ << 1)) -#define IWM_EEPROM_CALIB_RXIQ_LEN sizeof(struct iwm_lmac_calib_rxiq) - -struct iwm_eeprom_entry { - char *name; - u32 offset; - u32 length; -}; - -int iwm_eeprom_init(struct iwm_priv *iwm); -void iwm_eeprom_exit(struct iwm_priv *iwm); -u8 *iwm_eeprom_access(struct iwm_priv *iwm, u8 eeprom_id); -int iwm_eeprom_fat_channels(struct iwm_priv *iwm); -u32 iwm_eeprom_wireless_mode(struct iwm_priv *iwm); - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/fw.c b/drivers/net/wireless/iwmc3200wifi/fw.c deleted file mode 100644 index 6f1afe6bbc8c..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/fw.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#include <linux/kernel.h> -#include <linux/firmware.h> - -#include "iwm.h" -#include "bus.h" -#include "hal.h" -#include "umac.h" -#include "debug.h" -#include "fw.h" -#include "commands.h" - -static const char fw_barker[] = "*WESTOPFORNOONE*"; - -/* - * @op_code: Op code we're looking for. - * @index: There can be several instances of the same opcode within - * the firmware. Index specifies which one we're looking for. - */ -static int iwm_fw_op_offset(struct iwm_priv *iwm, const struct firmware *fw, - u16 op_code, u32 index) -{ - int offset = -EINVAL, fw_offset; - u32 op_index = 0; - const u8 *fw_ptr; - struct iwm_fw_hdr_rec *rec; - - fw_offset = 0; - fw_ptr = fw->data; - - /* We first need to look for the firmware barker */ - if (memcmp(fw_ptr, fw_barker, IWM_HDR_BARKER_LEN)) { - IWM_ERR(iwm, "No barker string in this FW\n"); - return -EINVAL; - } - - if (fw->size < IWM_HDR_LEN) { - IWM_ERR(iwm, "FW is too small (%zu)\n", fw->size); - return -EINVAL; - } - - fw_offset += IWM_HDR_BARKER_LEN; - - while (fw_offset < fw->size) { - rec = (struct iwm_fw_hdr_rec *)(fw_ptr + fw_offset); - - IWM_DBG_FW(iwm, DBG, "FW: op_code: 0x%x, len: %d @ 0x%x\n", - rec->op_code, rec->len, fw_offset); - - if (rec->op_code == IWM_HDR_REC_OP_INVALID) { - IWM_DBG_FW(iwm, DBG, "Reached INVALID op code\n"); - break; - } - - if (rec->op_code == op_code) { - if (op_index == index) { - fw_offset += sizeof(struct iwm_fw_hdr_rec); - offset = fw_offset; - goto out; - } - op_index++; - } - - fw_offset += sizeof(struct iwm_fw_hdr_rec) + rec->len; - } - - out: - return offset; -} - -static int iwm_load_firmware_chunk(struct iwm_priv *iwm, - const struct firmware *fw, - struct iwm_fw_img_desc *img_desc) -{ - struct iwm_udma_nonwifi_cmd target_cmd; - u32 chunk_size; - const u8 *chunk_ptr; - int ret = 0; - - IWM_DBG_FW(iwm, INFO, "Loading FW chunk: %d bytes @ 0x%x\n", - img_desc->length, img_desc->address); - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; - target_cmd.handle_by_hw = 1; - target_cmd.op2 = 0; - target_cmd.resp = 0; - target_cmd.eop = 1; - - chunk_size = img_desc->length; - chunk_ptr = fw->data + img_desc->offset; - - while (chunk_size > 0) { - u32 tmp_chunk_size; - - tmp_chunk_size = min_t(u32, chunk_size, - IWM_MAX_NONWIFI_CMD_BUFF_SIZE); - - target_cmd.addr = cpu_to_le32(img_desc->address + - (chunk_ptr - fw->data - img_desc->offset)); - target_cmd.op1_sz = cpu_to_le32(tmp_chunk_size); - - IWM_DBG_FW(iwm, DBG, "\t%d bytes @ 0x%x\n", - tmp_chunk_size, target_cmd.addr); - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, chunk_ptr); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't load FW chunk\n"); - break; - } - - chunk_size -= tmp_chunk_size; - chunk_ptr += tmp_chunk_size; - } - - return ret; -} -/* - * To load a fw image to the target, we basically go through the - * fw, looking for OP_MEM_DESC records. Once we found one, we - * pass it to iwm_load_firmware_chunk(). - * The OP_MEM_DESC records contain the actuall memory chunk to be - * sent, but also the destination address. - */ -static int iwm_load_img(struct iwm_priv *iwm, const char *img_name) -{ - const struct firmware *fw; - struct iwm_fw_img_desc *img_desc; - struct iwm_fw_img_ver *ver; - int ret = 0, fw_offset; - u32 opcode_idx = 0, build_date; - char *build_tag; - - ret = request_firmware(&fw, img_name, iwm_to_dev(iwm)); - if (ret) { - IWM_ERR(iwm, "Request firmware failed"); - return ret; - } - - IWM_DBG_FW(iwm, INFO, "Start to load FW %s\n", img_name); - - while (1) { - fw_offset = iwm_fw_op_offset(iwm, fw, - IWM_HDR_REC_OP_MEM_DESC, - opcode_idx); - if (fw_offset < 0) - break; - - img_desc = (struct iwm_fw_img_desc *)(fw->data + fw_offset); - ret = iwm_load_firmware_chunk(iwm, fw, img_desc); - if (ret < 0) - goto err_release_fw; - opcode_idx++; - } - - /* Read firmware version */ - fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0); - if (fw_offset < 0) - goto err_release_fw; - - ver = (struct iwm_fw_img_ver *)(fw->data + fw_offset); - - /* Read build tag */ - fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_TAG, 0); - if (fw_offset < 0) - goto err_release_fw; - - build_tag = (char *)(fw->data + fw_offset); - - /* Read build date */ - fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_BUILD_DATE, 0); - if (fw_offset < 0) - goto err_release_fw; - - build_date = *(u32 *)(fw->data + fw_offset); - - IWM_INFO(iwm, "%s:\n", img_name); - IWM_INFO(iwm, "\tVersion: %02X.%02X\n", ver->major, ver->minor); - IWM_INFO(iwm, "\tBuild tag: %s\n", build_tag); - IWM_INFO(iwm, "\tBuild date: %x-%x-%x\n", - IWM_BUILD_YEAR(build_date), IWM_BUILD_MONTH(build_date), - IWM_BUILD_DAY(build_date)); - - if (!strcmp(img_name, iwm->bus_ops->umac_name)) - sprintf(iwm->umac_version, "%02X.%02X", - ver->major, ver->minor); - - if (!strcmp(img_name, iwm->bus_ops->lmac_name)) - sprintf(iwm->lmac_version, "%02X.%02X", - ver->major, ver->minor); - - err_release_fw: - release_firmware(fw); - - return ret; -} - -static int iwm_load_umac(struct iwm_priv *iwm) -{ - struct iwm_udma_nonwifi_cmd target_cmd; - int ret; - - ret = iwm_load_img(iwm, iwm->bus_ops->umac_name); - if (ret < 0) - return ret; - - /* We've loaded the UMAC, we can tell the target to jump there */ - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_JUMP; - target_cmd.addr = cpu_to_le32(UMAC_MU_FW_INST_DATA_12_ADDR); - target_cmd.op1_sz = 0; - target_cmd.op2 = 0; - target_cmd.handle_by_hw = 0; - target_cmd.resp = 1 ; - target_cmd.eop = 1; - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, NULL); - if (ret < 0) - IWM_ERR(iwm, "Couldn't send JMP command\n"); - - return ret; -} - -static int iwm_load_lmac(struct iwm_priv *iwm, const char *img_name) -{ - int ret; - - ret = iwm_load_img(iwm, img_name); - if (ret < 0) - return ret; - - return iwm_send_umac_reset(iwm, - cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_CLK_EN), 0); -} - -static int iwm_init_calib(struct iwm_priv *iwm, unsigned long cfg_bitmap, - unsigned long expected_bitmap, u8 rx_iq_cmd) -{ - /* Read RX IQ calibration result from EEPROM */ - if (test_bit(rx_iq_cmd, &cfg_bitmap)) { - iwm_store_rxiq_calib_result(iwm); - set_bit(PHY_CALIBRATE_RX_IQ_CMD, &iwm->calib_done_map); - } - - iwm_send_prio_table(iwm); - iwm_send_init_calib_cfg(iwm, cfg_bitmap); - - while (iwm->calib_done_map != expected_bitmap) { - if (iwm_notif_handle(iwm, CALIBRATION_RES_NOTIFICATION, - IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT)) { - IWM_DBG_FW(iwm, DBG, "Initial calibration timeout\n"); - return -ETIMEDOUT; - } - - IWM_DBG_FW(iwm, DBG, "Got calibration result. calib_done_map: " - "0x%lx, expected calibrations: 0x%lx\n", - iwm->calib_done_map, expected_bitmap); - } - - return 0; -} - -/* - * We currently have to load 3 FWs: - * 1) The UMAC (Upper MAC). - * 2) The calibration LMAC (Lower MAC). - * We then send the calibration init command, so that the device can - * run a first calibration round. - * 3) The operational LMAC, which replaces the calibration one when it's - * done with the first calibration round. - * - * Once those 3 FWs have been loaded, we send the periodic calibration - * command, and then the device is available for regular 802.11 operations. - */ -int iwm_load_fw(struct iwm_priv *iwm) -{ - unsigned long init_calib_map, periodic_calib_map; - unsigned long expected_calib_map; - int ret; - - /* We first start downloading the UMAC */ - ret = iwm_load_umac(iwm); - if (ret < 0) { - IWM_ERR(iwm, "UMAC loading failed\n"); - return ret; - } - - /* Handle UMAC_ALIVE notification */ - ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_ALIVE, IWM_SRC_UMAC, - WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Handle UMAC_ALIVE failed: %d\n", ret); - return ret; - } - - /* UMAC is alive, we can download the calibration LMAC */ - ret = iwm_load_lmac(iwm, iwm->bus_ops->calib_lmac_name); - if (ret) { - IWM_ERR(iwm, "Calibration LMAC loading failed\n"); - return ret; - } - - /* Handle UMAC_INIT_COMPLETE notification */ - ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, - IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Handle INIT_COMPLETE failed for calibration " - "LMAC: %d\n", ret); - return ret; - } - - /* Read EEPROM data */ - ret = iwm_eeprom_init(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't init eeprom array\n"); - return ret; - } - - init_calib_map = iwm->conf.calib_map & IWM_CALIB_MAP_INIT_MSK; - expected_calib_map = iwm->conf.expected_calib_map & - IWM_CALIB_MAP_INIT_MSK; - periodic_calib_map = IWM_CALIB_MAP_PER_LMAC(iwm->conf.calib_map); - - ret = iwm_init_calib(iwm, init_calib_map, expected_calib_map, - CALIB_CFG_RX_IQ_IDX); - if (ret < 0) { - /* Let's try the old way */ - ret = iwm_init_calib(iwm, expected_calib_map, - expected_calib_map, - PHY_CALIBRATE_RX_IQ_CMD); - if (ret < 0) { - IWM_ERR(iwm, "Calibration result timeout\n"); - goto out; - } - } - - /* Handle LMAC CALIBRATION_COMPLETE notification */ - ret = iwm_notif_handle(iwm, CALIBRATION_COMPLETE_NOTIFICATION, - IWM_SRC_LMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Wait for CALIBRATION_COMPLETE timeout\n"); - goto out; - } - - IWM_INFO(iwm, "LMAC calibration done: 0x%lx\n", iwm->calib_done_map); - - iwm_send_umac_reset(iwm, cpu_to_le32(UMAC_RST_CTRL_FLG_LARC_RESET), 1); - - ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_RESET, IWM_SRC_UMAC, - WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Wait for UMAC RESET timeout\n"); - goto out; - } - - /* Download the operational LMAC */ - ret = iwm_load_lmac(iwm, iwm->bus_ops->lmac_name); - if (ret) { - IWM_ERR(iwm, "LMAC loading failed\n"); - goto out; - } - - ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_INIT_COMPLETE, - IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Handle INIT_COMPLETE failed for LMAC: %d\n", ret); - goto out; - } - - iwm_send_prio_table(iwm); - iwm_send_calib_results(iwm); - iwm_send_periodic_calib_cfg(iwm, periodic_calib_map); - iwm_send_ct_kill_cfg(iwm, iwm->conf.ct_kill_entry, - iwm->conf.ct_kill_exit); - - return 0; - - out: - iwm_eeprom_exit(iwm); - return ret; -} diff --git a/drivers/net/wireless/iwmc3200wifi/fw.h b/drivers/net/wireless/iwmc3200wifi/fw.h deleted file mode 100644 index c70a3b40dad3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/fw.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_FW_H__ -#define __IWM_FW_H__ - -/** - * struct iwm_fw_hdr_rec - An iwm firmware image is a - * concatenation of various records. Each of them is - * defined by an ID (aka op code), a length, and the - * actual data. - * @op_code: The record ID, see IWM_HDR_REC_OP_* - * - * @len: The record payload length - * - * @buf: The record payload - */ -struct iwm_fw_hdr_rec { - u16 op_code; - u16 len; - u8 buf[0]; -}; - -/* Header's definitions */ -#define IWM_HDR_LEN (512) -#define IWM_HDR_BARKER_LEN (16) - -/* Header's opcodes */ -#define IWM_HDR_REC_OP_INVALID (0x00) -#define IWM_HDR_REC_OP_BUILD_DATE (0x01) -#define IWM_HDR_REC_OP_BUILD_TAG (0x02) -#define IWM_HDR_REC_OP_SW_VER (0x03) -#define IWM_HDR_REC_OP_HW_SKU (0x04) -#define IWM_HDR_REC_OP_BUILD_OPT (0x05) -#define IWM_HDR_REC_OP_MEM_DESC (0x06) -#define IWM_HDR_REC_USERDEFS (0x07) - -/* Header's records length (in bytes) */ -#define IWM_HDR_REC_LEN_BUILD_DATE (4) -#define IWM_HDR_REC_LEN_BUILD_TAG (64) -#define IWM_HDR_REC_LEN_SW_VER (4) -#define IWM_HDR_REC_LEN_HW_SKU (4) -#define IWM_HDR_REC_LEN_BUILD_OPT (4) -#define IWM_HDR_REC_LEN_MEM_DESC (12) -#define IWM_HDR_REC_LEN_USERDEF (64) - -#define IWM_BUILD_YEAR(date) ((date >> 16) & 0xffff) -#define IWM_BUILD_MONTH(date) ((date >> 8) & 0xff) -#define IWM_BUILD_DAY(date) (date & 0xff) - -struct iwm_fw_img_desc { - u32 offset; - u32 address; - u32 length; -}; - -struct iwm_fw_img_ver { - u8 minor; - u8 major; - u16 reserved; -}; - -int iwm_load_fw(struct iwm_priv *iwm); - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/hal.c b/drivers/net/wireless/iwmc3200wifi/hal.c deleted file mode 100644 index 1cabcb39643f..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/hal.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -/* - * Hardware Abstraction Layer for iwm. - * - * This file mostly defines an abstraction API for - * sending various commands to the target. - * - * We have 2 types of commands: wifi and non-wifi ones. - * - * - wifi commands: - * They are used for sending LMAC and UMAC commands, - * and thus are the most commonly used ones. - * There are 2 different wifi command types, the regular - * one and the LMAC one. The former is used to send - * UMAC commands (see UMAC_CMD_OPCODE_* from umac.h) - * while the latter is used for sending commands to the - * LMAC. If you look at LMAC commands you'll se that they - * are actually regular iwlwifi target commands encapsulated - * into a special UMAC command called UMAC passthrough. - * This is due to the fact the host talks exclusively - * to the UMAC and so there needs to be a special UMAC - * command for talking to the LMAC. - * This is how a wifi command is laid out: - * ------------------------ - * | iwm_udma_out_wifi_hdr | - * ------------------------ - * | SW meta_data (32 bits) | - * ------------------------ - * | iwm_dev_cmd_hdr | - * ------------------------ - * | payload | - * | .... | - * - * - non-wifi, or general commands: - * Those commands are handled by the device's bootrom, - * and are typically sent when the UMAC and the LMAC - * are not yet available. - * * This is how a non-wifi command is laid out: - * --------------------------- - * | iwm_udma_out_nonwifi_hdr | - * --------------------------- - * | payload | - * | .... | - - * - * All the commands start with a UDMA header, which is - * basically a 32 bits field. The 4 LSB there define - * an opcode that allows the target to differentiate - * between wifi (opcode is 0xf) and non-wifi commands - * (opcode is [0..0xe]). - * - * When a command (wifi or non-wifi) is supposed to receive - * an answer, we queue the command buffer. When we do receive - * a command response from the UMAC, we go through the list - * of pending command, and pass both the command and the answer - * to the rx handler. Each command is sent with a unique - * sequence id, and the answer is sent with the same one. This - * is how we're supposed to match an answer with its command. - * See rx.c:iwm_rx_handle_[non]wifi() and iwm_get_pending_[non]wifi() - * for the implementation details. - */ -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/slab.h> - -#include "iwm.h" -#include "bus.h" -#include "hal.h" -#include "umac.h" -#include "debug.h" -#include "trace.h" - -static int iwm_nonwifi_cmd_init(struct iwm_priv *iwm, - struct iwm_nonwifi_cmd *cmd, - struct iwm_udma_nonwifi_cmd *udma_cmd) -{ - INIT_LIST_HEAD(&cmd->pending); - - spin_lock(&iwm->cmd_lock); - - cmd->resp_received = 0; - - cmd->seq_num = iwm->nonwifi_seq_num; - udma_cmd->seq_num = cpu_to_le16(cmd->seq_num); - - iwm->nonwifi_seq_num++; - iwm->nonwifi_seq_num %= UMAC_NONWIFI_SEQ_NUM_MAX; - - if (udma_cmd->resp) - list_add_tail(&cmd->pending, &iwm->nonwifi_pending_cmd); - - spin_unlock(&iwm->cmd_lock); - - cmd->buf.start = cmd->buf.payload; - cmd->buf.len = 0; - - memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); - - return cmd->seq_num; -} - -u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm) -{ - u16 seq_num = iwm->wifi_seq_num; - - iwm->wifi_seq_num++; - iwm->wifi_seq_num %= UMAC_WIFI_SEQ_NUM_MAX; - - return seq_num; -} - -static void iwm_wifi_cmd_init(struct iwm_priv *iwm, - struct iwm_wifi_cmd *cmd, - struct iwm_udma_wifi_cmd *udma_cmd, - struct iwm_umac_cmd *umac_cmd, - struct iwm_lmac_cmd *lmac_cmd, - u16 payload_size) -{ - INIT_LIST_HEAD(&cmd->pending); - - spin_lock(&iwm->cmd_lock); - - cmd->seq_num = iwm_alloc_wifi_cmd_seq(iwm); - umac_cmd->seq_num = cpu_to_le16(cmd->seq_num); - - if (umac_cmd->resp) - list_add_tail(&cmd->pending, &iwm->wifi_pending_cmd); - - spin_unlock(&iwm->cmd_lock); - - cmd->buf.start = cmd->buf.payload; - cmd->buf.len = 0; - - if (lmac_cmd) { - cmd->buf.start -= sizeof(struct iwm_lmac_hdr); - - lmac_cmd->seq_num = cpu_to_le16(cmd->seq_num); - lmac_cmd->count = cpu_to_le16(payload_size); - - memcpy(&cmd->lmac_cmd, lmac_cmd, sizeof(*lmac_cmd)); - - umac_cmd->count = cpu_to_le16(sizeof(struct iwm_lmac_hdr)); - } else - umac_cmd->count = 0; - - umac_cmd->count = cpu_to_le16(payload_size + - le16_to_cpu(umac_cmd->count)); - udma_cmd->count = cpu_to_le16(sizeof(struct iwm_umac_fw_cmd_hdr) + - le16_to_cpu(umac_cmd->count)); - - memcpy(&cmd->udma_cmd, udma_cmd, sizeof(*udma_cmd)); - memcpy(&cmd->umac_cmd, umac_cmd, sizeof(*umac_cmd)); -} - -void iwm_cmd_flush(struct iwm_priv *iwm) -{ - struct iwm_wifi_cmd *wcmd, *wnext; - struct iwm_nonwifi_cmd *nwcmd, *nwnext; - - list_for_each_entry_safe(wcmd, wnext, &iwm->wifi_pending_cmd, pending) { - list_del(&wcmd->pending); - kfree(wcmd); - } - - list_for_each_entry_safe(nwcmd, nwnext, &iwm->nonwifi_pending_cmd, - pending) { - list_del(&nwcmd->pending); - kfree(nwcmd); - } -} - -struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, u16 seq_num) -{ - struct iwm_wifi_cmd *cmd; - - list_for_each_entry(cmd, &iwm->wifi_pending_cmd, pending) - if (cmd->seq_num == seq_num) { - list_del(&cmd->pending); - return cmd; - } - - return NULL; -} - -struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, - u8 seq_num, u8 cmd_opcode) -{ - struct iwm_nonwifi_cmd *cmd; - - list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) - if ((cmd->seq_num == seq_num) && - (cmd->udma_cmd.opcode == cmd_opcode) && - (cmd->resp_received)) { - list_del(&cmd->pending); - return cmd; - } - - return NULL; -} - -static void iwm_build_udma_nonwifi_hdr(struct iwm_priv *iwm, - struct iwm_udma_out_nonwifi_hdr *hdr, - struct iwm_udma_nonwifi_cmd *cmd) -{ - memset(hdr, 0, sizeof(*hdr)); - - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, cmd->opcode); - SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP, cmd->resp); - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, 1); - SET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW, - cmd->handle_by_hw); - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); - SET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM, - le16_to_cpu(cmd->seq_num)); - - hdr->addr = cmd->addr; - hdr->op1_sz = cmd->op1_sz; - hdr->op2 = cmd->op2; -} - -static int iwm_send_udma_nonwifi_cmd(struct iwm_priv *iwm, - struct iwm_nonwifi_cmd *cmd) -{ - struct iwm_udma_out_nonwifi_hdr *udma_hdr; - struct iwm_nonwifi_cmd_buff *buf; - struct iwm_udma_nonwifi_cmd *udma_cmd = &cmd->udma_cmd; - - buf = &cmd->buf; - - buf->start -= sizeof(struct iwm_umac_nonwifi_out_hdr); - buf->len += sizeof(struct iwm_umac_nonwifi_out_hdr); - - udma_hdr = (struct iwm_udma_out_nonwifi_hdr *)(buf->start); - - iwm_build_udma_nonwifi_hdr(iwm, udma_hdr, udma_cmd); - - IWM_DBG_CMD(iwm, DBG, - "Send UDMA nonwifi cmd: opcode = 0x%x, resp = 0x%x, " - "hw = 0x%x, seqnum = %d, addr = 0x%x, op1_sz = 0x%x, " - "op2 = 0x%x\n", udma_cmd->opcode, udma_cmd->resp, - udma_cmd->handle_by_hw, cmd->seq_num, udma_cmd->addr, - udma_cmd->op1_sz, udma_cmd->op2); - - trace_iwm_tx_nonwifi_cmd(iwm, udma_hdr); - return iwm_bus_send_chunk(iwm, buf->start, buf->len); -} - -void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop) -{ - struct iwm_udma_out_wifi_hdr *hdr = (struct iwm_udma_out_wifi_hdr *)buf; - - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, eop); -} - -void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, - struct iwm_udma_out_wifi_hdr *hdr, - struct iwm_udma_wifi_cmd *cmd) -{ - memset(hdr, 0, sizeof(*hdr)); - - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE, UMAC_HDI_OUT_OPCODE_WIFI); - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT, cmd->eop); - SET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_SIGNATURE, UMAC_HDI_OUT_SIGNATURE); - - SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_BYTE_COUNT, - le16_to_cpu(cmd->count)); - SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_CREDIT_GRP, cmd->credit_group); - SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_RATID, cmd->ra_tid); - SET_VAL32(hdr->meta_data, UMAC_HDI_OUT_LMAC_OFFSET, cmd->lmac_offset); -} - -void iwm_build_umac_hdr(struct iwm_priv *iwm, - struct iwm_umac_fw_cmd_hdr *hdr, - struct iwm_umac_cmd *cmd) -{ - memset(hdr, 0, sizeof(*hdr)); - - SET_VAL32(hdr->meta_data, UMAC_FW_CMD_BYTE_COUNT, - le16_to_cpu(cmd->count)); - SET_VAL32(hdr->meta_data, UMAC_FW_CMD_TX_STA_COLOR, cmd->color); - SET_VAL8(hdr->cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ, cmd->resp); - - hdr->cmd.cmd = cmd->id; - hdr->cmd.seq_num = cmd->seq_num; -} - -static int iwm_send_udma_wifi_cmd(struct iwm_priv *iwm, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_wifi_out_hdr *umac_hdr; - struct iwm_wifi_cmd_buff *buf; - struct iwm_udma_wifi_cmd *udma_cmd = &cmd->udma_cmd; - struct iwm_umac_cmd *umac_cmd = &cmd->umac_cmd; - int ret; - - buf = &cmd->buf; - - buf->start -= sizeof(struct iwm_umac_wifi_out_hdr); - buf->len += sizeof(struct iwm_umac_wifi_out_hdr); - - umac_hdr = (struct iwm_umac_wifi_out_hdr *)(buf->start); - - iwm_build_udma_wifi_hdr(iwm, &umac_hdr->hw_hdr, udma_cmd); - iwm_build_umac_hdr(iwm, &umac_hdr->sw_hdr, umac_cmd); - - IWM_DBG_CMD(iwm, DBG, - "Send UDMA wifi cmd: opcode = 0x%x, UMAC opcode = 0x%x, " - "eop = 0x%x, count = 0x%x, credit_group = 0x%x, " - "ra_tid = 0x%x, lmac_offset = 0x%x, seqnum = %d\n", - UMAC_HDI_OUT_OPCODE_WIFI, umac_cmd->id, - udma_cmd->eop, udma_cmd->count, udma_cmd->credit_group, - udma_cmd->ra_tid, udma_cmd->lmac_offset, cmd->seq_num); - - if (umac_cmd->id == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH) - IWM_DBG_CMD(iwm, DBG, "\tLMAC opcode: 0x%x\n", - cmd->lmac_cmd.id); - - ret = iwm_tx_credit_alloc(iwm, udma_cmd->credit_group, buf->len); - - /* We keep sending UMAC reset regardless of the command credits. - * The UMAC is supposed to be reset anyway and the Tx credits are - * reinitialized afterwards. If we are lucky, the reset could - * still be done even though we have run out of credits for the - * command pool at this moment.*/ - if (ret && (umac_cmd->id != UMAC_CMD_OPCODE_RESET)) { - IWM_DBG_TX(iwm, DBG, "Failed to alloc tx credit for cmd %d\n", - umac_cmd->id); - return ret; - } - - trace_iwm_tx_wifi_cmd(iwm, umac_hdr); - return iwm_bus_send_chunk(iwm, buf->start, buf->len); -} - -/* target_cmd a.k.a udma_nonwifi_cmd can be sent when UMAC is not available */ -int iwm_hal_send_target_cmd(struct iwm_priv *iwm, - struct iwm_udma_nonwifi_cmd *udma_cmd, - const void *payload) -{ - struct iwm_nonwifi_cmd *cmd; - int ret, seq_num; - - cmd = kzalloc(sizeof(struct iwm_nonwifi_cmd), GFP_KERNEL); - if (!cmd) { - IWM_ERR(iwm, "Couldn't alloc memory for hal cmd\n"); - return -ENOMEM; - } - - seq_num = iwm_nonwifi_cmd_init(iwm, cmd, udma_cmd); - - if (cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE || - cmd->udma_cmd.opcode == UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT) { - cmd->buf.len = le32_to_cpu(cmd->udma_cmd.op1_sz); - memcpy(&cmd->buf.payload, payload, cmd->buf.len); - } - - ret = iwm_send_udma_nonwifi_cmd(iwm, cmd); - - if (!udma_cmd->resp) - kfree(cmd); - - if (ret < 0) - return ret; - - return seq_num; -} - -static void iwm_build_lmac_hdr(struct iwm_priv *iwm, struct iwm_lmac_hdr *hdr, - struct iwm_lmac_cmd *cmd) -{ - memset(hdr, 0, sizeof(*hdr)); - - hdr->id = cmd->id; - hdr->flags = 0; /* Is this ever used? */ - hdr->seq_num = cmd->seq_num; -} - -/* - * iwm_hal_send_host_cmd(): sends commands to the UMAC or the LMAC. - * Sending command to the LMAC is equivalent to sending a - * regular UMAC command with the LMAC passthrough or the LMAC - * wrapper UMAC command IDs. - */ -int iwm_hal_send_host_cmd(struct iwm_priv *iwm, - struct iwm_udma_wifi_cmd *udma_cmd, - struct iwm_umac_cmd *umac_cmd, - struct iwm_lmac_cmd *lmac_cmd, - const void *payload, u16 payload_size) -{ - struct iwm_wifi_cmd *cmd; - struct iwm_lmac_hdr *hdr; - int lmac_hdr_len = 0; - int ret; - - cmd = kzalloc(sizeof(struct iwm_wifi_cmd), GFP_KERNEL); - if (!cmd) { - IWM_ERR(iwm, "Couldn't alloc memory for wifi hal cmd\n"); - return -ENOMEM; - } - - iwm_wifi_cmd_init(iwm, cmd, udma_cmd, umac_cmd, lmac_cmd, payload_size); - - if (lmac_cmd) { - hdr = (struct iwm_lmac_hdr *)(cmd->buf.start); - - iwm_build_lmac_hdr(iwm, hdr, &cmd->lmac_cmd); - lmac_hdr_len = sizeof(struct iwm_lmac_hdr); - } - - memcpy(cmd->buf.payload, payload, payload_size); - cmd->buf.len = le16_to_cpu(umac_cmd->count); - - ret = iwm_send_udma_wifi_cmd(iwm, cmd); - - /* We free the cmd if we're not expecting any response */ - if (!umac_cmd->resp) - kfree(cmd); - return ret; -} - -/* - * iwm_hal_send_umac_cmd(): This is a special case for - * iwm_hal_send_host_cmd() to send direct UMAC cmd (without - * LMAC involved). - */ -int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, - struct iwm_udma_wifi_cmd *udma_cmd, - struct iwm_umac_cmd *umac_cmd, - const void *payload, u16 payload_size) -{ - return iwm_hal_send_host_cmd(iwm, udma_cmd, umac_cmd, NULL, - payload, payload_size); -} diff --git a/drivers/net/wireless/iwmc3200wifi/hal.h b/drivers/net/wireless/iwmc3200wifi/hal.h deleted file mode 100644 index c20936d9b6b7..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/hal.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef _IWM_HAL_H_ -#define _IWM_HAL_H_ - -#include "umac.h" - -#define GET_VAL8(s, name) ((s >> name##_POS) & name##_SEED) -#define GET_VAL16(s, name) ((le16_to_cpu(s) >> name##_POS) & name##_SEED) -#define GET_VAL32(s, name) ((le32_to_cpu(s) >> name##_POS) & name##_SEED) - -#define SET_VAL8(s, name, val) \ -do { \ - s = (s & ~(name##_SEED << name##_POS)) | \ - ((val & name##_SEED) << name##_POS); \ -} while (0) - -#define SET_VAL16(s, name, val) \ -do { \ - s = cpu_to_le16((le16_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ - ((val & name##_SEED) << name##_POS)); \ -} while (0) - -#define SET_VAL32(s, name, val) \ -do { \ - s = cpu_to_le32((le32_to_cpu(s) & ~(name##_SEED << name##_POS)) | \ - ((val & name##_SEED) << name##_POS)); \ -} while (0) - - -#define UDMA_UMAC_INIT { .eop = 1, \ - .credit_group = 0x4, \ - .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ - .lmac_offset = 0 } -#define UDMA_LMAC_INIT { .eop = 1, \ - .credit_group = 0x4, \ - .ra_tid = UMAC_HDI_ACT_TBL_IDX_HOST_CMD, \ - .lmac_offset = 4 } - - -/* UDMA IN OP CODE -- cmd bits [3:0] */ -#define UDMA_HDI_IN_NW_CMD_OPCODE_POS 0 -#define UDMA_HDI_IN_NW_CMD_OPCODE_SEED 0xF - -#define UDMA_IN_OPCODE_GENERAL_RESP 0x0 -#define UDMA_IN_OPCODE_READ_RESP 0x1 -#define UDMA_IN_OPCODE_WRITE_RESP 0x2 -#define UDMA_IN_OPCODE_PERS_WRITE_RESP 0x5 -#define UDMA_IN_OPCODE_PERS_READ_RESP 0x6 -#define UDMA_IN_OPCODE_RD_MDFY_WR_RESP 0x7 -#define UDMA_IN_OPCODE_EP_MNGMT_MSG 0x8 -#define UDMA_IN_OPCODE_CRDT_CHNG_MSG 0x9 -#define UDMA_IN_OPCODE_CNTRL_DATABASE_MSG 0xA -#define UDMA_IN_OPCODE_SW_MSG 0xB -#define UDMA_IN_OPCODE_WIFI 0xF -#define UDMA_IN_OPCODE_WIFI_LMAC 0x1F -#define UDMA_IN_OPCODE_WIFI_UMAC 0x2F - -/* HW API: udma_hdi_nonwifi API (OUT and IN) */ - -/* iwm_udma_nonwifi_cmd request response -- bits [9:9] */ -#define UDMA_HDI_OUT_NW_CMD_RESP_POS 9 -#define UDMA_HDI_OUT_NW_CMD_RESP_SEED 0x1 - -/* iwm_udma_nonwifi_cmd handle by HW -- bits [11:11] */ -#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_POS 11 -#define UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW_SEED 0x1 - -/* iwm_udma_nonwifi_cmd sequence-number -- bits [12:15] */ -#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_POS 12 -#define UDMA_HDI_OUT_NW_CMD_SEQ_NUM_SEED 0xF - -/* UDMA IN Non-WIFI HW sequence number -- bits [12:15] */ -#define UDMA_IN_NW_HW_SEQ_NUM_POS 12 -#define UDMA_IN_NW_HW_SEQ_NUM_SEED 0xF - -/* UDMA IN Non-WIFI HW signature -- bits [16:31] */ -#define UDMA_IN_NW_HW_SIG_POS 16 -#define UDMA_IN_NW_HW_SIG_SEED 0xFFFF - -/* fixed signature */ -#define UDMA_IN_NW_HW_SIG 0xCBBC - -/* UDMA IN Non-WIFI HW block length -- bits [32:35] */ -#define UDMA_IN_NW_HW_LENGTH_SEED 0xF -#define UDMA_IN_NW_HW_LENGTH_POS 32 - -/* End of HW API: udma_hdi_nonwifi API (OUT and IN) */ - -#define IWM_SDIO_FW_MAX_CHUNK_SIZE 2032 -#define IWM_MAX_WIFI_HEADERS_SIZE 32 -#define IWM_MAX_NONWIFI_HEADERS_SIZE 16 -#define IWM_MAX_NONWIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ - IWM_MAX_NONWIFI_HEADERS_SIZE) -#define IWM_MAX_WIFI_CMD_BUFF_SIZE (IWM_SDIO_FW_MAX_CHUNK_SIZE - \ - IWM_MAX_WIFI_HEADERS_SIZE) - -#define IWM_HAL_CONCATENATE_BUF_SIZE (32 * 1024) - -struct iwm_wifi_cmd_buff { - u16 len; - u8 *start; - u8 hdr[IWM_MAX_WIFI_HEADERS_SIZE]; - u8 payload[IWM_MAX_WIFI_CMD_BUFF_SIZE]; -}; - -struct iwm_nonwifi_cmd_buff { - u16 len; - u8 *start; - u8 hdr[IWM_MAX_NONWIFI_HEADERS_SIZE]; - u8 payload[IWM_MAX_NONWIFI_CMD_BUFF_SIZE]; -}; - -struct iwm_udma_nonwifi_cmd { - u8 opcode; - u8 eop; - u8 resp; - u8 handle_by_hw; - __le32 addr; - __le32 op1_sz; - __le32 op2; - __le16 seq_num; -}; - -struct iwm_udma_wifi_cmd { - __le16 count; - u8 eop; - u8 credit_group; - u8 ra_tid; - u8 lmac_offset; -}; - -struct iwm_umac_cmd { - u8 id; - __le16 count; - u8 resp; - __le16 seq_num; - u8 color; -}; - -struct iwm_lmac_cmd { - u8 id; - __le16 count; - u8 resp; - __le16 seq_num; -}; - -struct iwm_nonwifi_cmd { - u16 seq_num; - bool resp_received; - struct list_head pending; - struct iwm_udma_nonwifi_cmd udma_cmd; - struct iwm_umac_cmd umac_cmd; - struct iwm_lmac_cmd lmac_cmd; - struct iwm_nonwifi_cmd_buff buf; - u32 flags; -}; - -struct iwm_wifi_cmd { - u16 seq_num; - struct list_head pending; - struct iwm_udma_wifi_cmd udma_cmd; - struct iwm_umac_cmd umac_cmd; - struct iwm_lmac_cmd lmac_cmd; - struct iwm_wifi_cmd_buff buf; - u32 flags; -}; - -void iwm_cmd_flush(struct iwm_priv *iwm); - -struct iwm_wifi_cmd *iwm_get_pending_wifi_cmd(struct iwm_priv *iwm, - u16 seq_num); -struct iwm_nonwifi_cmd *iwm_get_pending_nonwifi_cmd(struct iwm_priv *iwm, - u8 seq_num, u8 cmd_opcode); - - -int iwm_hal_send_target_cmd(struct iwm_priv *iwm, - struct iwm_udma_nonwifi_cmd *ucmd, - const void *payload); - -int iwm_hal_send_host_cmd(struct iwm_priv *iwm, - struct iwm_udma_wifi_cmd *udma_cmd, - struct iwm_umac_cmd *umac_cmd, - struct iwm_lmac_cmd *lmac_cmd, - const void *payload, u16 payload_size); - -int iwm_hal_send_umac_cmd(struct iwm_priv *iwm, - struct iwm_udma_wifi_cmd *udma_cmd, - struct iwm_umac_cmd *umac_cmd, - const void *payload, u16 payload_size); - -u16 iwm_alloc_wifi_cmd_seq(struct iwm_priv *iwm); - -void iwm_udma_wifi_hdr_set_eop(struct iwm_priv *iwm, u8 *buf, u8 eop); -void iwm_build_udma_wifi_hdr(struct iwm_priv *iwm, - struct iwm_udma_out_wifi_hdr *hdr, - struct iwm_udma_wifi_cmd *cmd); -void iwm_build_umac_hdr(struct iwm_priv *iwm, - struct iwm_umac_fw_cmd_hdr *hdr, - struct iwm_umac_cmd *cmd); -#endif /* _IWM_HAL_H_ */ diff --git a/drivers/net/wireless/iwmc3200wifi/iwm.h b/drivers/net/wireless/iwmc3200wifi/iwm.h deleted file mode 100644 index 51d7efa15ae6..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/iwm.h +++ /dev/null @@ -1,367 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_H__ -#define __IWM_H__ - -#include <linux/netdevice.h> -#include <linux/wireless.h> -#include <net/cfg80211.h> - -#include "debug.h" -#include "hal.h" -#include "umac.h" -#include "lmac.h" -#include "eeprom.h" -#include "trace.h" - -#define IWM_COPYRIGHT "Copyright(c) 2009 Intel Corporation" -#define IWM_AUTHOR "<ilw@linux.intel.com>" - -#define IWM_SRC_LMAC UMAC_HDI_IN_SOURCE_FHRX -#define IWM_SRC_UDMA UMAC_HDI_IN_SOURCE_UDMA -#define IWM_SRC_UMAC UMAC_HDI_IN_SOURCE_FW -#define IWM_SRC_NUM 3 - -#define IWM_POWER_INDEX_MIN 0 -#define IWM_POWER_INDEX_MAX 5 -#define IWM_POWER_INDEX_DEFAULT 3 - -struct iwm_conf { - u32 sdio_ior_timeout; - unsigned long calib_map; - unsigned long expected_calib_map; - u8 ct_kill_entry; - u8 ct_kill_exit; - bool reset_on_fatal_err; - bool auto_connect; - bool wimax_not_present; - bool enable_qos; - u32 mode; - - u32 power_index; - u32 frag_threshold; - u32 rts_threshold; - bool cts_to_self; - - u32 assoc_timeout; - u32 roam_timeout; - u32 wireless_mode; - - u8 ibss_band; - u8 ibss_channel; - - u8 mac_addr[ETH_ALEN]; -}; - -enum { - COEX_MODE_SA = 1, - COEX_MODE_XOR, - COEX_MODE_CM, - COEX_MODE_MAX, -}; - -struct iwm_if_ops; -struct iwm_wifi_cmd; - -struct pool_entry { - int id; /* group id */ - int sid; /* super group id */ - int min_pages; /* min capacity in pages */ - int max_pages; /* max capacity in pages */ - int alloc_pages; /* allocated # of pages. incresed by driver */ - int total_freed_pages; /* total freed # of pages. incresed by UMAC */ -}; - -struct spool_entry { - int id; - int max_pages; - int alloc_pages; -}; - -struct iwm_tx_credit { - spinlock_t lock; - int pool_nr; - unsigned long full_pools_map; /* bitmap for # of filled tx pools */ - struct pool_entry pools[IWM_MACS_OUT_GROUPS]; - struct spool_entry spools[IWM_MACS_OUT_SGROUPS]; -}; - -struct iwm_notif { - struct list_head pending; - u32 cmd_id; - void *cmd; - u8 src; - void *buf; - unsigned long buf_size; -}; - -struct iwm_tid_info { - __le16 last_seq_num; - bool stopped; - struct mutex mutex; -}; - -struct iwm_sta_info { - u8 addr[ETH_ALEN]; - bool valid; - bool qos; - u8 color; - struct iwm_tid_info tid_info[IWM_UMAC_TID_NR]; -}; - -struct iwm_tx_info { - u8 sta; - u8 color; - u8 tid; -}; - -struct iwm_rx_info { - unsigned long rx_size; - unsigned long rx_buf_size; -}; - -#define IWM_NUM_KEYS 4 - -struct iwm_umac_key_hdr { - u8 mac[ETH_ALEN]; - u8 key_idx; - u8 multicast; /* BCast encrypt & BCast decrypt of frames FROM mac */ -} __packed; - -struct iwm_key { - struct iwm_umac_key_hdr hdr; - u32 cipher; - u8 key[WLAN_MAX_KEY_LEN]; - u8 seq[IW_ENCODE_SEQ_MAX_SIZE]; - int key_len; - int seq_len; -}; - -#define IWM_RX_ID_HASH 0xff -#define IWM_RX_ID_GET_HASH(id) ((id) % IWM_RX_ID_HASH) - -#define IWM_STA_TABLE_NUM 16 -#define IWM_TX_LIST_SIZE 64 -#define IWM_RX_LIST_SIZE 256 - -#define IWM_SCAN_ID_MAX 0xff - -#define IWM_STATUS_READY 0 -#define IWM_STATUS_SCANNING 1 -#define IWM_STATUS_SCAN_ABORTING 2 -#define IWM_STATUS_SME_CONNECTING 3 -#define IWM_STATUS_ASSOCIATED 4 -#define IWM_STATUS_RESETTING 5 - -struct iwm_tx_queue { - int id; - struct sk_buff_head queue; - struct sk_buff_head stopped_queue; - spinlock_t lock; - struct workqueue_struct *wq; - struct work_struct worker; - u8 concat_buf[IWM_HAL_CONCATENATE_BUF_SIZE]; - int concat_count; - u8 *concat_ptr; -}; - -/* Queues 0 ~ 3 for AC data, 5 for iPAN */ -#define IWM_TX_QUEUES 5 -#define IWM_TX_DATA_QUEUES 4 -#define IWM_TX_CMD_QUEUE 4 - -struct iwm_bss_info { - struct list_head node; - struct cfg80211_bss *cfg_bss; - struct iwm_umac_notif_bss_info *bss; -}; - -typedef int (*iwm_handler)(struct iwm_priv *priv, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd); - -#define IWM_WATCHDOG_PERIOD (6 * HZ) - -struct iwm_priv { - struct wireless_dev *wdev; - struct iwm_if_ops *bus_ops; - - struct iwm_conf conf; - - unsigned long status; - - struct list_head pending_notif; - wait_queue_head_t notif_queue; - - wait_queue_head_t nonwifi_queue; - - unsigned long calib_done_map; - struct { - u8 *buf; - u32 size; - } calib_res[CALIBRATION_CMD_NUM]; - - struct iwm_umac_profile *umac_profile; - bool umac_profile_active; - - u8 bssid[ETH_ALEN]; - u8 channel; - u16 rate; - u32 txpower; - - struct iwm_sta_info sta_table[IWM_STA_TABLE_NUM]; - struct list_head bss_list; - - void (*nonwifi_rx_handlers[UMAC_HDI_IN_OPCODE_NONWIFI_MAX]) - (struct iwm_priv *priv, u8 *buf, unsigned long buf_size); - - const iwm_handler *umac_handlers; - const iwm_handler *lmac_handlers; - DECLARE_BITMAP(lmac_handler_map, LMAC_COMMAND_ID_NUM); - DECLARE_BITMAP(umac_handler_map, LMAC_COMMAND_ID_NUM); - DECLARE_BITMAP(udma_handler_map, LMAC_COMMAND_ID_NUM); - - struct list_head wifi_pending_cmd; - struct list_head nonwifi_pending_cmd; - u16 wifi_seq_num; - u8 nonwifi_seq_num; - spinlock_t cmd_lock; - - u32 core_enabled; - - u8 scan_id; - struct cfg80211_scan_request *scan_request; - - struct sk_buff_head rx_list; - struct list_head rx_tickets; - spinlock_t ticket_lock; - struct list_head rx_packets[IWM_RX_ID_HASH]; - spinlock_t packet_lock[IWM_RX_ID_HASH]; - struct workqueue_struct *rx_wq; - struct work_struct rx_worker; - - struct iwm_tx_credit tx_credit; - struct iwm_tx_queue txq[IWM_TX_QUEUES]; - - struct iwm_key keys[IWM_NUM_KEYS]; - s8 default_key; - - DECLARE_BITMAP(wifi_ntfy, WIFI_IF_NTFY_MAX); - wait_queue_head_t wifi_ntfy_queue; - - wait_queue_head_t mlme_queue; - - struct iw_statistics wstats; - struct delayed_work stats_request; - struct delayed_work disconnect; - struct delayed_work ct_kill_delay; - - struct iwm_debugfs dbg; - - u8 *eeprom; - struct timer_list watchdog; - struct work_struct reset_worker; - struct work_struct auth_retry_worker; - struct mutex mutex; - - u8 *req_ie; - int req_ie_len; - u8 *resp_ie; - int resp_ie_len; - - struct iwm_fw_error_hdr *last_fw_err; - char umac_version[8]; - char lmac_version[8]; - - char private[0] __attribute__((__aligned__(NETDEV_ALIGN))); -}; - -static inline void *iwm_private(struct iwm_priv *iwm) -{ - BUG_ON(!iwm); - return &iwm->private; -} - -#define hw_to_iwm(h) (h->iwm) -#define iwm_to_dev(i) (wiphy_dev(i->wdev->wiphy)) -#define iwm_to_wiphy(i) (i->wdev->wiphy) -#define wiphy_to_iwm(w) (struct iwm_priv *)(wiphy_priv(w)) -#define iwm_to_wdev(i) (i->wdev) -#define wdev_to_iwm(w) (struct iwm_priv *)(wdev_priv(w)) -#define iwm_to_ndev(i) (i->wdev->netdev) -#define ndev_to_iwm(n) (wdev_to_iwm(n->ieee80211_ptr)) -#define skb_to_rx_info(s) ((struct iwm_rx_info *)(s->cb)) -#define skb_to_tx_info(s) ((struct iwm_tx_info *)s->cb) - -void *iwm_if_alloc(int sizeof_bus, struct device *dev, - struct iwm_if_ops *if_ops); -void iwm_if_free(struct iwm_priv *iwm); -int iwm_if_add(struct iwm_priv *iwm); -void iwm_if_remove(struct iwm_priv *iwm); -int iwm_mode_to_nl80211_iftype(int mode); -int iwm_priv_init(struct iwm_priv *iwm); -void iwm_priv_deinit(struct iwm_priv *iwm); -void iwm_reset(struct iwm_priv *iwm); -void iwm_resetting(struct iwm_priv *iwm); -void iwm_tx_credit_init_pools(struct iwm_priv *iwm, - struct iwm_umac_notif_alive *alive); -int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb); -int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, - u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size); -int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout); -void iwm_init_default_profile(struct iwm_priv *iwm, - struct iwm_umac_profile *profile); -void iwm_link_on(struct iwm_priv *iwm); -void iwm_link_off(struct iwm_priv *iwm); -int iwm_up(struct iwm_priv *iwm); -int iwm_down(struct iwm_priv *iwm); - -/* TX API */ -int iwm_tid_to_queue(u16 tid); -void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages); -void iwm_tx_worker(struct work_struct *work); -int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev); - -/* RX API */ -void iwm_rx_setup_handlers(struct iwm_priv *iwm); -int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size); -int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, - struct iwm_wifi_cmd *cmd); -void iwm_rx_free(struct iwm_priv *iwm); - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/lmac.h b/drivers/net/wireless/iwmc3200wifi/lmac.h deleted file mode 100644 index 5ddcdf8c70c0..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/lmac.h +++ /dev/null @@ -1,484 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_LMAC_H__ -#define __IWM_LMAC_H__ - -struct iwm_lmac_hdr { - u8 id; - u8 flags; - __le16 seq_num; -} __packed; - -/* LMAC commands */ -#define CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK 0x1 - -struct iwm_lmac_cal_cfg_elt { - __le32 enable; /* 1 means LMAC needs to do something */ - __le32 start; /* 1 to start calibration, 0 to stop */ - __le32 send_res; /* 1 for sending back results */ - __le32 apply_res; /* 1 for applying calibration results to HW */ - __le32 reserved; -} __packed; - -struct iwm_lmac_cal_cfg_status { - struct iwm_lmac_cal_cfg_elt init; - struct iwm_lmac_cal_cfg_elt periodic; - __le32 flags; /* CALIB_CFG_FLAG_SEND_COMPLETE_NTFY_AFTER_MSK */ -} __packed; - -struct iwm_lmac_cal_cfg_cmd { - struct iwm_lmac_cal_cfg_status ucode_cfg; - struct iwm_lmac_cal_cfg_status driver_cfg; - __le32 reserved; -} __packed; - -struct iwm_lmac_cal_cfg_resp { - __le32 status; -} __packed; - -#define IWM_CARD_STATE_SW_HW_ENABLED 0x00 -#define IWM_CARD_STATE_HW_DISABLED 0x01 -#define IWM_CARD_STATE_SW_DISABLED 0x02 -#define IWM_CARD_STATE_CTKILL_DISABLED 0x04 -#define IWM_CARD_STATE_IS_RXON 0x10 - -struct iwm_lmac_card_state { - __le32 flags; -} __packed; - -/** - * COEX_PRIORITY_TABLE_CMD - * - * Priority entry for each state - * Will keep two tables, for STA and WIPAN - */ -enum { - /* UN-ASSOCIATION PART */ - COEX_UNASSOC_IDLE = 0, - COEX_UNASSOC_MANUAL_SCAN, - COEX_UNASSOC_AUTO_SCAN, - - /* CALIBRATION */ - COEX_CALIBRATION, - COEX_PERIODIC_CALIBRATION, - - /* CONNECTION */ - COEX_CONNECTION_ESTAB, - - /* ASSOCIATION PART */ - COEX_ASSOCIATED_IDLE, - COEX_ASSOC_MANUAL_SCAN, - COEX_ASSOC_AUTO_SCAN, - COEX_ASSOC_ACTIVE_LEVEL, - - /* RF ON/OFF */ - COEX_RF_ON, - COEX_RF_OFF, - COEX_STAND_ALONE_DEBUG, - - /* IPNN */ - COEX_IPAN_ASSOC_LEVEL, - - /* RESERVED */ - COEX_RSRVD1, - COEX_RSRVD2, - - COEX_EVENTS_NUM -}; - -#define COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK 0x1 -#define COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK 0x2 -#define COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK 0x4 - -struct coex_event { - u8 req_prio; - u8 win_med_prio; - u8 reserved; - u8 flags; -} __packed; - -#define COEX_FLAGS_STA_TABLE_VALID_MSK 0x1 -#define COEX_FLAGS_UNASSOC_WAKEUP_UMASK_MSK 0x4 -#define COEX_FLAGS_ASSOC_WAKEUP_UMASK_MSK 0x8 -#define COEX_FLAGS_COEX_ENABLE_MSK 0x80 - -struct iwm_coex_prio_table_cmd { - u8 flags; - u8 reserved[3]; - struct coex_event sta_prio[COEX_EVENTS_NUM]; -} __packed; - -/* Coexistence definitions - * - * Constants to fill in the Priorities' Tables - * RP - Requested Priority - * WP - Win Medium Priority: priority assigned when the contention has been won - * FLAGS - Combination of COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK and - * COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK - */ - -#define COEX_UNASSOC_IDLE_FLAGS 0 -#define COEX_UNASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_UNASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_CALIBRATION_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_PERIODIC_CALIBRATION_FLAGS 0 -/* COEX_CONNECTION_ESTAB: we need DELAY_MEDIUM_FREE_NTFY to let WiMAX - * disconnect from network. */ -#define COEX_CONNECTION_ESTAB_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ - COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) -#define COEX_ASSOCIATED_IDLE_FLAGS 0 -#define COEX_ASSOC_MANUAL_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_ASSOC_AUTO_SCAN_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_ASSOC_ACTIVE_LEVEL_FLAGS 0 -#define COEX_RF_ON_FLAGS 0 -#define COEX_RF_OFF_FLAGS 0 -#define COEX_STAND_ALONE_DEBUG_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK) -#define COEX_IPAN_ASSOC_LEVEL_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ - COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) -#define COEX_RSRVD1_FLAGS 0 -#define COEX_RSRVD2_FLAGS 0 -/* XOR_RF_ON is the event wrapping all radio ownership. We need - * DELAY_MEDIUM_FREE_NTFY to let WiMAX disconnect from network. */ -#define COEX_XOR_RF_ON_FLAGS (COEX_EVT_FLAG_MEDIUM_FREE_NTFY_MSK | \ - COEX_EVT_FLAG_MEDIUM_ACTV_NTFY_MSK | \ - COEX_EVT_FLAG_DELAY_MEDIUM_FREE_NTFY_MSK) - -/* CT kill config command */ -struct iwm_ct_kill_cfg_cmd { - u32 exit_threshold; - u32 reserved; - u32 entry_threshold; -} __packed; - - -/* LMAC OP CODES */ -#define REPLY_PAD 0x0 -#define REPLY_ALIVE 0x1 -#define REPLY_ERROR 0x2 -#define REPLY_ECHO 0x3 -#define REPLY_HALT 0x6 - -/* RXON state commands */ -#define REPLY_RX_ON 0x10 -#define REPLY_RX_ON_ASSOC 0x11 -#define REPLY_RX_OFF 0x12 -#define REPLY_QOS_PARAM 0x13 -#define REPLY_RX_ON_TIMING 0x14 -#define REPLY_INTERNAL_QOS_PARAM 0x15 -#define REPLY_RX_INT_TIMEOUT_CNFG 0x16 -#define REPLY_NULL 0x17 - -/* Multi-Station support */ -#define REPLY_ADD_STA 0x18 -#define REPLY_REMOVE_STA 0x19 -#define REPLY_RESET_ALL_STA 0x1a - -/* RX, TX */ -#define REPLY_ALM_RX 0x1b -#define REPLY_TX 0x1c -#define REPLY_TXFIFO_FLUSH 0x1e - -/* MISC commands */ -#define REPLY_MGMT_MCAST_KEY 0x1f -#define REPLY_WEPKEY 0x20 -#define REPLY_INIT_IV 0x21 -#define REPLY_WRITE_MIB 0x22 -#define REPLY_READ_MIB 0x23 -#define REPLY_RADIO_FE 0x24 -#define REPLY_TXFIFO_CFG 0x25 -#define REPLY_WRITE_READ 0x26 -#define REPLY_INSTALL_SEC_KEY 0x27 - - -#define REPLY_RATE_SCALE 0x47 -#define REPLY_LEDS_CMD 0x48 -#define REPLY_TX_LINK_QUALITY_CMD 0x4e -#define REPLY_ANA_MIB_OVERRIDE_CMD 0x4f -#define REPLY_WRITE2REG_CMD 0x50 - -/* winfi-wifi coexistence */ -#define COEX_PRIORITY_TABLE_CMD 0x5a -#define COEX_MEDIUM_NOTIFICATION 0x5b -#define COEX_EVENT_CMD 0x5c - -/* more Protocol and Protocol-test commands */ -#define REPLY_MAX_SLEEP_TIME_CMD 0x61 -#define CALIBRATION_CFG_CMD 0x65 -#define CALIBRATION_RES_NOTIFICATION 0x66 -#define CALIBRATION_COMPLETE_NOTIFICATION 0x67 - -/* Measurements */ -#define REPLY_QUIET_CMD 0x71 -#define REPLY_CHANNEL_SWITCH 0x72 -#define CHANNEL_SWITCH_NOTIFICATION 0x73 - -#define REPLY_SPECTRUM_MEASUREMENT_CMD 0x74 -#define SPECTRUM_MEASURE_NOTIFICATION 0x75 -#define REPLY_MEASUREMENT_ABORT_CMD 0x76 - -/* Power Management */ -#define POWER_TABLE_CMD 0x77 -#define SAVE_RESTORE_ADDRESS_CMD 0x78 -#define REPLY_WATERMARK_CMD 0x79 -#define PM_DEBUG_STATISTIC_NOTIFIC 0x7B -#define PD_FLUSH_N_NOTIFICATION 0x7C - -/* Scan commands and notifications */ -#define REPLY_SCAN_REQUEST_CMD 0x80 -#define REPLY_SCAN_ABORT_CMD 0x81 -#define SCAN_START_NOTIFICATION 0x82 -#define SCAN_RESULTS_NOTIFICATION 0x83 -#define SCAN_COMPLETE_NOTIFICATION 0x84 - -/* Continuous TX commands */ -#define REPLY_CONT_TX_CMD 0x85 -#define END_OF_CONT_TX_NOTIFICATION 0x86 - -/* Timer/Eeprom commands */ -#define TIMER_CMD 0x87 -#define EEPROM_WRITE_CMD 0x88 - -/* PAPD commands */ -#define FEEDBACK_REQUEST_NOTIFICATION 0x8b -#define REPLY_CW_CMD 0x8c - -/* IBSS/AP commands Continue */ -#define BEACON_NOTIFICATION 0x90 -#define REPLY_TX_BEACON 0x91 -#define REPLY_REQUEST_ATIM 0x93 -#define WHO_IS_AWAKE_NOTIFICATION 0x94 -#define TX_PWR_DBM_LIMIT_CMD 0x95 -#define QUIET_NOTIFICATION 0x96 -#define TX_PWR_TABLE_CMD 0x97 -#define TX_ANT_CONFIGURATION_CMD 0x98 -#define MEASURE_ABORT_NOTIFICATION 0x99 -#define REPLY_CALIBRATION_TUNE 0x9a - -/* bt config command */ -#define REPLY_BT_CONFIG 0x9b -#define REPLY_STATISTICS_CMD 0x9c -#define STATISTICS_NOTIFICATION 0x9d - -/* RF-KILL commands and notifications */ -#define REPLY_CARD_STATE_CMD 0xa0 -#define CARD_STATE_NOTIFICATION 0xa1 - -/* Missed beacons notification */ -#define MISSED_BEACONS_NOTIFICATION 0xa2 -#define MISSED_BEACONS_NOTIFICATION_TH_CMD 0xa3 - -#define REPLY_CT_KILL_CONFIG_CMD 0xa4 - -/* HD commands and notifications */ -#define REPLY_HD_PARAMS_CMD 0xa6 -#define HD_PARAMS_NOTIFICATION 0xa7 -#define SENSITIVITY_CMD 0xa8 -#define U_APSD_PARAMS_CMD 0xa9 -#define NOISY_PLATFORM_CMD 0xaa -#define ILLEGAL_CMD 0xac -#define REPLY_PHY_CALIBRATION_CMD 0xb0 -#define REPLAY_RX_GAIN_CALIB_CMD 0xb1 - -/* WiPAN commands */ -#define REPLY_WIPAN_PARAMS_CMD 0xb2 -#define REPLY_WIPAN_RX_ON_CMD 0xb3 -#define REPLY_WIPAN_RX_ON_TIMING 0xb4 -#define REPLY_WIPAN_TX_PWR_TABLE_CMD 0xb5 -#define REPLY_WIPAN_RXON_ASSOC_CMD 0xb6 -#define REPLY_WIPAN_QOS_PARAM 0xb7 -#define WIPAN_REPLY_WEPKEY 0xb8 - -/* BeamForming commands */ -#define BEAMFORMER_CFG_CMD 0xba -#define BEAMFORMEE_NOTIFICATION 0xbb - -/* TGn new Commands */ -#define REPLY_RX_PHY_CMD 0xc0 -#define REPLY_RX_MPDU_CMD 0xc1 -#define REPLY_MULTICAST_HASH 0xc2 -#define REPLY_KDR_RX 0xc3 -#define REPLY_RX_DSP_EXT_INFO 0xc4 -#define REPLY_COMPRESSED_BA 0xc5 - -/* PNC commands */ -#define PNC_CONFIG_CMD 0xc8 -#define PNC_UPDATE_TABLE_CMD 0xc9 -#define XVT_GENERAL_CTRL_CMD 0xca -#define REPLY_LEGACY_RADIO_FE 0xdd - -/* WoWLAN commands */ -#define WOWLAN_PATTERNS 0xe0 -#define WOWLAN_WAKEUP_FILTER 0xe1 -#define WOWLAN_TSC_RSC_PARAM 0xe2 -#define WOWLAN_TKIP_PARAM 0xe3 -#define WOWLAN_KEK_KCK_MATERIAL 0xe4 -#define WOWLAN_GET_STATUSES 0xe5 -#define WOWLAN_TX_POWER_PER_DB 0xe6 -#define REPLY_WOWLAN_GET_STATUSES WOWLAN_GET_STATUSES - -#define REPLY_DEBUG_CMD 0xf0 -#define REPLY_DSP_DEBUG_CMD 0xf1 -#define REPLY_DEBUG_MONITOR_CMD 0xf2 -#define REPLY_DEBUG_XVT_CMD 0xf3 -#define REPLY_DEBUG_DC_CALIB 0xf4 -#define REPLY_DYNAMIC_BP 0xf5 - -/* General purpose Commands */ -#define REPLY_GP1_CMD 0xfa -#define REPLY_GP2_CMD 0xfb -#define REPLY_GP3_CMD 0xfc -#define REPLY_GP4_CMD 0xfd -#define REPLY_REPLAY_WRAPPER 0xfe -#define REPLY_FRAME_DURATION_CALC_CMD 0xff - -#define LMAC_COMMAND_ID_MAX 0xff -#define LMAC_COMMAND_ID_NUM (LMAC_COMMAND_ID_MAX + 1) - - -/* Calibration */ - -enum { - PHY_CALIBRATE_DC_CMD = 0, - PHY_CALIBRATE_LO_CMD = 1, - PHY_CALIBRATE_RX_BB_CMD = 2, - PHY_CALIBRATE_TX_IQ_CMD = 3, - PHY_CALIBRATE_RX_IQ_CMD = 4, - PHY_CALIBRATION_NOISE_CMD = 5, - PHY_CALIBRATE_AGC_TABLE_CMD = 6, - PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 7, - PHY_CALIBRATE_OPCODES_NUM, - SHILOH_PHY_CALIBRATE_DC_CMD = 8, - SHILOH_PHY_CALIBRATE_LO_CMD = 9, - SHILOH_PHY_CALIBRATE_RX_BB_CMD = 10, - SHILOH_PHY_CALIBRATE_TX_IQ_CMD = 11, - SHILOH_PHY_CALIBRATE_RX_IQ_CMD = 12, - SHILOH_PHY_CALIBRATION_NOISE_CMD = 13, - SHILOH_PHY_CALIBRATE_AGC_TABLE_CMD = 14, - SHILOH_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, - SHILOH_PHY_CALIBRATE_BASE_BAND_CMD = 16, - SHILOH_PHY_CALIBRATE_TXIQ_PERIODIC_CMD = 17, - CALIBRATION_CMD_NUM, -}; - -enum { - CALIB_CFG_RX_BB_IDX = 0, - CALIB_CFG_DC_IDX = 1, - CALIB_CFG_LO_IDX = 2, - CALIB_CFG_TX_IQ_IDX = 3, - CALIB_CFG_RX_IQ_IDX = 4, - CALIB_CFG_NOISE_IDX = 5, - CALIB_CFG_CRYSTAL_IDX = 6, - CALIB_CFG_TEMPERATURE_IDX = 7, - CALIB_CFG_PAPD_IDX = 8, - CALIB_CFG_LAST_IDX = CALIB_CFG_PAPD_IDX, - CALIB_CFG_MODULE_NUM, -}; - -#define IWM_CALIB_MAP_INIT_MSK 0xFFFF -#define IWM_CALIB_MAP_PER_LMAC(m) ((m & 0xFF0000) >> 16) -#define IWM_CALIB_MAP_PER_UMAC(m) ((m & 0xFF000000) >> 24) -#define IWM_CALIB_OPCODE_TO_INDEX(op) (op - PHY_CALIBRATE_OPCODES_NUM) - -struct iwm_lmac_calib_hdr { - u8 opcode; - u8 first_grp; - u8 grp_num; - u8 all_data_valid; -} __packed; - -#define IWM_LMAC_CALIB_FREQ_GROUPS_NR 7 -#define IWM_CALIB_FREQ_GROUPS_NR 5 -#define IWM_CALIB_DC_MODES_NR 12 - -struct iwm_calib_rxiq_entry { - u16 ptam_postdist_ars; - u16 ptam_postdist_arc; -} __packed; - -struct iwm_calib_rxiq_group { - struct iwm_calib_rxiq_entry mode[IWM_CALIB_DC_MODES_NR]; -} __packed; - -struct iwm_lmac_calib_rxiq { - struct iwm_calib_rxiq_group group[IWM_LMAC_CALIB_FREQ_GROUPS_NR]; -} __packed; - -struct iwm_calib_rxiq { - struct iwm_lmac_calib_hdr hdr; - struct iwm_calib_rxiq_group group[IWM_CALIB_FREQ_GROUPS_NR]; -} __packed; - -#define LMAC_STA_ID_SEED 0x0f -#define LMAC_STA_ID_POS 0 - -#define LMAC_STA_COLOR_SEED 0x7 -#define LMAC_STA_COLOR_POS 4 - -struct iwm_lmac_power_report { - u8 pa_status; - u8 pa_integ_res_A[3]; - u8 pa_integ_res_B[3]; - u8 pa_integ_res_C[3]; -} __packed; - -struct iwm_lmac_tx_resp { - u8 frame_cnt; /* 1-no aggregation, greater then 1 - aggregation */ - u8 bt_kill_cnt; - __le16 retry_cnt; - __le32 initial_tx_rate; - __le16 wireless_media_time; - struct iwm_lmac_power_report power_report; - __le32 tfd_info; - __le16 seq_ctl; - __le16 byte_cnt; - u8 tlc_rate_info; - u8 ra_tid; - __le16 frame_ctl; - __le32 status; -} __packed; - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/main.c b/drivers/net/wireless/iwmc3200wifi/main.c deleted file mode 100644 index 1f868b166d10..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/main.c +++ /dev/null @@ -1,847 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/sched.h> -#include <linux/ieee80211.h> -#include <linux/wireless.h> -#include <linux/slab.h> -#include <linux/moduleparam.h> - -#include "iwm.h" -#include "debug.h" -#include "bus.h" -#include "umac.h" -#include "commands.h" -#include "hal.h" -#include "fw.h" -#include "rx.h" - -static struct iwm_conf def_iwm_conf = { - - .sdio_ior_timeout = 5000, - .calib_map = BIT(CALIB_CFG_DC_IDX) | - BIT(CALIB_CFG_LO_IDX) | - BIT(CALIB_CFG_TX_IQ_IDX) | - BIT(CALIB_CFG_RX_IQ_IDX) | - BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), - .expected_calib_map = BIT(PHY_CALIBRATE_DC_CMD) | - BIT(PHY_CALIBRATE_LO_CMD) | - BIT(PHY_CALIBRATE_TX_IQ_CMD) | - BIT(PHY_CALIBRATE_RX_IQ_CMD) | - BIT(SHILOH_PHY_CALIBRATE_BASE_BAND_CMD), - .ct_kill_entry = 110, - .ct_kill_exit = 110, - .reset_on_fatal_err = 1, - .auto_connect = 1, - .enable_qos = 1, - .mode = UMAC_MODE_BSS, - - /* UMAC configuration */ - .power_index = 0, - .frag_threshold = IEEE80211_MAX_FRAG_THRESHOLD, - .rts_threshold = IEEE80211_MAX_RTS_THRESHOLD, - .cts_to_self = 0, - - .assoc_timeout = 2, - .roam_timeout = 10, - .wireless_mode = WIRELESS_MODE_11A | WIRELESS_MODE_11G | - WIRELESS_MODE_11N, - - /* IBSS */ - .ibss_band = UMAC_BAND_2GHZ, - .ibss_channel = 1, - - .mac_addr = {0x00, 0x02, 0xb3, 0x01, 0x02, 0x03}, -}; - -static bool modparam_reset; -module_param_named(reset, modparam_reset, bool, 0644); -MODULE_PARM_DESC(reset, "reset on firmware errors (default 0 [not reset])"); - -static bool modparam_wimax_enable = true; -module_param_named(wimax_enable, modparam_wimax_enable, bool, 0644); -MODULE_PARM_DESC(wimax_enable, "Enable wimax core (default 1 [wimax enabled])"); - -int iwm_mode_to_nl80211_iftype(int mode) -{ - switch (mode) { - case UMAC_MODE_BSS: - return NL80211_IFTYPE_STATION; - case UMAC_MODE_IBSS: - return NL80211_IFTYPE_ADHOC; - default: - return NL80211_IFTYPE_UNSPECIFIED; - } - - return 0; -} - -static void iwm_statistics_request(struct work_struct *work) -{ - struct iwm_priv *iwm = - container_of(work, struct iwm_priv, stats_request.work); - - iwm_send_umac_stats_req(iwm, 0); -} - -static void iwm_disconnect_work(struct work_struct *work) -{ - struct iwm_priv *iwm = - container_of(work, struct iwm_priv, disconnect.work); - - if (iwm->umac_profile_active) - iwm_invalidate_mlme_profile(iwm); - - clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - iwm->umac_profile_active = false; - memset(iwm->bssid, 0, ETH_ALEN); - iwm->channel = 0; - - iwm_link_off(iwm); - - wake_up_interruptible(&iwm->mlme_queue); - - cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, GFP_KERNEL); -} - -static void iwm_ct_kill_work(struct work_struct *work) -{ - struct iwm_priv *iwm = - container_of(work, struct iwm_priv, ct_kill_delay.work); - struct wiphy *wiphy = iwm_to_wiphy(iwm); - - IWM_INFO(iwm, "CT kill delay timeout\n"); - - wiphy_rfkill_set_hw_state(wiphy, false); -} - -static int __iwm_up(struct iwm_priv *iwm); -static int __iwm_down(struct iwm_priv *iwm); - -static void iwm_reset_worker(struct work_struct *work) -{ - struct iwm_priv *iwm; - struct iwm_umac_profile *profile = NULL; - int uninitialized_var(ret), retry = 0; - - iwm = container_of(work, struct iwm_priv, reset_worker); - - /* - * XXX: The iwm->mutex is introduced purely for this reset work, - * because the other users for iwm_up and iwm_down are only netdev - * ndo_open and ndo_stop which are already protected by rtnl. - * Please remove iwm->mutex together if iwm_reset_worker() is not - * required in the future. - */ - if (!mutex_trylock(&iwm->mutex)) { - IWM_WARN(iwm, "We are in the middle of interface bringing " - "UP/DOWN. Skip driver resetting.\n"); - return; - } - - if (iwm->umac_profile_active) { - profile = kmalloc(sizeof(struct iwm_umac_profile), GFP_KERNEL); - if (profile) - memcpy(profile, iwm->umac_profile, sizeof(*profile)); - else - IWM_ERR(iwm, "Couldn't alloc memory for profile\n"); - } - - __iwm_down(iwm); - - while (retry++ < 3) { - ret = __iwm_up(iwm); - if (!ret) - break; - - schedule_timeout_uninterruptible(10 * HZ); - } - - if (ret) { - IWM_WARN(iwm, "iwm_up() failed: %d\n", ret); - - kfree(profile); - goto out; - } - - if (profile) { - IWM_DBG_MLME(iwm, DBG, "Resend UMAC profile\n"); - memcpy(iwm->umac_profile, profile, sizeof(*profile)); - iwm_send_mlme_profile(iwm); - kfree(profile); - } else - clear_bit(IWM_STATUS_RESETTING, &iwm->status); - - out: - mutex_unlock(&iwm->mutex); -} - -static void iwm_auth_retry_worker(struct work_struct *work) -{ - struct iwm_priv *iwm; - int i, ret; - - iwm = container_of(work, struct iwm_priv, auth_retry_worker); - if (iwm->umac_profile_active) { - ret = iwm_invalidate_mlme_profile(iwm); - if (ret < 0) - return; - } - - iwm->umac_profile->sec.auth_type = UMAC_AUTH_TYPE_LEGACY_PSK; - - ret = iwm_send_mlme_profile(iwm); - if (ret < 0) - return; - - for (i = 0; i < IWM_NUM_KEYS; i++) - if (iwm->keys[i].key_len) - iwm_set_key(iwm, 0, &iwm->keys[i]); - - iwm_set_tx_key(iwm, iwm->default_key); -} - - - -static void iwm_watchdog(unsigned long data) -{ - struct iwm_priv *iwm = (struct iwm_priv *)data; - - IWM_WARN(iwm, "Watchdog expired: UMAC stalls!\n"); - - if (modparam_reset) - iwm_resetting(iwm); -} - -int iwm_priv_init(struct iwm_priv *iwm) -{ - int i, j; - char name[32]; - - iwm->status = 0; - INIT_LIST_HEAD(&iwm->pending_notif); - init_waitqueue_head(&iwm->notif_queue); - init_waitqueue_head(&iwm->nonwifi_queue); - init_waitqueue_head(&iwm->wifi_ntfy_queue); - init_waitqueue_head(&iwm->mlme_queue); - memcpy(&iwm->conf, &def_iwm_conf, sizeof(struct iwm_conf)); - spin_lock_init(&iwm->tx_credit.lock); - INIT_LIST_HEAD(&iwm->wifi_pending_cmd); - INIT_LIST_HEAD(&iwm->nonwifi_pending_cmd); - iwm->wifi_seq_num = UMAC_WIFI_SEQ_NUM_BASE; - iwm->nonwifi_seq_num = UMAC_NONWIFI_SEQ_NUM_BASE; - spin_lock_init(&iwm->cmd_lock); - iwm->scan_id = 1; - INIT_DELAYED_WORK(&iwm->stats_request, iwm_statistics_request); - INIT_DELAYED_WORK(&iwm->disconnect, iwm_disconnect_work); - INIT_DELAYED_WORK(&iwm->ct_kill_delay, iwm_ct_kill_work); - INIT_WORK(&iwm->reset_worker, iwm_reset_worker); - INIT_WORK(&iwm->auth_retry_worker, iwm_auth_retry_worker); - INIT_LIST_HEAD(&iwm->bss_list); - - skb_queue_head_init(&iwm->rx_list); - INIT_LIST_HEAD(&iwm->rx_tickets); - spin_lock_init(&iwm->ticket_lock); - for (i = 0; i < IWM_RX_ID_HASH; i++) { - INIT_LIST_HEAD(&iwm->rx_packets[i]); - spin_lock_init(&iwm->packet_lock[i]); - } - - INIT_WORK(&iwm->rx_worker, iwm_rx_worker); - - iwm->rx_wq = create_singlethread_workqueue(KBUILD_MODNAME "_rx"); - if (!iwm->rx_wq) - return -EAGAIN; - - for (i = 0; i < IWM_TX_QUEUES; i++) { - INIT_WORK(&iwm->txq[i].worker, iwm_tx_worker); - snprintf(name, 32, KBUILD_MODNAME "_tx_%d", i); - iwm->txq[i].id = i; - iwm->txq[i].wq = create_singlethread_workqueue(name); - if (!iwm->txq[i].wq) - return -EAGAIN; - - skb_queue_head_init(&iwm->txq[i].queue); - skb_queue_head_init(&iwm->txq[i].stopped_queue); - spin_lock_init(&iwm->txq[i].lock); - } - - for (i = 0; i < IWM_NUM_KEYS; i++) - memset(&iwm->keys[i], 0, sizeof(struct iwm_key)); - - iwm->default_key = -1; - - for (i = 0; i < IWM_STA_TABLE_NUM; i++) - for (j = 0; j < IWM_UMAC_TID_NR; j++) { - mutex_init(&iwm->sta_table[i].tid_info[j].mutex); - iwm->sta_table[i].tid_info[j].stopped = false; - } - - init_timer(&iwm->watchdog); - iwm->watchdog.function = iwm_watchdog; - iwm->watchdog.data = (unsigned long)iwm; - mutex_init(&iwm->mutex); - - iwm->last_fw_err = kzalloc(sizeof(struct iwm_fw_error_hdr), - GFP_KERNEL); - if (iwm->last_fw_err == NULL) - return -ENOMEM; - - return 0; -} - -void iwm_priv_deinit(struct iwm_priv *iwm) -{ - int i; - - for (i = 0; i < IWM_TX_QUEUES; i++) - destroy_workqueue(iwm->txq[i].wq); - - destroy_workqueue(iwm->rx_wq); - kfree(iwm->last_fw_err); -} - -/* - * We reset all the structures, and we reset the UMAC. - * After calling this routine, you're expected to reload - * the firmware. - */ -void iwm_reset(struct iwm_priv *iwm) -{ - struct iwm_notif *notif, *next; - - if (test_bit(IWM_STATUS_READY, &iwm->status)) - iwm_target_reset(iwm); - - if (test_bit(IWM_STATUS_RESETTING, &iwm->status)) { - iwm->status = 0; - set_bit(IWM_STATUS_RESETTING, &iwm->status); - } else - iwm->status = 0; - iwm->scan_id = 1; - - list_for_each_entry_safe(notif, next, &iwm->pending_notif, pending) { - list_del(¬if->pending); - kfree(notif->buf); - kfree(notif); - } - - iwm_cmd_flush(iwm); - - flush_workqueue(iwm->rx_wq); - - iwm_link_off(iwm); -} - -void iwm_resetting(struct iwm_priv *iwm) -{ - set_bit(IWM_STATUS_RESETTING, &iwm->status); - - schedule_work(&iwm->reset_worker); -} - -/* - * Notification code: - * - * We're faced with the following issue: Any host command can - * have an answer or not, and if there's an answer to expect, - * it can be treated synchronously or asynchronously. - * To work around the synchronous answer case, we implemented - * our notification mechanism. - * When a code path needs to wait for a command response - * synchronously, it calls notif_handle(), which waits for the - * right notification to show up, and then process it. Before - * starting to wait, it registered as a waiter for this specific - * answer (by toggling a bit in on of the handler_map), so that - * the rx code knows that it needs to send a notification to the - * waiting processes. It does so by calling iwm_notif_send(), - * which adds the notification to the pending notifications list, - * and then wakes the waiting processes up. - */ -int iwm_notif_send(struct iwm_priv *iwm, struct iwm_wifi_cmd *cmd, - u8 cmd_id, u8 source, u8 *buf, unsigned long buf_size) -{ - struct iwm_notif *notif; - - notif = kzalloc(sizeof(struct iwm_notif), GFP_KERNEL); - if (!notif) { - IWM_ERR(iwm, "Couldn't alloc memory for notification\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(¬if->pending); - notif->cmd = cmd; - notif->cmd_id = cmd_id; - notif->src = source; - notif->buf = kzalloc(buf_size, GFP_KERNEL); - if (!notif->buf) { - IWM_ERR(iwm, "Couldn't alloc notification buffer\n"); - kfree(notif); - return -ENOMEM; - } - notif->buf_size = buf_size; - memcpy(notif->buf, buf, buf_size); - list_add_tail(¬if->pending, &iwm->pending_notif); - - wake_up_interruptible(&iwm->notif_queue); - - return 0; -} - -static struct iwm_notif *iwm_notif_find(struct iwm_priv *iwm, u32 cmd, - u8 source) -{ - struct iwm_notif *notif; - - list_for_each_entry(notif, &iwm->pending_notif, pending) { - if ((notif->cmd_id == cmd) && (notif->src == source)) { - list_del(¬if->pending); - return notif; - } - } - - return NULL; -} - -static struct iwm_notif *iwm_notif_wait(struct iwm_priv *iwm, u32 cmd, - u8 source, long timeout) -{ - int ret; - struct iwm_notif *notif; - unsigned long *map = NULL; - - switch (source) { - case IWM_SRC_LMAC: - map = &iwm->lmac_handler_map[0]; - break; - case IWM_SRC_UMAC: - map = &iwm->umac_handler_map[0]; - break; - case IWM_SRC_UDMA: - map = &iwm->udma_handler_map[0]; - break; - } - - set_bit(cmd, map); - - ret = wait_event_interruptible_timeout(iwm->notif_queue, - ((notif = iwm_notif_find(iwm, cmd, source)) != NULL), - timeout); - clear_bit(cmd, map); - - if (!ret) - return NULL; - - return notif; -} - -int iwm_notif_handle(struct iwm_priv *iwm, u32 cmd, u8 source, long timeout) -{ - int ret; - struct iwm_notif *notif; - - notif = iwm_notif_wait(iwm, cmd, source, timeout); - if (!notif) - return -ETIME; - - ret = iwm_rx_handle_resp(iwm, notif->buf, notif->buf_size, notif->cmd); - kfree(notif->buf); - kfree(notif); - - return ret; -} - -static int iwm_config_boot_params(struct iwm_priv *iwm) -{ - struct iwm_udma_nonwifi_cmd target_cmd; - int ret; - - /* check Wimax is off and config debug monitor */ - if (!modparam_wimax_enable) { - u32 data1 = 0x1f; - u32 addr1 = 0x606BE258; - - u32 data2_set = 0x0; - u32 data2_clr = 0x1; - u32 addr2 = 0x606BE100; - - u32 data3 = 0x1; - u32 addr3 = 0x606BEC00; - - target_cmd.resp = 0; - target_cmd.handle_by_hw = 0; - target_cmd.eop = 1; - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; - target_cmd.addr = cpu_to_le32(addr1); - target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); - target_cmd.op2 = 0; - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); - if (ret < 0) { - IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); - return ret; - } - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE; - target_cmd.addr = cpu_to_le32(addr2); - target_cmd.op1_sz = cpu_to_le32(data2_set); - target_cmd.op2 = cpu_to_le32(data2_clr); - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data1); - if (ret < 0) { - IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); - return ret; - } - - target_cmd.opcode = UMAC_HDI_OUT_OPCODE_WRITE; - target_cmd.addr = cpu_to_le32(addr3); - target_cmd.op1_sz = cpu_to_le32(sizeof(u32)); - target_cmd.op2 = 0; - - ret = iwm_hal_send_target_cmd(iwm, &target_cmd, &data3); - if (ret < 0) { - IWM_ERR(iwm, "iwm_hal_send_target_cmd failed\n"); - return ret; - } - } - - return 0; -} - -void iwm_init_default_profile(struct iwm_priv *iwm, - struct iwm_umac_profile *profile) -{ - memset(profile, 0, sizeof(struct iwm_umac_profile)); - - profile->sec.auth_type = UMAC_AUTH_TYPE_OPEN; - profile->sec.flags = UMAC_SEC_FLG_LEGACY_PROFILE; - profile->sec.ucast_cipher = UMAC_CIPHER_TYPE_NONE; - profile->sec.mcast_cipher = UMAC_CIPHER_TYPE_NONE; - - if (iwm->conf.enable_qos) - profile->flags |= cpu_to_le16(UMAC_PROFILE_QOS_ALLOWED); - - profile->wireless_mode = iwm->conf.wireless_mode; - profile->mode = cpu_to_le32(iwm->conf.mode); - - profile->ibss.atim = 0; - profile->ibss.beacon_interval = 100; - profile->ibss.join_only = 0; - profile->ibss.band = iwm->conf.ibss_band; - profile->ibss.channel = iwm->conf.ibss_channel; -} - -void iwm_link_on(struct iwm_priv *iwm) -{ - netif_carrier_on(iwm_to_ndev(iwm)); - netif_tx_wake_all_queues(iwm_to_ndev(iwm)); - - iwm_send_umac_stats_req(iwm, 0); -} - -void iwm_link_off(struct iwm_priv *iwm) -{ - struct iw_statistics *wstats = &iwm->wstats; - int i; - - netif_tx_stop_all_queues(iwm_to_ndev(iwm)); - netif_carrier_off(iwm_to_ndev(iwm)); - - for (i = 0; i < IWM_TX_QUEUES; i++) { - skb_queue_purge(&iwm->txq[i].queue); - skb_queue_purge(&iwm->txq[i].stopped_queue); - - iwm->txq[i].concat_count = 0; - iwm->txq[i].concat_ptr = iwm->txq[i].concat_buf; - - flush_workqueue(iwm->txq[i].wq); - } - - iwm_rx_free(iwm); - - cancel_delayed_work_sync(&iwm->stats_request); - memset(wstats, 0, sizeof(struct iw_statistics)); - wstats->qual.updated = IW_QUAL_ALL_INVALID; - - kfree(iwm->req_ie); - iwm->req_ie = NULL; - iwm->req_ie_len = 0; - kfree(iwm->resp_ie); - iwm->resp_ie = NULL; - iwm->resp_ie_len = 0; - - del_timer_sync(&iwm->watchdog); -} - -static void iwm_bss_list_clean(struct iwm_priv *iwm) -{ - struct iwm_bss_info *bss, *next; - - list_for_each_entry_safe(bss, next, &iwm->bss_list, node) { - list_del(&bss->node); - kfree(bss->bss); - kfree(bss); - } -} - -static int iwm_channels_init(struct iwm_priv *iwm) -{ - int ret; - - ret = iwm_send_umac_channel_list(iwm); - if (ret) { - IWM_ERR(iwm, "Send channel list failed\n"); - return ret; - } - - ret = iwm_notif_handle(iwm, UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST, - IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Didn't get a channel list notification\n"); - return ret; - } - - return 0; -} - -static int __iwm_up(struct iwm_priv *iwm) -{ - int ret; - struct iwm_notif *notif_reboot, *notif_ack = NULL; - struct wiphy *wiphy = iwm_to_wiphy(iwm); - u32 wireless_mode; - - ret = iwm_bus_enable(iwm); - if (ret) { - IWM_ERR(iwm, "Couldn't enable function\n"); - return ret; - } - - iwm_rx_setup_handlers(iwm); - - /* Wait for initial BARKER_REBOOT from hardware */ - notif_reboot = iwm_notif_wait(iwm, IWM_BARKER_REBOOT_NOTIFICATION, - IWM_SRC_UDMA, 2 * HZ); - if (!notif_reboot) { - IWM_ERR(iwm, "Wait for REBOOT_BARKER timeout\n"); - goto err_disable; - } - - /* We send the barker back */ - ret = iwm_bus_send_chunk(iwm, notif_reboot->buf, 16); - if (ret) { - IWM_ERR(iwm, "REBOOT barker response failed\n"); - kfree(notif_reboot); - goto err_disable; - } - - kfree(notif_reboot->buf); - kfree(notif_reboot); - - /* Wait for ACK_BARKER from hardware */ - notif_ack = iwm_notif_wait(iwm, IWM_ACK_BARKER_NOTIFICATION, - IWM_SRC_UDMA, 2 * HZ); - if (!notif_ack) { - IWM_ERR(iwm, "Wait for ACK_BARKER timeout\n"); - goto err_disable; - } - - kfree(notif_ack->buf); - kfree(notif_ack); - - /* We start to config static boot parameters */ - ret = iwm_config_boot_params(iwm); - if (ret) { - IWM_ERR(iwm, "Config boot parameters failed\n"); - goto err_disable; - } - - ret = iwm_read_mac(iwm, iwm_to_ndev(iwm)->dev_addr); - if (ret) { - IWM_ERR(iwm, "MAC reading failed\n"); - goto err_disable; - } - memcpy(iwm_to_ndev(iwm)->perm_addr, iwm_to_ndev(iwm)->dev_addr, - ETH_ALEN); - - /* We can load the FWs */ - ret = iwm_load_fw(iwm); - if (ret) { - IWM_ERR(iwm, "FW loading failed\n"); - goto err_disable; - } - - ret = iwm_eeprom_fat_channels(iwm); - if (ret) { - IWM_ERR(iwm, "Couldnt read HT channels EEPROM entries\n"); - goto err_fw; - } - - /* - * Read our SKU capabilities. - * If it's valid, we AND the configured wireless mode with the - * device EEPROM value as the current profile wireless mode. - */ - wireless_mode = iwm_eeprom_wireless_mode(iwm); - if (wireless_mode) { - iwm->conf.wireless_mode &= wireless_mode; - if (iwm->umac_profile) - iwm->umac_profile->wireless_mode = - iwm->conf.wireless_mode; - } else - IWM_ERR(iwm, "Wrong SKU capabilities: 0x%x\n", - *((u16 *)iwm_eeprom_access(iwm, IWM_EEPROM_SKU_CAP))); - - snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "L%s_U%s", - iwm->lmac_version, iwm->umac_version); - - /* We configure the UMAC and enable the wifi module */ - ret = iwm_send_umac_config(iwm, - cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_CORE_EN) | - cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_LINK_EN) | - cpu_to_le32(UMAC_RST_CTRL_FLG_WIFI_MLME_EN)); - if (ret) { - IWM_ERR(iwm, "UMAC config failed\n"); - goto err_fw; - } - - ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, - IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Didn't get a wifi core status notification\n"); - goto err_fw; - } - - if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | - UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { - IWM_DBG_BOOT(iwm, DBG, "Not all cores enabled:0x%x\n", - iwm->core_enabled); - ret = iwm_notif_handle(iwm, UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS, - IWM_SRC_UMAC, WAIT_NOTIF_TIMEOUT); - if (ret) { - IWM_ERR(iwm, "Didn't get a core status notification\n"); - goto err_fw; - } - - if (iwm->core_enabled != (UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN | - UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN)) { - IWM_ERR(iwm, "Not all cores enabled: 0x%x\n", - iwm->core_enabled); - goto err_fw; - } else { - IWM_INFO(iwm, "All cores enabled\n"); - } - } - - ret = iwm_channels_init(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't init channels\n"); - goto err_fw; - } - - /* Set the READY bit to indicate interface is brought up successfully */ - set_bit(IWM_STATUS_READY, &iwm->status); - - return 0; - - err_fw: - iwm_eeprom_exit(iwm); - - err_disable: - ret = iwm_bus_disable(iwm); - if (ret < 0) - IWM_ERR(iwm, "Couldn't disable function\n"); - - return -EIO; -} - -int iwm_up(struct iwm_priv *iwm) -{ - int ret; - - mutex_lock(&iwm->mutex); - ret = __iwm_up(iwm); - mutex_unlock(&iwm->mutex); - - return ret; -} - -static int __iwm_down(struct iwm_priv *iwm) -{ - int ret; - - /* The interface is already down */ - if (!test_bit(IWM_STATUS_READY, &iwm->status)) - return 0; - - if (iwm->scan_request) { - cfg80211_scan_done(iwm->scan_request, true); - iwm->scan_request = NULL; - } - - clear_bit(IWM_STATUS_READY, &iwm->status); - - iwm_eeprom_exit(iwm); - iwm_bss_list_clean(iwm); - iwm_init_default_profile(iwm, iwm->umac_profile); - iwm->umac_profile_active = false; - iwm->default_key = -1; - iwm->core_enabled = 0; - - ret = iwm_bus_disable(iwm); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't disable function\n"); - return ret; - } - - return 0; -} - -int iwm_down(struct iwm_priv *iwm) -{ - int ret; - - mutex_lock(&iwm->mutex); - ret = __iwm_down(iwm); - mutex_unlock(&iwm->mutex); - - return ret; -} diff --git a/drivers/net/wireless/iwmc3200wifi/netdev.c b/drivers/net/wireless/iwmc3200wifi/netdev.c deleted file mode 100644 index 5091d77e02ce..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/netdev.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License version - * 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. - * - */ - -/* - * This is the netdev related hooks for iwm. - * - * Some interesting code paths: - * - * iwm_open() (Called at netdev interface bringup time) - * -> iwm_up() (main.c) - * -> iwm_bus_enable() - * -> if_sdio_enable() (In case of an SDIO bus) - * -> sdio_enable_func() - * -> iwm_notif_wait(BARKER_REBOOT) (wait for reboot barker) - * -> iwm_notif_wait(ACK_BARKER) (wait for ACK barker) - * -> iwm_load_fw() (fw.c) - * -> iwm_load_umac() - * -> iwm_load_lmac() (Calibration LMAC) - * -> iwm_load_lmac() (Operational LMAC) - * -> iwm_send_umac_config() - * - * iwm_stop() (Called at netdev interface bringdown time) - * -> iwm_down() - * -> iwm_bus_disable() - * -> if_sdio_disable() (In case of an SDIO bus) - * -> sdio_disable_func() - */ -#include <linux/netdevice.h> -#include <linux/slab.h> - -#include "iwm.h" -#include "commands.h" -#include "cfg80211.h" -#include "debug.h" - -static int iwm_open(struct net_device *ndev) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - - return iwm_up(iwm); -} - -static int iwm_stop(struct net_device *ndev) -{ - struct iwm_priv *iwm = ndev_to_iwm(ndev); - - return iwm_down(iwm); -} - -/* - * iwm AC to queue mapping - * - * AC_VO -> queue 3 - * AC_VI -> queue 2 - * AC_BE -> queue 1 - * AC_BK -> queue 0 - */ -static const u16 iwm_1d_to_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 }; - -int iwm_tid_to_queue(u16 tid) -{ - if (tid > IWM_UMAC_TID_NR - 2) - return -EINVAL; - - return iwm_1d_to_queue[tid]; -} - -static u16 iwm_select_queue(struct net_device *dev, struct sk_buff *skb) -{ - skb->priority = cfg80211_classify8021d(skb); - - return iwm_1d_to_queue[skb->priority]; -} - -static const struct net_device_ops iwm_netdev_ops = { - .ndo_open = iwm_open, - .ndo_stop = iwm_stop, - .ndo_start_xmit = iwm_xmit_frame, - .ndo_select_queue = iwm_select_queue, -}; - -void *iwm_if_alloc(int sizeof_bus, struct device *dev, - struct iwm_if_ops *if_ops) -{ - struct net_device *ndev; - struct wireless_dev *wdev; - struct iwm_priv *iwm; - int ret = 0; - - wdev = iwm_wdev_alloc(sizeof_bus, dev); - if (IS_ERR(wdev)) - return wdev; - - iwm = wdev_to_iwm(wdev); - iwm->bus_ops = if_ops; - iwm->wdev = wdev; - - ret = iwm_priv_init(iwm); - if (ret) { - dev_err(dev, "failed to init iwm_priv\n"); - goto out_wdev; - } - - wdev->iftype = iwm_mode_to_nl80211_iftype(iwm->conf.mode); - - ndev = alloc_netdev_mq(0, "wlan%d", ether_setup, IWM_TX_QUEUES); - if (!ndev) { - dev_err(dev, "no memory for network device instance\n"); - ret = -ENOMEM; - goto out_priv; - } - - ndev->netdev_ops = &iwm_netdev_ops; - ndev->ieee80211_ptr = wdev; - SET_NETDEV_DEV(ndev, wiphy_dev(wdev->wiphy)); - wdev->netdev = ndev; - - iwm->umac_profile = kmalloc(sizeof(struct iwm_umac_profile), - GFP_KERNEL); - if (!iwm->umac_profile) { - dev_err(dev, "Couldn't alloc memory for profile\n"); - ret = -ENOMEM; - goto out_profile; - } - - iwm_init_default_profile(iwm, iwm->umac_profile); - - return iwm; - - out_profile: - free_netdev(ndev); - - out_priv: - iwm_priv_deinit(iwm); - - out_wdev: - iwm_wdev_free(iwm); - return ERR_PTR(ret); -} - -void iwm_if_free(struct iwm_priv *iwm) -{ - if (!iwm_to_ndev(iwm)) - return; - - cancel_delayed_work_sync(&iwm->ct_kill_delay); - free_netdev(iwm_to_ndev(iwm)); - iwm_priv_deinit(iwm); - kfree(iwm->umac_profile); - iwm->umac_profile = NULL; - iwm_wdev_free(iwm); -} - -int iwm_if_add(struct iwm_priv *iwm) -{ - struct net_device *ndev = iwm_to_ndev(iwm); - int ret; - - ret = register_netdev(ndev); - if (ret < 0) { - dev_err(&ndev->dev, "Failed to register netdev: %d\n", ret); - return ret; - } - - return 0; -} - -void iwm_if_remove(struct iwm_priv *iwm) -{ - unregister_netdev(iwm_to_ndev(iwm)); -} diff --git a/drivers/net/wireless/iwmc3200wifi/rx.c b/drivers/net/wireless/iwmc3200wifi/rx.c deleted file mode 100644 index 7d708f4395f3..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rx.c +++ /dev/null @@ -1,1701 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#include <linux/kernel.h> -#include <linux/netdevice.h> -#include <linux/sched.h> -#include <linux/etherdevice.h> -#include <linux/wireless.h> -#include <linux/ieee80211.h> -#include <linux/if_arp.h> -#include <linux/list.h> -#include <linux/slab.h> -#include <net/iw_handler.h> - -#include "iwm.h" -#include "debug.h" -#include "hal.h" -#include "umac.h" -#include "lmac.h" -#include "commands.h" -#include "rx.h" -#include "cfg80211.h" -#include "eeprom.h" - -static int iwm_rx_check_udma_hdr(struct iwm_udma_in_hdr *hdr) -{ - if ((le32_to_cpu(hdr->cmd) == UMAC_PAD_TERMINAL) || - (le32_to_cpu(hdr->size) == UMAC_PAD_TERMINAL)) - return -EINVAL; - - return 0; -} - -static inline int iwm_rx_resp_size(struct iwm_udma_in_hdr *hdr) -{ - return ALIGN(le32_to_cpu(hdr->size) + sizeof(struct iwm_udma_in_hdr), - 16); -} - -/* - * Notification handlers: - * - * For every possible notification we can receive from the - * target, we have a handler. - * When we get a target notification, and there is no one - * waiting for it, it's just processed through the rx code - * path: - * - * iwm_rx_handle() - * -> iwm_rx_handle_umac() - * -> iwm_rx_handle_wifi() - * -> iwm_rx_handle_resp() - * -> iwm_ntf_*() - * - * OR - * - * -> iwm_rx_handle_non_wifi() - * - * If there are processes waiting for this notification, then - * iwm_rx_handle_wifi() just wakes those processes up and they - * grab the pending notification. - */ -static int iwm_ntf_error(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_error *error; - struct iwm_fw_error_hdr *fw_err; - - error = (struct iwm_umac_notif_error *)buf; - fw_err = &error->err; - - memcpy(iwm->last_fw_err, fw_err, sizeof(struct iwm_fw_error_hdr)); - - IWM_ERR(iwm, "%cMAC FW ERROR:\n", - (le32_to_cpu(fw_err->category) == UMAC_SYS_ERR_CAT_LMAC) ? 'L' : 'U'); - IWM_ERR(iwm, "\tCategory: %d\n", le32_to_cpu(fw_err->category)); - IWM_ERR(iwm, "\tStatus: 0x%x\n", le32_to_cpu(fw_err->status)); - IWM_ERR(iwm, "\tPC: 0x%x\n", le32_to_cpu(fw_err->pc)); - IWM_ERR(iwm, "\tblink1: %d\n", le32_to_cpu(fw_err->blink1)); - IWM_ERR(iwm, "\tblink2: %d\n", le32_to_cpu(fw_err->blink2)); - IWM_ERR(iwm, "\tilink1: %d\n", le32_to_cpu(fw_err->ilink1)); - IWM_ERR(iwm, "\tilink2: %d\n", le32_to_cpu(fw_err->ilink2)); - IWM_ERR(iwm, "\tData1: 0x%x\n", le32_to_cpu(fw_err->data1)); - IWM_ERR(iwm, "\tData2: 0x%x\n", le32_to_cpu(fw_err->data2)); - IWM_ERR(iwm, "\tLine number: %d\n", le32_to_cpu(fw_err->line_num)); - IWM_ERR(iwm, "\tUMAC status: 0x%x\n", le32_to_cpu(fw_err->umac_status)); - IWM_ERR(iwm, "\tLMAC status: 0x%x\n", le32_to_cpu(fw_err->lmac_status)); - IWM_ERR(iwm, "\tSDIO status: 0x%x\n", le32_to_cpu(fw_err->sdio_status)); - - iwm_resetting(iwm); - - return 0; -} - -static int iwm_ntf_umac_alive(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_alive *alive_resp = - (struct iwm_umac_notif_alive *)(buf); - u16 status = le16_to_cpu(alive_resp->status); - - if (status == UMAC_NTFY_ALIVE_STATUS_ERR) { - IWM_ERR(iwm, "Receive error UMAC_ALIVE\n"); - return -EIO; - } - - iwm_tx_credit_init_pools(iwm, alive_resp); - - return 0; -} - -static int iwm_ntf_init_complete(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct iwm_umac_notif_init_complete *init_complete = - (struct iwm_umac_notif_init_complete *)(buf); - u16 status = le16_to_cpu(init_complete->status); - bool blocked = (status == UMAC_NTFY_INIT_COMPLETE_STATUS_ERR); - - if (blocked) - IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is on (radio off)\n"); - else - IWM_DBG_NTF(iwm, DBG, "Hardware rf kill is off (radio on)\n"); - - wiphy_rfkill_set_hw_state(wiphy, blocked); - - return 0; -} - -static int iwm_ntf_tx_credit_update(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - int pool_nr, total_freed_pages; - unsigned long pool_map; - int i, id; - struct iwm_umac_notif_page_dealloc *dealloc = - (struct iwm_umac_notif_page_dealloc *)buf; - - pool_nr = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_CNT); - pool_map = GET_VAL32(dealloc->changes, UMAC_DEALLOC_NTFY_CHANGES_MSK); - - IWM_DBG_TX(iwm, DBG, "UMAC dealloc notification: pool nr %d, " - "update map 0x%lx\n", pool_nr, pool_map); - - spin_lock(&iwm->tx_credit.lock); - - for (i = 0; i < pool_nr; i++) { - id = GET_VAL32(dealloc->grp_info[i], - UMAC_DEALLOC_NTFY_GROUP_NUM); - if (test_bit(id, &pool_map)) { - total_freed_pages = GET_VAL32(dealloc->grp_info[i], - UMAC_DEALLOC_NTFY_PAGE_CNT); - iwm_tx_credit_inc(iwm, id, total_freed_pages); - } - } - - spin_unlock(&iwm->tx_credit.lock); - - return 0; -} - -static int iwm_ntf_umac_reset(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - IWM_DBG_NTF(iwm, DBG, "UMAC RESET done\n"); - - return 0; -} - -static int iwm_ntf_lmac_version(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - IWM_DBG_NTF(iwm, INFO, "LMAC Version: %x.%x\n", buf[9], buf[8]); - - return 0; -} - -static int iwm_ntf_tx(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_lmac_tx_resp *tx_resp; - struct iwm_umac_wifi_in_hdr *hdr; - - tx_resp = (struct iwm_lmac_tx_resp *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - hdr = (struct iwm_umac_wifi_in_hdr *)buf; - - IWM_DBG_TX(iwm, DBG, "REPLY_TX, buf size: %lu\n", buf_size); - - IWM_DBG_TX(iwm, DBG, "Seqnum: %d\n", - le16_to_cpu(hdr->sw_hdr.cmd.seq_num)); - IWM_DBG_TX(iwm, DBG, "\tFrame cnt: %d\n", tx_resp->frame_cnt); - IWM_DBG_TX(iwm, DBG, "\tRetry cnt: %d\n", - le16_to_cpu(tx_resp->retry_cnt)); - IWM_DBG_TX(iwm, DBG, "\tSeq ctl: %d\n", le16_to_cpu(tx_resp->seq_ctl)); - IWM_DBG_TX(iwm, DBG, "\tByte cnt: %d\n", - le16_to_cpu(tx_resp->byte_cnt)); - IWM_DBG_TX(iwm, DBG, "\tStatus: 0x%x\n", le32_to_cpu(tx_resp->status)); - - return 0; -} - - -static int iwm_ntf_calib_res(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - u8 opcode; - u8 *calib_buf; - struct iwm_lmac_calib_hdr *hdr = (struct iwm_lmac_calib_hdr *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - - opcode = hdr->opcode; - - BUG_ON(opcode >= CALIBRATION_CMD_NUM || - opcode < PHY_CALIBRATE_OPCODES_NUM); - - IWM_DBG_NTF(iwm, DBG, "Store calibration result for opcode: %d\n", - opcode); - - buf_size -= sizeof(struct iwm_umac_wifi_in_hdr); - calib_buf = iwm->calib_res[opcode].buf; - - if (!calib_buf || (iwm->calib_res[opcode].size < buf_size)) { - kfree(calib_buf); - calib_buf = kzalloc(buf_size, GFP_KERNEL); - if (!calib_buf) { - IWM_ERR(iwm, "Memory allocation failed: calib_res\n"); - return -ENOMEM; - } - iwm->calib_res[opcode].buf = calib_buf; - iwm->calib_res[opcode].size = buf_size; - } - - memcpy(calib_buf, hdr, buf_size); - set_bit(opcode - PHY_CALIBRATE_OPCODES_NUM, &iwm->calib_done_map); - - return 0; -} - -static int iwm_ntf_calib_complete(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - IWM_DBG_NTF(iwm, DBG, "Calibration completed\n"); - - return 0; -} - -static int iwm_ntf_calib_cfg(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_lmac_cal_cfg_resp *cal_resp; - - cal_resp = (struct iwm_lmac_cal_cfg_resp *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - - IWM_DBG_NTF(iwm, DBG, "Calibration CFG command status: %d\n", - le32_to_cpu(cal_resp->status)); - - return 0; -} - -static int iwm_ntf_wifi_status(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_wifi_status *status = - (struct iwm_umac_notif_wifi_status *)buf; - - iwm->core_enabled |= le16_to_cpu(status->status); - - return 0; -} - -static struct iwm_rx_ticket_node * -iwm_rx_ticket_node_alloc(struct iwm_priv *iwm, struct iwm_rx_ticket *ticket) -{ - struct iwm_rx_ticket_node *ticket_node; - - ticket_node = kzalloc(sizeof(struct iwm_rx_ticket_node), GFP_KERNEL); - if (!ticket_node) { - IWM_ERR(iwm, "Couldn't allocate ticket node\n"); - return ERR_PTR(-ENOMEM); - } - - ticket_node->ticket = kmemdup(ticket, sizeof(struct iwm_rx_ticket), - GFP_KERNEL); - if (!ticket_node->ticket) { - IWM_ERR(iwm, "Couldn't allocate RX ticket\n"); - kfree(ticket_node); - return ERR_PTR(-ENOMEM); - } - - INIT_LIST_HEAD(&ticket_node->node); - - return ticket_node; -} - -static void iwm_rx_ticket_node_free(struct iwm_rx_ticket_node *ticket_node) -{ - kfree(ticket_node->ticket); - kfree(ticket_node); -} - -static struct iwm_rx_packet *iwm_rx_packet_get(struct iwm_priv *iwm, u16 id) -{ - u8 id_hash = IWM_RX_ID_GET_HASH(id); - struct iwm_rx_packet *packet; - - spin_lock(&iwm->packet_lock[id_hash]); - list_for_each_entry(packet, &iwm->rx_packets[id_hash], node) - if (packet->id == id) { - list_del(&packet->node); - spin_unlock(&iwm->packet_lock[id_hash]); - return packet; - } - - spin_unlock(&iwm->packet_lock[id_hash]); - return NULL; -} - -static struct iwm_rx_packet *iwm_rx_packet_alloc(struct iwm_priv *iwm, u8 *buf, - u32 size, u16 id) -{ - struct iwm_rx_packet *packet; - - packet = kzalloc(sizeof(struct iwm_rx_packet), GFP_KERNEL); - if (!packet) { - IWM_ERR(iwm, "Couldn't allocate packet\n"); - return ERR_PTR(-ENOMEM); - } - - packet->skb = dev_alloc_skb(size); - if (!packet->skb) { - IWM_ERR(iwm, "Couldn't allocate packet SKB\n"); - kfree(packet); - return ERR_PTR(-ENOMEM); - } - - packet->pkt_size = size; - - skb_put(packet->skb, size); - memcpy(packet->skb->data, buf, size); - INIT_LIST_HEAD(&packet->node); - packet->id = id; - - return packet; -} - -void iwm_rx_free(struct iwm_priv *iwm) -{ - struct iwm_rx_ticket_node *ticket, *nt; - struct iwm_rx_packet *packet, *np; - int i; - - spin_lock(&iwm->ticket_lock); - list_for_each_entry_safe(ticket, nt, &iwm->rx_tickets, node) { - list_del(&ticket->node); - iwm_rx_ticket_node_free(ticket); - } - spin_unlock(&iwm->ticket_lock); - - for (i = 0; i < IWM_RX_ID_HASH; i++) { - spin_lock(&iwm->packet_lock[i]); - list_for_each_entry_safe(packet, np, &iwm->rx_packets[i], - node) { - list_del(&packet->node); - kfree_skb(packet->skb); - kfree(packet); - } - spin_unlock(&iwm->packet_lock[i]); - } -} - -static int iwm_ntf_rx_ticket(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_rx_ticket *ntf_rx_ticket = - (struct iwm_umac_notif_rx_ticket *)buf; - struct iwm_rx_ticket *ticket = - (struct iwm_rx_ticket *)ntf_rx_ticket->tickets; - int i, schedule_rx = 0; - - for (i = 0; i < ntf_rx_ticket->num_tickets; i++) { - struct iwm_rx_ticket_node *ticket_node; - - switch (le16_to_cpu(ticket->action)) { - case IWM_RX_TICKET_RELEASE: - case IWM_RX_TICKET_DROP: - /* We can push the packet to the stack */ - ticket_node = iwm_rx_ticket_node_alloc(iwm, ticket); - if (IS_ERR(ticket_node)) - return PTR_ERR(ticket_node); - - IWM_DBG_RX(iwm, DBG, "TICKET %s(%d)\n", - __le16_to_cpu(ticket->action) == - IWM_RX_TICKET_RELEASE ? - "RELEASE" : "DROP", - ticket->id); - spin_lock(&iwm->ticket_lock); - list_add_tail(&ticket_node->node, &iwm->rx_tickets); - spin_unlock(&iwm->ticket_lock); - - /* - * We received an Rx ticket, most likely there's - * a packet pending for it, it's not worth going - * through the packet hash list to double check. - * Let's just fire the rx worker.. - */ - schedule_rx = 1; - - break; - - default: - IWM_ERR(iwm, "Invalid RX ticket action: 0x%x\n", - ticket->action); - } - - ticket++; - } - - if (schedule_rx) - queue_work(iwm->rx_wq, &iwm->rx_worker); - - return 0; -} - -static int iwm_ntf_rx_packet(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_wifi_in_hdr *wifi_hdr; - struct iwm_rx_packet *packet; - u16 id, buf_offset; - u32 packet_size; - u8 id_hash; - - IWM_DBG_RX(iwm, DBG, "\n"); - - wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; - id = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); - buf_offset = sizeof(struct iwm_umac_wifi_in_hdr); - packet_size = buf_size - sizeof(struct iwm_umac_wifi_in_hdr); - - IWM_DBG_RX(iwm, DBG, "CMD:0x%x, seqnum: %d, packet size: %d\n", - wifi_hdr->sw_hdr.cmd.cmd, id, packet_size); - IWM_DBG_RX(iwm, DBG, "Packet id: %d\n", id); - IWM_HEXDUMP(iwm, DBG, RX, "PACKET: ", buf + buf_offset, packet_size); - - packet = iwm_rx_packet_alloc(iwm, buf + buf_offset, packet_size, id); - if (IS_ERR(packet)) - return PTR_ERR(packet); - - id_hash = IWM_RX_ID_GET_HASH(id); - spin_lock(&iwm->packet_lock[id_hash]); - list_add_tail(&packet->node, &iwm->rx_packets[id_hash]); - spin_unlock(&iwm->packet_lock[id_hash]); - - /* We might (unlikely) have received the packet _after_ the ticket */ - queue_work(iwm->rx_wq, &iwm->rx_worker); - - return 0; -} - -/* MLME handlers */ -static int iwm_mlme_assoc_start(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_assoc_start *start; - - start = (struct iwm_umac_notif_assoc_start *)buf; - - IWM_DBG_MLME(iwm, INFO, "Association with %pM Started, reason: %d\n", - start->bssid, le32_to_cpu(start->roam_reason)); - - wake_up_interruptible(&iwm->mlme_queue); - - return 0; -} - -static u8 iwm_is_open_wep_profile(struct iwm_priv *iwm) -{ - if ((iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_40 || - iwm->umac_profile->sec.ucast_cipher == UMAC_CIPHER_TYPE_WEP_104) && - (iwm->umac_profile->sec.ucast_cipher == - iwm->umac_profile->sec.mcast_cipher) && - (iwm->umac_profile->sec.auth_type == UMAC_AUTH_TYPE_OPEN)) - return 1; - - return 0; -} - -static int iwm_mlme_assoc_complete(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct ieee80211_channel *chan; - struct iwm_umac_notif_assoc_complete *complete = - (struct iwm_umac_notif_assoc_complete *)buf; - - IWM_DBG_MLME(iwm, INFO, "Association with %pM completed, status: %d\n", - complete->bssid, complete->status); - - switch (le32_to_cpu(complete->status)) { - case UMAC_ASSOC_COMPLETE_SUCCESS: - chan = ieee80211_get_channel(wiphy, - ieee80211_channel_to_frequency(complete->channel, - complete->band == UMAC_BAND_2GHZ ? - IEEE80211_BAND_2GHZ : - IEEE80211_BAND_5GHZ)); - if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) { - /* Associated to a unallowed channel, disassociate. */ - __iwm_invalidate_mlme_profile(iwm); - IWM_WARN(iwm, "Couldn't associate with %pM due to " - "channel %d is disabled. Check your local " - "regulatory setting.\n", - complete->bssid, complete->channel); - goto failure; - } - - set_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - memcpy(iwm->bssid, complete->bssid, ETH_ALEN); - iwm->channel = complete->channel; - - /* Internal roaming state, avoid notifying SME. */ - if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) - && iwm->conf.mode == UMAC_MODE_BSS) { - cancel_delayed_work(&iwm->disconnect); - cfg80211_roamed(iwm_to_ndev(iwm), NULL, - complete->bssid, - iwm->req_ie, iwm->req_ie_len, - iwm->resp_ie, iwm->resp_ie_len, - GFP_KERNEL); - break; - } - - iwm_link_on(iwm); - - if (iwm->conf.mode == UMAC_MODE_IBSS) - goto ibss; - - if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) - cfg80211_connect_result(iwm_to_ndev(iwm), - complete->bssid, - iwm->req_ie, iwm->req_ie_len, - iwm->resp_ie, iwm->resp_ie_len, - WLAN_STATUS_SUCCESS, - GFP_KERNEL); - else - cfg80211_roamed(iwm_to_ndev(iwm), NULL, - complete->bssid, - iwm->req_ie, iwm->req_ie_len, - iwm->resp_ie, iwm->resp_ie_len, - GFP_KERNEL); - break; - case UMAC_ASSOC_COMPLETE_FAILURE: - failure: - clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - memset(iwm->bssid, 0, ETH_ALEN); - iwm->channel = 0; - - /* Internal roaming state, avoid notifying SME. */ - if (!test_and_clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status) - && iwm->conf.mode == UMAC_MODE_BSS) { - cancel_delayed_work(&iwm->disconnect); - break; - } - - iwm_link_off(iwm); - - if (iwm->conf.mode == UMAC_MODE_IBSS) - goto ibss; - - if (!test_bit(IWM_STATUS_RESETTING, &iwm->status)) - if (!iwm_is_open_wep_profile(iwm)) { - cfg80211_connect_result(iwm_to_ndev(iwm), - complete->bssid, - NULL, 0, NULL, 0, - WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - } else { - /* Let's try shared WEP auth */ - IWM_ERR(iwm, "Trying WEP shared auth\n"); - schedule_work(&iwm->auth_retry_worker); - } - else - cfg80211_disconnected(iwm_to_ndev(iwm), 0, NULL, 0, - GFP_KERNEL); - break; - default: - break; - } - - clear_bit(IWM_STATUS_RESETTING, &iwm->status); - return 0; - - ibss: - cfg80211_ibss_joined(iwm_to_ndev(iwm), iwm->bssid, GFP_KERNEL); - clear_bit(IWM_STATUS_RESETTING, &iwm->status); - return 0; -} - -static int iwm_mlme_profile_invalidate(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_profile_invalidate *invalid; - u32 reason; - - invalid = (struct iwm_umac_notif_profile_invalidate *)buf; - reason = le32_to_cpu(invalid->reason); - - IWM_DBG_MLME(iwm, INFO, "Profile Invalidated. Reason: %d\n", reason); - - if (reason != UMAC_PROFILE_INVALID_REQUEST && - test_bit(IWM_STATUS_SME_CONNECTING, &iwm->status)) - cfg80211_connect_result(iwm_to_ndev(iwm), NULL, NULL, 0, NULL, - 0, WLAN_STATUS_UNSPECIFIED_FAILURE, - GFP_KERNEL); - - clear_bit(IWM_STATUS_SME_CONNECTING, &iwm->status); - clear_bit(IWM_STATUS_ASSOCIATED, &iwm->status); - - iwm->umac_profile_active = false; - memset(iwm->bssid, 0, ETH_ALEN); - iwm->channel = 0; - - iwm_link_off(iwm); - - wake_up_interruptible(&iwm->mlme_queue); - - return 0; -} - -#define IWM_DISCONNECT_INTERVAL (5 * HZ) - -static int iwm_mlme_connection_terminated(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - IWM_DBG_MLME(iwm, DBG, "Connection terminated\n"); - - schedule_delayed_work(&iwm->disconnect, IWM_DISCONNECT_INTERVAL); - - return 0; -} - -static int iwm_mlme_scan_complete(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - int ret; - struct iwm_umac_notif_scan_complete *scan_complete = - (struct iwm_umac_notif_scan_complete *)buf; - u32 result = le32_to_cpu(scan_complete->result); - - IWM_DBG_MLME(iwm, INFO, "type:0x%x result:0x%x seq:%d\n", - le32_to_cpu(scan_complete->type), - le32_to_cpu(scan_complete->result), - scan_complete->seq_num); - - if (!test_and_clear_bit(IWM_STATUS_SCANNING, &iwm->status)) { - IWM_ERR(iwm, "Scan complete while device not scanning\n"); - return -EIO; - } - if (!iwm->scan_request) - return 0; - - ret = iwm_cfg80211_inform_bss(iwm); - - cfg80211_scan_done(iwm->scan_request, - (result & UMAC_SCAN_RESULT_ABORTED) ? 1 : !!ret); - iwm->scan_request = NULL; - - return ret; -} - -static int iwm_mlme_update_sta_table(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_sta_info *umac_sta = - (struct iwm_umac_notif_sta_info *)buf; - struct iwm_sta_info *sta; - int i; - - switch (le32_to_cpu(umac_sta->opcode)) { - case UMAC_OPCODE_ADD_MODIFY: - sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; - - IWM_DBG_MLME(iwm, INFO, "%s STA: ID = %d, Color = %d, " - "addr = %pM, qos = %d\n", - sta->valid ? "Modify" : "Add", - GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), - GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), - umac_sta->mac_addr, - umac_sta->flags & UMAC_STA_FLAG_QOS); - - sta->valid = true; - sta->qos = umac_sta->flags & UMAC_STA_FLAG_QOS; - sta->color = GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR); - memcpy(sta->addr, umac_sta->mac_addr, ETH_ALEN); - break; - case UMAC_OPCODE_REMOVE: - IWM_DBG_MLME(iwm, INFO, "Remove STA: ID = %d, Color = %d, " - "addr = %pM\n", - GET_VAL8(umac_sta->sta_id, LMAC_STA_ID), - GET_VAL8(umac_sta->sta_id, LMAC_STA_COLOR), - umac_sta->mac_addr); - - sta = &iwm->sta_table[GET_VAL8(umac_sta->sta_id, LMAC_STA_ID)]; - - if (!memcmp(sta->addr, umac_sta->mac_addr, ETH_ALEN)) - sta->valid = false; - - break; - case UMAC_OPCODE_CLEAR_ALL: - for (i = 0; i < IWM_STA_TABLE_NUM; i++) - iwm->sta_table[i].valid = false; - - break; - default: - break; - } - - return 0; -} - -static int iwm_mlme_medium_lost(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - - IWM_DBG_NTF(iwm, DBG, "WiFi/WiMax coexistence radio is OFF\n"); - - wiphy_rfkill_set_hw_state(wiphy, true); - - return 0; -} - -static int iwm_mlme_update_bss_table(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct ieee80211_mgmt *mgmt; - struct iwm_umac_notif_bss_info *umac_bss = - (struct iwm_umac_notif_bss_info *)buf; - struct ieee80211_channel *channel; - struct ieee80211_supported_band *band; - struct iwm_bss_info *bss; - s32 signal; - int freq; - u16 frame_len = le16_to_cpu(umac_bss->frame_len); - size_t bss_len = sizeof(struct iwm_umac_notif_bss_info) + frame_len; - - mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf); - - IWM_DBG_MLME(iwm, DBG, "New BSS info entry: %pM\n", mgmt->bssid); - IWM_DBG_MLME(iwm, DBG, "\tType: 0x%x\n", le32_to_cpu(umac_bss->type)); - IWM_DBG_MLME(iwm, DBG, "\tTimestamp: %d\n", - le32_to_cpu(umac_bss->timestamp)); - IWM_DBG_MLME(iwm, DBG, "\tTable Index: %d\n", - le16_to_cpu(umac_bss->table_idx)); - IWM_DBG_MLME(iwm, DBG, "\tBand: %d\n", umac_bss->band); - IWM_DBG_MLME(iwm, DBG, "\tChannel: %d\n", umac_bss->channel); - IWM_DBG_MLME(iwm, DBG, "\tRSSI: %d\n", umac_bss->rssi); - IWM_DBG_MLME(iwm, DBG, "\tFrame Length: %d\n", frame_len); - - list_for_each_entry(bss, &iwm->bss_list, node) - if (bss->bss->table_idx == umac_bss->table_idx) - break; - - if (&bss->node != &iwm->bss_list) { - /* Remove the old BSS entry, we will add it back later. */ - list_del(&bss->node); - kfree(bss->bss); - } else { - /* New BSS entry */ - - bss = kzalloc(sizeof(struct iwm_bss_info), GFP_KERNEL); - if (!bss) { - IWM_ERR(iwm, "Couldn't allocate bss_info\n"); - return -ENOMEM; - } - } - - bss->bss = kzalloc(bss_len, GFP_KERNEL); - if (!bss->bss) { - kfree(bss); - IWM_ERR(iwm, "Couldn't allocate bss\n"); - return -ENOMEM; - } - - INIT_LIST_HEAD(&bss->node); - memcpy(bss->bss, umac_bss, bss_len); - - if (umac_bss->band == UMAC_BAND_2GHZ) - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - else if (umac_bss->band == UMAC_BAND_5GHZ) - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - else { - IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band); - goto err; - } - - freq = ieee80211_channel_to_frequency(umac_bss->channel, band->band); - channel = ieee80211_get_channel(wiphy, freq); - signal = umac_bss->rssi * 100; - - bss->cfg_bss = cfg80211_inform_bss_frame(wiphy, channel, - mgmt, frame_len, - signal, GFP_KERNEL); - if (!bss->cfg_bss) - goto err; - - list_add_tail(&bss->node, &iwm->bss_list); - - return 0; - err: - kfree(bss->bss); - kfree(bss); - - return -EINVAL; -} - -static int iwm_mlme_remove_bss(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_bss_removed *bss_rm = - (struct iwm_umac_notif_bss_removed *)buf; - struct iwm_bss_info *bss, *next; - u16 table_idx; - int i; - - for (i = 0; i < le32_to_cpu(bss_rm->count); i++) { - table_idx = le16_to_cpu(bss_rm->entries[i]) & - IWM_BSS_REMOVE_INDEX_MSK; - list_for_each_entry_safe(bss, next, &iwm->bss_list, node) - if (bss->bss->table_idx == cpu_to_le16(table_idx)) { - struct ieee80211_mgmt *mgmt; - - mgmt = (struct ieee80211_mgmt *) - (bss->bss->frame_buf); - IWM_DBG_MLME(iwm, ERR, "BSS removed: %pM\n", - mgmt->bssid); - list_del(&bss->node); - kfree(bss->bss); - kfree(bss); - } - } - - return 0; -} - -static int iwm_mlme_mgt_frame(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_mgt_frame *mgt_frame = - (struct iwm_umac_notif_mgt_frame *)buf; - struct ieee80211_mgmt *mgt = (struct ieee80211_mgmt *)mgt_frame->frame; - - IWM_HEXDUMP(iwm, DBG, MLME, "MGT: ", mgt_frame->frame, - le16_to_cpu(mgt_frame->len)); - - if (ieee80211_is_assoc_req(mgt->frame_control)) { - iwm->req_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.assoc_req.variable); - kfree(iwm->req_ie); - iwm->req_ie = kmemdup(mgt->u.assoc_req.variable, - iwm->req_ie_len, GFP_KERNEL); - } else if (ieee80211_is_reassoc_req(mgt->frame_control)) { - iwm->req_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.reassoc_req.variable); - kfree(iwm->req_ie); - iwm->req_ie = kmemdup(mgt->u.reassoc_req.variable, - iwm->req_ie_len, GFP_KERNEL); - } else if (ieee80211_is_assoc_resp(mgt->frame_control)) { - iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.assoc_resp.variable); - kfree(iwm->resp_ie); - iwm->resp_ie = kmemdup(mgt->u.assoc_resp.variable, - iwm->resp_ie_len, GFP_KERNEL); - } else if (ieee80211_is_reassoc_resp(mgt->frame_control)) { - iwm->resp_ie_len = le16_to_cpu(mgt_frame->len) - - offsetof(struct ieee80211_mgmt, - u.reassoc_resp.variable); - kfree(iwm->resp_ie); - iwm->resp_ie = kmemdup(mgt->u.reassoc_resp.variable, - iwm->resp_ie_len, GFP_KERNEL); - } else { - IWM_ERR(iwm, "Unsupported management frame: 0x%x", - le16_to_cpu(mgt->frame_control)); - return 0; - } - - return 0; -} - -static int iwm_ntf_mlme(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_wifi_if *notif = - (struct iwm_umac_notif_wifi_if *)buf; - - switch (notif->status) { - case WIFI_IF_NTFY_ASSOC_START: - return iwm_mlme_assoc_start(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_ASSOC_COMPLETE: - return iwm_mlme_assoc_complete(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE: - return iwm_mlme_profile_invalidate(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_CONNECTION_TERMINATED: - return iwm_mlme_connection_terminated(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_SCAN_COMPLETE: - return iwm_mlme_scan_complete(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_STA_TABLE_CHANGE: - return iwm_mlme_update_sta_table(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_EXTENDED_IE_REQUIRED: - IWM_DBG_MLME(iwm, DBG, "Extended IE required\n"); - break; - case WIFI_IF_NTFY_RADIO_PREEMPTION: - return iwm_mlme_medium_lost(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED: - return iwm_mlme_update_bss_table(iwm, buf, buf_size, cmd); - case WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED: - return iwm_mlme_remove_bss(iwm, buf, buf_size, cmd); - break; - case WIFI_IF_NTFY_MGMT_FRAME: - return iwm_mlme_mgt_frame(iwm, buf, buf_size, cmd); - case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START: - case WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE: - case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START: - case WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT: - case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START: - case WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE: - case WIFI_DBG_IF_NTFY_CNCT_ATC_START: - case WIFI_DBG_IF_NTFY_COEX_NOTIFICATION: - case WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP: - case WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP: - IWM_DBG_MLME(iwm, DBG, "MLME debug notification: 0x%x\n", - notif->status); - break; - default: - IWM_ERR(iwm, "Unhandled notification: 0x%x\n", notif->status); - break; - } - - return 0; -} - -#define IWM_STATS_UPDATE_INTERVAL (2 * HZ) - -static int iwm_ntf_statistics(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_stats *stats = (struct iwm_umac_notif_stats *)buf; - struct iw_statistics *wstats = &iwm->wstats; - u16 max_rate = 0; - int i; - - IWM_DBG_MLME(iwm, DBG, "Statistics notification received\n"); - - if (test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - for (i = 0; i < UMAC_NTF_RATE_SAMPLE_NR; i++) { - max_rate = max_t(u16, max_rate, - max(le16_to_cpu(stats->tx_rate[i]), - le16_to_cpu(stats->rx_rate[i]))); - } - /* UMAC passes rate info multiplies by 2 */ - iwm->rate = max_rate >> 1; - } - iwm->txpower = le32_to_cpu(stats->tx_power); - - wstats->status = 0; - - wstats->discard.nwid = le32_to_cpu(stats->rx_drop_other_bssid); - wstats->discard.code = le32_to_cpu(stats->rx_drop_decode); - wstats->discard.fragment = le32_to_cpu(stats->rx_drop_reassembly); - wstats->discard.retries = le32_to_cpu(stats->tx_drop_max_retry); - - wstats->miss.beacon = le32_to_cpu(stats->missed_beacons); - - /* according to cfg80211 */ - if (stats->rssi_dbm < -110) - wstats->qual.qual = 0; - else if (stats->rssi_dbm > -40) - wstats->qual.qual = 70; - else - wstats->qual.qual = stats->rssi_dbm + 110; - - wstats->qual.level = stats->rssi_dbm; - wstats->qual.noise = stats->noise_dbm; - wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; - - schedule_delayed_work(&iwm->stats_request, IWM_STATS_UPDATE_INTERVAL); - - mod_timer(&iwm->watchdog, round_jiffies(jiffies + IWM_WATCHDOG_PERIOD)); - - return 0; -} - -static int iwm_ntf_eeprom_proxy(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_cmd_eeprom_proxy *eeprom_proxy = - (struct iwm_umac_cmd_eeprom_proxy *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - struct iwm_umac_cmd_eeprom_proxy_hdr *hdr = &eeprom_proxy->hdr; - u32 hdr_offset = le32_to_cpu(hdr->offset); - u32 hdr_len = le32_to_cpu(hdr->len); - u32 hdr_type = le32_to_cpu(hdr->type); - - IWM_DBG_NTF(iwm, DBG, "type: 0x%x, len: %d, offset: 0x%x\n", - hdr_type, hdr_len, hdr_offset); - - if ((hdr_offset + hdr_len) > IWM_EEPROM_LEN) - return -EINVAL; - - switch (hdr_type) { - case IWM_UMAC_CMD_EEPROM_TYPE_READ: - memcpy(iwm->eeprom + hdr_offset, eeprom_proxy->buf, hdr_len); - break; - case IWM_UMAC_CMD_EEPROM_TYPE_WRITE: - default: - return -ENOTSUPP; - } - - return 0; -} - -static int iwm_ntf_channel_info_list(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_cmd_get_channel_list *ch_list = - (struct iwm_umac_cmd_get_channel_list *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct ieee80211_supported_band *band; - int i; - - band = wiphy->bands[IEEE80211_BAND_2GHZ]; - - for (i = 0; i < band->n_channels; i++) { - unsigned long ch_mask_0 = - le32_to_cpu(ch_list->ch[0].channels_mask); - unsigned long ch_mask_2 = - le32_to_cpu(ch_list->ch[2].channels_mask); - - if (!test_bit(i, &ch_mask_0)) - band->channels[i].flags |= IEEE80211_CHAN_DISABLED; - - if (!test_bit(i, &ch_mask_2)) - band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; - } - - band = wiphy->bands[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < min(band->n_channels, 32); i++) { - unsigned long ch_mask_1 = - le32_to_cpu(ch_list->ch[1].channels_mask); - unsigned long ch_mask_3 = - le32_to_cpu(ch_list->ch[3].channels_mask); - - if (!test_bit(i, &ch_mask_1)) - band->channels[i].flags |= IEEE80211_CHAN_DISABLED; - - if (!test_bit(i, &ch_mask_3)) - band->channels[i].flags |= IEEE80211_CHAN_NO_IBSS; - } - - return 0; -} - -static int iwm_ntf_stop_resume_tx(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_notif_stop_resume_tx *stp_res_tx = - (struct iwm_umac_notif_stop_resume_tx *)buf; - struct iwm_sta_info *sta_info; - struct iwm_tid_info *tid_info; - u8 sta_id = STA_ID_N_COLOR_ID(stp_res_tx->sta_id); - u16 tid_msk = le16_to_cpu(stp_res_tx->stop_resume_tid_msk); - int bit, ret = 0; - bool stop = false; - - IWM_DBG_NTF(iwm, DBG, "stop/resume notification:\n" - "\tflags: 0x%x\n" - "\tSTA id: %d\n" - "\tTID bitmask: 0x%x\n", - stp_res_tx->flags, stp_res_tx->sta_id, - stp_res_tx->stop_resume_tid_msk); - - if (stp_res_tx->flags & UMAC_STOP_TX_FLAG) - stop = true; - - sta_info = &iwm->sta_table[sta_id]; - if (!sta_info->valid) { - IWM_ERR(iwm, "Stoping an invalid STA: %d %d\n", - sta_id, stp_res_tx->sta_id); - return -EINVAL; - } - - for_each_set_bit(bit, (unsigned long *)&tid_msk, IWM_UMAC_TID_NR) { - tid_info = &sta_info->tid_info[bit]; - - mutex_lock(&tid_info->mutex); - tid_info->stopped = stop; - mutex_unlock(&tid_info->mutex); - - if (!stop) { - struct iwm_tx_queue *txq; - int queue = iwm_tid_to_queue(bit); - - if (queue < 0) - continue; - - txq = &iwm->txq[queue]; - /* - * If we resume, we have to move our SKBs - * back to the tx queue and queue some work. - */ - spin_lock_bh(&txq->lock); - skb_queue_splice_init(&txq->queue, &txq->stopped_queue); - spin_unlock_bh(&txq->lock); - - queue_work(txq->wq, &txq->worker); - } - - } - - /* We send an ACK only for the stop case */ - if (stop) - ret = iwm_send_umac_stop_resume_tx(iwm, stp_res_tx); - - return ret; -} - -static int iwm_ntf_wifi_if_wrapper(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - struct iwm_umac_wifi_if *hdr; - - if (cmd == NULL) { - IWM_ERR(iwm, "Couldn't find expected wifi command\n"); - return -EINVAL; - } - - hdr = (struct iwm_umac_wifi_if *)cmd->buf.payload; - - IWM_DBG_NTF(iwm, DBG, "WIFI_IF_WRAPPER cmd is delivered to UMAC: " - "oid is 0x%x\n", hdr->oid); - - set_bit(hdr->oid, &iwm->wifi_ntfy[0]); - wake_up_interruptible(&iwm->wifi_ntfy_queue); - - switch (hdr->oid) { - case UMAC_WIFI_IF_CMD_SET_PROFILE: - iwm->umac_profile_active = true; - break; - default: - break; - } - - return 0; -} - -#define CT_KILL_DELAY (30 * HZ) -static int iwm_ntf_card_state(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size, struct iwm_wifi_cmd *cmd) -{ - struct wiphy *wiphy = iwm_to_wiphy(iwm); - struct iwm_lmac_card_state *state = (struct iwm_lmac_card_state *) - (buf + sizeof(struct iwm_umac_wifi_in_hdr)); - u32 flags = le32_to_cpu(state->flags); - - IWM_INFO(iwm, "HW RF Kill %s, CT Kill %s\n", - flags & IWM_CARD_STATE_HW_DISABLED ? "ON" : "OFF", - flags & IWM_CARD_STATE_CTKILL_DISABLED ? "ON" : "OFF"); - - if (flags & IWM_CARD_STATE_CTKILL_DISABLED) { - /* - * We got a CTKILL event: We bring the interface down in - * oder to cool the device down, and try to bring it up - * 30 seconds later. If it's still too hot, we'll go through - * this code path again. - */ - cancel_delayed_work_sync(&iwm->ct_kill_delay); - schedule_delayed_work(&iwm->ct_kill_delay, CT_KILL_DELAY); - } - - wiphy_rfkill_set_hw_state(wiphy, flags & - (IWM_CARD_STATE_HW_DISABLED | - IWM_CARD_STATE_CTKILL_DISABLED)); - - return 0; -} - -static int iwm_rx_handle_wifi(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size) -{ - struct iwm_umac_wifi_in_hdr *wifi_hdr; - struct iwm_wifi_cmd *cmd; - u8 source, cmd_id; - u16 seq_num; - u32 count; - - wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; - cmd_id = wifi_hdr->sw_hdr.cmd.cmd; - source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); - if (source >= IWM_SRC_NUM) { - IWM_CRIT(iwm, "invalid source %d\n", source); - return -EINVAL; - } - - if (cmd_id == REPLY_RX_MPDU_CMD) - trace_iwm_rx_packet(iwm, buf, buf_size); - else if ((cmd_id == UMAC_NOTIFY_OPCODE_RX_TICKET) && - (source == UMAC_HDI_IN_SOURCE_FW)) - trace_iwm_rx_ticket(iwm, buf, buf_size); - else - trace_iwm_rx_wifi_cmd(iwm, wifi_hdr); - - count = GET_VAL32(wifi_hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT); - count += sizeof(struct iwm_umac_wifi_in_hdr) - - sizeof(struct iwm_dev_cmd_hdr); - if (count > buf_size) { - IWM_CRIT(iwm, "count %d, buf size:%ld\n", count, buf_size); - return -EINVAL; - } - - seq_num = le16_to_cpu(wifi_hdr->sw_hdr.cmd.seq_num); - - IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x, seqnum: %d\n", - cmd_id, source, seq_num); - - /* - * If this is a response to a previously sent command, there must - * be a pending command for this sequence number. - */ - cmd = iwm_get_pending_wifi_cmd(iwm, seq_num); - - /* Notify the caller only for sync commands. */ - switch (source) { - case UMAC_HDI_IN_SOURCE_FHRX: - if (iwm->lmac_handlers[cmd_id] && - test_bit(cmd_id, &iwm->lmac_handler_map[0])) - return iwm_notif_send(iwm, cmd, cmd_id, source, - buf, count); - break; - case UMAC_HDI_IN_SOURCE_FW: - if (iwm->umac_handlers[cmd_id] && - test_bit(cmd_id, &iwm->umac_handler_map[0])) - return iwm_notif_send(iwm, cmd, cmd_id, source, - buf, count); - break; - case UMAC_HDI_IN_SOURCE_UDMA: - break; - } - - return iwm_rx_handle_resp(iwm, buf, count, cmd); -} - -int iwm_rx_handle_resp(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size, - struct iwm_wifi_cmd *cmd) -{ - u8 source, cmd_id; - struct iwm_umac_wifi_in_hdr *wifi_hdr; - int ret = 0; - - wifi_hdr = (struct iwm_umac_wifi_in_hdr *)buf; - cmd_id = wifi_hdr->sw_hdr.cmd.cmd; - - source = GET_VAL32(wifi_hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); - - IWM_DBG_RX(iwm, DBG, "CMD:0x%x, source: 0x%x\n", cmd_id, source); - - switch (source) { - case UMAC_HDI_IN_SOURCE_FHRX: - if (iwm->lmac_handlers[cmd_id]) - ret = iwm->lmac_handlers[cmd_id] - (iwm, buf, buf_size, cmd); - break; - case UMAC_HDI_IN_SOURCE_FW: - if (iwm->umac_handlers[cmd_id]) - ret = iwm->umac_handlers[cmd_id] - (iwm, buf, buf_size, cmd); - break; - case UMAC_HDI_IN_SOURCE_UDMA: - ret = -EINVAL; - break; - } - - kfree(cmd); - - return ret; -} - -static int iwm_rx_handle_nonwifi(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size) -{ - u8 seq_num; - struct iwm_udma_in_hdr *hdr = (struct iwm_udma_in_hdr *)buf; - struct iwm_nonwifi_cmd *cmd; - - trace_iwm_rx_nonwifi_cmd(iwm, buf, buf_size); - seq_num = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); - - /* - * We received a non wifi answer. - * Let's check if there's a pending command for it, and if so - * replace the command payload with the buffer, and then wake the - * callers up. - * That means we only support synchronised non wifi command response - * schemes. - */ - list_for_each_entry(cmd, &iwm->nonwifi_pending_cmd, pending) - if (cmd->seq_num == seq_num) { - cmd->resp_received = true; - cmd->buf.len = buf_size; - memcpy(cmd->buf.hdr, buf, buf_size); - wake_up_interruptible(&iwm->nonwifi_queue); - } - - return 0; -} - -static int iwm_rx_handle_umac(struct iwm_priv *iwm, u8 *buf, - unsigned long buf_size) -{ - int ret = 0; - u8 op_code; - unsigned long buf_offset = 0; - struct iwm_udma_in_hdr *hdr; - - /* - * To allow for a more efficient bus usage, UMAC - * messages are encapsulated into UDMA ones. This - * way we can have several UMAC messages in one bus - * transfer. - * A UDMA frame size is always aligned on 16 bytes, - * and a UDMA frame must not start with a UMAC_PAD_TERMINAL - * word. This is how we parse a bus frame into several - * UDMA ones. - */ - while (buf_offset < buf_size) { - - hdr = (struct iwm_udma_in_hdr *)(buf + buf_offset); - - if (iwm_rx_check_udma_hdr(hdr) < 0) { - IWM_DBG_RX(iwm, DBG, "End of frame\n"); - break; - } - - op_code = GET_VAL32(hdr->cmd, UMAC_HDI_IN_CMD_OPCODE); - - IWM_DBG_RX(iwm, DBG, "Op code: 0x%x\n", op_code); - - if (op_code == UMAC_HDI_IN_OPCODE_WIFI) { - ret |= iwm_rx_handle_wifi(iwm, buf + buf_offset, - buf_size - buf_offset); - } else if (op_code < UMAC_HDI_IN_OPCODE_NONWIFI_MAX) { - if (GET_VAL32(hdr->cmd, - UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) != - UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG) { - IWM_ERR(iwm, "Incorrect hw signature\n"); - return -EINVAL; - } - ret |= iwm_rx_handle_nonwifi(iwm, buf + buf_offset, - buf_size - buf_offset); - } else { - IWM_ERR(iwm, "Invalid RX opcode: 0x%x\n", op_code); - ret |= -EINVAL; - } - - buf_offset += iwm_rx_resp_size(hdr); - } - - return ret; -} - -int iwm_rx_handle(struct iwm_priv *iwm, u8 *buf, unsigned long buf_size) -{ - struct iwm_udma_in_hdr *hdr; - - hdr = (struct iwm_udma_in_hdr *)buf; - - switch (le32_to_cpu(hdr->cmd)) { - case UMAC_REBOOT_BARKER: - if (test_bit(IWM_STATUS_READY, &iwm->status)) { - IWM_ERR(iwm, "Unexpected BARKER\n"); - - schedule_work(&iwm->reset_worker); - - return 0; - } - - return iwm_notif_send(iwm, NULL, IWM_BARKER_REBOOT_NOTIFICATION, - IWM_SRC_UDMA, buf, buf_size); - case UMAC_ACK_BARKER: - return iwm_notif_send(iwm, NULL, IWM_ACK_BARKER_NOTIFICATION, - IWM_SRC_UDMA, NULL, 0); - default: - IWM_DBG_RX(iwm, DBG, "Received cmd: 0x%x\n", hdr->cmd); - return iwm_rx_handle_umac(iwm, buf, buf_size); - } - - return 0; -} - -static const iwm_handler iwm_umac_handlers[] = -{ - [UMAC_NOTIFY_OPCODE_ERROR] = iwm_ntf_error, - [UMAC_NOTIFY_OPCODE_ALIVE] = iwm_ntf_umac_alive, - [UMAC_NOTIFY_OPCODE_INIT_COMPLETE] = iwm_ntf_init_complete, - [UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS] = iwm_ntf_wifi_status, - [UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_mlme, - [UMAC_NOTIFY_OPCODE_PAGE_DEALLOC] = iwm_ntf_tx_credit_update, - [UMAC_NOTIFY_OPCODE_RX_TICKET] = iwm_ntf_rx_ticket, - [UMAC_CMD_OPCODE_RESET] = iwm_ntf_umac_reset, - [UMAC_NOTIFY_OPCODE_STATS] = iwm_ntf_statistics, - [UMAC_CMD_OPCODE_EEPROM_PROXY] = iwm_ntf_eeprom_proxy, - [UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST] = iwm_ntf_channel_info_list, - [UMAC_CMD_OPCODE_STOP_RESUME_STA_TX] = iwm_ntf_stop_resume_tx, - [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, - [UMAC_CMD_OPCODE_WIFI_IF_WRAPPER] = iwm_ntf_wifi_if_wrapper, -}; - -static const iwm_handler iwm_lmac_handlers[] = -{ - [REPLY_TX] = iwm_ntf_tx, - [REPLY_ALIVE] = iwm_ntf_lmac_version, - [CALIBRATION_RES_NOTIFICATION] = iwm_ntf_calib_res, - [CALIBRATION_COMPLETE_NOTIFICATION] = iwm_ntf_calib_complete, - [CALIBRATION_CFG_CMD] = iwm_ntf_calib_cfg, - [REPLY_RX_MPDU_CMD] = iwm_ntf_rx_packet, - [CARD_STATE_NOTIFICATION] = iwm_ntf_card_state, -}; - -void iwm_rx_setup_handlers(struct iwm_priv *iwm) -{ - iwm->umac_handlers = (iwm_handler *) iwm_umac_handlers; - iwm->lmac_handlers = (iwm_handler *) iwm_lmac_handlers; -} - -static void iwm_remove_iv(struct sk_buff *skb, u32 hdr_total_len) -{ - struct ieee80211_hdr *hdr; - unsigned int hdr_len; - - hdr = (struct ieee80211_hdr *)skb->data; - - if (!ieee80211_has_protected(hdr->frame_control)) - return; - - hdr_len = ieee80211_hdrlen(hdr->frame_control); - if (hdr_total_len <= hdr_len) - return; - - memmove(skb->data + (hdr_total_len - hdr_len), skb->data, hdr_len); - skb_pull(skb, (hdr_total_len - hdr_len)); -} - -static void iwm_rx_adjust_packet(struct iwm_priv *iwm, - struct iwm_rx_packet *packet, - struct iwm_rx_ticket_node *ticket_node) -{ - u32 payload_offset = 0, payload_len; - struct iwm_rx_ticket *ticket = ticket_node->ticket; - struct iwm_rx_mpdu_hdr *mpdu_hdr; - struct ieee80211_hdr *hdr; - - mpdu_hdr = (struct iwm_rx_mpdu_hdr *)packet->skb->data; - payload_offset += sizeof(struct iwm_rx_mpdu_hdr); - /* Padding is 0 or 2 bytes */ - payload_len = le16_to_cpu(mpdu_hdr->len) + - (le16_to_cpu(ticket->flags) & IWM_RX_TICKET_PAD_SIZE_MSK); - payload_len -= ticket->tail_len; - - IWM_DBG_RX(iwm, DBG, "Packet adjusted, len:%d, offset:%d, " - "ticket offset:%d ticket tail len:%d\n", - payload_len, payload_offset, ticket->payload_offset, - ticket->tail_len); - - IWM_HEXDUMP(iwm, DBG, RX, "RAW: ", packet->skb->data, packet->skb->len); - - skb_pull(packet->skb, payload_offset); - skb_trim(packet->skb, payload_len); - - iwm_remove_iv(packet->skb, ticket->payload_offset); - - hdr = (struct ieee80211_hdr *) packet->skb->data; - if (ieee80211_is_data_qos(hdr->frame_control)) { - /* UMAC handed QOS_DATA frame with 2 padding bytes appended - * to the qos_ctl field in IEEE 802.11 headers. */ - memmove(packet->skb->data + IEEE80211_QOS_CTL_LEN + 2, - packet->skb->data, - ieee80211_hdrlen(hdr->frame_control) - - IEEE80211_QOS_CTL_LEN); - hdr = (struct ieee80211_hdr *) skb_pull(packet->skb, - IEEE80211_QOS_CTL_LEN + 2); - hdr->frame_control &= ~cpu_to_le16(IEEE80211_STYPE_QOS_DATA); - } - - IWM_HEXDUMP(iwm, DBG, RX, "ADJUSTED: ", - packet->skb->data, packet->skb->len); -} - -static void classify8023(struct sk_buff *skb) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - - if (ieee80211_is_data_qos(hdr->frame_control)) { - u8 *qc = ieee80211_get_qos_ctl(hdr); - /* frame has qos control */ - skb->priority = *qc & IEEE80211_QOS_CTL_TID_MASK; - } else { - skb->priority = 0; - } -} - -static void iwm_rx_process_amsdu(struct iwm_priv *iwm, struct sk_buff *skb) -{ - struct wireless_dev *wdev = iwm_to_wdev(iwm); - struct net_device *ndev = iwm_to_ndev(iwm); - struct sk_buff_head list; - struct sk_buff *frame; - - IWM_HEXDUMP(iwm, DBG, RX, "A-MSDU: ", skb->data, skb->len); - - __skb_queue_head_init(&list); - ieee80211_amsdu_to_8023s(skb, &list, ndev->dev_addr, wdev->iftype, 0, - true); - - while ((frame = __skb_dequeue(&list))) { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += frame->len; - - frame->protocol = eth_type_trans(frame, ndev); - frame->ip_summed = CHECKSUM_NONE; - memset(frame->cb, 0, sizeof(frame->cb)); - - if (netif_rx_ni(frame) == NET_RX_DROP) { - IWM_ERR(iwm, "Packet dropped\n"); - ndev->stats.rx_dropped++; - } - } -} - -static void iwm_rx_process_packet(struct iwm_priv *iwm, - struct iwm_rx_packet *packet, - struct iwm_rx_ticket_node *ticket_node) -{ - int ret; - struct sk_buff *skb = packet->skb; - struct wireless_dev *wdev = iwm_to_wdev(iwm); - struct net_device *ndev = iwm_to_ndev(iwm); - - IWM_DBG_RX(iwm, DBG, "Processing packet ID %d\n", packet->id); - - switch (le16_to_cpu(ticket_node->ticket->action)) { - case IWM_RX_TICKET_RELEASE: - IWM_DBG_RX(iwm, DBG, "RELEASE packet\n"); - - iwm_rx_adjust_packet(iwm, packet, ticket_node); - skb->dev = iwm_to_ndev(iwm); - classify8023(skb); - - if (le16_to_cpu(ticket_node->ticket->flags) & - IWM_RX_TICKET_AMSDU_MSK) { - iwm_rx_process_amsdu(iwm, skb); - break; - } - - ret = ieee80211_data_to_8023(skb, ndev->dev_addr, wdev->iftype); - if (ret < 0) { - IWM_DBG_RX(iwm, DBG, "Couldn't convert 802.11 header - " - "%d\n", ret); - kfree_skb(packet->skb); - break; - } - - IWM_HEXDUMP(iwm, DBG, RX, "802.3: ", skb->data, skb->len); - - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += skb->len; - - skb->protocol = eth_type_trans(skb, ndev); - skb->ip_summed = CHECKSUM_NONE; - memset(skb->cb, 0, sizeof(skb->cb)); - - if (netif_rx_ni(skb) == NET_RX_DROP) { - IWM_ERR(iwm, "Packet dropped\n"); - ndev->stats.rx_dropped++; - } - break; - case IWM_RX_TICKET_DROP: - IWM_DBG_RX(iwm, DBG, "DROP packet: 0x%x\n", - le16_to_cpu(ticket_node->ticket->flags)); - kfree_skb(packet->skb); - break; - default: - IWM_ERR(iwm, "Unknown ticket action: %d\n", - le16_to_cpu(ticket_node->ticket->action)); - kfree_skb(packet->skb); - } - - kfree(packet); - iwm_rx_ticket_node_free(ticket_node); -} - -/* - * Rx data processing: - * - * We're receiving Rx packet from the LMAC, and Rx ticket from - * the UMAC. - * To forward a target data packet upstream (i.e. to the - * kernel network stack), we must have received an Rx ticket - * that tells us we're allowed to release this packet (ticket - * action is IWM_RX_TICKET_RELEASE). The Rx ticket also indicates, - * among other things, where valid data actually starts in the Rx - * packet. - */ -void iwm_rx_worker(struct work_struct *work) -{ - struct iwm_priv *iwm; - struct iwm_rx_ticket_node *ticket, *next; - - iwm = container_of(work, struct iwm_priv, rx_worker); - - /* - * We go through the tickets list and if there is a pending - * packet for it, we push it upstream. - * We stop whenever a ticket is missing its packet, as we're - * supposed to send the packets in order. - */ - spin_lock(&iwm->ticket_lock); - list_for_each_entry_safe(ticket, next, &iwm->rx_tickets, node) { - struct iwm_rx_packet *packet = - iwm_rx_packet_get(iwm, le16_to_cpu(ticket->ticket->id)); - - if (!packet) { - IWM_DBG_RX(iwm, DBG, "Skip rx_work: Wait for ticket %d " - "to be handled first\n", - le16_to_cpu(ticket->ticket->id)); - break; - } - - list_del(&ticket->node); - iwm_rx_process_packet(iwm, packet, ticket); - } - spin_unlock(&iwm->ticket_lock); -} - diff --git a/drivers/net/wireless/iwmc3200wifi/rx.h b/drivers/net/wireless/iwmc3200wifi/rx.h deleted file mode 100644 index da0db91cee59..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/rx.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_RX_H__ -#define __IWM_RX_H__ - -#include <linux/skbuff.h> - -#include "umac.h" - -struct iwm_rx_ticket_node { - struct list_head node; - struct iwm_rx_ticket *ticket; -}; - -struct iwm_rx_packet { - struct list_head node; - u16 id; - struct sk_buff *skb; - unsigned long pkt_size; -}; - -void iwm_rx_worker(struct work_struct *work); - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.c b/drivers/net/wireless/iwmc3200wifi/sdio.c deleted file mode 100644 index 0042f204b07f..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/sdio.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -/* - * This is the SDIO bus specific hooks for iwm. - * It also is the module's entry point. - * - * Interesting code paths: - * iwm_sdio_probe() (Called by an SDIO bus scan) - * -> iwm_if_alloc() (netdev.c) - * -> iwm_wdev_alloc() (cfg80211.c, allocates and register our wiphy) - * -> wiphy_new() - * -> wiphy_register() - * -> alloc_netdev_mq() - * -> register_netdev() - * - * iwm_sdio_remove() - * -> iwm_if_free() (netdev.c) - * -> unregister_netdev() - * -> iwm_wdev_free() (cfg80211.c) - * -> wiphy_unregister() - * -> wiphy_free() - * - * iwm_sdio_isr() (called in process context from the SDIO core code) - * -> queue_work(.., isr_worker) - * -- [async] --> iwm_sdio_isr_worker() - * -> iwm_rx_handle() - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/netdevice.h> -#include <linux/debugfs.h> -#include <linux/mmc/sdio_ids.h> -#include <linux/mmc/sdio.h> -#include <linux/mmc/sdio_func.h> - -#include "iwm.h" -#include "debug.h" -#include "bus.h" -#include "sdio.h" - -static void iwm_sdio_isr_worker(struct work_struct *work) -{ - struct iwm_sdio_priv *hw; - struct iwm_priv *iwm; - struct iwm_rx_info *rx_info; - struct sk_buff *skb; - u8 *rx_buf; - unsigned long rx_size; - - hw = container_of(work, struct iwm_sdio_priv, isr_worker); - iwm = hw_to_iwm(hw); - - while (!skb_queue_empty(&iwm->rx_list)) { - skb = skb_dequeue(&iwm->rx_list); - rx_info = skb_to_rx_info(skb); - rx_size = rx_info->rx_size; - rx_buf = skb->data; - - IWM_HEXDUMP(iwm, DBG, SDIO, "RX: ", rx_buf, rx_size); - if (iwm_rx_handle(iwm, rx_buf, rx_size) < 0) - IWM_WARN(iwm, "RX error\n"); - - kfree_skb(skb); - } -} - -static void iwm_sdio_isr(struct sdio_func *func) -{ - struct iwm_priv *iwm; - struct iwm_sdio_priv *hw; - struct iwm_rx_info *rx_info; - struct sk_buff *skb; - unsigned long buf_size, read_size; - int ret; - u8 val; - - hw = sdio_get_drvdata(func); - iwm = hw_to_iwm(hw); - - buf_size = hw->blk_size; - - /* We're checking the status */ - val = sdio_readb(func, IWM_SDIO_INTR_STATUS_ADDR, &ret); - if (val == 0 || ret < 0) { - IWM_ERR(iwm, "Wrong INTR_STATUS\n"); - return; - } - - /* See if we have free buffers */ - if (skb_queue_len(&iwm->rx_list) > IWM_RX_LIST_SIZE) { - IWM_ERR(iwm, "No buffer for more Rx frames\n"); - return; - } - - /* We first read the transaction size */ - read_size = sdio_readb(func, IWM_SDIO_INTR_GET_SIZE_ADDR + 1, &ret); - read_size = read_size << 8; - - if (ret < 0) { - IWM_ERR(iwm, "Couldn't read the xfer size\n"); - return; - } - - /* We need to clear the INT register */ - sdio_writeb(func, 1, IWM_SDIO_INTR_CLEAR_ADDR, &ret); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't clear the INT register\n"); - return; - } - - while (buf_size < read_size) - buf_size <<= 1; - - skb = dev_alloc_skb(buf_size); - if (!skb) { - IWM_ERR(iwm, "Couldn't alloc RX skb\n"); - return; - } - rx_info = skb_to_rx_info(skb); - rx_info->rx_size = read_size; - rx_info->rx_buf_size = buf_size; - - /* Now we can read the actual buffer */ - ret = sdio_memcpy_fromio(func, skb_put(skb, read_size), - IWM_SDIO_DATA_ADDR, read_size); - - /* The skb is put on a driver's specific Rx SKB list */ - skb_queue_tail(&iwm->rx_list, skb); - - /* We can now schedule the actual worker */ - queue_work(hw->isr_wq, &hw->isr_worker); -} - -static void iwm_sdio_rx_free(struct iwm_sdio_priv *hw) -{ - struct iwm_priv *iwm = hw_to_iwm(hw); - - flush_workqueue(hw->isr_wq); - - skb_queue_purge(&iwm->rx_list); -} - -/* Bus ops */ -static int if_sdio_enable(struct iwm_priv *iwm) -{ - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - int ret; - - sdio_claim_host(hw->func); - - ret = sdio_enable_func(hw->func); - if (ret) { - IWM_ERR(iwm, "Couldn't enable the device: is TOP driver " - "loaded and functional?\n"); - goto release_host; - } - - iwm_reset(iwm); - - ret = sdio_claim_irq(hw->func, iwm_sdio_isr); - if (ret) { - IWM_ERR(iwm, "Failed to claim irq: %d\n", ret); - goto release_host; - } - - sdio_writeb(hw->func, 1, IWM_SDIO_INTR_ENABLE_ADDR, &ret); - if (ret < 0) { - IWM_ERR(iwm, "Couldn't enable INTR: %d\n", ret); - goto release_irq; - } - - sdio_release_host(hw->func); - - IWM_DBG_SDIO(iwm, INFO, "IWM SDIO enable\n"); - - return 0; - - release_irq: - sdio_release_irq(hw->func); - release_host: - sdio_release_host(hw->func); - - return ret; -} - -static int if_sdio_disable(struct iwm_priv *iwm) -{ - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - int ret; - - sdio_claim_host(hw->func); - sdio_writeb(hw->func, 0, IWM_SDIO_INTR_ENABLE_ADDR, &ret); - if (ret < 0) - IWM_WARN(iwm, "Couldn't disable INTR: %d\n", ret); - - sdio_release_irq(hw->func); - sdio_disable_func(hw->func); - sdio_release_host(hw->func); - - iwm_sdio_rx_free(hw); - - iwm_reset(iwm); - - IWM_DBG_SDIO(iwm, INFO, "IWM SDIO disable\n"); - - return 0; -} - -static int if_sdio_send_chunk(struct iwm_priv *iwm, u8 *buf, int count) -{ - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - int aligned_count = ALIGN(count, hw->blk_size); - int ret; - - if ((unsigned long)buf & 0x3) { - IWM_ERR(iwm, "buf <%p> is not dword aligned\n", buf); - /* TODO: Is this a hardware limitation? use get_unligned */ - return -EINVAL; - } - - sdio_claim_host(hw->func); - ret = sdio_memcpy_toio(hw->func, IWM_SDIO_DATA_ADDR, buf, - aligned_count); - sdio_release_host(hw->func); - - return ret; -} - -static ssize_t iwm_debugfs_sdio_read(struct file *filp, char __user *buffer, - size_t count, loff_t *ppos) -{ - struct iwm_priv *iwm = filp->private_data; - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - char *buf; - u8 cccr; - int buf_len = 4096, ret; - size_t len = 0; - - if (*ppos != 0) - return 0; - if (count < sizeof(buf)) - return -ENOSPC; - - buf = kzalloc(buf_len, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - sdio_claim_host(hw->func); - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IOEx, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_IOEx\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_IOEx: 0x%x\n", cccr); - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IORx, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_IORx\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_IORx: 0x%x\n", cccr); - - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IENx, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_IENx\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_IENx: 0x%x\n", cccr); - - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_INTx, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_INTx\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_INTx: 0x%x\n", cccr); - - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_ABORT, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_ABORTx\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_ABORT: 0x%x\n", cccr); - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_IF, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_IF\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_IF: 0x%x\n", cccr); - - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CAPS, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_CAPS\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_CAPS: 0x%x\n", cccr); - - cccr = sdio_f0_readb(hw->func, SDIO_CCCR_CIS, &ret); - if (ret) { - IWM_ERR(iwm, "Could not read SDIO_CCCR_CIS\n"); - goto err; - } - len += snprintf(buf + len, buf_len - len, "CCCR_CIS: 0x%x\n", cccr); - - ret = simple_read_from_buffer(buffer, len, ppos, buf, buf_len); -err: - sdio_release_host(hw->func); - - kfree(buf); - - return ret; -} - -static const struct file_operations iwm_debugfs_sdio_fops = { - .owner = THIS_MODULE, - .open = simple_open, - .read = iwm_debugfs_sdio_read, - .llseek = default_llseek, -}; - -static void if_sdio_debugfs_init(struct iwm_priv *iwm, struct dentry *parent_dir) -{ - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - - hw->cccr_dentry = debugfs_create_file("cccr", 0200, - parent_dir, iwm, - &iwm_debugfs_sdio_fops); -} - -static void if_sdio_debugfs_exit(struct iwm_priv *iwm) -{ - struct iwm_sdio_priv *hw = iwm_to_if_sdio(iwm); - - debugfs_remove(hw->cccr_dentry); -} - -static struct iwm_if_ops if_sdio_ops = { - .enable = if_sdio_enable, - .disable = if_sdio_disable, - .send_chunk = if_sdio_send_chunk, - .debugfs_init = if_sdio_debugfs_init, - .debugfs_exit = if_sdio_debugfs_exit, - .umac_name = "iwmc3200wifi-umac-sdio.bin", - .calib_lmac_name = "iwmc3200wifi-calib-sdio.bin", - .lmac_name = "iwmc3200wifi-lmac-sdio.bin", -}; -MODULE_FIRMWARE("iwmc3200wifi-umac-sdio.bin"); -MODULE_FIRMWARE("iwmc3200wifi-calib-sdio.bin"); -MODULE_FIRMWARE("iwmc3200wifi-lmac-sdio.bin"); - -static int iwm_sdio_probe(struct sdio_func *func, - const struct sdio_device_id *id) -{ - struct iwm_priv *iwm; - struct iwm_sdio_priv *hw; - struct device *dev = &func->dev; - int ret; - - /* check if TOP has already initialized the card */ - sdio_claim_host(func); - ret = sdio_enable_func(func); - if (ret) { - dev_err(dev, "wait for TOP to enable the device\n"); - sdio_release_host(func); - return ret; - } - - ret = sdio_set_block_size(func, IWM_SDIO_BLK_SIZE); - - sdio_disable_func(func); - sdio_release_host(func); - - if (ret < 0) { - dev_err(dev, "Failed to set block size: %d\n", ret); - return ret; - } - - iwm = iwm_if_alloc(sizeof(struct iwm_sdio_priv), dev, &if_sdio_ops); - if (IS_ERR(iwm)) { - dev_err(dev, "allocate SDIO interface failed\n"); - return PTR_ERR(iwm); - } - - hw = iwm_private(iwm); - hw->iwm = iwm; - - iwm_debugfs_init(iwm); - - sdio_set_drvdata(func, hw); - - hw->func = func; - hw->blk_size = IWM_SDIO_BLK_SIZE; - - hw->isr_wq = create_singlethread_workqueue(KBUILD_MODNAME "_sdio"); - if (!hw->isr_wq) { - ret = -ENOMEM; - goto debugfs_exit; - } - - INIT_WORK(&hw->isr_worker, iwm_sdio_isr_worker); - - ret = iwm_if_add(iwm); - if (ret) { - dev_err(dev, "add SDIO interface failed\n"); - goto destroy_wq; - } - - dev_info(dev, "IWM SDIO probe\n"); - - return 0; - - destroy_wq: - destroy_workqueue(hw->isr_wq); - debugfs_exit: - iwm_debugfs_exit(iwm); - iwm_if_free(iwm); - return ret; -} - -static void iwm_sdio_remove(struct sdio_func *func) -{ - struct iwm_sdio_priv *hw = sdio_get_drvdata(func); - struct iwm_priv *iwm = hw_to_iwm(hw); - struct device *dev = &func->dev; - - iwm_if_remove(iwm); - destroy_workqueue(hw->isr_wq); - iwm_debugfs_exit(iwm); - iwm_if_free(iwm); - - sdio_set_drvdata(func, NULL); - - dev_info(dev, "IWM SDIO remove\n"); -} - -static const struct sdio_device_id iwm_sdio_ids[] = { - /* Global/AGN SKU */ - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1403) }, - /* BGN SKU */ - { SDIO_DEVICE(SDIO_VENDOR_ID_INTEL, 0x1408) }, - { /* end: all zeroes */ }, -}; -MODULE_DEVICE_TABLE(sdio, iwm_sdio_ids); - -static struct sdio_driver iwm_sdio_driver = { - .name = "iwm_sdio", - .id_table = iwm_sdio_ids, - .probe = iwm_sdio_probe, - .remove = iwm_sdio_remove, -}; - -static int __init iwm_sdio_init_module(void) -{ - return sdio_register_driver(&iwm_sdio_driver); -} - -static void __exit iwm_sdio_exit_module(void) -{ - sdio_unregister_driver(&iwm_sdio_driver); -} - -module_init(iwm_sdio_init_module); -module_exit(iwm_sdio_exit_module); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR(IWM_COPYRIGHT " " IWM_AUTHOR); diff --git a/drivers/net/wireless/iwmc3200wifi/sdio.h b/drivers/net/wireless/iwmc3200wifi/sdio.h deleted file mode 100644 index aab6b6892e45..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/sdio.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_SDIO_H__ -#define __IWM_SDIO_H__ - -#define IWM_SDIO_DATA_ADDR 0x0 -#define IWM_SDIO_INTR_ENABLE_ADDR 0x14 -#define IWM_SDIO_INTR_STATUS_ADDR 0x13 -#define IWM_SDIO_INTR_CLEAR_ADDR 0x13 -#define IWM_SDIO_INTR_GET_SIZE_ADDR 0x2C - -#define IWM_SDIO_BLK_SIZE 256 - -#define iwm_to_if_sdio(i) (struct iwm_sdio_priv *)(iwm->private) - -struct iwm_sdio_priv { - struct sdio_func *func; - struct iwm_priv *iwm; - - struct workqueue_struct *isr_wq; - struct work_struct isr_worker; - - struct dentry *cccr_dentry; - - unsigned int blk_size; -}; - -#endif diff --git a/drivers/net/wireless/iwmc3200wifi/trace.c b/drivers/net/wireless/iwmc3200wifi/trace.c deleted file mode 100644 index 904d36f22311..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/trace.c +++ /dev/null @@ -1,3 +0,0 @@ -#include "iwm.h" -#define CREATE_TRACE_POINTS -#include "trace.h" diff --git a/drivers/net/wireless/iwmc3200wifi/trace.h b/drivers/net/wireless/iwmc3200wifi/trace.h deleted file mode 100644 index f5f7070b7e22..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/trace.h +++ /dev/null @@ -1,283 +0,0 @@ -#if !defined(__IWM_TRACE_H__) || defined(TRACE_HEADER_MULTI_READ) -#define __IWM_TRACE_H__ - -#include <linux/tracepoint.h> - -#if !defined(CONFIG_IWM_TRACING) -#undef TRACE_EVENT -#define TRACE_EVENT(name, proto, ...) \ -static inline void trace_ ## name(proto) {} -#endif - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM iwm - -#define IWM_ENTRY __array(char, ndev_name, 16) -#define IWM_ASSIGN strlcpy(__entry->ndev_name, iwm_to_ndev(iwm)->name, 16) -#define IWM_PR_FMT "%s" -#define IWM_PR_ARG __entry->ndev_name - -TRACE_EVENT(iwm_tx_nonwifi_cmd, - TP_PROTO(struct iwm_priv *iwm, struct iwm_udma_out_nonwifi_hdr *hdr), - - TP_ARGS(iwm, hdr), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, opcode) - __field(u8, resp) - __field(u8, eot) - __field(u8, hw) - __field(u16, seq) - __field(u32, addr) - __field(u32, op1) - __field(u32, op2) - ), - - TP_fast_assign( - IWM_ASSIGN; - __entry->opcode = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_OPCODE); - __entry->resp = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_RESP); - __entry->eot = GET_VAL32(hdr->cmd, UMAC_HDI_OUT_CMD_EOT); - __entry->hw = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_NW_CMD_HANDLE_BY_HW); - __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM); - __entry->addr = le32_to_cpu(hdr->addr); - __entry->op1 = le32_to_cpu(hdr->op1_sz); - __entry->op2 = le32_to_cpu(hdr->op2); - ), - - TP_printk( - IWM_PR_FMT " Tx TARGET CMD: opcode 0x%x, resp %d, eot %d, " - "hw %d, seq 0x%x, addr 0x%x, op1 0x%x, op2 0x%x", - IWM_PR_ARG, __entry->opcode, __entry->resp, __entry->eot, - __entry->hw, __entry->seq, __entry->addr, __entry->op1, - __entry->op2 - ) -); - -TRACE_EVENT(iwm_tx_wifi_cmd, - TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_out_hdr *hdr), - - TP_ARGS(iwm, hdr), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, opcode) - __field(u8, lmac) - __field(u8, resp) - __field(u8, eot) - __field(u8, ra_tid) - __field(u8, credit_group) - __field(u8, color) - __field(u16, seq) - ), - - TP_fast_assign( - IWM_ASSIGN; - __entry->opcode = hdr->sw_hdr.cmd.cmd; - __entry->lmac = 0; - __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num); - __entry->resp = GET_VAL8(hdr->sw_hdr.cmd.flags, UMAC_DEV_CMD_FLAGS_RESP_REQ); - __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR); - __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT); - __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID); - __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP); - if (__entry->opcode == UMAC_CMD_OPCODE_WIFI_PASS_THROUGH || - __entry->opcode == UMAC_CMD_OPCODE_WIFI_IF_WRAPPER) { - __entry->lmac = 1; - __entry->opcode = ((struct iwm_lmac_hdr *)(hdr + 1))->id; - } - ), - - TP_printk( - IWM_PR_FMT " Tx %cMAC CMD: opcode 0x%x, resp %d, eot %d, " - "seq 0x%x, sta_color 0x%x, ra_tid 0x%x, credit_group 0x%x", - IWM_PR_ARG, __entry->lmac ? 'L' : 'U', __entry->opcode, - __entry->resp, __entry->eot, __entry->seq, __entry->color, - __entry->ra_tid, __entry->credit_group - ) -); - -TRACE_EVENT(iwm_tx_packets, - TP_PROTO(struct iwm_priv *iwm, u8 *buf, int len), - - TP_ARGS(iwm, buf, len), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, eot) - __field(u8, ra_tid) - __field(u8, credit_group) - __field(u8, color) - __field(u16, seq) - __field(u8, npkt) - __field(u32, bytes) - ), - - TP_fast_assign( - struct iwm_umac_wifi_out_hdr *hdr = - (struct iwm_umac_wifi_out_hdr *)buf; - - IWM_ASSIGN; - __entry->eot = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_OUT_CMD_EOT); - __entry->ra_tid = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_RATID); - __entry->credit_group = GET_VAL32(hdr->hw_hdr.meta_data, UMAC_HDI_OUT_CREDIT_GRP); - __entry->color = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_TX_STA_COLOR); - __entry->seq = __le16_to_cpu(hdr->sw_hdr.cmd.seq_num); - __entry->npkt = 1; - __entry->bytes = len; - - if (!__entry->eot) { - int count; - u8 *ptr = buf; - - __entry->npkt = 0; - while (ptr < buf + len) { - count = GET_VAL32(hdr->sw_hdr.meta_data, - UMAC_FW_CMD_BYTE_COUNT); - ptr += ALIGN(sizeof(*hdr) + count, 16); - hdr = (struct iwm_umac_wifi_out_hdr *)ptr; - __entry->npkt++; - } - } - ), - - TP_printk( - IWM_PR_FMT " Tx %spacket: eot %d, seq 0x%x, sta_color 0x%x, " - "ra_tid 0x%x, credit_group 0x%x, embedded_packets %d, %d bytes", - IWM_PR_ARG, !__entry->eot ? "concatenated " : "", - __entry->eot, __entry->seq, __entry->color, __entry->ra_tid, - __entry->credit_group, __entry->npkt, __entry->bytes - ) -); - -TRACE_EVENT(iwm_rx_nonwifi_cmd, - TP_PROTO(struct iwm_priv *iwm, void *buf, int len), - - TP_ARGS(iwm, buf, len), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, opcode) - __field(u16, seq) - __field(u32, len) - ), - - TP_fast_assign( - struct iwm_udma_in_hdr *hdr = buf; - - IWM_ASSIGN; - __entry->opcode = GET_VAL32(hdr->cmd, UDMA_HDI_IN_NW_CMD_OPCODE); - __entry->seq = GET_VAL32(hdr->cmd, UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM); - __entry->len = len; - ), - - TP_printk( - IWM_PR_FMT " Rx TARGET RESP: opcode 0x%x, seq 0x%x, len 0x%x", - IWM_PR_ARG, __entry->opcode, __entry->seq, __entry->len - ) -); - -TRACE_EVENT(iwm_rx_wifi_cmd, - TP_PROTO(struct iwm_priv *iwm, struct iwm_umac_wifi_in_hdr *hdr), - - TP_ARGS(iwm, hdr), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, cmd) - __field(u8, source) - __field(u16, seq) - __field(u32, count) - ), - - TP_fast_assign( - IWM_ASSIGN; - __entry->cmd = hdr->sw_hdr.cmd.cmd; - __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); - __entry->count = GET_VAL32(hdr->sw_hdr.meta_data, UMAC_FW_CMD_BYTE_COUNT); - __entry->seq = le16_to_cpu(hdr->sw_hdr.cmd.seq_num); - ), - - TP_printk( - IWM_PR_FMT " Rx %s RESP: cmd 0x%x, seq 0x%x, count 0x%x", - IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? "LMAC" : - __entry->source == UMAC_HDI_IN_SOURCE_FW ? "UMAC" : "UDMA", - __entry->cmd, __entry->seq, __entry->count - ) -); - -#define iwm_ticket_action_symbol \ - { IWM_RX_TICKET_DROP, "DROP" }, \ - { IWM_RX_TICKET_RELEASE, "RELEASE" }, \ - { IWM_RX_TICKET_SNIFFER, "SNIFFER" }, \ - { IWM_RX_TICKET_ENQUEUE, "ENQUEUE" } - -TRACE_EVENT(iwm_rx_ticket, - TP_PROTO(struct iwm_priv *iwm, void *buf, int len), - - TP_ARGS(iwm, buf, len), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, action) - __field(u8, reason) - __field(u16, id) - __field(u16, flags) - ), - - TP_fast_assign( - struct iwm_rx_ticket *ticket = - ((struct iwm_umac_notif_rx_ticket *)buf)->tickets; - - IWM_ASSIGN; - __entry->id = le16_to_cpu(ticket->id); - __entry->action = le16_to_cpu(ticket->action); - __entry->flags = le16_to_cpu(ticket->flags); - __entry->reason = (__entry->flags & IWM_RX_TICKET_DROP_REASON_MSK) >> IWM_RX_TICKET_DROP_REASON_POS; - ), - - TP_printk( - IWM_PR_FMT " Rx ticket: id 0x%x, action %s, %s 0x%x%s", - IWM_PR_ARG, __entry->id, - __print_symbolic(__entry->action, iwm_ticket_action_symbol), - __entry->reason ? "reason" : "flags", - __entry->reason ? __entry->reason : __entry->flags, - __entry->flags & IWM_RX_TICKET_AMSDU_MSK ? ", AMSDU frame" : "" - ) -); - -TRACE_EVENT(iwm_rx_packet, - TP_PROTO(struct iwm_priv *iwm, void *buf, int len), - - TP_ARGS(iwm, buf, len), - - TP_STRUCT__entry( - IWM_ENTRY - __field(u8, source) - __field(u16, id) - __field(u32, len) - ), - - TP_fast_assign( - struct iwm_umac_wifi_in_hdr *hdr = buf; - - IWM_ASSIGN; - __entry->source = GET_VAL32(hdr->hw_hdr.cmd, UMAC_HDI_IN_CMD_SOURCE); - __entry->id = le16_to_cpu(hdr->sw_hdr.cmd.seq_num); - __entry->len = len - sizeof(*hdr); - ), - - TP_printk( - IWM_PR_FMT " Rx %s packet: id 0x%x, %d bytes", - IWM_PR_ARG, __entry->source == UMAC_HDI_IN_SOURCE_FHRX ? - "LMAC" : "UMAC", __entry->id, __entry->len - ) -); -#endif - -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH . -#undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE trace -#include <trace/define_trace.h> diff --git a/drivers/net/wireless/iwmc3200wifi/tx.c b/drivers/net/wireless/iwmc3200wifi/tx.c deleted file mode 100644 index be98074c0608..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/tx.c +++ /dev/null @@ -1,529 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -/* - * iwm Tx theory of operation: - * - * 1) We receive a 802.3 frame from the stack - * 2) We convert it to a 802.11 frame [iwm_xmit_frame] - * 3) We queue it to its corresponding tx queue [iwm_xmit_frame] - * 4) We schedule the tx worker. There is one worker per tx - * queue. [iwm_xmit_frame] - * 5) The tx worker is scheduled - * 6) We go through every queued skb on the tx queue, and for each - * and every one of them: [iwm_tx_worker] - * a) We check if we have enough Tx credits (see below for a Tx - * credits description) for the frame length. [iwm_tx_worker] - * b) If we do, we aggregate the Tx frame into a UDMA one, by - * concatenating one REPLY_TX command per Tx frame. [iwm_tx_worker] - * c) When we run out of credits, or when we reach the maximum - * concatenation size, we actually send the concatenated UDMA - * frame. [iwm_tx_worker] - * - * When we run out of Tx credits, the skbs are filling the tx queue, - * and eventually we will stop the netdev queue. [iwm_tx_worker] - * The tx queue is emptied as we're getting new tx credits, by - * scheduling the tx_worker. [iwm_tx_credit_inc] - * The netdev queue is started again when we have enough tx credits, - * and when our tx queue has some reasonable amout of space available - * (i.e. half of the max size). [iwm_tx_worker] - */ - -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/netdevice.h> -#include <linux/ieee80211.h> - -#include "iwm.h" -#include "debug.h" -#include "commands.h" -#include "hal.h" -#include "umac.h" -#include "bus.h" - -#define IWM_UMAC_PAGE_ALLOC_WRAP 0xffff - -#define BYTES_TO_PAGES(n) (1 + ((n) >> ilog2(IWM_UMAC_PAGE_SIZE)) - \ - (((n) & (IWM_UMAC_PAGE_SIZE - 1)) == 0)) - -#define pool_id_to_queue(id) ((id < IWM_TX_CMD_QUEUE) ? id : id - 1) -#define queue_to_pool_id(q) ((q < IWM_TX_CMD_QUEUE) ? q : q + 1) - -/* require to hold tx_credit lock */ -static int iwm_tx_credit_get(struct iwm_tx_credit *tx_credit, int id) -{ - struct pool_entry *pool = &tx_credit->pools[id]; - struct spool_entry *spool = &tx_credit->spools[pool->sid]; - int spool_pages; - - /* number of pages can be taken from spool by this pool */ - spool_pages = spool->max_pages - spool->alloc_pages + - max(pool->min_pages - pool->alloc_pages, 0); - - return min(pool->max_pages - pool->alloc_pages, spool_pages); -} - -static bool iwm_tx_credit_ok(struct iwm_priv *iwm, int id, int nb) -{ - u32 npages = BYTES_TO_PAGES(nb); - - if (npages <= iwm_tx_credit_get(&iwm->tx_credit, id)) - return 1; - - set_bit(id, &iwm->tx_credit.full_pools_map); - - IWM_DBG_TX(iwm, DBG, "LINK: stop txq[%d], available credit: %d\n", - pool_id_to_queue(id), - iwm_tx_credit_get(&iwm->tx_credit, id)); - - return 0; -} - -void iwm_tx_credit_inc(struct iwm_priv *iwm, int id, int total_freed_pages) -{ - struct pool_entry *pool; - struct spool_entry *spool; - int freed_pages; - int queue; - - BUG_ON(id >= IWM_MACS_OUT_GROUPS); - - pool = &iwm->tx_credit.pools[id]; - spool = &iwm->tx_credit.spools[pool->sid]; - - freed_pages = total_freed_pages - pool->total_freed_pages; - IWM_DBG_TX(iwm, DBG, "Free %d pages for pool[%d]\n", freed_pages, id); - - if (!freed_pages) { - IWM_DBG_TX(iwm, DBG, "No pages are freed by UMAC\n"); - return; - } else if (freed_pages < 0) - freed_pages += IWM_UMAC_PAGE_ALLOC_WRAP + 1; - - if (pool->alloc_pages > pool->min_pages) { - int spool_pages = pool->alloc_pages - pool->min_pages; - spool_pages = min(spool_pages, freed_pages); - spool->alloc_pages -= spool_pages; - } - - pool->alloc_pages -= freed_pages; - pool->total_freed_pages = total_freed_pages; - - IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " - "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, - pool->total_freed_pages, pool->sid, spool->alloc_pages); - - if (test_bit(id, &iwm->tx_credit.full_pools_map) && - (pool->alloc_pages < pool->max_pages / 2)) { - clear_bit(id, &iwm->tx_credit.full_pools_map); - - queue = pool_id_to_queue(id); - - IWM_DBG_TX(iwm, DBG, "LINK: start txq[%d], available " - "credit: %d\n", queue, - iwm_tx_credit_get(&iwm->tx_credit, id)); - queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); - } -} - -static void iwm_tx_credit_dec(struct iwm_priv *iwm, int id, int alloc_pages) -{ - struct pool_entry *pool; - struct spool_entry *spool; - int spool_pages; - - IWM_DBG_TX(iwm, DBG, "Allocate %d pages for pool[%d]\n", - alloc_pages, id); - - BUG_ON(id >= IWM_MACS_OUT_GROUPS); - - pool = &iwm->tx_credit.pools[id]; - spool = &iwm->tx_credit.spools[pool->sid]; - - spool_pages = pool->alloc_pages + alloc_pages - pool->min_pages; - - if (pool->alloc_pages >= pool->min_pages) - spool->alloc_pages += alloc_pages; - else if (spool_pages > 0) - spool->alloc_pages += spool_pages; - - pool->alloc_pages += alloc_pages; - - IWM_DBG_TX(iwm, DBG, "Pool[%d] pages alloc: %d, total_freed: %d, " - "Spool[%d] pages alloc: %d\n", id, pool->alloc_pages, - pool->total_freed_pages, pool->sid, spool->alloc_pages); -} - -int iwm_tx_credit_alloc(struct iwm_priv *iwm, int id, int nb) -{ - u32 npages = BYTES_TO_PAGES(nb); - int ret = 0; - - spin_lock(&iwm->tx_credit.lock); - - if (!iwm_tx_credit_ok(iwm, id, nb)) { - IWM_DBG_TX(iwm, DBG, "No credit available for pool[%d]\n", id); - ret = -ENOSPC; - goto out; - } - - iwm_tx_credit_dec(iwm, id, npages); - - out: - spin_unlock(&iwm->tx_credit.lock); - return ret; -} - -/* - * Since we're on an SDIO or USB bus, we are not sharing memory - * for storing to be transmitted frames. The host needs to push - * them upstream. As a consequence there needs to be a way for - * the target to let us know if it can actually take more TX frames - * or not. This is what Tx credits are for. - * - * For each Tx HW queue, we have a Tx pool, and then we have one - * unique super pool (spool), which is actually a global pool of - * all the UMAC pages. - * For each Tx pool we have a min_pages, a max_pages fields, and a - * alloc_pages fields. The alloc_pages tracks the number of pages - * currently allocated from the tx pool. - * Here are the rules to check if given a tx frame we have enough - * tx credits for it: - * 1) We translate the frame length into a number of UMAC pages. - * Let's call them n_pages. - * 2) For the corresponding tx pool, we check if n_pages + - * pool->alloc_pages is higher than pool->min_pages. min_pages - * represent a set of pre-allocated pages on the tx pool. If - * that's the case, then we need to allocate those pages from - * the spool. We can do so until we reach spool->max_pages. - * 3) Each tx pool is not allowed to allocate more than pool->max_pages - * from the spool, so once we're over min_pages, we can allocate - * pages from the spool, but not more than max_pages. - * - * When the tx code path needs to send a tx frame, it checks first - * if it has enough tx credits, following those rules. [iwm_tx_credit_get] - * If it does, it then updates the pool and spool counters and - * then send the frame. [iwm_tx_credit_alloc and iwm_tx_credit_dec] - * On the other side, when the UMAC is done transmitting frames, it - * will send a credit update notification to the host. This is when - * the pool and spool counters gets to be decreased. [iwm_tx_credit_inc, - * called from rx.c:iwm_ntf_tx_credit_update] - * - */ -void iwm_tx_credit_init_pools(struct iwm_priv *iwm, - struct iwm_umac_notif_alive *alive) -{ - int i, sid, pool_pages; - - spin_lock(&iwm->tx_credit.lock); - - iwm->tx_credit.pool_nr = le16_to_cpu(alive->page_grp_count); - iwm->tx_credit.full_pools_map = 0; - memset(&iwm->tx_credit.spools[0], 0, sizeof(struct spool_entry)); - - IWM_DBG_TX(iwm, DBG, "Pools number is %d\n", iwm->tx_credit.pool_nr); - - for (i = 0; i < iwm->tx_credit.pool_nr; i++) { - __le32 page_grp_state = alive->page_grp_state[i]; - - iwm->tx_credit.pools[i].id = GET_VAL32(page_grp_state, - UMAC_ALIVE_PAGE_STS_GRP_NUM); - iwm->tx_credit.pools[i].sid = GET_VAL32(page_grp_state, - UMAC_ALIVE_PAGE_STS_SGRP_NUM); - iwm->tx_credit.pools[i].min_pages = GET_VAL32(page_grp_state, - UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE); - iwm->tx_credit.pools[i].max_pages = GET_VAL32(page_grp_state, - UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE); - iwm->tx_credit.pools[i].alloc_pages = 0; - iwm->tx_credit.pools[i].total_freed_pages = 0; - - sid = iwm->tx_credit.pools[i].sid; - pool_pages = iwm->tx_credit.pools[i].min_pages; - - if (iwm->tx_credit.spools[sid].max_pages == 0) { - iwm->tx_credit.spools[sid].id = sid; - iwm->tx_credit.spools[sid].max_pages = - GET_VAL32(page_grp_state, - UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE); - iwm->tx_credit.spools[sid].alloc_pages = 0; - } - - iwm->tx_credit.spools[sid].alloc_pages += pool_pages; - - IWM_DBG_TX(iwm, DBG, "Pool idx: %d, id: %d, sid: %d, capacity " - "min: %d, max: %d, pool alloc: %d, total_free: %d, " - "super poll alloc: %d\n", - i, iwm->tx_credit.pools[i].id, - iwm->tx_credit.pools[i].sid, - iwm->tx_credit.pools[i].min_pages, - iwm->tx_credit.pools[i].max_pages, - iwm->tx_credit.pools[i].alloc_pages, - iwm->tx_credit.pools[i].total_freed_pages, - iwm->tx_credit.spools[sid].alloc_pages); - } - - spin_unlock(&iwm->tx_credit.lock); -} - -#define IWM_UDMA_HDR_LEN sizeof(struct iwm_umac_wifi_out_hdr) - -static __le16 iwm_tx_build_packet(struct iwm_priv *iwm, struct sk_buff *skb, - int pool_id, u8 *buf) -{ - struct iwm_umac_wifi_out_hdr *hdr = (struct iwm_umac_wifi_out_hdr *)buf; - struct iwm_udma_wifi_cmd udma_cmd; - struct iwm_umac_cmd umac_cmd; - struct iwm_tx_info *tx_info = skb_to_tx_info(skb); - - udma_cmd.count = cpu_to_le16(skb->len + - sizeof(struct iwm_umac_fw_cmd_hdr)); - /* set EOP to 0 here. iwm_udma_wifi_hdr_set_eop() will be - * called later to set EOP for the last packet. */ - udma_cmd.eop = 0; - udma_cmd.credit_group = pool_id; - udma_cmd.ra_tid = tx_info->sta << 4 | tx_info->tid; - udma_cmd.lmac_offset = 0; - - umac_cmd.id = REPLY_TX; - umac_cmd.count = cpu_to_le16(skb->len); - umac_cmd.color = tx_info->color; - umac_cmd.resp = 0; - umac_cmd.seq_num = cpu_to_le16(iwm_alloc_wifi_cmd_seq(iwm)); - - iwm_build_udma_wifi_hdr(iwm, &hdr->hw_hdr, &udma_cmd); - iwm_build_umac_hdr(iwm, &hdr->sw_hdr, &umac_cmd); - - memcpy(buf + sizeof(*hdr), skb->data, skb->len); - - return umac_cmd.seq_num; -} - -static int iwm_tx_send_concat_packets(struct iwm_priv *iwm, - struct iwm_tx_queue *txq) -{ - int ret; - - if (!txq->concat_count) - return 0; - - IWM_DBG_TX(iwm, DBG, "Send concatenated Tx: queue %d, %d bytes\n", - txq->id, txq->concat_count); - - /* mark EOP for the last packet */ - iwm_udma_wifi_hdr_set_eop(iwm, txq->concat_ptr, 1); - - trace_iwm_tx_packets(iwm, txq->concat_buf, txq->concat_count); - ret = iwm_bus_send_chunk(iwm, txq->concat_buf, txq->concat_count); - - txq->concat_count = 0; - txq->concat_ptr = txq->concat_buf; - - return ret; -} - -void iwm_tx_worker(struct work_struct *work) -{ - struct iwm_priv *iwm; - struct iwm_tx_info *tx_info = NULL; - struct sk_buff *skb; - struct iwm_tx_queue *txq; - struct iwm_sta_info *sta_info; - struct iwm_tid_info *tid_info; - int cmdlen, ret, pool_id; - - txq = container_of(work, struct iwm_tx_queue, worker); - iwm = container_of(txq, struct iwm_priv, txq[txq->id]); - - pool_id = queue_to_pool_id(txq->id); - - while (!test_bit(pool_id, &iwm->tx_credit.full_pools_map) && - !skb_queue_empty(&txq->queue)) { - - spin_lock_bh(&txq->lock); - skb = skb_dequeue(&txq->queue); - spin_unlock_bh(&txq->lock); - - tx_info = skb_to_tx_info(skb); - sta_info = &iwm->sta_table[tx_info->sta]; - if (!sta_info->valid) { - IWM_ERR(iwm, "Trying to send a frame to unknown STA\n"); - kfree_skb(skb); - continue; - } - - tid_info = &sta_info->tid_info[tx_info->tid]; - - mutex_lock(&tid_info->mutex); - - /* - * If the RAxTID is stopped, we queue the skb to the stopped - * queue. - * Whenever we'll get a UMAC notification to resume the tx flow - * for this RAxTID, we'll merge back the stopped queue into the - * regular queue. See iwm_ntf_stop_resume_tx() from rx.c. - */ - if (tid_info->stopped) { - IWM_DBG_TX(iwm, DBG, "%dx%d stopped\n", - tx_info->sta, tx_info->tid); - spin_lock_bh(&txq->lock); - skb_queue_tail(&txq->stopped_queue, skb); - spin_unlock_bh(&txq->lock); - - mutex_unlock(&tid_info->mutex); - continue; - } - - cmdlen = IWM_UDMA_HDR_LEN + skb->len; - - IWM_DBG_TX(iwm, DBG, "Tx frame on queue %d: skb: 0x%p, sta: " - "%d, color: %d\n", txq->id, skb, tx_info->sta, - tx_info->color); - - if (txq->concat_count + cmdlen > IWM_HAL_CONCATENATE_BUF_SIZE) - iwm_tx_send_concat_packets(iwm, txq); - - ret = iwm_tx_credit_alloc(iwm, pool_id, cmdlen); - if (ret) { - IWM_DBG_TX(iwm, DBG, "not enough tx_credit for queue " - "%d, Tx worker stopped\n", txq->id); - spin_lock_bh(&txq->lock); - skb_queue_head(&txq->queue, skb); - spin_unlock_bh(&txq->lock); - - mutex_unlock(&tid_info->mutex); - break; - } - - txq->concat_ptr = txq->concat_buf + txq->concat_count; - tid_info->last_seq_num = - iwm_tx_build_packet(iwm, skb, pool_id, txq->concat_ptr); - txq->concat_count += ALIGN(cmdlen, 16); - - mutex_unlock(&tid_info->mutex); - - kfree_skb(skb); - } - - iwm_tx_send_concat_packets(iwm, txq); - - if (__netif_subqueue_stopped(iwm_to_ndev(iwm), txq->id) && - !test_bit(pool_id, &iwm->tx_credit.full_pools_map) && - (skb_queue_len(&txq->queue) < IWM_TX_LIST_SIZE / 2)) { - IWM_DBG_TX(iwm, DBG, "LINK: start netif_subqueue[%d]", txq->id); - netif_wake_subqueue(iwm_to_ndev(iwm), txq->id); - } -} - -int iwm_xmit_frame(struct sk_buff *skb, struct net_device *netdev) -{ - struct iwm_priv *iwm = ndev_to_iwm(netdev); - struct wireless_dev *wdev = iwm_to_wdev(iwm); - struct iwm_tx_info *tx_info; - struct iwm_tx_queue *txq; - struct iwm_sta_info *sta_info; - u8 *dst_addr, sta_id; - u16 queue; - int ret; - - - if (!test_bit(IWM_STATUS_ASSOCIATED, &iwm->status)) { - IWM_DBG_TX(iwm, DBG, "LINK: stop netif_all_queues: " - "not associated\n"); - netif_tx_stop_all_queues(netdev); - goto drop; - } - - queue = skb_get_queue_mapping(skb); - BUG_ON(queue >= IWM_TX_DATA_QUEUES); /* no iPAN yet */ - - txq = &iwm->txq[queue]; - - /* No free space for Tx, tx_worker is too slow */ - if ((skb_queue_len(&txq->queue) > IWM_TX_LIST_SIZE) || - (skb_queue_len(&txq->stopped_queue) > IWM_TX_LIST_SIZE)) { - IWM_DBG_TX(iwm, DBG, "LINK: stop netif_subqueue[%d]\n", queue); - netif_stop_subqueue(netdev, queue); - return NETDEV_TX_BUSY; - } - - ret = ieee80211_data_from_8023(skb, netdev->dev_addr, wdev->iftype, - iwm->bssid, 0); - if (ret) { - IWM_ERR(iwm, "build wifi header failed\n"); - goto drop; - } - - dst_addr = ((struct ieee80211_hdr *)(skb->data))->addr1; - - for (sta_id = 0; sta_id < IWM_STA_TABLE_NUM; sta_id++) { - sta_info = &iwm->sta_table[sta_id]; - if (sta_info->valid && - !memcmp(dst_addr, sta_info->addr, ETH_ALEN)) - break; - } - - if (sta_id == IWM_STA_TABLE_NUM) { - IWM_ERR(iwm, "STA %pM not found in sta_table, Tx ignored\n", - dst_addr); - goto drop; - } - - tx_info = skb_to_tx_info(skb); - tx_info->sta = sta_id; - tx_info->color = sta_info->color; - /* UMAC uses TID 8 (vs. 0) for non QoS packets */ - if (sta_info->qos) - tx_info->tid = skb->priority; - else - tx_info->tid = IWM_UMAC_MGMT_TID; - - spin_lock_bh(&iwm->txq[queue].lock); - skb_queue_tail(&iwm->txq[queue].queue, skb); - spin_unlock_bh(&iwm->txq[queue].lock); - - queue_work(iwm->txq[queue].wq, &iwm->txq[queue].worker); - - netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; - return NETDEV_TX_OK; - - drop: - netdev->stats.tx_dropped++; - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; -} diff --git a/drivers/net/wireless/iwmc3200wifi/umac.h b/drivers/net/wireless/iwmc3200wifi/umac.h deleted file mode 100644 index 4a137d334a42..000000000000 --- a/drivers/net/wireless/iwmc3200wifi/umac.h +++ /dev/null @@ -1,789 +0,0 @@ -/* - * Intel Wireless Multicomm 3200 WiFi driver - * - * Copyright (C) 2009 Intel Corporation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * Intel Corporation <ilw@linux.intel.com> - * Samuel Ortiz <samuel.ortiz@intel.com> - * Zhu Yi <yi.zhu@intel.com> - * - */ - -#ifndef __IWM_UMAC_H__ -#define __IWM_UMAC_H__ - -struct iwm_udma_in_hdr { - __le32 cmd; - __le32 size; -} __packed; - -struct iwm_udma_out_nonwifi_hdr { - __le32 cmd; - __le32 addr; - __le32 op1_sz; - __le32 op2; -} __packed; - -struct iwm_udma_out_wifi_hdr { - __le32 cmd; - __le32 meta_data; -} __packed; - -/* Sequence numbering */ -#define UMAC_WIFI_SEQ_NUM_BASE 1 -#define UMAC_WIFI_SEQ_NUM_MAX 0x4000 -#define UMAC_NONWIFI_SEQ_NUM_BASE 1 -#define UMAC_NONWIFI_SEQ_NUM_MAX 0x10 - -/* MAC address address */ -#define WICO_MAC_ADDRESS_ADDR 0x604008F8 - -/* RA / TID */ -#define UMAC_HDI_ACT_TBL_IDX_TID_POS 0 -#define UMAC_HDI_ACT_TBL_IDX_TID_SEED 0xF - -#define UMAC_HDI_ACT_TBL_IDX_RA_POS 4 -#define UMAC_HDI_ACT_TBL_IDX_RA_SEED 0xF - -#define UMAC_HDI_ACT_TBL_IDX_RA_UMAC 0xF -#define UMAC_HDI_ACT_TBL_IDX_TID_UMAC 0x9 -#define UMAC_HDI_ACT_TBL_IDX_TID_LMAC 0xA - -#define UMAC_HDI_ACT_TBL_IDX_HOST_CMD \ - ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ - (UMAC_HDI_ACT_TBL_IDX_TID_UMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) -#define UMAC_HDI_ACT_TBL_IDX_UMAC_CMD \ - ((UMAC_HDI_ACT_TBL_IDX_RA_UMAC << UMAC_HDI_ACT_TBL_IDX_RA_POS) |\ - (UMAC_HDI_ACT_TBL_IDX_TID_LMAC << UMAC_HDI_ACT_TBL_IDX_TID_POS)) - -/* STA ID and color */ -#define STA_ID_SEED (0x0f) -#define STA_ID_POS (0) -#define STA_ID_MSK (STA_ID_SEED << STA_ID_POS) - -#define STA_COLOR_SEED (0x7) -#define STA_COLOR_POS (4) -#define STA_COLOR_MSK (STA_COLOR_SEED << STA_COLOR_POS) - -#define STA_ID_N_COLOR_COLOR(id_n_color) \ - (((id_n_color) & STA_COLOR_MSK) >> STA_COLOR_POS) -#define STA_ID_N_COLOR_ID(id_n_color) \ - (((id_n_color) & STA_ID_MSK) >> STA_ID_POS) - -/* iwm_umac_notif_alive.page_grp_state Group number -- bits [3:0] */ -#define UMAC_ALIVE_PAGE_STS_GRP_NUM_POS 0 -#define UMAC_ALIVE_PAGE_STS_GRP_NUM_SEED 0xF - -/* iwm_umac_notif_alive.page_grp_state Super group number -- bits [7:4] */ -#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_POS 4 -#define UMAC_ALIVE_PAGE_STS_SGRP_NUM_SEED 0xF - -/* iwm_umac_notif_alive.page_grp_state Group min size -- bits [15:8] */ -#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_POS 8 -#define UMAC_ALIVE_PAGE_STS_GRP_MIN_SIZE_SEED 0xFF - -/* iwm_umac_notif_alive.page_grp_state Group max size -- bits [23:16] */ -#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_POS 16 -#define UMAC_ALIVE_PAGE_STS_GRP_MAX_SIZE_SEED 0xFF - -/* iwm_umac_notif_alive.page_grp_state Super group max size -- bits [31:24] */ -#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_POS 24 -#define UMAC_ALIVE_PAGE_STS_SGRP_MAX_SIZE_SEED 0xFF - -/* Barkers */ -#define UMAC_REBOOT_BARKER 0xdeadbeef -#define UMAC_ACK_BARKER 0xfeedbabe -#define UMAC_PAD_TERMINAL 0xadadadad - -/* UMAC JMP address */ -#define UMAC_MU_FW_INST_DATA_12_ADDR 0xBF0000 - -/* iwm_umac_hdi_out_hdr.cmd OP code -- bits [3:0] */ -#define UMAC_HDI_OUT_CMD_OPCODE_POS 0 -#define UMAC_HDI_OUT_CMD_OPCODE_SEED 0xF - -/* iwm_umac_hdi_out_hdr.cmd End-Of-Transfer -- bits [10:10] */ -#define UMAC_HDI_OUT_CMD_EOT_POS 10 -#define UMAC_HDI_OUT_CMD_EOT_SEED 0x1 - -/* iwm_umac_hdi_out_hdr.cmd UTFD only usage -- bits [11:11] */ -#define UMAC_HDI_OUT_CMD_UTFD_ONLY_POS 11 -#define UMAC_HDI_OUT_CMD_UTFD_ONLY_SEED 0x1 - -/* iwm_umac_hdi_out_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ -#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 -#define UDMA_HDI_OUT_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF - -/* iwm_umac_hdi_out_hdr.cmd Signature -- bits [31:16] */ -#define UMAC_HDI_OUT_CMD_SIGNATURE_POS 16 -#define UMAC_HDI_OUT_CMD_SIGNATURE_SEED 0xFFFF - -/* iwm_umac_hdi_out_hdr.meta_data Byte count -- bits [11:0] */ -#define UMAC_HDI_OUT_BYTE_COUNT_POS 0 -#define UMAC_HDI_OUT_BYTE_COUNT_SEED 0xFFF - -/* iwm_umac_hdi_out_hdr.meta_data Credit group -- bits [15:12] */ -#define UMAC_HDI_OUT_CREDIT_GRP_POS 12 -#define UMAC_HDI_OUT_CREDIT_GRP_SEED 0xF - -/* iwm_umac_hdi_out_hdr.meta_data RA/TID -- bits [23:16] */ -#define UMAC_HDI_OUT_RATID_POS 16 -#define UMAC_HDI_OUT_RATID_SEED 0xFF - -/* iwm_umac_hdi_out_hdr.meta_data LMAC offset -- bits [31:24] */ -#define UMAC_HDI_OUT_LMAC_OFFSET_POS 24 -#define UMAC_HDI_OUT_LMAC_OFFSET_SEED 0xFF - -/* Signature */ -#define UMAC_HDI_OUT_SIGNATURE 0xCBBC - -/* buffer alignment */ -#define UMAC_HDI_BUF_ALIGN_MSK 0xF - -/* iwm_umac_hdi_in_hdr.cmd OP code -- bits [3:0] */ -#define UMAC_HDI_IN_CMD_OPCODE_POS 0 -#define UMAC_HDI_IN_CMD_OPCODE_SEED 0xF - -/* iwm_umac_hdi_in_hdr.cmd Non-WiFi API response -- bits [6:4] */ -#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_POS 4 -#define UMAC_HDI_IN_CMD_NON_WIFI_RESP_SEED 0x7 - -/* iwm_umac_hdi_in_hdr.cmd WiFi API source -- bits [5:4] */ -#define UMAC_HDI_IN_CMD_SOURCE_POS 4 -#define UMAC_HDI_IN_CMD_SOURCE_SEED 0x3 - -/* iwm_umac_hdi_in_hdr.cmd WiFi API EOT -- bits [6:6] */ -#define UMAC_HDI_IN_CMD_EOT_POS 6 -#define UMAC_HDI_IN_CMD_EOT_SEED 0x1 - -/* iwm_umac_hdi_in_hdr.cmd timestamp present -- bits [7:7] */ -#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_POS 7 -#define UMAC_HDI_IN_CMD_TIME_STAMP_PRESENT_SEED 0x1 - -/* iwm_umac_hdi_in_hdr.cmd WiFi Non-last AMSDU -- bits [8:8] */ -#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_POS 8 -#define UMAC_HDI_IN_CMD_NON_LAST_AMSDU_SEED 0x1 - -/* iwm_umac_hdi_in_hdr.cmd WiFi HW sequence number -- bits [31:9] */ -#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_POS 9 -#define UMAC_HDI_IN_CMD_HW_SEQ_NUM_SEED 0x7FFFFF - -/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW sequence number -- bits [12:15] */ -#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_POS 12 -#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SEQ_NUM_SEED 0xF - -/* iwm_umac_hdi_in_hdr.cmd Non-WiFi HW signature -- bits [16:31] */ -#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_POS 16 -#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG_SEED 0xFFFF - -/* Fixed Non-WiFi signature */ -#define UDMA_HDI_IN_CMD_NON_WIFI_HW_SIG 0xCBBC - -/* IN NTFY op-codes */ -#define UMAC_NOTIFY_OPCODE_ALIVE 0xA1 -#define UMAC_NOTIFY_OPCODE_INIT_COMPLETE 0xA2 -#define UMAC_NOTIFY_OPCODE_WIFI_CORE_STATUS 0xA3 -#define UMAC_NOTIFY_OPCODE_ERROR 0xA4 -#define UMAC_NOTIFY_OPCODE_DEBUG 0xA5 -#define UMAC_NOTIFY_OPCODE_WIFI_IF_WRAPPER 0xB0 -#define UMAC_NOTIFY_OPCODE_STATS 0xB1 -#define UMAC_NOTIFY_OPCODE_PAGE_DEALLOC 0xB3 -#define UMAC_NOTIFY_OPCODE_RX_TICKET 0xB4 -#define UMAC_NOTIFY_OPCODE_MAX (UMAC_NOTIFY_OPCODE_RX_TICKET -\ - UMAC_NOTIFY_OPCODE_ALIVE + 1) -#define UMAC_NOTIFY_OPCODE_FIRST (UMAC_NOTIFY_OPCODE_ALIVE) - -/* HDI OUT OP CODE */ -#define UMAC_HDI_OUT_OPCODE_PING 0x0 -#define UMAC_HDI_OUT_OPCODE_READ 0x1 -#define UMAC_HDI_OUT_OPCODE_WRITE 0x2 -#define UMAC_HDI_OUT_OPCODE_JUMP 0x3 -#define UMAC_HDI_OUT_OPCODE_REBOOT 0x4 -#define UMAC_HDI_OUT_OPCODE_WRITE_PERSISTENT 0x5 -#define UMAC_HDI_OUT_OPCODE_READ_PERSISTENT 0x6 -#define UMAC_HDI_OUT_OPCODE_READ_MODIFY_WRITE 0x7 -/* #define UMAC_HDI_OUT_OPCODE_RESERVED 0x8..0xA */ -#define UMAC_HDI_OUT_OPCODE_WRITE_AUX_REG 0xB -#define UMAC_HDI_OUT_OPCODE_WIFI 0xF - -/* HDI IN OP CODE -- Non WiFi*/ -#define UMAC_HDI_IN_OPCODE_PING 0x0 -#define UMAC_HDI_IN_OPCODE_READ 0x1 -#define UMAC_HDI_IN_OPCODE_WRITE 0x2 -#define UMAC_HDI_IN_OPCODE_WRITE_PERSISTENT 0x5 -#define UMAC_HDI_IN_OPCODE_READ_PERSISTENT 0x6 -#define UMAC_HDI_IN_OPCODE_READ_MODIFY_WRITE 0x7 -#define UMAC_HDI_IN_OPCODE_EP_MGMT 0x8 -#define UMAC_HDI_IN_OPCODE_CREDIT_CHANGE 0x9 -#define UMAC_HDI_IN_OPCODE_CTRL_DATABASE 0xA -#define UMAC_HDI_IN_OPCODE_WRITE_AUX_REG 0xB -#define UMAC_HDI_IN_OPCODE_NONWIFI_MAX \ - (UMAC_HDI_IN_OPCODE_WRITE_AUX_REG + 1) -#define UMAC_HDI_IN_OPCODE_WIFI 0xF - -/* HDI IN SOURCE */ -#define UMAC_HDI_IN_SOURCE_FHRX 0x0 -#define UMAC_HDI_IN_SOURCE_UDMA 0x1 -#define UMAC_HDI_IN_SOURCE_FW 0x2 -#define UMAC_HDI_IN_SOURCE_RESERVED 0x3 - -/* OUT CMD op-codes */ -#define UMAC_CMD_OPCODE_ECHO 0x01 -#define UMAC_CMD_OPCODE_HALT 0x02 -#define UMAC_CMD_OPCODE_RESET 0x03 -#define UMAC_CMD_OPCODE_BULK_EP_INACT_TIMEOUT 0x09 -#define UMAC_CMD_OPCODE_URB_CANCEL_ACK 0x0A -#define UMAC_CMD_OPCODE_DCACHE_FLUSH 0x0B -#define UMAC_CMD_OPCODE_EEPROM_PROXY 0x0C -#define UMAC_CMD_OPCODE_TX_ECHO 0x0D -#define UMAC_CMD_OPCODE_DBG_MON 0x0E -#define UMAC_CMD_OPCODE_INTERNAL_TX 0x0F -#define UMAC_CMD_OPCODE_SET_PARAM_FIX 0x10 -#define UMAC_CMD_OPCODE_SET_PARAM_VAR 0x11 -#define UMAC_CMD_OPCODE_GET_PARAM 0x12 -#define UMAC_CMD_OPCODE_DBG_EVENT_WRAPPER 0x13 -#define UMAC_CMD_OPCODE_TARGET 0x14 -#define UMAC_CMD_OPCODE_STATISTIC_REQUEST 0x15 -#define UMAC_CMD_OPCODE_GET_CHAN_INFO_LIST 0x16 -#define UMAC_CMD_OPCODE_SET_PARAM_LIST 0x17 -#define UMAC_CMD_OPCODE_GET_PARAM_LIST 0x18 -#define UMAC_CMD_OPCODE_STOP_RESUME_STA_TX 0x19 -#define UMAC_CMD_OPCODE_TEST_BLOCK_ACK 0x1A - -#define UMAC_CMD_OPCODE_BASE_WRAPPER 0xFA -#define UMAC_CMD_OPCODE_LMAC_WRAPPER 0xFB -#define UMAC_CMD_OPCODE_HW_TEST_WRAPPER 0xFC -#define UMAC_CMD_OPCODE_WIFI_IF_WRAPPER 0xFD -#define UMAC_CMD_OPCODE_WIFI_WRAPPER 0xFE -#define UMAC_CMD_OPCODE_WIFI_PASS_THROUGH 0xFF - -/* UMAC WiFi interface op-codes */ -#define UMAC_WIFI_IF_CMD_SET_PROFILE 0x11 -#define UMAC_WIFI_IF_CMD_INVALIDATE_PROFILE 0x12 -#define UMAC_WIFI_IF_CMD_SET_EXCLUDE_LIST 0x13 -#define UMAC_WIFI_IF_CMD_SCAN_REQUEST 0x14 -#define UMAC_WIFI_IF_CMD_SCAN_CONFIG 0x15 -#define UMAC_WIFI_IF_CMD_ADD_WEP40_KEY 0x16 -#define UMAC_WIFI_IF_CMD_ADD_WEP104_KEY 0x17 -#define UMAC_WIFI_IF_CMD_ADD_TKIP_KEY 0x18 -#define UMAC_WIFI_IF_CMD_ADD_CCMP_KEY 0x19 -#define UMAC_WIFI_IF_CMD_REMOVE_KEY 0x1A -#define UMAC_WIFI_IF_CMD_GLOBAL_TX_KEY_ID 0x1B -#define UMAC_WIFI_IF_CMD_SET_HOST_EXTENDED_IE 0x1C -#define UMAC_WIFI_IF_CMD_GET_SUPPORTED_CHANNELS 0x1E -#define UMAC_WIFI_IF_CMD_PMKID_UPDATE 0x1F -#define UMAC_WIFI_IF_CMD_TX_PWR_TRIGGER 0x20 - -/* UMAC WiFi interface ports */ -#define UMAC_WIFI_IF_FLG_PORT_DEF 0x00 -#define UMAC_WIFI_IF_FLG_PORT_PAN 0x01 -#define UMAC_WIFI_IF_FLG_PORT_PAN_INVALID WIFI_IF_FLG_PORT_DEF - -/* UMAC WiFi interface actions */ -#define UMAC_WIFI_IF_FLG_ACT_GET 0x10 -#define UMAC_WIFI_IF_FLG_ACT_SET 0x20 - -/* iwm_umac_fw_cmd_hdr.meta_data byte count -- bits [11:0] */ -#define UMAC_FW_CMD_BYTE_COUNT_POS 0 -#define UMAC_FW_CMD_BYTE_COUNT_SEED 0xFFF - -/* iwm_umac_fw_cmd_hdr.meta_data status -- bits [15:12] */ -#define UMAC_FW_CMD_STATUS_POS 12 -#define UMAC_FW_CMD_STATUS_SEED 0xF - -/* iwm_umac_fw_cmd_hdr.meta_data full TX command by Driver -- bits [16:16] */ -#define UMAC_FW_CMD_TX_DRV_FULL_CMD_POS 16 -#define UMAC_FW_CMD_TX_DRV_FULL_CMD_SEED 0x1 - -/* iwm_umac_fw_cmd_hdr.meta_data TX command by FW -- bits [17:17] */ -#define UMAC_FW_CMD_TX_FW_CMD_POS 17 -#define UMAC_FW_CMD_TX_FW_CMD_SEED 0x1 - -/* iwm_umac_fw_cmd_hdr.meta_data TX plaintext mode -- bits [18:18] */ -#define UMAC_FW_CMD_TX_PLAINTEXT_POS 18 -#define UMAC_FW_CMD_TX_PLAINTEXT_SEED 0x1 - -/* iwm_umac_fw_cmd_hdr.meta_data STA color -- bits [22:20] */ -#define UMAC_FW_CMD_TX_STA_COLOR_POS 20 -#define UMAC_FW_CMD_TX_STA_COLOR_SEED 0x7 - -/* iwm_umac_fw_cmd_hdr.meta_data TX life time (TU) -- bits [31:24] */ -#define UMAC_FW_CMD_TX_LIFETIME_TU_POS 24 -#define UMAC_FW_CMD_TX_LIFETIME_TU_SEED 0xFF - -/* iwm_dev_cmd_hdr.flags Response required -- bits [5:5] */ -#define UMAC_DEV_CMD_FLAGS_RESP_REQ_POS 5 -#define UMAC_DEV_CMD_FLAGS_RESP_REQ_SEED 0x1 - -/* iwm_dev_cmd_hdr.flags Aborted command -- bits [6:6] */ -#define UMAC_DEV_CMD_FLAGS_ABORT_POS 6 -#define UMAC_DEV_CMD_FLAGS_ABORT_SEED 0x1 - -/* iwm_dev_cmd_hdr.flags Internal command -- bits [7:7] */ -#define DEV_CMD_FLAGS_FLD_INTERNAL_POS 7 -#define DEV_CMD_FLAGS_FLD_INTERNAL_SEED 0x1 - -/* Rx */ -/* Rx actions */ -#define IWM_RX_TICKET_DROP 0x0 -#define IWM_RX_TICKET_RELEASE 0x1 -#define IWM_RX_TICKET_SNIFFER 0x2 -#define IWM_RX_TICKET_ENQUEUE 0x3 - -/* Rx flags */ -#define IWM_RX_TICKET_PAD_SIZE_MSK 0x2 -#define IWM_RX_TICKET_SPECIAL_SNAP_MSK 0x4 -#define IWM_RX_TICKET_AMSDU_MSK 0x8 -#define IWM_RX_TICKET_DROP_REASON_POS 4 -#define IWM_RX_TICKET_DROP_REASON_MSK (0x1F << IWM_RX_TICKET_DROP_REASON_POS) - -#define IWM_RX_DROP_NO_DROP 0x0 -#define IWM_RX_DROP_BAD_CRC 0x1 -/* L2P no address match */ -#define IWM_RX_DROP_LMAC_ADDR_FILTER 0x2 -/* Multicast address not in list */ -#define IWM_RX_DROP_MCAST_ADDR_FILTER 0x3 -/* Control frames are not sent to the driver */ -#define IWM_RX_DROP_CTL_FRAME 0x4 -/* Our frame is back */ -#define IWM_RX_DROP_OUR_TX 0x5 -/* Association class filtering */ -#define IWM_RX_DROP_CLASS_FILTER 0x6 -/* Duplicated frame */ -#define IWM_RX_DROP_DUPLICATE_FILTER 0x7 -/* Decryption error */ -#define IWM_RX_DROP_SEC_ERR 0x8 -/* Unencrypted frame while encryption is on */ -#define IWM_RX_DROP_SEC_NO_ENCRYPTION 0x9 -/* Replay check failure */ -#define IWM_RX_DROP_SEC_REPLAY_ERR 0xa -/* uCode and FW key color mismatch, check before replay */ -#define IWM_RX_DROP_SEC_KEY_COLOR_MISMATCH 0xb -#define IWM_RX_DROP_SEC_TKIP_COUNTER_MEASURE 0xc -/* No fragmentations Db is found */ -#define IWM_RX_DROP_FRAG_NO_RESOURCE 0xd -/* Fragmention Db has seqCtl mismatch Vs. non-1st frag */ -#define IWM_RX_DROP_FRAG_ERR 0xe -#define IWM_RX_DROP_FRAG_LOST 0xf -#define IWM_RX_DROP_FRAG_COMPLETE 0x10 -/* Should be handled by UMAC */ -#define IWM_RX_DROP_MANAGEMENT 0x11 -/* STA not found by UMAC */ -#define IWM_RX_DROP_NO_STATION 0x12 -/* NULL or QoS NULL */ -#define IWM_RX_DROP_NULL_DATA 0x13 -#define IWM_RX_DROP_BA_REORDER_OLD_SEQCTL 0x14 -#define IWM_RX_DROP_BA_REORDER_DUPLICATE 0x15 - -struct iwm_rx_ticket { - __le16 action; - __le16 id; - __le16 flags; - u8 payload_offset; /* includes: MAC header, pad, IV */ - u8 tail_len; /* includes: MIC, ICV, CRC (w/o STATUS) */ -} __packed; - -struct iwm_rx_mpdu_hdr { - __le16 len; - __le16 reserved; -} __packed; - -/* UMAC SW WIFI API */ - -struct iwm_dev_cmd_hdr { - u8 cmd; - u8 flags; - __le16 seq_num; -} __packed; - -struct iwm_umac_fw_cmd_hdr { - __le32 meta_data; - struct iwm_dev_cmd_hdr cmd; -} __packed; - -struct iwm_umac_wifi_out_hdr { - struct iwm_udma_out_wifi_hdr hw_hdr; - struct iwm_umac_fw_cmd_hdr sw_hdr; -} __packed; - -struct iwm_umac_nonwifi_out_hdr { - struct iwm_udma_out_nonwifi_hdr hw_hdr; -} __packed; - -struct iwm_umac_wifi_in_hdr { - struct iwm_udma_in_hdr hw_hdr; - struct iwm_umac_fw_cmd_hdr sw_hdr; -} __packed; - -struct iwm_umac_nonwifi_in_hdr { - struct iwm_udma_in_hdr hw_hdr; - __le32 time_stamp; -} __packed; - -#define IWM_UMAC_PAGE_SIZE 0x200 - -/* Notify structures */ -struct iwm_fw_version { - u8 minor; - u8 major; - __le16 id; -}; - -struct iwm_fw_build { - u8 type; - u8 subtype; - u8 platform; - u8 opt; -}; - -struct iwm_fw_alive_hdr { - struct iwm_fw_version ver; - struct iwm_fw_build build; - __le32 os_build; - __le32 log_hdr_addr; - __le32 log_buf_addr; - __le32 sys_timer_addr; -}; - -#define WAIT_NOTIF_TIMEOUT (2 * HZ) -#define SCAN_COMPLETE_TIMEOUT (3 * HZ) - -#define UMAC_NTFY_ALIVE_STATUS_ERR 0xDEAD -#define UMAC_NTFY_ALIVE_STATUS_OK 0xCAFE - -#define UMAC_NTFY_INIT_COMPLETE_STATUS_ERR 0xDEAD -#define UMAC_NTFY_INIT_COMPLETE_STATUS_OK 0xCAFE - -#define UMAC_NTFY_WIFI_CORE_STATUS_LINK_EN 0x40 -#define UMAC_NTFY_WIFI_CORE_STATUS_MLME_EN 0x80 - -#define IWM_MACS_OUT_GROUPS 6 -#define IWM_MACS_OUT_SGROUPS 1 - - -#define WIFI_IF_NTFY_ASSOC_START 0x80 -#define WIFI_IF_NTFY_ASSOC_COMPLETE 0x81 -#define WIFI_IF_NTFY_PROFILE_INVALIDATE_COMPLETE 0x82 -#define WIFI_IF_NTFY_CONNECTION_TERMINATED 0x83 -#define WIFI_IF_NTFY_SCAN_COMPLETE 0x84 -#define WIFI_IF_NTFY_STA_TABLE_CHANGE 0x85 -#define WIFI_IF_NTFY_EXTENDED_IE_REQUIRED 0x86 -#define WIFI_IF_NTFY_RADIO_PREEMPTION 0x87 -#define WIFI_IF_NTFY_BSS_TRK_TABLE_CHANGED 0x88 -#define WIFI_IF_NTFY_BSS_TRK_ENTRIES_REMOVED 0x89 -#define WIFI_IF_NTFY_LINK_QUALITY_STATISTICS 0x8A -#define WIFI_IF_NTFY_MGMT_FRAME 0x8B - -/* DEBUG INDICATIONS */ -#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_START 0xE0 -#define WIFI_DBG_IF_NTFY_SCAN_SUPER_JOB_COMPLETE 0xE1 -#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_START 0xE2 -#define WIFI_DBG_IF_NTFY_SCAN_CHANNEL_RESULT 0xE3 -#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_START 0xE4 -#define WIFI_DBG_IF_NTFY_SCAN_MINI_JOB_COMPLETE 0xE5 -#define WIFI_DBG_IF_NTFY_CNCT_ATC_START 0xE6 -#define WIFI_DBG_IF_NTFY_COEX_NOTIFICATION 0xE7 -#define WIFI_DBG_IF_NTFY_COEX_HANDLE_ENVELOP 0xE8 -#define WIFI_DBG_IF_NTFY_COEX_HANDLE_RELEASE_ENVELOP 0xE9 - -#define WIFI_IF_NTFY_MAX 0xff - -/* Notification structures */ -struct iwm_umac_notif_wifi_if { - struct iwm_umac_wifi_in_hdr hdr; - u8 status; - u8 flags; - __le16 buf_size; -} __packed; - -#define UMAC_ROAM_REASON_FIRST_SELECTION 0x1 -#define UMAC_ROAM_REASON_AP_DEAUTH 0x2 -#define UMAC_ROAM_REASON_AP_CONNECT_LOST 0x3 -#define UMAC_ROAM_REASON_RSSI 0x4 -#define UMAC_ROAM_REASON_AP_ASSISTED_ROAM 0x5 -#define UMAC_ROAM_REASON_IBSS_COALESCING 0x6 - -struct iwm_umac_notif_assoc_start { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 roam_reason; - u8 bssid[ETH_ALEN]; - u8 reserved[2]; -} __packed; - -#define UMAC_ASSOC_COMPLETE_SUCCESS 0x0 -#define UMAC_ASSOC_COMPLETE_FAILURE 0x1 - -struct iwm_umac_notif_assoc_complete { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 status; - u8 bssid[ETH_ALEN]; - u8 band; - u8 channel; -} __packed; - -#define UMAC_PROFILE_INVALID_ASSOC_TIMEOUT 0x0 -#define UMAC_PROFILE_INVALID_ROAM_TIMEOUT 0x1 -#define UMAC_PROFILE_INVALID_REQUEST 0x2 -#define UMAC_PROFILE_INVALID_RF_PREEMPTED 0x3 - -struct iwm_umac_notif_profile_invalidate { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 reason; -} __packed; - -#define UMAC_SCAN_RESULT_SUCCESS 0x0 -#define UMAC_SCAN_RESULT_ABORTED 0x1 -#define UMAC_SCAN_RESULT_REJECTED 0x2 -#define UMAC_SCAN_RESULT_FAILED 0x3 - -struct iwm_umac_notif_scan_complete { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 type; - __le32 result; - u8 seq_num; -} __packed; - -#define UMAC_OPCODE_ADD_MODIFY 0x0 -#define UMAC_OPCODE_REMOVE 0x1 -#define UMAC_OPCODE_CLEAR_ALL 0x2 - -#define UMAC_STA_FLAG_QOS 0x1 - -struct iwm_umac_notif_sta_info { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 opcode; - u8 mac_addr[ETH_ALEN]; - u8 sta_id; /* bits 0-3: station ID, bits 4-7: station color */ - u8 flags; -} __packed; - -#define UMAC_BAND_2GHZ 0 -#define UMAC_BAND_5GHZ 1 - -#define UMAC_CHANNEL_WIDTH_20MHZ 0 -#define UMAC_CHANNEL_WIDTH_40MHZ 1 - -struct iwm_umac_notif_bss_info { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 type; - __le32 timestamp; - __le16 table_idx; - __le16 frame_len; - u8 band; - u8 channel; - s8 rssi; - u8 reserved; - u8 frame_buf[1]; -} __packed; - -#define IWM_BSS_REMOVE_INDEX_MSK 0x0fff -#define IWM_BSS_REMOVE_FLAGS_MSK 0xfc00 - -#define IWM_BSS_REMOVE_FLG_AGE 0x1000 -#define IWM_BSS_REMOVE_FLG_TIMEOUT 0x2000 -#define IWM_BSS_REMOVE_FLG_TABLE_FULL 0x4000 - -struct iwm_umac_notif_bss_removed { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le32 count; - __le16 entries[0]; -} __packed; - -struct iwm_umac_notif_mgt_frame { - struct iwm_umac_notif_wifi_if mlme_hdr; - __le16 len; - u8 frame[1]; -} __packed; - -struct iwm_umac_notif_alive { - struct iwm_umac_wifi_in_hdr hdr; - __le16 status; - __le16 reserved1; - struct iwm_fw_alive_hdr alive_data; - __le16 reserved2; - __le16 page_grp_count; - __le32 page_grp_state[IWM_MACS_OUT_GROUPS]; -} __packed; - -struct iwm_umac_notif_init_complete { - struct iwm_umac_wifi_in_hdr hdr; - __le16 status; - __le16 reserved; -} __packed; - -/* error categories */ -enum { - UMAC_SYS_ERR_CAT_NONE = 0, - UMAC_SYS_ERR_CAT_BOOT, - UMAC_SYS_ERR_CAT_UMAC, - UMAC_SYS_ERR_CAT_UAXM, - UMAC_SYS_ERR_CAT_LMAC, - UMAC_SYS_ERR_CAT_MAX -}; - -struct iwm_fw_error_hdr { - __le32 category; - __le32 status; - __le32 pc; - __le32 blink1; - __le32 blink2; - __le32 ilink1; - __le32 ilink2; - __le32 data1; - __le32 data2; - __le32 line_num; - __le32 umac_status; - __le32 lmac_status; - __le32 sdio_status; - __le32 dbm_sample_ctrl; - __le32 dbm_buf_base; - __le32 dbm_buf_end; - __le32 dbm_buf_write_ptr; - __le32 dbm_buf_cycle_cnt; -} __packed; - -struct iwm_umac_notif_error { - struct iwm_umac_wifi_in_hdr hdr; - struct iwm_fw_error_hdr err; -} __packed; - -#define UMAC_DEALLOC_NTFY_CHANGES_CNT_POS 0 -#define UMAC_DEALLOC_NTFY_CHANGES_CNT_SEED 0xff -#define UMAC_DEALLOC_NTFY_CHANGES_MSK_POS 8 -#define UMAC_DEALLOC_NTFY_CHANGES_MSK_SEED 0xffffff -#define UMAC_DEALLOC_NTFY_PAGE_CNT_POS 0 -#define UMAC_DEALLOC_NTFY_PAGE_CNT_SEED 0xffffff -#define UMAC_DEALLOC_NTFY_GROUP_NUM_POS 24 -#define UMAC_DEALLOC_NTFY_GROUP_NUM_SEED 0xf - -struct iwm_umac_notif_page_dealloc { - struct iwm_umac_wifi_in_hdr hdr; - __le32 changes; - __le32 grp_info[IWM_MACS_OUT_GROUPS]; -} __packed; - -struct iwm_umac_notif_wifi_status { - struct iwm_umac_wifi_in_hdr hdr; - __le16 status; - __le16 reserved; -} __packed; - -struct iwm_umac_notif_rx_ticket { - struct iwm_umac_wifi_in_hdr hdr; - u8 num_tickets; - u8 reserved[3]; - struct iwm_rx_ticket tickets[1]; -} __packed; - -/* Tx/Rx rates window (number of max of last update window per second) */ -#define UMAC_NTF_RATE_SAMPLE_NR 4 - -/* Max numbers of bits required to go through all antennae in bitmasks */ -#define UMAC_PHY_NUM_CHAINS 3 - -#define IWM_UMAC_MGMT_TID 8 -#define IWM_UMAC_TID_NR 9 /* 8 TIDs + MGMT */ - -struct iwm_umac_notif_stats { - struct iwm_umac_wifi_in_hdr hdr; - __le32 flags; - __le32 timestamp; - __le16 tid_load[IWM_UMAC_TID_NR + 1]; /* 1 non-QoS + 1 dword align */ - __le16 tx_rate[UMAC_NTF_RATE_SAMPLE_NR]; - __le16 rx_rate[UMAC_NTF_RATE_SAMPLE_NR]; - __le32 chain_energy[UMAC_PHY_NUM_CHAINS]; - s32 rssi_dbm; - s32 noise_dbm; - __le32 supp_rates; - __le32 supp_ht_rates; - __le32 missed_beacons; - __le32 rx_beacons; - __le32 rx_dir_pkts; - __le32 rx_nondir_pkts; - __le32 rx_multicast; - __le32 rx_errors; - __le32 rx_drop_other_bssid; - __le32 rx_drop_decode; - __le32 rx_drop_reassembly; - __le32 rx_drop_bad_len; - __le32 rx_drop_overflow; - __le32 rx_drop_crc; - __le32 rx_drop_missed; - __le32 tx_dir_pkts; - __le32 tx_nondir_pkts; - __le32 tx_failure; - __le32 tx_errors; - __le32 tx_drop_max_retry; - __le32 tx_err_abort; - __le32 tx_err_carrier; - __le32 rx_bytes; - __le32 tx_bytes; - __le32 tx_power; - __le32 tx_max_power; - __le32 roam_threshold; - __le32 ap_assoc_nr; - __le32 scan_full; - __le32 scan_abort; - __le32 ap_nr; - __le32 roam_nr; - __le32 roam_missed_beacons; - __le32 roam_rssi; - __le32 roam_unassoc; - __le32 roam_deauth; - __le32 roam_ap_loadblance; -} __packed; - -#define UMAC_STOP_TX_FLAG 0x1 -#define UMAC_RESUME_TX_FLAG 0x2 - -#define LAST_SEQ_NUM_INVALID 0xFFFF - -struct iwm_umac_notif_stop_resume_tx { - struct iwm_umac_wifi_in_hdr hdr; - u8 flags; /* UMAC_*_TX_FLAG_* */ - u8 sta_id; - __le16 stop_resume_tid_msk; /* tid bitmask */ -} __packed; - -#define UMAC_MAX_NUM_PMKIDS 4 - -/* WiFi interface wrapper header */ -struct iwm_umac_wifi_if { - u8 oid; - u8 flags; - __le16 buf_size; -} __packed; - -#define IWM_SEQ_NUM_HOST_MSK 0x0000 -#define IWM_SEQ_NUM_UMAC_MSK 0x4000 -#define IWM_SEQ_NUM_LMAC_MSK 0x8000 -#define IWM_SEQ_NUM_MSK 0xC000 - -#endif diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index f4a203049fb4..706781316195 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -805,7 +805,6 @@ void lbs_scan_done(struct lbs_private *priv) } static int lbs_cfg_scan(struct wiphy *wiphy, - struct net_device *dev, struct cfg80211_scan_request *request) { struct lbs_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 2e2dbfa2ee50..96726f79a1dd 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -68,7 +68,6 @@ #define CMD_802_11_BEACON_STOP 0x0049 #define CMD_802_11_MAC_ADDRESS 0x004d #define CMD_802_11_LED_GPIO_CTRL 0x004e -#define CMD_802_11_EEPROM_ACCESS 0x0059 #define CMD_802_11_BAND_CONFIG 0x0058 #define CMD_GSPI_BUS_CONFIG 0x005a #define CMD_802_11D_DOMAIN_INFO 0x005b diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index a0b7cfd34685..3f38d846b093 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -292,7 +292,7 @@ struct mac80211_hwsim_data { struct list_head list; struct ieee80211_hw *hw; struct device *dev; - struct ieee80211_supported_band bands[2]; + struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)]; struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)]; struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)]; @@ -678,8 +678,7 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw, continue; if (data2->idle || !data2->started || - !hwsim_ps_rx_ok(data2, skb) || - !data->channel || !data2->channel || + !hwsim_ps_rx_ok(data2, skb) || !data2->channel || data->channel->center_freq != data2->channel->center_freq || !(data->group & data2->group)) continue; @@ -1083,6 +1082,8 @@ enum hwsim_testmode_attr { enum hwsim_testmode_cmd { HWSIM_TM_CMD_SET_PS = 0, HWSIM_TM_CMD_GET_PS = 1, + HWSIM_TM_CMD_STOP_QUEUES = 2, + HWSIM_TM_CMD_WAKE_QUEUES = 3, }; static const struct nla_policy hwsim_testmode_policy[HWSIM_TM_ATTR_MAX + 1] = { @@ -1122,6 +1123,12 @@ static int mac80211_hwsim_testmode_cmd(struct ieee80211_hw *hw, if (nla_put_u32(skb, HWSIM_TM_ATTR_PS, hwsim->ps)) goto nla_put_failure; return cfg80211_testmode_reply(skb); + case HWSIM_TM_CMD_STOP_QUEUES: + ieee80211_stop_queues(hw); + return 0; + case HWSIM_TM_CMD_WAKE_QUEUES: + ieee80211_wake_queues(hw); + return 0; default: return -EOPNOTSUPP; } @@ -1486,7 +1493,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, struct mac80211_hwsim_data *data2; struct ieee80211_tx_info *txi; struct hwsim_tx_rate *tx_attempts; - struct sk_buff __user *ret_skb; + unsigned long ret_skb_ptr; struct sk_buff *skb, *tmp; struct mac_address *src; unsigned int hwsim_flags; @@ -1504,8 +1511,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]); hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]); - ret_skb = (struct sk_buff __user *) - (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); + ret_skb_ptr = nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]); data2 = get_hwsim_data_ref_from_addr(src); @@ -1514,7 +1520,7 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, /* look for the skb matching the cookie passed back from user */ skb_queue_walk_safe(&data2->pending, skb, tmp) { - if (skb == ret_skb) { + if ((unsigned long)skb == ret_skb_ptr) { skb_unlink(skb, &data2->pending); found = true; break; @@ -1857,7 +1863,7 @@ static int __init init_mac80211_hwsim(void) sband->n_bitrates = ARRAY_SIZE(hwsim_rates) - 4; break; default: - break; + continue; } sband->ht_cap.ht_supported = true; diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c index 9c44088054dd..900ee129e825 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.c +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c @@ -256,7 +256,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta, else last_seq = priv->rx_seq[tid]; - if (last_seq >= new_node->start_win) + if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM && + last_seq >= new_node->start_win) new_node->start_win = last_seq + 1; new_node->win_size = win_size; @@ -596,5 +597,5 @@ void mwifiex_11n_cleanup_reorder_tbl(struct mwifiex_private *priv) spin_unlock_irqrestore(&priv->rx_reorder_tbl_lock, flags); INIT_LIST_HEAD(&priv->rx_reorder_tbl_ptr); - memset(priv->rx_seq, 0, sizeof(priv->rx_seq)); + mwifiex_reset_11n_rx_seq_num(priv); } diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.h b/drivers/net/wireless/mwifiex/11n_rxreorder.h index f1bffebabc60..6c9815a0f5d8 100644 --- a/drivers/net/wireless/mwifiex/11n_rxreorder.h +++ b/drivers/net/wireless/mwifiex/11n_rxreorder.h @@ -37,6 +37,13 @@ #define ADDBA_RSP_STATUS_ACCEPT 0 +#define MWIFIEX_DEF_11N_RX_SEQ_NUM 0xffff + +static inline void mwifiex_reset_11n_rx_seq_num(struct mwifiex_private *priv) +{ + memset(priv->rx_seq, 0xff, sizeof(priv->rx_seq)); +} + int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *, u16 seqNum, u16 tid, u8 *ta, diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 015fec3371a0..e27b3168862c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -170,7 +170,9 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, if (!priv->sec_info.wep_enabled) return 0; - if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) { + if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) { + priv->wep_key_curr_index = key_index; + } else if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) { wiphy_err(wiphy, "set default Tx key index\n"); return -EFAULT; } @@ -187,9 +189,25 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, struct key_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); + struct mwifiex_wep_key *wep_key; const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const u8 *peer_mac = pairwise ? mac_addr : bc_mac; + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP && + (params->cipher == WLAN_CIPHER_SUITE_WEP40 || + params->cipher == WLAN_CIPHER_SUITE_WEP104)) { + if (params->key && params->key_len) { + wep_key = &priv->wep_key[key_index]; + memset(wep_key, 0, sizeof(struct mwifiex_wep_key)); + memcpy(wep_key->key_material, params->key, + params->key_len); + wep_key->key_index = key_index; + wep_key->key_length = params->key_len; + priv->sec_info.wep_enabled = 1; + } + return 0; + } + if (mwifiex_set_encode(priv, params->key, params->key_len, key_index, peer_mac, 0)) { wiphy_err(wiphy, "crypto keys added\n"); @@ -242,13 +260,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) flag = 1; first_chan = (u32) ch->hw_value; next_chan = first_chan; - max_pwr = ch->max_power; + max_pwr = ch->max_reg_power; no_of_parsed_chan = 1; continue; } if (ch->hw_value == next_chan + 1 && - ch->max_power == max_pwr) { + ch->max_reg_power == max_pwr) { next_chan++; no_of_parsed_chan++; } else { @@ -259,7 +277,7 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) no_of_triplet++; first_chan = (u32) ch->hw_value; next_chan = first_chan; - max_pwr = ch->max_power; + max_pwr = ch->max_reg_power; no_of_parsed_chan = 1; } } @@ -384,13 +402,13 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, cfp.freq = chan->center_freq; cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); - if (mwifiex_bss_set_channel(priv, &cfp)) - return -EFAULT; - - if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { + if (mwifiex_bss_set_channel(priv, &cfp)) + return -EFAULT; return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); - else - return mwifiex_uap_set_channel(priv, cfp.channel); + } + + return 0; } /* @@ -896,6 +914,69 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, return 0; } +/* cfg80211 operation handler for change_beacon. + * Function retrieves and sets modified management IEs to FW. + */ +static int mwifiex_cfg80211_change_beacon(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_beacon_data *data) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + wiphy_err(wiphy, "%s: bss_type mismatched\n", __func__); + return -EINVAL; + } + + if (!priv->bss_started) { + wiphy_err(wiphy, "%s: bss not started\n", __func__); + return -EINVAL; + } + + if (mwifiex_set_mgmt_ies(priv, data)) { + wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__); + return -EFAULT; + } + + return 0; +} + +static int +mwifiex_cfg80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) +{ + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv = mwifiex_get_priv(adapter, + MWIFIEX_BSS_ROLE_ANY); + struct mwifiex_ds_ant_cfg ant_cfg; + + if (!tx_ant || !rx_ant) + return -EOPNOTSUPP; + + if (adapter->hw_dev_mcs_support != HT_STREAM_2X2) { + /* Not a MIMO chip. User should provide specific antenna number + * for Tx/Rx path or enable all antennas for diversity + */ + if (tx_ant != rx_ant) + return -EOPNOTSUPP; + + if ((tx_ant & (tx_ant - 1)) && + (tx_ant != BIT(adapter->number_of_antenna) - 1)) + return -EOPNOTSUPP; + + if ((tx_ant == BIT(adapter->number_of_antenna) - 1) && + (priv->adapter->number_of_antenna > 1)) { + tx_ant = RF_ANTENNA_AUTO; + rx_ant = RF_ANTENNA_AUTO; + } + } + + ant_cfg.tx_ant = tx_ant; + ant_cfg.rx_ant = rx_ant; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_RF_ANTENNA, + HostCmd_ACT_GEN_SET, 0, &ant_cfg); +} + /* cfg80211 operation handler for stop ap. * Function stops BSS running at uAP interface. */ @@ -929,7 +1010,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) return -1; - if (mwifiex_set_mgmt_ies(priv, params)) + if (mwifiex_set_mgmt_ies(priv, ¶ms->beacon)) return -1; bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); @@ -958,15 +1039,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, case NL80211_HIDDEN_SSID_ZERO_CONTENTS: /* firmware doesn't support this type of hidden SSID */ default: + kfree(bss_cfg); return -EINVAL; } + bss_cfg->channel = + (u8)ieee80211_frequency_to_channel(params->channel->center_freq); + bss_cfg->band_cfg = BAND_CONFIG_MANUAL; + + if (mwifiex_set_rf_channel(priv, params->channel, + params->channel_type)) { + kfree(bss_cfg); + wiphy_err(wiphy, "Failed to set band config information!\n"); + return -1; + } + if (mwifiex_set_secure_params(priv, bss_cfg, params)) { kfree(bss_cfg); wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); return -1; } + mwifiex_set_ht_params(priv, bss_cfg, params); + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "Failed to stop the BSS\n"); @@ -990,6 +1085,16 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, return -1; } + if (priv->sec_info.wep_enabled) + priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE; + else + priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE; + + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_MAC_CONTROL, + HostCmd_ACT_GEN_SET, 0, + &priv->curr_pkt_filter)) + return -1; + return 0; } @@ -1335,9 +1440,10 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) * it also informs the results. */ static int -mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, +mwifiex_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *dev = request->wdev->netdev; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int i; struct ieee80211_channel *chan; @@ -1381,7 +1487,7 @@ mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, priv->user_scan_cfg->chan_list[i].scan_time = 0; } - if (mwifiex_set_user_scan_ioctl(priv, priv->user_scan_cfg)) + if (mwifiex_scan_networks(priv, priv->user_scan_cfg)) return -EFAULT; if (request->ie && request->ie_len) { @@ -1471,11 +1577,11 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, /* * create a new virtual interface with the given name */ -struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; @@ -1484,7 +1590,7 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev; if (!adapter) - return NULL; + return ERR_PTR(-EFAULT); switch (type) { case NL80211_IFTYPE_UNSPECIFIED: @@ -1494,12 +1600,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, if (priv->bss_mode) { wiphy_err(wiphy, "cannot create multiple sta/adhoc ifaces\n"); - return NULL; + return ERR_PTR(-EINVAL); } wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) - return NULL; + return ERR_PTR(-ENOMEM); wdev->wiphy = wiphy; priv->wdev = wdev; @@ -1522,12 +1628,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, if (priv->bss_mode) { wiphy_err(wiphy, "Can't create multiple AP interfaces"); - return NULL; + return ERR_PTR(-EINVAL); } wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); if (!wdev) - return NULL; + return ERR_PTR(-ENOMEM); priv->wdev = wdev; wdev->wiphy = wiphy; @@ -1544,14 +1650,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, break; default: wiphy_err(wiphy, "type not supported\n"); - return NULL; + return ERR_PTR(-EINVAL); } dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name, ether_setup, 1); if (!dev) { wiphy_err(wiphy, "no memory available for netdevice\n"); - goto error; + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-ENOMEM); } mwifiex_init_priv_params(priv, dev); @@ -1582,7 +1689,9 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, /* Register network device */ if (register_netdevice(dev)) { wiphy_err(wiphy, "cannot register virtual network device\n"); - goto error; + free_netdev(dev); + priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; + return ERR_PTR(-EFAULT); } sema_init(&priv->async_sem, 1); @@ -1593,22 +1702,16 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_init(priv); #endif - return dev; -error: - if (dev && (dev->reg_state == NETREG_UNREGISTERED)) - free_netdev(dev); - priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED; - - return NULL; + return wdev; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); /* * del_virtual_intf: remove the virtual interface determined by dev */ -int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); @@ -1620,11 +1723,11 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); - if (dev->reg_state == NETREG_REGISTERED) - unregister_netdevice(dev); + if (wdev->netdev->reg_state == NETREG_REGISTERED) + unregister_netdevice(wdev->netdev); - if (dev->reg_state == NETREG_UNREGISTERED) - free_netdev(dev); + if (wdev->netdev->reg_state == NETREG_UNREGISTERED) + free_netdev(wdev->netdev); /* Clear the priv in adapter */ priv->netdev = NULL; @@ -1658,7 +1761,9 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, .start_ap = mwifiex_cfg80211_start_ap, .stop_ap = mwifiex_cfg80211_stop_ap, + .change_beacon = mwifiex_cfg80211_change_beacon, .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, + .set_antenna = mwifiex_cfg80211_set_antenna, }; /* @@ -1705,7 +1810,14 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; - wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY; + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | + WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD; + + wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2; + + wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; + wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; /* Reserve space for mwifiex specific private data for BSS */ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 51e023ec1de4..c68adec3cc8b 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -578,6 +578,7 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, } else { adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + queue_work(adapter->workqueue, &adapter->main_work); } return ret; @@ -1102,7 +1103,8 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, &resp->params.opt_hs_cfg; uint32_t conditions = le32_to_cpu(phs_cfg->params.hs_config.conditions); - if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE)) { + if (phs_cfg->action == cpu_to_le16(HS_ACTIVATE) && + adapter->iface_type == MWIFIEX_SDIO) { mwifiex_hs_activated_event(priv, true); return 0; } else { @@ -1114,6 +1116,9 @@ int mwifiex_ret_802_11_hs_cfg(struct mwifiex_private *priv, } if (conditions != HOST_SLEEP_CFG_CANCEL) { adapter->is_hs_configured = true; + if (adapter->iface_type == MWIFIEX_USB || + adapter->iface_type == MWIFIEX_PCIE) + mwifiex_hs_activated_event(priv, true); } else { adapter->is_hs_configured = false; if (adapter->hs_activated) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 561452a5c818..14e985d01dee 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -124,6 +124,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45) #define TLV_TYPE_UAP_BCAST_SSID (PROPRIETARY_TLV_BASE_ID + 48) #define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51) +#define TLV_TYPE_UAP_WEP_KEY (PROPRIETARY_TLV_BASE_ID + 59) #define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60) #define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64) #define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65) @@ -162,6 +163,12 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define ISSUPP_11NENABLED(FwCapInfo) (FwCapInfo & BIT(11)) +#define MWIFIEX_DEF_HT_CAP (IEEE80211_HT_CAP_DSSSCCK40 | \ + (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT) | \ + IEEE80211_HT_CAP_SM_PS) + +#define MWIFIEX_DEF_AMPDU IEEE80211_HT_AMPDU_PARM_FACTOR + /* dev_cap bitmap * BIT * 0-16 reserved @@ -219,6 +226,8 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_RF_REG_ACCESS 0x001b #define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad #define HostCmd_CMD_802_11_RF_CHANNEL 0x001d +#define HostCmd_CMD_RF_TX_PWR 0x001e +#define HostCmd_CMD_RF_ANTENNA 0x0020 #define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 #define HostCmd_CMD_MAC_CONTROL 0x0028 #define HostCmd_CMD_802_11_AD_HOC_START 0x002b @@ -314,6 +323,12 @@ enum ENH_PS_MODES { #define HostCmd_BSS_TYPE_MASK 0xf000 +#define HostCmd_ACT_SET_RX 0x0001 +#define HostCmd_ACT_SET_TX 0x0002 +#define HostCmd_ACT_SET_BOTH 0x0003 + +#define RF_ANTENNA_AUTO 0xFFFF + #define HostCmd_SET_SEQ_NO_BSS_INFO(seq, num, type) { \ (((seq) & 0x00ff) | \ (((num) & 0x000f) << 8)) | \ @@ -869,6 +884,25 @@ struct host_cmd_ds_txpwr_cfg { __le32 mode; } __packed; +struct host_cmd_ds_rf_tx_pwr { + __le16 action; + __le16 cur_level; + u8 max_power; + u8 min_power; +} __packed; + +struct host_cmd_ds_rf_ant_mimo { + __le16 action_tx; + __le16 tx_ant_mode; + __le16 action_rx; + __le16 rx_ant_mode; +}; + +struct host_cmd_ds_rf_ant_siso { + __le16 action; + __le16 ant_mode; +}; + struct mwifiex_bcn_param { u8 bssid[ETH_ALEN]; u8 rssi; @@ -1195,6 +1229,13 @@ struct host_cmd_tlv_passphrase { u8 passphrase[0]; } __packed; +struct host_cmd_tlv_wep_key { + struct host_cmd_tlv tlv; + u8 key_index; + u8 is_default; + u8 key[1]; +}; + struct host_cmd_tlv_auth_type { struct host_cmd_tlv tlv; u8 auth_type; @@ -1347,6 +1388,9 @@ struct host_cmd_ds_command { struct host_cmd_ds_tx_rate_query tx_rate; struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; struct host_cmd_ds_txpwr_cfg txp_cfg; + struct host_cmd_ds_rf_tx_pwr txp; + struct host_cmd_ds_rf_ant_mimo ant_mimo; + struct host_cmd_ds_rf_ant_siso ant_siso; struct host_cmd_ds_802_11_ps_mode_enh psmode_enh; struct host_cmd_ds_802_11_hs_cfg_enh opt_hs_cfg; struct host_cmd_ds_802_11_scan scan; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c index ceb82cd749cc..1d8dd003e396 100644 --- a/drivers/net/wireless/mwifiex/ie.c +++ b/drivers/net/wireless/mwifiex/ie.c @@ -51,8 +51,7 @@ mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask, for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) { mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask); - len = le16_to_cpu(priv->mgmt_ie[i].ie_length) + - le16_to_cpu(ie->ie_length); + len = le16_to_cpu(ie->ie_length); if (mask == MWIFIEX_AUTO_IDX_MASK) continue; @@ -108,10 +107,8 @@ mwifiex_update_autoindex_ies(struct mwifiex_private *priv, return -1; tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer; - tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length); memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length)); - le16_add_cpu(&priv->mgmt_ie[index].ie_length, - le16_to_cpu(ie->ie_length)); + priv->mgmt_ie[index].ie_length = ie->ie_length; priv->mgmt_ie[index].ie_index = cpu_to_le16(index); priv->mgmt_ie[index].mgmt_subtype_mask = cpu_to_le16(mask); @@ -213,95 +210,67 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, /* save assoc resp ie index after auto-indexing */ *assoc_idx = *((u16 *)pos); + kfree(ap_custom_ie); return ret; } -/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs, - * association response IEs from cfg80211_ap_settings function and sets these IE - * to FW. +/* This function checks if WPS IE is present in passed buffer and copies it to + * mwifiex_ie structure. + * Function takes pointer to struct mwifiex_ie pointer as argument. + * If WPS IE is present memory is allocated for mwifiex_ie pointer and filled + * in with WPS IE. Caller should take care of freeing this memory. */ -int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, - struct cfg80211_ap_settings *params) +static int mwifiex_update_wps_ie(const u8 *ies, int ies_len, + struct mwifiex_ie **ie_ptr, u16 mask) { - struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; - struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL; - struct ieee_types_header *ie = NULL; - u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK; - u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK; - u16 mask; - int ret = 0; - - if (params->beacon.tail && params->beacon.tail_len) { - ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail, - params->beacon.tail_len); - if (ie) { - rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!rsn_ie) - return -ENOMEM; - - rsn_ie->ie_index = cpu_to_le16(rsn_idx); - mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP; - rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask); - rsn_ie->ie_length = cpu_to_le16(ie->len + 2); - memcpy(rsn_ie->ie_buffer, ie, ie->len + 2); - - if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx, - NULL, NULL, - NULL, NULL)) { - ret = -1; - goto done; - } + struct ieee_types_header *wps_ie; + struct mwifiex_ie *ie = NULL; + const u8 *vendor_ie; + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPS, + ies, ies_len); + if (vendor_ie) { + ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!ie) + return -ENOMEM; - priv->rsn_idx = rsn_idx; - } + wps_ie = (struct ieee_types_header *)vendor_ie; + memcpy(ie->ie_buffer, wps_ie, wps_ie->len + 2); + ie->ie_length = cpu_to_le16(wps_ie->len + 2); + ie->mgmt_subtype_mask = cpu_to_le16(mask); + ie->ie_index = cpu_to_le16(MWIFIEX_AUTO_IDX_MASK); } - if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) { - beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!beacon_ie) { - ret = -ENOMEM; - goto done; - } - - beacon_ie->ie_index = cpu_to_le16(beacon_idx); - beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON); - beacon_ie->ie_length = - cpu_to_le16(params->beacon.beacon_ies_len); - memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies, - params->beacon.beacon_ies_len); - } + *ie_ptr = ie; + return 0; +} - if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) { - pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!pr_ie) { - ret = -ENOMEM; - goto done; - } +/* This function parses beacon IEs, probe response IEs, association response IEs + * from cfg80211_ap_settings->beacon and sets these IE to FW. + */ +static int mwifiex_set_mgmt_beacon_data_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *data) +{ + struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL, *ar_ie = NULL; + u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK; + u16 ar_idx = MWIFIEX_AUTO_IDX_MASK; + int ret = 0; - pr_ie->ie_index = cpu_to_le16(pr_idx); - pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP); - pr_ie->ie_length = - cpu_to_le16(params->beacon.proberesp_ies_len); - memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies, - params->beacon.proberesp_ies_len); - } + if (data->beacon_ies && data->beacon_ies_len) + mwifiex_update_wps_ie(data->beacon_ies, data->beacon_ies_len, + &beacon_ie, MGMT_MASK_BEACON); - if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) { - ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); - if (!ar_ie) { - ret = -ENOMEM; - goto done; - } + if (data->proberesp_ies && data->proberesp_ies_len) + mwifiex_update_wps_ie(data->proberesp_ies, + data->proberesp_ies_len, &pr_ie, + MGMT_MASK_PROBE_RESP); - ar_ie->ie_index = cpu_to_le16(ar_idx); - mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP; - ar_ie->mgmt_subtype_mask = cpu_to_le16(mask); - ar_ie->ie_length = - cpu_to_le16(params->beacon.assocresp_ies_len); - memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies, - params->beacon.assocresp_ies_len); - } + if (data->assocresp_ies && data->assocresp_ies_len) + mwifiex_update_wps_ie(data->assocresp_ies, + data->assocresp_ies_len, &ar_ie, + MGMT_MASK_ASSOC_RESP | + MGMT_MASK_REASSOC_RESP); if (beacon_ie || pr_ie || ar_ie) { ret = mwifiex_update_uap_custom_ie(priv, beacon_ie, @@ -319,11 +288,67 @@ done: kfree(beacon_ie); kfree(pr_ie); kfree(ar_ie); - kfree(rsn_ie); return ret; } +/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs, + * association response IEs from cfg80211_ap_settings function and sets these IE + * to FW. + */ +int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, + struct cfg80211_beacon_data *info) +{ + struct mwifiex_ie *gen_ie; + struct ieee_types_header *rsn_ie, *wpa_ie = NULL; + u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0; + const u8 *vendor_ie; + + if (info->tail && info->tail_len) { + gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!gen_ie) + return -ENOMEM; + gen_ie->ie_index = cpu_to_le16(rsn_idx); + gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON | + MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP); + + rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, + info->tail, info->tail_len); + if (rsn_ie) { + memcpy(gen_ie->ie_buffer, rsn_ie, rsn_ie->len + 2); + ie_len = rsn_ie->len + 2; + gen_ie->ie_length = cpu_to_le16(ie_len); + } + + vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, + WLAN_OUI_TYPE_MICROSOFT_WPA, + info->tail, + info->tail_len); + if (vendor_ie) { + wpa_ie = (struct ieee_types_header *)vendor_ie; + memcpy(gen_ie->ie_buffer + ie_len, + wpa_ie, wpa_ie->len + 2); + ie_len += wpa_ie->len + 2; + gen_ie->ie_length = cpu_to_le16(ie_len); + } + + if (rsn_ie || wpa_ie) { + if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, + NULL, NULL, + NULL, NULL)) { + kfree(gen_ie); + return -1; + } + priv->rsn_idx = rsn_idx; + } + + kfree(gen_ie); + } + + return mwifiex_set_mgmt_beacon_data_ies(priv, info); +} + /* This function removes management IE set */ int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) { diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index 0f18ef6a30c8..b543a4d82ff3 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -103,6 +103,7 @@ static void scan_delay_timer_fn(unsigned long data) msecs_to_jiffies(MWIFIEX_SCAN_DELAY_MSEC)); adapter->scan_delay_cnt++; } + queue_work(priv->adapter->workqueue, &priv->adapter->main_work); } else { /* * Tx data queue is empty. Get scan command from scan_pending_q diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index e6be6ee75951..e121294cc1ac 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -21,6 +21,7 @@ #define _MWIFIEX_IOCTL_H_ #include <net/mac80211.h> +#include <net/lib80211.h> enum { MWIFIEX_SCAN_TYPE_UNCHANGED = 0, @@ -71,6 +72,13 @@ struct wpa_param { u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN]; }; +struct wep_key { + u8 key_index; + u8 is_default; + u16 length; + u8 key[WLAN_KEY_LEN_WEP104]; +}; + #define KEY_MGMT_ON_HOST 0x03 #define MWIFIEX_AUTH_MODE_AUTO 0xFF #define BAND_CONFIG_MANUAL 0x00 @@ -90,6 +98,8 @@ struct mwifiex_uap_bss_param { u16 key_mgmt; u16 key_mgmt_operation; struct wpa_param wpa_cfg; + struct wep_key wep_cfg[NUM_WEP_KEYS]; + struct ieee80211_ht_cap ht_cap; }; enum { @@ -267,6 +277,11 @@ struct mwifiex_ds_11n_amsdu_aggr_ctrl { u16 curr_buf_size; }; +struct mwifiex_ds_ant_cfg { + u32 tx_ant; + u32 rx_ant; +}; + #define MWIFIEX_NUM_OF_CMD_BUFFER 20 #define MWIFIEX_SIZE_OF_CMD_BUFFER 2048 diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index 0f06f07a70e6..46803621d015 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -190,7 +190,8 @@ process_start: adapter->tx_lock_flag) break; - if (adapter->scan_processing || adapter->data_sent || + if ((adapter->scan_processing && + !adapter->scan_delay_cnt) || adapter->data_sent || mwifiex_wmm_lists_empty(adapter)) { if (adapter->cmd_sent || adapter->curr_cmd || (!is_command_pending(adapter))) @@ -376,7 +377,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); @@ -843,7 +844,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) rtnl_lock(); if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 5b32221077c4..774880d5cb56 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -840,6 +840,9 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, int mwifiex_set_secure_params(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_config, struct cfg80211_ap_settings *params); +void mwifiex_set_ht_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params); /* * This function checks if the queuing is RA based or not. @@ -946,8 +949,8 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, struct mwifiex_rate_cfg *rate); int mwifiex_request_scan(struct mwifiex_private *priv, struct cfg80211_ssid *req_ssid); -int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, - struct mwifiex_user_scan_cfg *scan_req); +int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in); int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel); @@ -990,7 +993,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, int mwifiex_main_process(struct mwifiex_adapter *); -int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel); int mwifiex_bss_set_channel(struct mwifiex_private *, struct mwifiex_chan_freq_power *cfp); int mwifiex_get_bss_info(struct mwifiex_private *, @@ -1003,15 +1005,17 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); -struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, enum nl80211_iftype type, - u32 *flags, struct vif_params *params); -int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); +struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config); int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, - struct cfg80211_ap_settings *params); + struct cfg80211_beacon_data *data); int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); u8 *mwifiex_11d_code_2_region(u8 code); diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c index efaf26ccd6ba..884ed6377003 100644 --- a/drivers/net/wireless/mwifiex/scan.c +++ b/drivers/net/wireless/mwifiex/scan.c @@ -1296,8 +1296,8 @@ mwifiex_radio_type_to_band(u8 radio_type) * order to send the appropriate scan commands to firmware to populate or * update the internal driver scan table. */ -static int mwifiex_scan_networks(struct mwifiex_private *priv, - const struct mwifiex_user_scan_cfg *user_scan_in) +int mwifiex_scan_networks(struct mwifiex_private *priv, + const struct mwifiex_user_scan_cfg *user_scan_in) { int ret = 0; struct mwifiex_adapter *adapter = priv->adapter; @@ -1362,6 +1362,7 @@ static int mwifiex_scan_networks(struct mwifiex_private *priv, adapter->cmd_queued = cmd_node; mwifiex_insert_cmd_to_pending_q(adapter, cmd_node, true); + queue_work(adapter->workqueue, &adapter->main_work); } else { spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags); @@ -1378,26 +1379,6 @@ static int mwifiex_scan_networks(struct mwifiex_private *priv, } /* - * Sends IOCTL request to start a scan with user configurations. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - * - * Upon completion, it also generates a wireless event to notify - * applications. - */ -int mwifiex_set_user_scan_ioctl(struct mwifiex_private *priv, - struct mwifiex_user_scan_cfg *scan_req) -{ - int status; - - status = mwifiex_scan_networks(priv, scan_req); - queue_work(priv->adapter->workqueue, &priv->adapter->main_work); - - return status; -} - -/* * This function prepares a scan command to be sent to the firmware. * * This uses the scan command configuration sent to the command processing diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c index e0377473282f..fc8a9bfa1248 100644 --- a/drivers/net/wireless/mwifiex/sdio.c +++ b/drivers/net/wireless/mwifiex/sdio.c @@ -978,10 +978,10 @@ static int mwifiex_decode_rx_packet(struct mwifiex_adapter *adapter, dev_dbg(adapter->dev, "info: --- Rx: Event ---\n"); adapter->event_cause = *(u32 *) skb->data; - skb_pull(skb, MWIFIEX_EVENT_HEADER_LEN); - if ((skb->len > 0) && (skb->len < MAX_EVENT_SIZE)) - memcpy(adapter->event_body, skb->data, skb->len); + memcpy(adapter->event_body, + skb->data + MWIFIEX_EVENT_HEADER_LEN, + skb->len); /* event cause has been saved to adapter->event_cause */ adapter->event_received = true; diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 40e025da6bc2..75eaa6f877fa 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -260,6 +260,56 @@ static int mwifiex_cmd_tx_power_cfg(struct host_cmd_ds_command *cmd, } /* + * This function prepares command to get RF Tx power. + */ +static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, void *data_buf) +{ + struct host_cmd_ds_rf_tx_pwr *txp = &cmd->params.txp; + + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_tx_pwr) + + S_DS_GEN); + cmd->command = cpu_to_le16(HostCmd_CMD_RF_TX_PWR); + txp->action = cpu_to_le16(cmd_action); + + return 0; +} + +/* + * This function prepares command to set rf antenna. + */ +static int mwifiex_cmd_rf_antenna(struct mwifiex_private *priv, + struct host_cmd_ds_command *cmd, + u16 cmd_action, + struct mwifiex_ds_ant_cfg *ant_cfg) +{ + struct host_cmd_ds_rf_ant_mimo *ant_mimo = &cmd->params.ant_mimo; + struct host_cmd_ds_rf_ant_siso *ant_siso = &cmd->params.ant_siso; + + cmd->command = cpu_to_le16(HostCmd_CMD_RF_ANTENNA); + + if (cmd_action != HostCmd_ACT_GEN_SET) + return 0; + + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) { + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_mimo) + + S_DS_GEN); + ant_mimo->action_tx = cpu_to_le16(HostCmd_ACT_SET_TX); + ant_mimo->tx_ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); + ant_mimo->action_rx = cpu_to_le16(HostCmd_ACT_SET_RX); + ant_mimo->rx_ant_mode = cpu_to_le16((u16)ant_cfg->rx_ant); + } else { + cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_rf_ant_siso) + + S_DS_GEN); + ant_siso->action = cpu_to_le16(HostCmd_ACT_SET_BOTH); + ant_siso->ant_mode = cpu_to_le16((u16)ant_cfg->tx_ant); + } + + return 0; +} + +/* * This function prepares command to set Host Sleep configuration. * * Preparation includes - @@ -1055,6 +1105,14 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, ret = mwifiex_cmd_tx_power_cfg(cmd_ptr, cmd_action, data_buf); break; + case HostCmd_CMD_RF_TX_PWR: + ret = mwifiex_cmd_rf_tx_power(priv, cmd_ptr, cmd_action, + data_buf); + break; + case HostCmd_CMD_RF_ANTENNA: + ret = mwifiex_cmd_rf_antenna(priv, cmd_ptr, cmd_action, + data_buf); + break; case HostCmd_CMD_802_11_PS_MODE_ENH: ret = mwifiex_cmd_enh_power_mode(priv, cmd_ptr, cmd_action, (uint16_t)cmd_oid, data_buf); @@ -1283,7 +1341,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) priv->data_rate = 0; /* get tx power */ - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_TXPWR_CFG, + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_RF_TX_PWR, HostCmd_ACT_GEN_GET, 0, NULL); if (ret) return -1; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index a79ed9bd9695..71c9b5b92e6d 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -451,6 +451,57 @@ static int mwifiex_ret_tx_power_cfg(struct mwifiex_private *priv, } /* + * This function handles the command response of get RF Tx power. + */ +static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_rf_tx_pwr *txp = &resp->params.txp; + u16 action = le16_to_cpu(txp->action); + + priv->tx_power_level = le16_to_cpu(txp->cur_level); + + if (action == HostCmd_ACT_GEN_GET) { + priv->max_tx_power_level = txp->max_power; + priv->min_tx_power_level = txp->min_power; + } + + dev_dbg(priv->adapter->dev, + "Current TxPower Level=%d, Max Power=%d, Min Power=%d\n", + priv->tx_power_level, priv->max_tx_power_level, + priv->min_tx_power_level); + + return 0; +} + +/* + * This function handles the command response of set rf antenna + */ +static int mwifiex_ret_rf_antenna(struct mwifiex_private *priv, + struct host_cmd_ds_command *resp) +{ + struct host_cmd_ds_rf_ant_mimo *ant_mimo = &resp->params.ant_mimo; + struct host_cmd_ds_rf_ant_siso *ant_siso = &resp->params.ant_siso; + struct mwifiex_adapter *adapter = priv->adapter; + + if (adapter->hw_dev_mcs_support == HT_STREAM_2X2) + dev_dbg(adapter->dev, + "RF_ANT_RESP: Tx action = 0x%x, Tx Mode = 0x%04x" + " Rx action = 0x%x, Rx Mode = 0x%04x\n", + le16_to_cpu(ant_mimo->action_tx), + le16_to_cpu(ant_mimo->tx_ant_mode), + le16_to_cpu(ant_mimo->action_rx), + le16_to_cpu(ant_mimo->rx_ant_mode)); + else + dev_dbg(adapter->dev, + "RF_ANT_RESP: action = 0x%x, Mode = 0x%04x\n", + le16_to_cpu(ant_siso->action), + le16_to_cpu(ant_siso->ant_mode)); + + return 0; +} + +/* * This function handles the command response of set/get MAC address. * * Handling includes saving the MAC address in driver. @@ -847,6 +898,12 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_TXPWR_CFG: ret = mwifiex_ret_tx_power_cfg(priv, resp); break; + case HostCmd_CMD_RF_TX_PWR: + ret = mwifiex_ret_rf_tx_power(priv, resp); + break; + case HostCmd_CMD_RF_ANTENNA: + ret = mwifiex_ret_rf_antenna(priv, resp); + break; case HostCmd_CMD_802_11_PS_MODE_ENH: ret = mwifiex_ret_enh_power_mode(priv, resp, data_buf); break; diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index 4ace5a3dcd23..11e731f3581c 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -406,9 +406,9 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) break; case EVENT_UAP_STA_ASSOC: - skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER); memset(&sinfo, 0, sizeof(sinfo)); - event = (struct mwifiex_assoc_event *)adapter->event_skb->data; + event = (struct mwifiex_assoc_event *) + (adapter->event_body + MWIFIEX_UAP_EVENT_EXTRA_HEADER); if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) { len = -1; @@ -433,9 +433,8 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) GFP_KERNEL); break; case EVENT_UAP_STA_DEAUTH: - skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER); - cfg80211_del_sta(priv->netdev, adapter->event_skb->data, - GFP_KERNEL); + cfg80211_del_sta(priv->netdev, adapter->event_body + + MWIFIEX_UAP_EVENT_EXTRA_HEADER, GFP_KERNEL); break; case EVENT_UAP_BSS_IDLE: priv->media_connected = false; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 106c449477b2..f2fd2423214f 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -66,9 +66,6 @@ int mwifiex_wait_queue_complete(struct mwifiex_adapter *adapter) dev_dbg(adapter->dev, "cmd pending\n"); atomic_inc(&adapter->cmd_pending); - /* Status pending, wake up main process */ - queue_work(adapter->workqueue, &adapter->main_work); - /* Wait for completion */ wait_event_interruptible(adapter->cmd_wait_q.wait, *(cmd_queued->condition)); diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c index e2faec4db108..cecb27283196 100644 --- a/drivers/net/wireless/mwifiex/txrx.c +++ b/drivers/net/wireless/mwifiex/txrx.c @@ -161,15 +161,11 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter, goto done; for (i = 0; i < adapter->priv_num; i++) { - tpriv = adapter->priv[i]; - if ((GET_BSS_ROLE(tpriv) == MWIFIEX_BSS_ROLE_STA) && - (tpriv->media_connected)) { - if (netif_queue_stopped(tpriv->netdev)) - mwifiex_wake_up_net_dev_queue(tpriv->netdev, - adapter); - } + if (tpriv->media_connected && + netif_queue_stopped(tpriv->netdev)) + mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter); } done: dev_kfree_skb_any(skb); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c index 8173ab66066d..f40e93fe894a 100644 --- a/drivers/net/wireless/mwifiex/uap_cmd.c +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -26,6 +26,18 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, struct mwifiex_uap_bss_param *bss_config, struct cfg80211_ap_settings *params) { int i; + struct mwifiex_wep_key wep_key; + + if (!params->privacy) { + bss_config->protocol = PROTOCOL_NO_SECURITY; + bss_config->key_mgmt = KEY_MGMT_NONE; + bss_config->wpa_cfg.length = 0; + priv->sec_info.wep_enabled = 0; + priv->sec_info.wpa_enabled = 0; + priv->sec_info.wpa2_enabled = 0; + + return 0; + } switch (params->auth_type) { case NL80211_AUTHTYPE_OPEN_SYSTEM: @@ -54,7 +66,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, } if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) { - bss_config->protocol = PROTOCOL_WPA2; + bss_config->protocol |= PROTOCOL_WPA2; bss_config->key_mgmt = KEY_MGMT_EAP; } break; @@ -66,7 +78,7 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, } if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) { - bss_config->protocol = PROTOCOL_WPA2; + bss_config->protocol |= PROTOCOL_WPA2; bss_config->key_mgmt = KEY_MGMT_PSK; } break; @@ -80,10 +92,19 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, case WLAN_CIPHER_SUITE_WEP104: break; case WLAN_CIPHER_SUITE_TKIP: - bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + bss_config->wpa_cfg.pairwise_cipher_wpa |= + CIPHER_TKIP; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + bss_config->wpa_cfg.pairwise_cipher_wpa2 |= + CIPHER_TKIP; break; case WLAN_CIPHER_SUITE_CCMP: - bss_config->wpa_cfg.pairwise_cipher_wpa2 = + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_1) + bss_config->wpa_cfg.pairwise_cipher_wpa |= + CIPHER_AES_CCMP; + if (params->crypto.wpa_versions & NL80211_WPA_VERSION_2) + bss_config->wpa_cfg.pairwise_cipher_wpa2 |= CIPHER_AES_CCMP; default: break; @@ -93,6 +114,27 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, switch (params->crypto.cipher_group) { case WLAN_CIPHER_SUITE_WEP40: case WLAN_CIPHER_SUITE_WEP104: + if (priv->sec_info.wep_enabled) { + bss_config->protocol = PROTOCOL_STATIC_WEP; + bss_config->key_mgmt = KEY_MGMT_NONE; + bss_config->wpa_cfg.length = 0; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + wep_key = priv->wep_key[i]; + bss_config->wep_cfg[i].key_index = i; + + if (priv->wep_key_curr_index == i) + bss_config->wep_cfg[i].is_default = 1; + else + bss_config->wep_cfg[i].is_default = 0; + + bss_config->wep_cfg[i].length = + wep_key.key_length; + memcpy(&bss_config->wep_cfg[i].key, + &wep_key.key_material, + wep_key.key_length); + } + } break; case WLAN_CIPHER_SUITE_TKIP: bss_config->wpa_cfg.group_cipher = CIPHER_TKIP; @@ -107,6 +149,33 @@ int mwifiex_set_secure_params(struct mwifiex_private *priv, return 0; } +/* This function updates 11n related parameters from IE and sets them into + * bss_config structure. + */ +void +mwifiex_set_ht_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_cfg, + struct cfg80211_ap_settings *params) +{ + const u8 *ht_ie; + + if (!ISSUPP_11NENABLED(priv->adapter->fw_cap_info)) + return; + + ht_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY, params->beacon.tail, + params->beacon.tail_len); + if (ht_ie) { + memcpy(&bss_cfg->ht_cap, ht_ie + 2, + sizeof(struct ieee80211_ht_cap)); + } else { + memset(&bss_cfg->ht_cap , 0, sizeof(struct ieee80211_ht_cap)); + bss_cfg->ht_cap.cap_info = cpu_to_le16(MWIFIEX_DEF_HT_CAP); + bss_cfg->ht_cap.ampdu_params_info = MWIFIEX_DEF_AMPDU; + } + + return; +} + /* This function initializes some of mwifiex_uap_bss_param variables. * This helps FW in ignoring invalid values. These values may or may not * be get updated to valid ones at later stage. @@ -124,6 +193,120 @@ void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) } /* This function parses BSS related parameters from structure + * and prepares TLVs specific to WPA/WPA2 security. + * These TLVs are appended to command buffer. + */ +static void +mwifiex_uap_bss_wpa(u8 **tlv_buf, void *cmd_buf, u16 *param_size) +{ + struct host_cmd_tlv_pwk_cipher *pwk_cipher; + struct host_cmd_tlv_gwk_cipher *gwk_cipher; + struct host_cmd_tlv_passphrase *passphrase; + struct host_cmd_tlv_akmp *tlv_akmp; + struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; + u16 cmd_size = *param_size; + u8 *tlv = *tlv_buf; + + tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; + tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); + tlv_akmp->tlv.len = cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - + sizeof(struct host_cmd_tlv)); + tlv_akmp->key_mgmt_operation = cpu_to_le16(bss_cfg->key_mgmt_operation); + tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); + cmd_size += sizeof(struct host_cmd_tlv_akmp); + tlv += sizeof(struct host_cmd_tlv_akmp); + + if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & VALID_CIPHER_BITMAP) { + pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; + pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - + sizeof(struct host_cmd_tlv)); + pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); + pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa; + cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); + tlv += sizeof(struct host_cmd_tlv_pwk_cipher); + } + + if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & VALID_CIPHER_BITMAP) { + pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; + pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_pwk_cipher) - + sizeof(struct host_cmd_tlv)); + pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); + pwk_cipher->cipher = bss_cfg->wpa_cfg.pairwise_cipher_wpa2; + cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); + tlv += sizeof(struct host_cmd_tlv_pwk_cipher); + } + + if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { + gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; + gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); + gwk_cipher->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_gwk_cipher) - + sizeof(struct host_cmd_tlv)); + gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; + cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); + tlv += sizeof(struct host_cmd_tlv_gwk_cipher); + } + + if (bss_cfg->wpa_cfg.length) { + passphrase = (struct host_cmd_tlv_passphrase *)tlv; + passphrase->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); + passphrase->tlv.len = cpu_to_le16(bss_cfg->wpa_cfg.length); + memcpy(passphrase->passphrase, bss_cfg->wpa_cfg.passphrase, + bss_cfg->wpa_cfg.length); + cmd_size += sizeof(struct host_cmd_tlv) + + bss_cfg->wpa_cfg.length; + tlv += sizeof(struct host_cmd_tlv) + bss_cfg->wpa_cfg.length; + } + + *param_size = cmd_size; + *tlv_buf = tlv; + + return; +} + +/* This function parses BSS related parameters from structure + * and prepares TLVs specific to WEP encryption. + * These TLVs are appended to command buffer. + */ +static void +mwifiex_uap_bss_wep(u8 **tlv_buf, void *cmd_buf, u16 *param_size) +{ + struct host_cmd_tlv_wep_key *wep_key; + u16 cmd_size = *param_size; + int i; + u8 *tlv = *tlv_buf; + struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; + + for (i = 0; i < NUM_WEP_KEYS; i++) { + if (bss_cfg->wep_cfg[i].length && + (bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP40 || + bss_cfg->wep_cfg[i].length == WLAN_KEY_LEN_WEP104)) { + wep_key = (struct host_cmd_tlv_wep_key *)tlv; + wep_key->tlv.type = cpu_to_le16(TLV_TYPE_UAP_WEP_KEY); + wep_key->tlv.len = + cpu_to_le16(bss_cfg->wep_cfg[i].length + 2); + wep_key->key_index = bss_cfg->wep_cfg[i].key_index; + wep_key->is_default = bss_cfg->wep_cfg[i].is_default; + memcpy(wep_key->key, bss_cfg->wep_cfg[i].key, + bss_cfg->wep_cfg[i].length); + cmd_size += sizeof(struct host_cmd_tlv) + 2 + + bss_cfg->wep_cfg[i].length; + tlv += sizeof(struct host_cmd_tlv) + 2 + + bss_cfg->wep_cfg[i].length; + } + } + + *param_size = cmd_size; + *tlv_buf = tlv; + + return; +} + +/* This function parses BSS related parameters from structure * and prepares TLVs. These TLVs are appended to command buffer. */ static int @@ -137,12 +320,9 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) struct host_cmd_tlv_frag_threshold *frag_threshold; struct host_cmd_tlv_rts_threshold *rts_threshold; struct host_cmd_tlv_retry_limit *retry_limit; - struct host_cmd_tlv_pwk_cipher *pwk_cipher; - struct host_cmd_tlv_gwk_cipher *gwk_cipher; struct host_cmd_tlv_encrypt_protocol *encrypt_protocol; struct host_cmd_tlv_auth_type *auth_type; - struct host_cmd_tlv_passphrase *passphrase; - struct host_cmd_tlv_akmp *tlv_akmp; + struct mwifiex_ie_types_htcap *htcap; struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; u16 cmd_size = *param_size; @@ -232,70 +412,11 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) } if ((bss_cfg->protocol & PROTOCOL_WPA) || (bss_cfg->protocol & PROTOCOL_WPA2) || - (bss_cfg->protocol & PROTOCOL_EAP)) { - tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; - tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); - tlv_akmp->tlv.len = - cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - - sizeof(struct host_cmd_tlv)); - tlv_akmp->key_mgmt_operation = - cpu_to_le16(bss_cfg->key_mgmt_operation); - tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); - cmd_size += sizeof(struct host_cmd_tlv_akmp); - tlv += sizeof(struct host_cmd_tlv_akmp); - - if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & - VALID_CIPHER_BITMAP) { - pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; - pwk_cipher->tlv.type = - cpu_to_le16(TLV_TYPE_PWK_CIPHER); - pwk_cipher->tlv.len = cpu_to_le16( - sizeof(struct host_cmd_tlv_pwk_cipher) - - sizeof(struct host_cmd_tlv)); - pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); - pwk_cipher->cipher = - bss_cfg->wpa_cfg.pairwise_cipher_wpa; - cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); - tlv += sizeof(struct host_cmd_tlv_pwk_cipher); - } - if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & - VALID_CIPHER_BITMAP) { - pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; - pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); - pwk_cipher->tlv.len = cpu_to_le16( - sizeof(struct host_cmd_tlv_pwk_cipher) - - sizeof(struct host_cmd_tlv)); - pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); - pwk_cipher->cipher = - bss_cfg->wpa_cfg.pairwise_cipher_wpa2; - cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); - tlv += sizeof(struct host_cmd_tlv_pwk_cipher); - } - if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { - gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; - gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); - gwk_cipher->tlv.len = cpu_to_le16( - sizeof(struct host_cmd_tlv_gwk_cipher) - - sizeof(struct host_cmd_tlv)); - gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; - cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); - tlv += sizeof(struct host_cmd_tlv_gwk_cipher); - } - if (bss_cfg->wpa_cfg.length) { - passphrase = (struct host_cmd_tlv_passphrase *)tlv; - passphrase->tlv.type = - cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); - passphrase->tlv.len = - cpu_to_le16(bss_cfg->wpa_cfg.length); - memcpy(passphrase->passphrase, - bss_cfg->wpa_cfg.passphrase, - bss_cfg->wpa_cfg.length); - cmd_size += sizeof(struct host_cmd_tlv) + - bss_cfg->wpa_cfg.length; - tlv += sizeof(struct host_cmd_tlv) + - bss_cfg->wpa_cfg.length; - } - } + (bss_cfg->protocol & PROTOCOL_EAP)) + mwifiex_uap_bss_wpa(&tlv, cmd_buf, &cmd_size); + else + mwifiex_uap_bss_wep(&tlv, cmd_buf, &cmd_size); + if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) || (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) { auth_type = (struct host_cmd_tlv_auth_type *)tlv; @@ -319,6 +440,25 @@ mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) tlv += sizeof(struct host_cmd_tlv_encrypt_protocol); } + if (bss_cfg->ht_cap.cap_info) { + htcap = (struct mwifiex_ie_types_htcap *)tlv; + htcap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY); + htcap->header.len = + cpu_to_le16(sizeof(struct ieee80211_ht_cap)); + htcap->ht_cap.cap_info = bss_cfg->ht_cap.cap_info; + htcap->ht_cap.ampdu_params_info = + bss_cfg->ht_cap.ampdu_params_info; + memcpy(&htcap->ht_cap.mcs, &bss_cfg->ht_cap.mcs, + sizeof(struct ieee80211_mcs_info)); + htcap->ht_cap.extended_ht_cap_info = + bss_cfg->ht_cap.extended_ht_cap_info; + htcap->ht_cap.tx_BF_cap_info = bss_cfg->ht_cap.tx_BF_cap_info; + htcap->ht_cap.antenna_selection_info = + bss_cfg->ht_cap.antenna_selection_info; + cmd_size += sizeof(struct mwifiex_ie_types_htcap); + tlv += sizeof(struct mwifiex_ie_types_htcap); + } + *param_size = cmd_size; return 0; @@ -410,33 +550,3 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, return 0; } - -/* This function sets the RF channel for AP. - * - * This function populates channel information in AP config structure - * and sends command to configure channel information in AP. - */ -int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel) -{ - struct mwifiex_uap_bss_param *bss_cfg; - struct wiphy *wiphy = priv->wdev->wiphy; - - bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); - if (!bss_cfg) - return -ENOMEM; - - mwifiex_set_sys_config_invalid_data(bss_cfg); - bss_cfg->band_cfg = BAND_CONFIG_MANUAL; - bss_cfg->channel = channel; - - if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, - HostCmd_ACT_GEN_SET, - UAP_BSS_PARAMS_I, bss_cfg)) { - wiphy_err(wiphy, "Failed to set the uAP channel\n"); - kfree(bss_cfg); - return -1; - } - - kfree(bss_cfg); - return 0; -} diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c index 49ebf20c56eb..22a5916564b8 100644 --- a/drivers/net/wireless/mwifiex/usb.c +++ b/drivers/net/wireless/mwifiex/usb.c @@ -49,6 +49,7 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, struct device *dev = adapter->dev; u32 recv_type; __le32 tmp; + int ret; if (adapter->hs_activated) mwifiex_process_hs_config(adapter); @@ -69,16 +70,19 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, case MWIFIEX_USB_TYPE_CMD: if (skb->len > MWIFIEX_SIZE_OF_CMD_BUFFER) { dev_err(dev, "CMD: skb->len too large\n"); - return -1; + ret = -1; + goto exit_restore_skb; } else if (!adapter->curr_cmd) { dev_dbg(dev, "CMD: no curr_cmd\n"); if (adapter->ps_state == PS_STATE_SLEEP_CFM) { mwifiex_process_sleep_confirm_resp( adapter, skb->data, skb->len); - return 0; + ret = 0; + goto exit_restore_skb; } - return -1; + ret = -1; + goto exit_restore_skb; } adapter->curr_cmd->resp_skb = skb; @@ -87,20 +91,22 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, case MWIFIEX_USB_TYPE_EVENT: if (skb->len < sizeof(u32)) { dev_err(dev, "EVENT: skb->len too small\n"); - return -1; + ret = -1; + goto exit_restore_skb; } skb_copy_from_linear_data(skb, &tmp, sizeof(u32)); adapter->event_cause = le32_to_cpu(tmp); - skb_pull(skb, sizeof(u32)); dev_dbg(dev, "event_cause %#x\n", adapter->event_cause); if (skb->len > MAX_EVENT_SIZE) { dev_err(dev, "EVENT: event body too large\n"); - return -1; + ret = -1; + goto exit_restore_skb; } - skb_copy_from_linear_data(skb, adapter->event_body, - skb->len); + memcpy(adapter->event_body, skb->data + + MWIFIEX_EVENT_HEADER_LEN, skb->len); + adapter->event_received = true; adapter->event_skb = skb; break; @@ -124,6 +130,12 @@ static int mwifiex_usb_recv(struct mwifiex_adapter *adapter, } return -EINPROGRESS; + +exit_restore_skb: + /* The buffer will be reused for further cmds/events */ + skb_push(skb, INTF_HEADER_LEN); + + return ret; } static void mwifiex_usb_rx_complete(struct urb *urb) diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index f3fc65515857..3fa4d4176993 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -404,6 +404,8 @@ mwifiex_wmm_init(struct mwifiex_adapter *adapter) priv->add_ba_param.tx_win_size = MWIFIEX_AMPDU_DEF_TXWINSIZE; priv->add_ba_param.rx_win_size = MWIFIEX_AMPDU_DEF_RXWINSIZE; + mwifiex_reset_11n_rx_seq_num(priv); + atomic_set(&priv->wmm.tx_pkts_queued, 0); atomic_set(&priv->wmm.highest_queued_prio, HIGH_PRIO_TID); } @@ -1221,6 +1223,7 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter) if (!ptr->is_11n_enabled || mwifiex_is_ba_stream_setup(priv, ptr, tid) || + priv->wps.session_enable || ((priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled) && !priv->wpa_is_gtk_set)) { diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index e15675585fb1..7b751fba7e1f 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -138,7 +138,7 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, return err; } -static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, +static int orinoco_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct orinoco_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 82a1cac920bd..f38786e02623 100644 --- a/drivers/net/wireless/p54/txrx.c +++ b/drivers/net/wireless/p54/txrx.c @@ -422,11 +422,11 @@ static void p54_rx_frame_sent(struct p54_common *priv, struct sk_buff *skb) * Clear manually, ieee80211_tx_info_clear_status would * clear the counts too and we need them. */ - memset(&info->status.ampdu_ack_len, 0, + memset(&info->status.ack_signal, 0, sizeof(struct ieee80211_tx_info) - - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + offsetof(struct ieee80211_tx_info, status.ack_signal)); BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, - status.ampdu_ack_len) != 23); + status.ack_signal) != 20); if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) pad = entry_data->align[0]; diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2e9e6af21362..241162e8111d 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -484,7 +484,7 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params); -static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, +static int rndis_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); @@ -1941,9 +1941,10 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) } #define SCAN_DELAY_JIFFIES (6 * HZ) -static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, +static int rndis_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *dev = request->wdev->netdev; struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; @@ -2110,7 +2111,7 @@ resize_buf: while (check_bssid_list_item(bssid, bssid_len, buf, len)) { if (rndis_bss_info_update(usbdev, bssid) && match_bssid && matched) { - if (!ether_addr_equal(bssid->mac, match_bssid)) + if (ether_addr_equal(bssid->mac, match_bssid)) *matched = true; } diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 299c3879582d..c7548da6573d 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -99,6 +99,14 @@ config RT2800PCI_RT53XX rt2800pci driver. Supported chips: RT5390 +config RT2800PCI_RT3290 + bool "rt2800pci - Include support for rt3290 devices (EXPERIMENTAL)" + depends on EXPERIMENTAL + default y + ---help--- + This adds support for rt3290 wireless chipset family to the + rt2800pci driver. + Supported chips: RT3290 endif config RT2500USB diff --git a/drivers/net/wireless/rt2x00/rt2800.h b/drivers/net/wireless/rt2x00/rt2800.h index 1ca88cdc6ece..e252e9bafd0e 100644 --- a/drivers/net/wireless/rt2x00/rt2800.h +++ b/drivers/net/wireless/rt2x00/rt2800.h @@ -68,6 +68,7 @@ #define RF3320 0x000b #define RF3322 0x000c #define RF3053 0x000d +#define RF3290 0x3290 #define RF5360 0x5360 #define RF5370 0x5370 #define RF5372 0x5372 @@ -117,6 +118,12 @@ * Registers. */ + +/* + * MAC_CSR0_3290: MAC_CSR0 for RT3290 to identity MAC version number. + */ +#define MAC_CSR0_3290 0x0000 + /* * E2PROM_CSR: PCI EEPROM control register. * RELOAD: Write 1 to reload eeprom content. @@ -133,6 +140,150 @@ #define E2PROM_CSR_RELOAD FIELD32(0x00000080) /* + * CMB_CTRL_CFG + */ +#define CMB_CTRL 0x0020 +#define AUX_OPT_BIT0 FIELD32(0x00000001) +#define AUX_OPT_BIT1 FIELD32(0x00000002) +#define AUX_OPT_BIT2 FIELD32(0x00000004) +#define AUX_OPT_BIT3 FIELD32(0x00000008) +#define AUX_OPT_BIT4 FIELD32(0x00000010) +#define AUX_OPT_BIT5 FIELD32(0x00000020) +#define AUX_OPT_BIT6 FIELD32(0x00000040) +#define AUX_OPT_BIT7 FIELD32(0x00000080) +#define AUX_OPT_BIT8 FIELD32(0x00000100) +#define AUX_OPT_BIT9 FIELD32(0x00000200) +#define AUX_OPT_BIT10 FIELD32(0x00000400) +#define AUX_OPT_BIT11 FIELD32(0x00000800) +#define AUX_OPT_BIT12 FIELD32(0x00001000) +#define AUX_OPT_BIT13 FIELD32(0x00002000) +#define AUX_OPT_BIT14 FIELD32(0x00004000) +#define AUX_OPT_BIT15 FIELD32(0x00008000) +#define LDO25_LEVEL FIELD32(0x00030000) +#define LDO25_LARGEA FIELD32(0x00040000) +#define LDO25_FRC_ON FIELD32(0x00080000) +#define CMB_RSV FIELD32(0x00300000) +#define XTAL_RDY FIELD32(0x00400000) +#define PLL_LD FIELD32(0x00800000) +#define LDO_CORE_LEVEL FIELD32(0x0F000000) +#define LDO_BGSEL FIELD32(0x30000000) +#define LDO3_EN FIELD32(0x40000000) +#define LDO0_EN FIELD32(0x80000000) + +/* + * EFUSE_CSR_3290: RT3290 EEPROM + */ +#define EFUSE_CTRL_3290 0x0024 + +/* + * EFUSE_DATA3 of 3290 + */ +#define EFUSE_DATA3_3290 0x0028 + +/* + * EFUSE_DATA2 of 3290 + */ +#define EFUSE_DATA2_3290 0x002c + +/* + * EFUSE_DATA1 of 3290 + */ +#define EFUSE_DATA1_3290 0x0030 + +/* + * EFUSE_DATA0 of 3290 + */ +#define EFUSE_DATA0_3290 0x0034 + +/* + * OSC_CTRL_CFG + * Ring oscillator configuration + */ +#define OSC_CTRL 0x0038 +#define OSC_REF_CYCLE FIELD32(0x00001fff) +#define OSC_RSV FIELD32(0x0000e000) +#define OSC_CAL_CNT FIELD32(0x0fff0000) +#define OSC_CAL_ACK FIELD32(0x10000000) +#define OSC_CLK_32K_VLD FIELD32(0x20000000) +#define OSC_CAL_REQ FIELD32(0x40000000) +#define OSC_ROSC_EN FIELD32(0x80000000) + +/* + * COEX_CFG_0 + */ +#define COEX_CFG0 0x0040 +#define COEX_CFG_ANT FIELD32(0xff000000) +/* + * COEX_CFG_1 + */ +#define COEX_CFG1 0x0044 + +/* + * COEX_CFG_2 + */ +#define COEX_CFG2 0x0048 +#define BT_COEX_CFG1 FIELD32(0xff000000) +#define BT_COEX_CFG0 FIELD32(0x00ff0000) +#define WL_COEX_CFG1 FIELD32(0x0000ff00) +#define WL_COEX_CFG0 FIELD32(0x000000ff) +/* + * PLL_CTRL_CFG + * PLL configuration register + */ +#define PLL_CTRL 0x0050 +#define PLL_RESERVED_INPUT1 FIELD32(0x000000ff) +#define PLL_RESERVED_INPUT2 FIELD32(0x0000ff00) +#define PLL_CONTROL FIELD32(0x00070000) +#define PLL_LPF_R1 FIELD32(0x00080000) +#define PLL_LPF_C1_CTRL FIELD32(0x00300000) +#define PLL_LPF_C2_CTRL FIELD32(0x00c00000) +#define PLL_CP_CURRENT_CTRL FIELD32(0x03000000) +#define PLL_PFD_DELAY_CTRL FIELD32(0x0c000000) +#define PLL_LOCK_CTRL FIELD32(0x70000000) +#define PLL_VBGBK_EN FIELD32(0x80000000) + + +/* + * WLAN_CTRL_CFG + * RT3290 wlan configuration + */ +#define WLAN_FUN_CTRL 0x0080 +#define WLAN_EN FIELD32(0x00000001) +#define WLAN_CLK_EN FIELD32(0x00000002) +#define WLAN_RSV1 FIELD32(0x00000004) +#define WLAN_RESET FIELD32(0x00000008) +#define PCIE_APP0_CLK_REQ FIELD32(0x00000010) +#define FRC_WL_ANT_SET FIELD32(0x00000020) +#define INV_TR_SW0 FIELD32(0x00000040) +#define WLAN_GPIO_IN_BIT0 FIELD32(0x00000100) +#define WLAN_GPIO_IN_BIT1 FIELD32(0x00000200) +#define WLAN_GPIO_IN_BIT2 FIELD32(0x00000400) +#define WLAN_GPIO_IN_BIT3 FIELD32(0x00000800) +#define WLAN_GPIO_IN_BIT4 FIELD32(0x00001000) +#define WLAN_GPIO_IN_BIT5 FIELD32(0x00002000) +#define WLAN_GPIO_IN_BIT6 FIELD32(0x00004000) +#define WLAN_GPIO_IN_BIT7 FIELD32(0x00008000) +#define WLAN_GPIO_IN_BIT_ALL FIELD32(0x0000ff00) +#define WLAN_GPIO_OUT_BIT0 FIELD32(0x00010000) +#define WLAN_GPIO_OUT_BIT1 FIELD32(0x00020000) +#define WLAN_GPIO_OUT_BIT2 FIELD32(0x00040000) +#define WLAN_GPIO_OUT_BIT3 FIELD32(0x00050000) +#define WLAN_GPIO_OUT_BIT4 FIELD32(0x00100000) +#define WLAN_GPIO_OUT_BIT5 FIELD32(0x00200000) +#define WLAN_GPIO_OUT_BIT6 FIELD32(0x00400000) +#define WLAN_GPIO_OUT_BIT7 FIELD32(0x00800000) +#define WLAN_GPIO_OUT_BIT_ALL FIELD32(0x00ff0000) +#define WLAN_GPIO_OUT_OE_BIT0 FIELD32(0x01000000) +#define WLAN_GPIO_OUT_OE_BIT1 FIELD32(0x02000000) +#define WLAN_GPIO_OUT_OE_BIT2 FIELD32(0x04000000) +#define WLAN_GPIO_OUT_OE_BIT3 FIELD32(0x08000000) +#define WLAN_GPIO_OUT_OE_BIT4 FIELD32(0x10000000) +#define WLAN_GPIO_OUT_OE_BIT5 FIELD32(0x20000000) +#define WLAN_GPIO_OUT_OE_BIT6 FIELD32(0x40000000) +#define WLAN_GPIO_OUT_OE_BIT7 FIELD32(0x80000000) +#define WLAN_GPIO_OUT_OE_BIT_ALL FIELD32(0xff000000) + +/* * AUX_CTRL: Aux/PCI-E related configuration */ #define AUX_CTRL 0x10c @@ -1763,9 +1914,11 @@ struct mac_iveiv_entry { /* * BBP 3: RX Antenna */ -#define BBP3_RX_ADC FIELD8(0x03) +#define BBP3_RX_ADC FIELD8(0x03) #define BBP3_RX_ANTENNA FIELD8(0x18) #define BBP3_HT40_MINUS FIELD8(0x20) +#define BBP3_ADC_MODE_SWITCH FIELD8(0x40) +#define BBP3_ADC_INIT_MODE FIELD8(0x80) /* * BBP 4: Bandwidth @@ -1775,6 +1928,14 @@ struct mac_iveiv_entry { #define BBP4_MAC_IF_CTRL FIELD8(0x40) /* + * BBP 47: Bandwidth + */ +#define BBP47_TSSI_REPORT_SEL FIELD8(0x03) +#define BBP47_TSSI_UPDATE_REQ FIELD8(0x04) +#define BBP47_TSSI_TSSI_MODE FIELD8(0x18) +#define BBP47_TSSI_ADC6 FIELD8(0x80) + +/* * BBP 109 */ #define BBP109_TX0_POWER FIELD8(0x0f) @@ -1917,6 +2078,16 @@ struct mac_iveiv_entry { #define RFCSR27_R4 FIELD8(0x40) /* + * RFCSR 29: + */ +#define RFCSR29_ADC6_TEST FIELD8(0x01) +#define RFCSR29_ADC6_INT_TEST FIELD8(0x02) +#define RFCSR29_RSSI_RESET FIELD8(0x04) +#define RFCSR29_RSSI_ON FIELD8(0x08) +#define RFCSR29_RSSI_RIP_CTRL FIELD8(0x30) +#define RFCSR29_RSSI_GAIN FIELD8(0xc0) + +/* * RFCSR 30: */ #define RFCSR30_TX_H20M FIELD8(0x02) diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 4d3747c3010b..e76f03c9b468 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -354,16 +354,15 @@ int rt2800_check_firmware(struct rt2x00_dev *rt2x00dev, * of 4kb. Certain USB chipsets however require different firmware, * which Ralink only provides attached to the original firmware * file. Thus for USB devices, firmware files have a length - * which is a multiple of 4kb. + * which is a multiple of 4kb. The firmware for rt3290 chip also + * have a length which is a multiple of 4kb. */ - if (rt2x00_is_usb(rt2x00dev)) { + if (rt2x00_is_usb(rt2x00dev) || rt2x00_rt(rt2x00dev, RT3290)) fw_len = 4096; - multiple = true; - } else { + else fw_len = 8192; - multiple = true; - } + multiple = true; /* * Validate the firmware length */ @@ -415,7 +414,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev, return -EBUSY; if (rt2x00_is_pci(rt2x00dev)) { - if (rt2x00_rt(rt2x00dev, RT3572) || + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { rt2800_register_read(rt2x00dev, AUX_CTRL, ®); @@ -851,8 +851,13 @@ int rt2800_rfkill_poll(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); - return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); + if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + return rt2x00_get_field32(reg, WLAN_GPIO_IN_BIT0); + } else { + rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, ®); + return rt2x00_get_field32(reg, GPIO_CTRL_CFG_BIT2); + } } EXPORT_SYMBOL_GPL(rt2800_rfkill_poll); @@ -1935,8 +1940,50 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } -#define RT5390_POWER_BOUND 0x27 -#define RT5390_FREQ_OFFSET_BOUND 0x5f +#define POWER_BOUND 0x27 +#define FREQ_OFFSET_BOUND 0x5f + +static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, + struct ieee80211_conf *conf, + struct rf_channel *rf, + struct channel_info *info) +{ + u8 rfcsr; + + rt2800_rfcsr_write(rt2x00dev, 8, rf->rf1); + rt2800_rfcsr_write(rt2x00dev, 9, rf->rf3); + rt2800_rfcsr_read(rt2x00dev, 11, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR11_R, rf->rf2); + rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); + if (info->default_power1 > POWER_BOUND) + rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); + else + rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); + rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); + if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND) + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND); + else + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); + rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); + + if (rf->channel <= 14) { + if (rf->channel == 6) + rt2800_bbp_write(rt2x00dev, 68, 0x0c); + else + rt2800_bbp_write(rt2x00dev, 68, 0x0b); + + if (rf->channel >= 1 && rf->channel <= 6) + rt2800_bbp_write(rt2x00dev, 59, 0x0f); + else if (rf->channel >= 7 && rf->channel <= 11) + rt2800_bbp_write(rt2x00dev, 59, 0x0e); + else if (rf->channel >= 12 && rf->channel <= 14) + rt2800_bbp_write(rt2x00dev, 59, 0x0d); + } +} static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, struct ieee80211_conf *conf, @@ -1952,17 +1999,16 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); - if (info->default_power1 > RT5390_POWER_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT5390_POWER_BOUND); + if (info->default_power1 > POWER_BOUND) + rt2x00_set_field8(&rfcsr, RFCSR49_TX, POWER_BOUND); else rt2x00_set_field8(&rfcsr, RFCSR49_TX, info->default_power1); rt2800_rfcsr_write(rt2x00dev, 49, rfcsr); if (rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 50, &rfcsr); - if (info->default_power1 > RT5390_POWER_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR50_TX, - RT5390_POWER_BOUND); + if (info->default_power1 > POWER_BOUND) + rt2x00_set_field8(&rfcsr, RFCSR50_TX, POWER_BOUND); else rt2x00_set_field8(&rfcsr, RFCSR50_TX, info->default_power2); @@ -1981,9 +2027,8 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 1, rfcsr); rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); - if (rt2x00dev->freq_offset > RT5390_FREQ_OFFSET_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, - RT5390_FREQ_OFFSET_BOUND); + if (rt2x00dev->freq_offset > FREQ_OFFSET_BOUND) + rt2x00_set_field8(&rfcsr, RFCSR17_CODE, FREQ_OFFSET_BOUND); else rt2x00_set_field8(&rfcsr, RFCSR17_CODE, rt2x00dev->freq_offset); rt2800_rfcsr_write(rt2x00dev, 17, rfcsr); @@ -2036,15 +2081,6 @@ static void rt2800_config_channel_rf53xx(struct rt2x00_dev *rt2x00dev, } } } - - rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0); - rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0); - rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); - - rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); - rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); - rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); } static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, @@ -2054,7 +2090,7 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, { u32 reg; unsigned int tx_pin; - u8 bbp; + u8 bbp, rfcsr; if (rf->channel <= 14) { info->default_power1 = TXPOWER_G_TO_DEV(info->default_power1); @@ -2075,6 +2111,9 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, case RF3052: rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info); break; + case RF3290: + rt2800_config_channel_rf3290(rt2x00dev, conf, rf, info); + break; case RF5360: case RF5370: case RF5372: @@ -2086,6 +2125,22 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_config_channel_rf2xxx(rt2x00dev, conf, rf, info); } + if (rt2x00_rf(rt2x00dev, RF3290) || + rt2x00_rf(rt2x00dev, RF5360) || + rt2x00_rf(rt2x00dev, RF5370) || + rt2x00_rf(rt2x00dev, RF5372) || + rt2x00_rf(rt2x00dev, RF5390) || + rt2x00_rf(rt2x00dev, RF5392)) { + rt2800_rfcsr_read(rt2x00dev, 30, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_TX_H20M, 0); + rt2x00_set_field8(&rfcsr, RFCSR30_RX_H20M, 0); + rt2800_rfcsr_write(rt2x00dev, 30, rfcsr); + + rt2800_rfcsr_read(rt2x00dev, 3, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR30_RF_CALIBRATION, 1); + rt2800_rfcsr_write(rt2x00dev, 3, rfcsr); + } + /* * Change BBP settings */ @@ -2566,6 +2621,7 @@ void rt2800_vco_calibration(struct rt2x00_dev *rt2x00dev) rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1); rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); break; + case RF3290: case RF5360: case RF5370: case RF5372: @@ -2701,6 +2757,7 @@ static u8 rt2800_get_default_vgc(struct rt2x00_dev *rt2x00dev) if (rt2x00_rt(rt2x00dev, RT3070) || rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || + rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT3390) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) @@ -2797,10 +2854,54 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, BKOFF_SLOT_CFG_CC_DELAY_TIME, 2); rt2800_register_write(rt2x00dev, BKOFF_SLOT_CFG, reg); + if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + if (rt2x00_get_field32(reg, WLAN_EN) == 1) { + rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 1); + rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); + } + + rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + if (!(rt2x00_get_field32(reg, LDO0_EN) == 1)) { + rt2x00_set_field32(®, LDO0_EN, 1); + rt2x00_set_field32(®, LDO_BGSEL, 3); + rt2800_register_write(rt2x00dev, CMB_CTRL, reg); + } + + rt2800_register_read(rt2x00dev, OSC_CTRL, ®); + rt2x00_set_field32(®, OSC_ROSC_EN, 1); + rt2x00_set_field32(®, OSC_CAL_REQ, 1); + rt2x00_set_field32(®, OSC_REF_CYCLE, 0x27); + rt2800_register_write(rt2x00dev, OSC_CTRL, reg); + + rt2800_register_read(rt2x00dev, COEX_CFG0, ®); + rt2x00_set_field32(®, COEX_CFG_ANT, 0x5e); + rt2800_register_write(rt2x00dev, COEX_CFG0, reg); + + rt2800_register_read(rt2x00dev, COEX_CFG2, ®); + rt2x00_set_field32(®, BT_COEX_CFG1, 0x00); + rt2x00_set_field32(®, BT_COEX_CFG0, 0x17); + rt2x00_set_field32(®, WL_COEX_CFG1, 0x93); + rt2x00_set_field32(®, WL_COEX_CFG0, 0x7f); + rt2800_register_write(rt2x00dev, COEX_CFG2, reg); + + rt2800_register_read(rt2x00dev, PLL_CTRL, ®); + rt2x00_set_field32(®, PLL_CONTROL, 1); + rt2800_register_write(rt2x00dev, PLL_CTRL, reg); + } + if (rt2x00_rt(rt2x00dev, RT3071) || rt2x00_rt(rt2x00dev, RT3090) || + rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT3390)) { - rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400); + + if (rt2x00_rt(rt2x00dev, RT3290)) + rt2800_register_write(rt2x00dev, TX_SW_CFG0, + 0x00000404); + else + rt2800_register_write(rt2x00dev, TX_SW_CFG0, + 0x00000400); + rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000); if (rt2x00_rt_rev_lt(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_lt(rt2x00dev, RT3090, REV_RT3090E) || @@ -3209,14 +3310,16 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_wait_bbp_ready(rt2x00dev))) return -EACCES; - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_bbp_read(rt2x00dev, 4, &value); rt2x00_set_field8(&value, BBP4_MAC_IF_CTRL, 1); rt2800_bbp_write(rt2x00dev, 4, value); } if (rt2800_is_305x_soc(rt2x00dev) || + rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) @@ -3225,20 +3328,26 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 65, 0x2c); rt2800_bbp_write(rt2x00dev, 66, 0x38); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 68, 0x0b); if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860C)) { rt2800_bbp_write(rt2x00dev, 69, 0x16); rt2800_bbp_write(rt2x00dev, 73, 0x12); - } else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + } else if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_bbp_write(rt2x00dev, 69, 0x12); rt2800_bbp_write(rt2x00dev, 73, 0x13); rt2800_bbp_write(rt2x00dev, 75, 0x46); rt2800_bbp_write(rt2x00dev, 76, 0x28); - rt2800_bbp_write(rt2x00dev, 77, 0x59); + + if (rt2x00_rt(rt2x00dev, RT3290)) + rt2800_bbp_write(rt2x00dev, 77, 0x58); + else + rt2800_bbp_write(rt2x00dev, 77, 0x59); } else { rt2800_bbp_write(rt2x00dev, 69, 0x12); rt2800_bbp_write(rt2x00dev, 73, 0x10); @@ -3263,23 +3372,33 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 81, 0x37); } + if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_bbp_write(rt2x00dev, 74, 0x0b); + rt2800_bbp_write(rt2x00dev, 79, 0x18); + rt2800_bbp_write(rt2x00dev, 80, 0x09); + rt2800_bbp_write(rt2x00dev, 81, 0x33); + } + rt2800_bbp_write(rt2x00dev, 82, 0x62); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 83, 0x7a); else rt2800_bbp_write(rt2x00dev, 83, 0x6a); if (rt2x00_rt_rev(rt2x00dev, RT2860, REV_RT2860D)) rt2800_bbp_write(rt2x00dev, 84, 0x19); - else if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + else if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 84, 0x9a); else rt2800_bbp_write(rt2x00dev, 84, 0x99); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 86, 0x38); else rt2800_bbp_write(rt2x00dev, 86, 0x00); @@ -3289,8 +3408,9 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 91, 0x04); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 92, 0x02); else rt2800_bbp_write(rt2x00dev, 92, 0x00); @@ -3304,6 +3424,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) || rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) || rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) || + rt2x00_rt(rt2x00dev, RT3290) || rt2x00_rt(rt2x00dev, RT3572) || rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392) || @@ -3312,27 +3433,32 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) else rt2800_bbp_write(rt2x00dev, 103, 0x00); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 104, 0x92); if (rt2800_is_305x_soc(rt2x00dev)) rt2800_bbp_write(rt2x00dev, 105, 0x01); + else if (rt2x00_rt(rt2x00dev, RT3290)) + rt2800_bbp_write(rt2x00dev, 105, 0x1c); else if (rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 105, 0x3c); else rt2800_bbp_write(rt2x00dev, 105, 0x05); - if (rt2x00_rt(rt2x00dev, RT5390)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390)) rt2800_bbp_write(rt2x00dev, 106, 0x03); else if (rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 106, 0x12); else rt2800_bbp_write(rt2x00dev, 106, 0x35); - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) rt2800_bbp_write(rt2x00dev, 128, 0x12); if (rt2x00_rt(rt2x00dev, RT5392)) { @@ -3357,6 +3483,29 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev) rt2800_bbp_write(rt2x00dev, 138, value); } + if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_bbp_write(rt2x00dev, 67, 0x24); + rt2800_bbp_write(rt2x00dev, 143, 0x04); + rt2800_bbp_write(rt2x00dev, 142, 0x99); + rt2800_bbp_write(rt2x00dev, 150, 0x30); + rt2800_bbp_write(rt2x00dev, 151, 0x2e); + rt2800_bbp_write(rt2x00dev, 152, 0x20); + rt2800_bbp_write(rt2x00dev, 153, 0x34); + rt2800_bbp_write(rt2x00dev, 154, 0x40); + rt2800_bbp_write(rt2x00dev, 155, 0x3b); + rt2800_bbp_write(rt2x00dev, 253, 0x04); + + rt2800_bbp_read(rt2x00dev, 47, &value); + rt2x00_set_field8(&value, BBP47_TSSI_ADC6, 1); + rt2800_bbp_write(rt2x00dev, 47, value); + + /* Use 5-bit ADC for Acquisition and 8-bit ADC for data */ + rt2800_bbp_read(rt2x00dev, 3, &value); + rt2x00_set_field8(&value, BBP3_ADC_MODE_SWITCH, 1); + rt2x00_set_field8(&value, BBP3_ADC_INIT_MODE, 1); + rt2800_bbp_write(rt2x00dev, 3, value); + } + if (rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { int ant, div_mode; @@ -3489,6 +3638,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) if (!rt2x00_rt(rt2x00dev, RT3070) && !rt2x00_rt(rt2x00dev, RT3071) && !rt2x00_rt(rt2x00dev, RT3090) && + !rt2x00_rt(rt2x00dev, RT3290) && !rt2x00_rt(rt2x00dev, RT3390) && !rt2x00_rt(rt2x00dev, RT3572) && !rt2x00_rt(rt2x00dev, RT5390) && @@ -3499,8 +3649,9 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) /* * Init RF calibration. */ - if (rt2x00_rt(rt2x00dev, RT5390) || - rt2x00_rt(rt2x00dev, RT5392)) { + if (rt2x00_rt(rt2x00dev, RT3290) || + rt2x00_rt(rt2x00dev, RT5390) || + rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 2, &rfcsr); rt2x00_set_field8(&rfcsr, RFCSR2_RESCAL_EN, 1); rt2800_rfcsr_write(rt2x00dev, 2, rfcsr); @@ -3538,6 +3689,53 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 24, 0x16); rt2800_rfcsr_write(rt2x00dev, 25, 0x01); rt2800_rfcsr_write(rt2x00dev, 29, 0x1f); + } else if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_rfcsr_write(rt2x00dev, 1, 0x0f); + rt2800_rfcsr_write(rt2x00dev, 2, 0x80); + rt2800_rfcsr_write(rt2x00dev, 3, 0x08); + rt2800_rfcsr_write(rt2x00dev, 4, 0x00); + rt2800_rfcsr_write(rt2x00dev, 6, 0xa0); + rt2800_rfcsr_write(rt2x00dev, 8, 0xf3); + rt2800_rfcsr_write(rt2x00dev, 9, 0x02); + rt2800_rfcsr_write(rt2x00dev, 10, 0x53); + rt2800_rfcsr_write(rt2x00dev, 11, 0x4a); + rt2800_rfcsr_write(rt2x00dev, 12, 0x46); + rt2800_rfcsr_write(rt2x00dev, 13, 0x9f); + rt2800_rfcsr_write(rt2x00dev, 18, 0x02); + rt2800_rfcsr_write(rt2x00dev, 22, 0x20); + rt2800_rfcsr_write(rt2x00dev, 25, 0x83); + rt2800_rfcsr_write(rt2x00dev, 26, 0x82); + rt2800_rfcsr_write(rt2x00dev, 27, 0x09); + rt2800_rfcsr_write(rt2x00dev, 29, 0x10); + rt2800_rfcsr_write(rt2x00dev, 30, 0x10); + rt2800_rfcsr_write(rt2x00dev, 31, 0x80); + rt2800_rfcsr_write(rt2x00dev, 32, 0x80); + rt2800_rfcsr_write(rt2x00dev, 33, 0x00); + rt2800_rfcsr_write(rt2x00dev, 34, 0x05); + rt2800_rfcsr_write(rt2x00dev, 35, 0x12); + rt2800_rfcsr_write(rt2x00dev, 36, 0x00); + rt2800_rfcsr_write(rt2x00dev, 38, 0x85); + rt2800_rfcsr_write(rt2x00dev, 39, 0x1b); + rt2800_rfcsr_write(rt2x00dev, 40, 0x0b); + rt2800_rfcsr_write(rt2x00dev, 41, 0xbb); + rt2800_rfcsr_write(rt2x00dev, 42, 0xd5); + rt2800_rfcsr_write(rt2x00dev, 43, 0x7b); + rt2800_rfcsr_write(rt2x00dev, 44, 0x0e); + rt2800_rfcsr_write(rt2x00dev, 45, 0xa2); + rt2800_rfcsr_write(rt2x00dev, 46, 0x73); + rt2800_rfcsr_write(rt2x00dev, 47, 0x00); + rt2800_rfcsr_write(rt2x00dev, 48, 0x10); + rt2800_rfcsr_write(rt2x00dev, 49, 0x98); + rt2800_rfcsr_write(rt2x00dev, 52, 0x38); + rt2800_rfcsr_write(rt2x00dev, 53, 0x00); + rt2800_rfcsr_write(rt2x00dev, 54, 0x78); + rt2800_rfcsr_write(rt2x00dev, 55, 0x43); + rt2800_rfcsr_write(rt2x00dev, 56, 0x02); + rt2800_rfcsr_write(rt2x00dev, 57, 0x80); + rt2800_rfcsr_write(rt2x00dev, 58, 0x7f); + rt2800_rfcsr_write(rt2x00dev, 59, 0x09); + rt2800_rfcsr_write(rt2x00dev, 60, 0x45); + rt2800_rfcsr_write(rt2x00dev, 61, 0xc1); } else if (rt2x00_rt(rt2x00dev, RT3390)) { rt2800_rfcsr_write(rt2x00dev, 0, 0xa0); rt2800_rfcsr_write(rt2x00dev, 1, 0xe1); @@ -3946,6 +4144,12 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) rt2800_rfcsr_write(rt2x00dev, 27, rfcsr); } + if (rt2x00_rt(rt2x00dev, RT3290)) { + rt2800_rfcsr_read(rt2x00dev, 29, &rfcsr); + rt2x00_set_field8(&rfcsr, RFCSR29_RSSI_GAIN, 3); + rt2800_rfcsr_write(rt2x00dev, 29, rfcsr); + } + if (rt2x00_rt(rt2x00dev, RT5390) || rt2x00_rt(rt2x00dev, RT5392)) { rt2800_rfcsr_read(rt2x00dev, 38, &rfcsr); @@ -4052,9 +4256,14 @@ EXPORT_SYMBOL_GPL(rt2800_disable_radio); int rt2800_efuse_detect(struct rt2x00_dev *rt2x00dev) { u32 reg; + u16 efuse_ctrl_reg; - rt2800_register_read(rt2x00dev, EFUSE_CTRL, ®); + if (rt2x00_rt(rt2x00dev, RT3290)) + efuse_ctrl_reg = EFUSE_CTRL_3290; + else + efuse_ctrl_reg = EFUSE_CTRL; + rt2800_register_read(rt2x00dev, efuse_ctrl_reg, ®); return rt2x00_get_field32(reg, EFUSE_CTRL_PRESENT); } EXPORT_SYMBOL_GPL(rt2800_efuse_detect); @@ -4062,27 +4271,44 @@ EXPORT_SYMBOL_GPL(rt2800_efuse_detect); static void rt2800_efuse_read(struct rt2x00_dev *rt2x00dev, unsigned int i) { u32 reg; - + u16 efuse_ctrl_reg; + u16 efuse_data0_reg; + u16 efuse_data1_reg; + u16 efuse_data2_reg; + u16 efuse_data3_reg; + + if (rt2x00_rt(rt2x00dev, RT3290)) { + efuse_ctrl_reg = EFUSE_CTRL_3290; + efuse_data0_reg = EFUSE_DATA0_3290; + efuse_data1_reg = EFUSE_DATA1_3290; + efuse_data2_reg = EFUSE_DATA2_3290; + efuse_data3_reg = EFUSE_DATA3_3290; + } else { + efuse_ctrl_reg = EFUSE_CTRL; + efuse_data0_reg = EFUSE_DATA0; + efuse_data1_reg = EFUSE_DATA1; + efuse_data2_reg = EFUSE_DATA2; + efuse_data3_reg = EFUSE_DATA3; + } mutex_lock(&rt2x00dev->csr_mutex); - rt2800_register_read_lock(rt2x00dev, EFUSE_CTRL, ®); + rt2800_register_read_lock(rt2x00dev, efuse_ctrl_reg, ®); rt2x00_set_field32(®, EFUSE_CTRL_ADDRESS_IN, i); rt2x00_set_field32(®, EFUSE_CTRL_MODE, 0); rt2x00_set_field32(®, EFUSE_CTRL_KICK, 1); - rt2800_register_write_lock(rt2x00dev, EFUSE_CTRL, reg); + rt2800_register_write_lock(rt2x00dev, efuse_ctrl_reg, reg); /* Wait until the EEPROM has been loaded */ - rt2800_regbusy_read(rt2x00dev, EFUSE_CTRL, EFUSE_CTRL_KICK, ®); - + rt2800_regbusy_read(rt2x00dev, efuse_ctrl_reg, EFUSE_CTRL_KICK, ®); /* Apparently the data is read from end to start */ - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA3, ®); + rt2800_register_read_lock(rt2x00dev, efuse_data3_reg, ®); /* The returned value is in CPU order, but eeprom is le */ *(u32 *)&rt2x00dev->eeprom[i] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA2, ®); + rt2800_register_read_lock(rt2x00dev, efuse_data2_reg, ®); *(u32 *)&rt2x00dev->eeprom[i + 2] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA1, ®); + rt2800_register_read_lock(rt2x00dev, efuse_data1_reg, ®); *(u32 *)&rt2x00dev->eeprom[i + 4] = cpu_to_le32(reg); - rt2800_register_read_lock(rt2x00dev, EFUSE_DATA0, ®); + rt2800_register_read_lock(rt2x00dev, efuse_data0_reg, ®); *(u32 *)&rt2x00dev->eeprom[i + 6] = cpu_to_le32(reg); mutex_unlock(&rt2x00dev->csr_mutex); @@ -4244,9 +4470,14 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) * RT28xx/RT30xx: defined in "EEPROM_NIC_CONF0_RF_TYPE" field * RT53xx: defined in "EEPROM_CHIP_ID" field */ - rt2800_register_read(rt2x00dev, MAC_CSR0, ®); - if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 || - rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392) + if (rt2x00_rt(rt2x00dev, RT3290)) + rt2800_register_read(rt2x00dev, MAC_CSR0_3290, ®); + else + rt2800_register_read(rt2x00dev, MAC_CSR0, ®); + + if (rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT3290 || + rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5390 || + rt2x00_get_field32(reg, MAC_CSR0_CHIPSET) == RT5392) rt2x00_eeprom_read(rt2x00dev, EEPROM_CHIP_ID, &value); else value = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); @@ -4261,6 +4492,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) case RT3070: case RT3071: case RT3090: + case RT3290: case RT3390: case RT3572: case RT5390: @@ -4281,6 +4513,7 @@ int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) case RF3021: case RF3022: case RF3052: + case RF3290: case RF3320: case RF5360: case RF5370: @@ -4597,6 +4830,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) rt2x00_rf(rt2x00dev, RF2020) || rt2x00_rf(rt2x00dev, RF3021) || rt2x00_rf(rt2x00dev, RF3022) || + rt2x00_rf(rt2x00dev, RF3290) || rt2x00_rf(rt2x00dev, RF3320) || rt2x00_rf(rt2x00dev, RF5360) || rt2x00_rf(rt2x00dev, RF5370) || @@ -4685,6 +4919,7 @@ int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev) case RF3022: case RF3320: case RF3052: + case RF3290: case RF5360: case RF5370: case RF5372: diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 206158b67426..235376e9cb04 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -280,7 +280,13 @@ static void rt2800pci_stop_queue(struct data_queue *queue) */ static char *rt2800pci_get_firmware_name(struct rt2x00_dev *rt2x00dev) { - return FIRMWARE_RT2860; + /* + * Chip rt3290 use specific 4KB firmware named rt3290.bin. + */ + if (rt2x00_rt(rt2x00dev, RT3290)) + return FIRMWARE_RT3290; + else + return FIRMWARE_RT2860; } static int rt2800pci_write_firmware(struct rt2x00_dev *rt2x00dev, @@ -974,6 +980,66 @@ static int rt2800pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) return rt2800_validate_eeprom(rt2x00dev); } +static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) +{ + u32 reg; + int i, count; + + rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + if (rt2x00_get_field32(reg, WLAN_EN)) + return 0; + + rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); + rt2x00_set_field32(®, FRC_WL_ANT_SET, 1); + rt2x00_set_field32(®, WLAN_CLK_EN, 0); + rt2x00_set_field32(®, WLAN_EN, 1); + rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); + + udelay(REGISTER_BUSY_DELAY); + + count = 0; + do { + /* + * Check PLL_LD & XTAL_RDY. + */ + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2800_register_read(rt2x00dev, CMB_CTRL, ®); + if (rt2x00_get_field32(reg, PLL_LD) && + rt2x00_get_field32(reg, XTAL_RDY)) + break; + udelay(REGISTER_BUSY_DELAY); + } + + if (i >= REGISTER_BUSY_COUNT) { + + if (count >= 10) + return -EIO; + + rt2800_register_write(rt2x00dev, 0x58, 0x018); + udelay(REGISTER_BUSY_DELAY); + rt2800_register_write(rt2x00dev, 0x58, 0x418); + udelay(REGISTER_BUSY_DELAY); + rt2800_register_write(rt2x00dev, 0x58, 0x618); + udelay(REGISTER_BUSY_DELAY); + count++; + } else { + count = 0; + } + + rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); + rt2x00_set_field32(®, PCIE_APP0_CLK_REQ, 0); + rt2x00_set_field32(®, WLAN_CLK_EN, 1); + rt2x00_set_field32(®, WLAN_RESET, 1); + rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); + udelay(10); + rt2x00_set_field32(®, WLAN_RESET, 0); + rt2800_register_write(rt2x00dev, WLAN_FUN_CTRL, reg); + udelay(10); + rt2800_register_write(rt2x00dev, INT_SOURCE_CSR, 0x7fffffff); + } while (count != 0); + + return 0; +} static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) { int retval; @@ -997,6 +1063,17 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev) return retval; /* + * In probe phase call rt2800_enable_wlan_rt3290 to enable wlan + * clk for rt3290. That avoid the MCU fail in start phase. + */ + if (rt2x00_rt(rt2x00dev, RT3290)) { + retval = rt2800_enable_wlan_rt3290(rt2x00dev); + + if (retval) + return retval; + } + + /* * This device has multiple filters for control frames * and has a separate filter for PS Poll frames. */ @@ -1175,6 +1252,9 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1432, 0x7768) }, { PCI_DEVICE(0x1462, 0x891a) }, { PCI_DEVICE(0x1a3b, 0x1059) }, +#ifdef CONFIG_RT2800PCI_RT3290 + { PCI_DEVICE(0x1814, 0x3290) }, +#endif #ifdef CONFIG_RT2800PCI_RT33XX { PCI_DEVICE(0x1814, 0x3390) }, #endif diff --git a/drivers/net/wireless/rt2x00/rt2800pci.h b/drivers/net/wireless/rt2x00/rt2800pci.h index 70e050d904c8..ab22a087c50d 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.h +++ b/drivers/net/wireless/rt2x00/rt2800pci.h @@ -47,6 +47,7 @@ * 8051 firmware image. */ #define FIRMWARE_RT2860 "rt2860.bin" +#define FIRMWARE_RT3290 "rt3290.bin" #define FIRMWARE_IMAGE_BASE 0x2000 /* diff --git a/drivers/net/wireless/rt2x00/rt2800usb.c b/drivers/net/wireless/rt2x00/rt2800usb.c index 20a504072895..6cf336595e25 100644 --- a/drivers/net/wireless/rt2x00/rt2800usb.c +++ b/drivers/net/wireless/rt2x00/rt2800usb.c @@ -971,6 +971,7 @@ static struct usb_device_id rt2800usb_device_table[] = { { USB_DEVICE(0x0411, 0x015d) }, { USB_DEVICE(0x0411, 0x016f) }, { USB_DEVICE(0x0411, 0x01a2) }, + { USB_DEVICE(0x0411, 0x01ee) }, /* Corega */ { USB_DEVICE(0x07aa, 0x002f) }, { USB_DEVICE(0x07aa, 0x003c) }, diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 8f754025b06e..8afb546c2b2d 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -187,6 +187,7 @@ struct rt2x00_chip { #define RT3070 0x3070 #define RT3071 0x3071 #define RT3090 0x3090 /* 2.4GHz PCIe */ +#define RT3290 0x3290 #define RT3390 0x3390 #define RT3572 0x3572 #define RT3593 0x3593 diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index e7361d913e8e..49a63e973934 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -102,7 +102,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, /* Update the AID, this is needed for dynamic PS support */ rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; - rt2x00dev->last_beacon = bss_conf->last_tsf; + rt2x00dev->last_beacon = bss_conf->sync_tsf; /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index 0a4653a92cab..a0c8caef3b0a 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -256,6 +256,7 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) struct ieee80211_hw *hw; struct rt2x00_dev *rt2x00dev; int retval; + u16 chip; retval = pci_enable_device(pci_dev); if (retval) { @@ -305,6 +306,14 @@ int rt2x00pci_probe(struct pci_dev *pci_dev, const struct rt2x00_ops *ops) if (retval) goto exit_free_device; + /* + * Because rt3290 chip use different efuse offset to read efuse data. + * So before read efuse it need to indicate it is the + * rt3290 or not. + */ + pci_read_config_word(pci_dev, PCI_DEVICE_ID, &chip); + rt2x00dev->chip.rt = chip; + retval = rt2x00lib_probe_dev(rt2x00dev); if (retval) goto exit_free_reg; diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2fd830103415..f7e74a0a7759 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -774,9 +774,7 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void *data, - bool (*fn)(struct queue_entry *entry, - void *data)) + bool (*fn)(struct queue_entry *entry)) { unsigned long irqflags; unsigned int index_start; @@ -807,17 +805,17 @@ bool rt2x00queue_for_each_entry(struct data_queue *queue, */ if (index_start < index_end) { for (i = index_start; i < index_end; i++) { - if (fn(&queue->entries[i], data)) + if (fn(&queue->entries[i])) return true; } } else { for (i = index_start; i < queue->limit; i++) { - if (fn(&queue->entries[i], data)) + if (fn(&queue->entries[i])) return true; } for (i = 0; i < index_end; i++) { - if (fn(&queue->entries[i], data)) + if (fn(&queue->entries[i])) return true; } } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 5f1392c72673..9b8c10a86dee 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -584,7 +584,6 @@ struct data_queue_desc { * @queue: Pointer to @data_queue * @start: &enum queue_index Pointer to start index * @end: &enum queue_index Pointer to end index - * @data: Data to pass to the callback function * @fn: The function to call for each &struct queue_entry * * This will walk through all entries in the queue, in chronological @@ -597,9 +596,7 @@ struct data_queue_desc { bool rt2x00queue_for_each_entry(struct data_queue *queue, enum queue_index start, enum queue_index end, - void *data, - bool (*fn)(struct queue_entry *entry, - void *data)); + bool (*fn)(struct queue_entry *entry)); /** * rt2x00queue_empty - Check if the queue is empty. diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index d357d1ed92f6..40ea80725a96 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -285,7 +285,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb) queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work); } -static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry, void* data) +static bool rt2x00usb_kick_tx_entry(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -390,7 +390,7 @@ static void rt2x00usb_interrupt_rxdone(struct urb *urb) queue_work(rt2x00dev->workqueue, &rt2x00dev->rxdone_work); } -static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry, void* data) +static bool rt2x00usb_kick_rx_entry(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); @@ -427,18 +427,12 @@ void rt2x00usb_kick_queue(struct data_queue *queue) case QID_AC_BE: case QID_AC_BK: if (!rt2x00queue_empty(queue)) - rt2x00queue_for_each_entry(queue, - Q_INDEX_DONE, - Q_INDEX, - NULL, + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, rt2x00usb_kick_tx_entry); break; case QID_RX: if (!rt2x00queue_full(queue)) - rt2x00queue_for_each_entry(queue, - Q_INDEX_DONE, - Q_INDEX, - NULL, + rt2x00queue_for_each_entry(queue, Q_INDEX, Q_INDEX_DONE, rt2x00usb_kick_rx_entry); break; default: @@ -447,7 +441,7 @@ void rt2x00usb_kick_queue(struct data_queue *queue) } EXPORT_SYMBOL_GPL(rt2x00usb_kick_queue); -static bool rt2x00usb_flush_entry(struct queue_entry *entry, void* data) +static bool rt2x00usb_flush_entry(struct queue_entry *entry) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; @@ -474,7 +468,7 @@ void rt2x00usb_flush_queue(struct data_queue *queue, bool drop) unsigned int i; if (drop) - rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, NULL, + rt2x00queue_for_each_entry(queue, Q_INDEX_DONE, Q_INDEX, rt2x00usb_flush_entry); /* @@ -565,7 +559,7 @@ void rt2x00usb_clear_entry(struct queue_entry *entry) entry->flags = 0; if (entry->queue->qid == QID_RX) - rt2x00usb_kick_rx_entry(entry, NULL); + rt2x00usb_kick_rx_entry(entry); } EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); diff --git a/drivers/net/wireless/rtl818x/rtl8180/dev.c b/drivers/net/wireless/rtl818x/rtl8180/dev.c index 2bebcb71a1e9..3b505395d869 100644 --- a/drivers/net/wireless/rtl818x/rtl8180/dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180/dev.c @@ -47,6 +47,8 @@ static DEFINE_PCI_DEVICE_TABLE(rtl8180_table) = { { PCI_DEVICE(0x1799, 0x6001) }, { PCI_DEVICE(0x1799, 0x6020) }, { PCI_DEVICE(PCI_VENDOR_ID_DLINK, 0x3300) }, + { PCI_DEVICE(0x1186, 0x3301) }, + { PCI_DEVICE(0x1432, 0x7106) }, { } }; diff --git a/drivers/net/wireless/rtlwifi/cam.c b/drivers/net/wireless/rtlwifi/cam.c index 3d8cc4a0c86d..6a2d72beb00d 100644 --- a/drivers/net/wireless/rtlwifi/cam.c +++ b/drivers/net/wireless/rtlwifi/cam.c @@ -128,7 +128,7 @@ u8 rtl_cam_add_one_entry(struct ieee80211_hw *hw, u8 *mac_addr, u32 us_config; struct rtl_priv *rtlpriv = rtl_priv(hw); - RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, "EntryNo:%x, ulKeyId=%x, ulEncAlg=%x, ulUseDK=%x MacAddr %pM\n", ul_entry_idx, ul_key_id, ul_enc_alg, ul_default_key, mac_addr); @@ -342,7 +342,8 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr) /* Remove from HW Security CAM */ memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN); rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i); - pr_info("&&&&&&&&&del entry %d\n", i); + RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD, + "del CAM entry %d\n", i); } } return; diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 2062ea1d7c80..36bffbc4519e 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -1273,17 +1273,18 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) *after reset, release previous pending packet, *and force the tx idx to the first one */ - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) { if (rtlpci->tx_ring[i].desc) { struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i]; while (skb_queue_len(&ring->queue)) { - struct rtl_tx_desc *entry = - &ring->desc[ring->idx]; - struct sk_buff *skb = - __skb_dequeue(&ring->queue); + struct rtl_tx_desc *entry; + struct sk_buff *skb; + spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, + flags); + entry = &ring->desc[ring->idx]; + skb = __skb_dequeue(&ring->queue); pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops-> get_desc((u8 *) @@ -1291,15 +1292,15 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw) true, HW_DESC_TXBUFF_ADDR), skb->len, PCI_DMA_TODEVICE); - kfree_skb(skb); ring->idx = (ring->idx + 1) % ring->entries; + spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, + flags); + kfree_skb(skb); } ring->idx = 0; } } - spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags); - return 0; } diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c index d228358e6a40..9970c2b1b199 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c @@ -301,9 +301,11 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/ {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/ + {RTL_USB_DEVICE(0x0bda, 0x5088, rtl92cu_hal_cfg)}, /*Thinkware-CC&C*/ {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/ {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/ + {RTL_USB_DEVICE(0x4856, 0x0091, rtl92cu_hal_cfg)}, /*NetweeN - Feixun*/ /* HP - Lite-On ,8188CUS Slim Combo */ {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)}, {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */ @@ -346,6 +348,7 @@ static struct usb_device_id rtl8192c_usb_ids[] = { {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/ {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/ {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/ + {RTL_USB_DEVICE(0x0bda, 0x8186, rtl92cu_hal_cfg)}, /*Realtek 92CE-VAU*/ {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/ {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/ {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/ diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c index 8d7099bc472c..b917a2a3caf7 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/phy.c @@ -1247,6 +1247,9 @@ static void _rtl92s_phy_get_txpower_index(struct ieee80211_hw *hw, u8 channel, /* Read HT 40 OFDM TX power */ ofdmpowerLevel[0] = rtlefuse->txpwrlevel_ht40_2s[0][index]; ofdmpowerLevel[1] = rtlefuse->txpwrlevel_ht40_2s[1][index]; + } else { + ofdmpowerLevel[0] = 0; + ofdmpowerLevel[1] = 0; } } diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c index 730bcc919529..ad4b4803482d 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c +++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c @@ -29,7 +29,6 @@ #include "../wifi.h" #include "../core.h" -#include "../pci.h" #include "../base.h" #include "../pci.h" #include "reg.h" diff --git a/drivers/net/wireless/ti/wl1251/acx.c b/drivers/net/wireless/ti/wl1251/acx.c index ad87a1ac6462..db6430c1a084 100644 --- a/drivers/net/wireless/ti/wl1251/acx.c +++ b/drivers/net/wireless/ti/wl1251/acx.c @@ -869,7 +869,7 @@ int wl1251_acx_tsf_info(struct wl1251 *wl, u64 *mactime) } *mactime = tsf_info->current_tsf_lsb | - (tsf_info->current_tsf_msb << 31); + ((u64)tsf_info->current_tsf_msb << 32); out: kfree(tsf_info); diff --git a/drivers/net/wireless/ti/wl1251/cmd.c b/drivers/net/wireless/ti/wl1251/cmd.c index d14d69d733a0..6822b845efc1 100644 --- a/drivers/net/wireless/ti/wl1251/cmd.c +++ b/drivers/net/wireless/ti/wl1251/cmd.c @@ -277,15 +277,6 @@ int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel, join->rx_config_options = wl->rx_config; join->rx_filter_options = wl->rx_filter; - /* - * FIXME: disable temporarily all filters because after commit - * 9cef8737 "mac80211: fix managed mode BSSID handling" broke - * association. The filter logic needs to be implemented properly - * and once that is done, this hack can be removed. - */ - join->rx_config_options = 0; - join->rx_filter_options = WL1251_DEFAULT_RX_FILTER; - join->basic_rate_set = RATE_MASK_1MBPS | RATE_MASK_2MBPS | RATE_MASK_5_5MBPS | RATE_MASK_11MBPS; diff --git a/drivers/net/wireless/ti/wl1251/event.c b/drivers/net/wireless/ti/wl1251/event.c index 9f15ccaf8f05..5ec50a476a69 100644 --- a/drivers/net/wireless/ti/wl1251/event.c +++ b/drivers/net/wireless/ti/wl1251/event.c @@ -76,8 +76,7 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox) } } - if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID && - wl->station_mode != STATION_ACTIVE_MODE) { + if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) { wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT"); /* indicate to the stack, that beacons have been lost */ diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c index d1afb8e3b2ef..3118c425bcf1 100644 --- a/drivers/net/wireless/ti/wl1251/main.c +++ b/drivers/net/wireless/ti/wl1251/main.c @@ -334,6 +334,12 @@ static int wl1251_join(struct wl1251 *wl, u8 bss_type, u8 channel, if (ret < 0) goto out; + /* + * Join command applies filters, and if we are not associated, + * BSSID filter must be disabled for association to work. + */ + if (is_zero_ether_addr(wl->bssid)) + wl->rx_config &= ~CFG_BSSID_FILTER_EN; ret = wl1251_cmd_join(wl, bss_type, channel, beacon_interval, dtim_period); @@ -348,33 +354,6 @@ out: return ret; } -static void wl1251_filter_work(struct work_struct *work) -{ - struct wl1251 *wl = - container_of(work, struct wl1251, filter_work); - int ret; - - mutex_lock(&wl->mutex); - - if (wl->state == WL1251_STATE_OFF) - goto out; - - ret = wl1251_ps_elp_wakeup(wl); - if (ret < 0) - goto out; - - ret = wl1251_join(wl, wl->bss_type, wl->channel, wl->beacon_int, - wl->dtim_period); - if (ret < 0) - goto out_sleep; - -out_sleep: - wl1251_ps_elp_sleep(wl); - -out: - mutex_unlock(&wl->mutex); -} - static void wl1251_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct wl1251 *wl = hw->priv; @@ -478,7 +457,6 @@ static void wl1251_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&wl->irq_work); cancel_work_sync(&wl->tx_work); - cancel_work_sync(&wl->filter_work); cancel_delayed_work_sync(&wl->elp_work); mutex_lock(&wl->mutex); @@ -681,13 +659,15 @@ out: FIF_FCSFAIL | \ FIF_BCN_PRBRESP_PROMISC | \ FIF_CONTROL | \ - FIF_OTHER_BSS) + FIF_OTHER_BSS | \ + FIF_PROBE_REQ) static void wl1251_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *total,u64 multicast) { struct wl1251 *wl = hw->priv; + int ret; wl1251_debug(DEBUG_MAC80211, "mac80211 configure filter"); @@ -698,7 +678,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, /* no filters which we support changed */ return; - /* FIXME: wl->rx_config and wl->rx_filter are not protected */ + mutex_lock(&wl->mutex); wl->rx_config = WL1251_DEFAULT_RX_CONFIG; wl->rx_filter = WL1251_DEFAULT_RX_FILTER; @@ -721,15 +701,25 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw, } if (*total & FIF_CONTROL) wl->rx_filter |= CFG_RX_CTL_EN; - if (*total & FIF_OTHER_BSS) - wl->rx_filter &= ~CFG_BSSID_FILTER_EN; + if (*total & FIF_OTHER_BSS || is_zero_ether_addr(wl->bssid)) + wl->rx_config &= ~CFG_BSSID_FILTER_EN; + if (*total & FIF_PROBE_REQ) + wl->rx_filter |= CFG_RX_PREQ_EN; - /* - * FIXME: workqueues need to be properly cancelled on stop(), for - * now let's just disable changing the filter settings. They will - * be updated any on config(). - */ - /* schedule_work(&wl->filter_work); */ + if (wl->state == WL1251_STATE_OFF) + goto out; + + ret = wl1251_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + /* send filters to firmware */ + wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter); + + wl1251_ps_elp_sleep(wl); + +out: + mutex_unlock(&wl->mutex); } /* HW encryption */ @@ -1390,7 +1380,6 @@ struct ieee80211_hw *wl1251_alloc_hw(void) skb_queue_head_init(&wl->tx_queue); - INIT_WORK(&wl->filter_work, wl1251_filter_work); INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work); wl->channel = WL1251_DEFAULT_CHANNEL; wl->scanning = false; diff --git a/drivers/net/wireless/ti/wl1251/spi.c b/drivers/net/wireless/ti/wl1251/spi.c index 87f6305bda2c..567660cd2fcd 100644 --- a/drivers/net/wireless/ti/wl1251/spi.c +++ b/drivers/net/wireless/ti/wl1251/spi.c @@ -73,6 +73,8 @@ static void wl1251_spi_reset(struct wl1251 *wl) spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi reset -> ", cmd, WSPI_INIT_CMD_LEN); + + kfree(cmd); } static void wl1251_spi_wake(struct wl1251 *wl) @@ -127,6 +129,8 @@ static void wl1251_spi_wake(struct wl1251 *wl) spi_sync(wl_to_spi(wl), &m); wl1251_dump(DEBUG_SPI, "spi init -> ", cmd, WSPI_INIT_CMD_LEN); + + kfree(cmd); } static void wl1251_spi_reset_wake(struct wl1251 *wl) diff --git a/drivers/net/wireless/ti/wl1251/wl1251.h b/drivers/net/wireless/ti/wl1251/wl1251.h index 9d8f5816c6f9..fd02060038de 100644 --- a/drivers/net/wireless/ti/wl1251/wl1251.h +++ b/drivers/net/wireless/ti/wl1251/wl1251.h @@ -315,7 +315,6 @@ struct wl1251 { bool tx_queue_stopped; struct work_struct tx_work; - struct work_struct filter_work; /* Pending TX frames */ struct sk_buff *tx_frames[16]; diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c index 50ba7480b790..30be784a40d8 100644 --- a/drivers/net/wireless/ti/wl12xx/cmd.c +++ b/drivers/net/wireless/ti/wl12xx/cmd.c @@ -174,7 +174,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) struct wl1271_nvs_file *nvs = (struct wl1271_nvs_file *)wl->nvs; struct wl1271_radio_parms_cmd *radio_parms; struct wl1271_ini_general_params *gp = &nvs->general_params; - int ret; + int ret, fem_idx; if (!wl->nvs) return -ENODEV; @@ -185,11 +185,13 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); + /* 2.4GHz parameters */ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl1271_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_2[fem_idx].params, sizeof(struct wl1271_ini_fem_params_2)); /* 5GHz parameters */ @@ -197,7 +199,7 @@ int wl1271_cmd_radio_parms(struct wl1271 *wl) &nvs->stat_radio_params_5, sizeof(struct wl1271_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_5[fem_idx].params, sizeof(struct wl1271_ini_fem_params_5)); wl1271_dump(DEBUG_CMD, "TEST_CMD_INI_FILE_RADIO_PARAM: ", @@ -216,7 +218,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl) struct wl128x_nvs_file *nvs = (struct wl128x_nvs_file *)wl->nvs; struct wl128x_radio_parms_cmd *radio_parms; struct wl128x_ini_general_params *gp = &nvs->general_params; - int ret; + int ret, fem_idx; if (!wl->nvs) return -ENODEV; @@ -227,11 +229,13 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl) radio_parms->test.id = TEST_CMD_INI_FILE_RADIO_PARAM; + fem_idx = WL12XX_FEM_TO_NVS_ENTRY(gp->tx_bip_fem_manufacturer); + /* 2.4GHz parameters */ memcpy(&radio_parms->static_params_2, &nvs->stat_radio_params_2, sizeof(struct wl128x_ini_band_params_2)); memcpy(&radio_parms->dyn_params_2, - &nvs->dyn_radio_params_2[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_2[fem_idx].params, sizeof(struct wl128x_ini_fem_params_2)); /* 5GHz parameters */ @@ -239,7 +243,7 @@ int wl128x_cmd_radio_parms(struct wl1271 *wl) &nvs->stat_radio_params_5, sizeof(struct wl128x_ini_band_params_5)); memcpy(&radio_parms->dyn_params_5, - &nvs->dyn_radio_params_5[gp->tx_bip_fem_manufacturer].params, + &nvs->dyn_radio_params_5[fem_idx].params, sizeof(struct wl128x_ini_fem_params_5)); radio_parms->fem_vendor_and_options = nvs->fem_vendor_and_options; diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 85d1600ee340..3d6c71b7a3c7 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -242,10 +242,11 @@ static struct wlcore_conf wl12xx_conf = { .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .dynamic_ps_timeout = 200, + .dynamic_ps_timeout = 1500, .forced_ps = false, .keep_alive_interval = 55000, .max_listen_interval = 20, + .sta_sleep_auth = WL1271_PSM_ILLEGAL, }, .itrim = { .enable = false, @@ -589,16 +590,18 @@ static const int wl12xx_rtable[REG_TABLE_LEN] = { }; /* TODO: maybe move to a new header file? */ -#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" -#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" -#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" +#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-5-mr.bin" +#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-5-sr.bin" +#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-5-plt.bin" -#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" -#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" -#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" +#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-5-mr.bin" +#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-5-sr.bin" +#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-5-plt.bin" -static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) +static int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) { + int ret; + if (wl->chip.id != CHIP_ID_1283_PG20) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; struct wl127x_rx_mem_pool_addr rx_mem_addr; @@ -615,9 +618,13 @@ static void wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) rx_mem_addr.addr_extra = rx_mem_addr.addr + 4; - wl1271_write(wl, WL1271_SLV_REG_DATA, - &rx_mem_addr, sizeof(rx_mem_addr), false); + ret = wlcore_write(wl, WL1271_SLV_REG_DATA, &rx_mem_addr, + sizeof(rx_mem_addr), false); + if (ret < 0) + return ret; } + + return 0; } static int wl12xx_identify_chip(struct wl1271 *wl) @@ -630,6 +637,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) wl->chip.id); wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | + WLCORE_QUIRK_DUAL_PROBE_TMPL | WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; wl->mr_fw_name = WL127X_FW_NAME_MULTI; @@ -639,6 +647,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; case CHIP_ID_1271_PG20: @@ -646,6 +657,7 @@ static int wl12xx_identify_chip(struct wl1271 *wl) wl->chip.id); wl->quirks |= WLCORE_QUIRK_LEGACY_NVS | + WLCORE_QUIRK_DUAL_PROBE_TMPL | WLCORE_QUIRK_TKIP_HEADER_SPACE; wl->plt_fw_name = WL127X_PLT_FW_NAME; wl->sr_fw_name = WL127X_FW_NAME_SINGLE; @@ -656,6 +668,9 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* read data preparation is only needed by wl127x */ wl->ops->prepare_read = wl127x_prepare_read; + wlcore_set_min_fw_ver(wl, WL127X_CHIP_VER, WL127X_IFTYPE_VER, + WL127X_MAJOR_VER, WL127X_SUBTYPE_VER, + WL127X_MINOR_VER); break; case CHIP_ID_1283_PG20: @@ -667,8 +682,12 @@ static int wl12xx_identify_chip(struct wl1271 *wl) /* wl128x requires TX blocksize alignment */ wl->quirks |= WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | + WLCORE_QUIRK_DUAL_PROBE_TMPL | WLCORE_QUIRK_TKIP_HEADER_SPACE; + wlcore_set_min_fw_ver(wl, WL128X_CHIP_VER, WL128X_IFTYPE_VER, + WL128X_MAJOR_VER, WL128X_SUBTYPE_VER, + WL128X_MINOR_VER); break; case CHIP_ID_1283_PG10: default: @@ -681,64 +700,95 @@ out: return ret; } -static void wl12xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) +static int __must_check wl12xx_top_reg_write(struct wl1271 *wl, int addr, + u16 val) { + int ret; + /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); + if (ret < 0) + goto out; /* write value to OCP_POR_WDATA */ - wl1271_write32(wl, WL12XX_OCP_DATA_WRITE, val); + ret = wlcore_write32(wl, WL12XX_OCP_DATA_WRITE, val); + if (ret < 0) + goto out; /* write 1 to OCP_CMD */ - wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); + ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_WRITE); + if (ret < 0) + goto out; + +out: + return ret; } -static u16 wl12xx_top_reg_read(struct wl1271 *wl, int addr) +static int __must_check wl12xx_top_reg_read(struct wl1271 *wl, int addr, + u16 *out) { u32 val; int timeout = OCP_CMD_LOOP; + int ret; /* write address >> 1 + 0x30000 to OCP_POR_CTR */ addr = (addr >> 1) + 0x30000; - wl1271_write32(wl, WL12XX_OCP_POR_CTR, addr); + ret = wlcore_write32(wl, WL12XX_OCP_POR_CTR, addr); + if (ret < 0) + return ret; /* write 2 to OCP_CMD */ - wl1271_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); + ret = wlcore_write32(wl, WL12XX_OCP_CMD, OCP_CMD_READ); + if (ret < 0) + return ret; /* poll for data ready */ do { - val = wl1271_read32(wl, WL12XX_OCP_DATA_READ); + ret = wlcore_read32(wl, WL12XX_OCP_DATA_READ, &val); + if (ret < 0) + return ret; } while (!(val & OCP_READY_MASK) && --timeout); if (!timeout) { wl1271_warning("Top register access timed out."); - return 0xffff; + return -ETIMEDOUT; } /* check data status and return if OK */ - if ((val & OCP_STATUS_MASK) == OCP_STATUS_OK) - return val & 0xffff; - else { + if ((val & OCP_STATUS_MASK) != OCP_STATUS_OK) { wl1271_warning("Top register access returned error."); - return 0xffff; + return -EIO; } + + if (out) + *out = val & 0xffff; + + return 0; } static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) { u16 spare_reg; + int ret; /* Mask bits [2] & [8:4] in the sys_clk_cfg register */ - spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); + if (ret < 0) + return ret; + if (spare_reg == 0xFFFF) return -EFAULT; spare_reg |= (BIT(3) | BIT(5) | BIT(6)); - wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + if (ret < 0) + return ret; /* Enable FREF_CLK_REQ & mux MCS and coex PLLs to FREF */ - wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, - WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + ret = wl12xx_top_reg_write(wl, SYS_CLK_CFG_REG, + WL_CLK_REQ_TYPE_PG2 | MCS_PLL_CLK_SEL_FREF); + if (ret < 0) + return ret; /* Delay execution for 15msec, to let the HW settle */ mdelay(15); @@ -749,8 +799,12 @@ static int wl128x_switch_tcxo_to_fref(struct wl1271 *wl) static bool wl128x_is_tcxo_valid(struct wl1271 *wl) { u16 tcxo_detection; + int ret; + + ret = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG, &tcxo_detection); + if (ret < 0) + return false; - tcxo_detection = wl12xx_top_reg_read(wl, TCXO_CLK_DETECT_REG); if (tcxo_detection & TCXO_DET_FAILED) return false; @@ -760,8 +814,12 @@ static bool wl128x_is_tcxo_valid(struct wl1271 *wl) static bool wl128x_is_fref_valid(struct wl1271 *wl) { u16 fref_detection; + int ret; + + ret = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG, &fref_detection); + if (ret < 0) + return false; - fref_detection = wl12xx_top_reg_read(wl, FREF_CLK_DETECT_REG); if (fref_detection & FREF_CLK_DETECT_FAIL) return false; @@ -770,11 +828,21 @@ static bool wl128x_is_fref_valid(struct wl1271 *wl) static int wl128x_manually_configure_mcs_pll(struct wl1271 *wl) { - wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); - wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); - wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, MCS_PLL_CONFIG_REG_VAL); + int ret; - return 0; + ret = wl12xx_top_reg_write(wl, MCS_PLL_M_REG, MCS_PLL_M_REG_VAL); + if (ret < 0) + goto out; + + ret = wl12xx_top_reg_write(wl, MCS_PLL_N_REG, MCS_PLL_N_REG_VAL); + if (ret < 0) + goto out; + + ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, + MCS_PLL_CONFIG_REG_VAL); + +out: + return ret; } static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) @@ -783,13 +851,19 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) u16 pll_config; u8 input_freq; struct wl12xx_priv *priv = wl->priv; + int ret; /* Mask bits [3:1] in the sys_clk_cfg register */ - spare_reg = wl12xx_top_reg_read(wl, WL_SPARE_REG); + ret = wl12xx_top_reg_read(wl, WL_SPARE_REG, &spare_reg); + if (ret < 0) + return ret; + if (spare_reg == 0xFFFF) return -EFAULT; spare_reg |= BIT(2); - wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + ret = wl12xx_top_reg_write(wl, WL_SPARE_REG, spare_reg); + if (ret < 0) + return ret; /* Handle special cases of the TCXO clock */ if (priv->tcxo_clock == WL12XX_TCXOCLOCK_16_8 || @@ -799,14 +873,17 @@ static int wl128x_configure_mcs_pll(struct wl1271 *wl, int clk) /* Set the input frequency according to the selected clock source */ input_freq = (clk & 1) + 1; - pll_config = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG); + ret = wl12xx_top_reg_read(wl, MCS_PLL_CONFIG_REG, &pll_config); + if (ret < 0) + return ret; + if (pll_config == 0xFFFF) return -EFAULT; pll_config |= (input_freq << MCS_SEL_IN_FREQ_SHIFT); pll_config |= MCS_PLL_ENABLE_HP; - wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); + ret = wl12xx_top_reg_write(wl, MCS_PLL_CONFIG_REG, pll_config); - return 0; + return ret; } /* @@ -820,6 +897,7 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) { struct wl12xx_priv *priv = wl->priv; u16 sys_clk_cfg; + int ret; /* For XTAL-only modes, FREF will be used after switching from TCXO */ if (priv->ref_clock == WL12XX_REFCLOCK_26_XTAL || @@ -830,7 +908,10 @@ static int wl128x_boot_clk(struct wl1271 *wl, int *selected_clock) } /* Query the HW, to determine which clock source we should use */ - sys_clk_cfg = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG); + ret = wl12xx_top_reg_read(wl, SYS_CLK_CFG_REG, &sys_clk_cfg); + if (ret < 0) + return ret; + if (sys_clk_cfg == 0xFFFF) return -EINVAL; if (sys_clk_cfg & PRCM_CM_EN_MUX_WLAN_FREF) @@ -865,6 +946,7 @@ static int wl127x_boot_clk(struct wl1271 *wl) struct wl12xx_priv *priv = wl->priv; u32 pause; u32 clk; + int ret; if (WL127X_PG_GET_MAJOR(wl->hw_pg_ver) < 3) wl->quirks |= WLCORE_QUIRK_END_OF_TRANSACTION; @@ -885,48 +967,74 @@ static int wl127x_boot_clk(struct wl1271 *wl) if (priv->ref_clock != CONF_REF_CLK_19_2_E) { u16 val; /* Set clock type (open drain) */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_TYPE, &val); + if (ret < 0) + goto out; + val &= FREF_CLK_TYPE_BITS; - wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_TYPE, val); + if (ret < 0) + goto out; /* Set clock pull mode (no pull) */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_PULL, &val); + if (ret < 0) + goto out; + val |= NO_PULL; - wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_PULL, val); + if (ret < 0) + goto out; } else { u16 val; /* Set clock polarity */ - val = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY); + ret = wl12xx_top_reg_read(wl, OCP_REG_CLK_POLARITY, &val); + if (ret < 0) + goto out; + val &= FREF_CLK_POLARITY_BITS; val |= CLK_REQ_OUTN_SEL; - wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + ret = wl12xx_top_reg_write(wl, OCP_REG_CLK_POLARITY, val); + if (ret < 0) + goto out; } - wl1271_write32(wl, WL12XX_PLL_PARAMETERS, clk); + ret = wlcore_write32(wl, WL12XX_PLL_PARAMETERS, clk); + if (ret < 0) + goto out; - pause = wl1271_read32(wl, WL12XX_PLL_PARAMETERS); + ret = wlcore_read32(wl, WL12XX_PLL_PARAMETERS, &pause); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "pause1 0x%x", pause); pause &= ~(WU_COUNTER_PAUSE_VAL); pause |= WU_COUNTER_PAUSE_VAL; - wl1271_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); + ret = wlcore_write32(wl, WL12XX_WU_COUNTER_PAUSE, pause); - return 0; +out: + return ret; } static int wl1271_boot_soft_reset(struct wl1271 *wl) { unsigned long timeout; u32 boot_data; + int ret = 0; /* perform soft reset */ - wl1271_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + ret = wlcore_write32(wl, WL12XX_SLV_SOFT_RESET, ACX_SLV_SOFT_RESET_BIT); + if (ret < 0) + goto out; /* SOFT_RESET is self clearing */ timeout = jiffies + usecs_to_jiffies(SOFT_RESET_MAX_TIME); while (1) { - boot_data = wl1271_read32(wl, WL12XX_SLV_SOFT_RESET); + ret = wlcore_read32(wl, WL12XX_SLV_SOFT_RESET, &boot_data); + if (ret < 0) + goto out; + wl1271_debug(DEBUG_BOOT, "soft reset bootdata 0x%x", boot_data); if ((boot_data & ACX_SLV_SOFT_RESET_BIT) == 0) break; @@ -942,12 +1050,15 @@ static int wl1271_boot_soft_reset(struct wl1271 *wl) } /* disable Rx/Tx */ - wl1271_write32(wl, WL12XX_ENABLE, 0x0); + ret = wlcore_write32(wl, WL12XX_ENABLE, 0x0); + if (ret < 0) + goto out; /* disable auto calibration on start*/ - wl1271_write32(wl, WL12XX_SPARE_A2, 0xffff); + ret = wlcore_write32(wl, WL12XX_SPARE_A2, 0xffff); - return 0; +out: + return ret; } static int wl12xx_pre_boot(struct wl1271 *wl) @@ -968,16 +1079,23 @@ static int wl12xx_pre_boot(struct wl1271 *wl) } /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + ret = wlcore_write32(wl, WL12XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + if (ret < 0) + goto out; + udelay(500); - wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + if (ret < 0) + goto out; /* Read-modify-write DRPW_SCRATCH_START register (see next state) to be used by DRPw FW. The RTRIM value will be added by the FW before taking DRPw out of reset */ - clk = wl1271_read32(wl, WL12XX_DRPW_SCRATCH_START); + ret = wlcore_read32(wl, WL12XX_DRPW_SCRATCH_START, &clk); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "clk2 0x%x", clk); @@ -986,12 +1104,18 @@ static int wl12xx_pre_boot(struct wl1271 *wl) else clk |= (priv->ref_clock << 1) << 4; - wl1271_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); + ret = wlcore_write32(wl, WL12XX_DRPW_SCRATCH_START, clk); + if (ret < 0) + goto out; - wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + if (ret < 0) + goto out; /* Disable interrupts */ - wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + if (ret < 0) + goto out; ret = wl1271_boot_soft_reset(wl); if (ret < 0) @@ -1001,47 +1125,72 @@ out: return ret; } -static void wl12xx_pre_upload(struct wl1271 *wl) +static int wl12xx_pre_upload(struct wl1271 *wl) { - u32 tmp, polarity; + u32 tmp; + u16 polarity; + int ret; /* write firmware's last address (ie. it's length) to * ACX_EEPROMLESS_IND_REG */ wl1271_debug(DEBUG_BOOT, "ACX_EEPROMLESS_IND_REG"); - wl1271_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); + ret = wlcore_write32(wl, WL12XX_EEPROMLESS_IND, WL12XX_EEPROMLESS_IND); + if (ret < 0) + goto out; - tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); + ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); /* 6. read the EEPROM parameters */ - tmp = wl1271_read32(wl, WL12XX_SCR_PAD2); + ret = wlcore_read32(wl, WL12XX_SCR_PAD2, &tmp); + if (ret < 0) + goto out; /* WL1271: The reference driver skips steps 7 to 10 (jumps directly * to upload_fw) */ - if (wl->chip.id == CHIP_ID_1283_PG20) - wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); + if (wl->chip.id == CHIP_ID_1283_PG20) { + ret = wl12xx_top_reg_write(wl, SDIO_IO_DS, HCI_IO_DS_6MA); + if (ret < 0) + goto out; + } /* polarity must be set before the firmware is loaded */ - polarity = wl12xx_top_reg_read(wl, OCP_REG_POLARITY); + ret = wl12xx_top_reg_read(wl, OCP_REG_POLARITY, &polarity); + if (ret < 0) + goto out; /* We use HIGH polarity, so unset the LOW bit */ polarity &= ~POLARITY_LOW; - wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); + ret = wl12xx_top_reg_write(wl, OCP_REG_POLARITY, polarity); +out: + return ret; } -static void wl12xx_enable_interrupts(struct wl1271 *wl) +static int wl12xx_enable_interrupts(struct wl1271 *wl) { - wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL12XX_ACX_ALL_EVENTS_VECTOR); + int ret; + + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL12XX_ACX_ALL_EVENTS_VECTOR); + if (ret < 0) + goto out; wlcore_enable_interrupts(wl); - wlcore_write_reg(wl, REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~(WL12XX_INTR_MASK)); + if (ret < 0) + goto out; - wl1271_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); + ret = wlcore_write32(wl, WL12XX_HI_CFG, HI_CFG_DEF_VAL); + +out: + return ret; } static int wl12xx_boot(struct wl1271 *wl) @@ -1056,7 +1205,9 @@ static int wl12xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl12xx_pre_upload(wl); + ret = wl12xx_pre_upload(wl); + if (ret < 0) + goto out; ret = wlcore_boot_upload_firmware(wl); if (ret < 0) @@ -1066,22 +1217,30 @@ static int wl12xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl12xx_enable_interrupts(wl); + ret = wl12xx_enable_interrupts(wl); out: return ret; } -static void wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, +static int wl12xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, void *buf, size_t len) { - wl1271_write(wl, cmd_box_addr, buf, len, false); - wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); + int ret; + + ret = wlcore_write(wl, cmd_box_addr, buf, len, false); + if (ret < 0) + return ret; + + ret = wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_CMD); + + return ret; } -static void wl12xx_ack_event(struct wl1271 *wl) +static int wl12xx_ack_event(struct wl1271 *wl) { - wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL12XX_INTR_TRIG_EVENT_ACK); + return wlcore_write_reg(wl, REG_INTERRUPT_TRIG, + WL12XX_INTR_TRIG_EVENT_ACK); } static u32 wl12xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) @@ -1161,13 +1320,13 @@ static u32 wl12xx_get_rx_packet_len(struct wl1271 *wl, void *rx_data, return data_len - sizeof(*desc) - desc->pad_len; } -static void wl12xx_tx_delayed_compl(struct wl1271 *wl) +static int wl12xx_tx_delayed_compl(struct wl1271 *wl) { if (wl->fw_status_1->tx_results_counter == (wl->tx_results_count & 0xff)) - return; + return 0; - wl1271_tx_complete(wl); + return wlcore_tx_complete(wl); } static int wl12xx_hw_init(struct wl1271 *wl) @@ -1268,39 +1427,58 @@ static bool wl12xx_mac_in_fuse(struct wl1271 *wl) return supported; } -static void wl12xx_get_fuse_mac(struct wl1271 *wl) +static int wl12xx_get_fuse_mac(struct wl1271 *wl) { u32 mac1, mac2; + int ret; - wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DRPW]); + if (ret < 0) + goto out; - mac1 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1); - mac2 = wl1271_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2); + ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_1, &mac1); + if (ret < 0) + goto out; + + ret = wlcore_read32(wl, WL12XX_REG_FUSE_BD_ADDR_2, &mac2); + if (ret < 0) + goto out; /* these are the two parts of the BD_ADDR */ wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + ((mac1 & 0xff000000) >> 24); wl->fuse_nic_addr = mac1 & 0xffffff; - wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + +out: + return ret; } -static s8 wl12xx_get_pg_ver(struct wl1271 *wl) +static int wl12xx_get_pg_ver(struct wl1271 *wl, s8 *ver) { - u32 die_info; + u16 die_info; + int ret; if (wl->chip.id == CHIP_ID_1283_PG20) - die_info = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1); + ret = wl12xx_top_reg_read(wl, WL128X_REG_FUSE_DATA_2_1, + &die_info); else - die_info = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1); + ret = wl12xx_top_reg_read(wl, WL127X_REG_FUSE_DATA_2_1, + &die_info); - return (s8) (die_info & PG_VER_MASK) >> PG_VER_OFFSET; + if (ret >= 0 && ver) + *ver = (s8)((die_info & PG_VER_MASK) >> PG_VER_OFFSET); + + return ret; } -static void wl12xx_get_mac(struct wl1271 *wl) +static int wl12xx_get_mac(struct wl1271 *wl) { if (wl12xx_mac_in_fuse(wl)) - wl12xx_get_fuse_mac(wl); + return wl12xx_get_fuse_mac(wl); + + return 0; } static void wl12xx_set_tx_desc_csum(struct wl1271 *wl, @@ -1448,10 +1626,8 @@ static int __devinit wl12xx_probe(struct platform_device *pdev) wl->hw_min_ht_rate = WL12XX_CONF_HW_RXTX_RATE_MCS0; wl->fw_status_priv_len = 0; wl->stats.fw_stats_len = sizeof(struct wl12xx_acx_statistics); - memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], &wl12xx_ht_cap, - sizeof(wl12xx_ht_cap)); - memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], &wl12xx_ht_cap, - sizeof(wl12xx_ht_cap)); + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl12xx_ht_cap); + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl12xx_ht_cap); wl12xx_conf_init(wl); if (!fref_param) { diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index de1132410876..26990fb4edea 100644 --- a/drivers/net/wireless/ti/wl12xx/wl12xx.h +++ b/drivers/net/wireless/ti/wl12xx/wl12xx.h @@ -24,6 +24,20 @@ #include "conf.h" +/* minimum FW required for driver for wl127x */ +#define WL127X_CHIP_VER 6 +#define WL127X_IFTYPE_VER 3 +#define WL127X_MAJOR_VER 10 +#define WL127X_SUBTYPE_VER 2 +#define WL127X_MINOR_VER 115 + +/* minimum FW required for driver for wl128x */ +#define WL128X_CHIP_VER 7 +#define WL128X_IFTYPE_VER 3 +#define WL128X_MAJOR_VER 10 +#define WL128X_SUBTYPE_VER 2 +#define WL128X_MINOR_VER 115 + struct wl127x_rx_mem_pool_addr { u32 addr; u32 addr_extra; diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h index ebbaf611e97b..e2609a6b7341 100644 --- a/drivers/net/wireless/ti/wl18xx/acx.h +++ b/drivers/net/wireless/ti/wl18xx/acx.h @@ -32,25 +32,21 @@ enum { /* numbers of bits the length field takes (add 1 for the actual number) */ #define WL18XX_HOST_IF_LEN_SIZE_FIELD 15 -#define WL18XX_ACX_EVENTS_VECTOR_PG1 (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_INIT_COMPLETE | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_CMD_COMPLETE | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -#define WL18XX_ACX_EVENTS_VECTOR_PG2 (WL18XX_ACX_EVENTS_VECTOR_PG1 | \ - WL1271_ACX_SW_INTR_WATCHDOG) - -#define WL18XX_INTR_MASK_PG1 (WL1271_ACX_INTR_WATCHDOG | \ - WL1271_ACX_INTR_EVENT_A | \ - WL1271_ACX_INTR_EVENT_B | \ - WL1271_ACX_INTR_HW_AVAILABLE | \ - WL1271_ACX_INTR_DATA) - -#define WL18XX_INTR_MASK_PG2 (WL18XX_INTR_MASK_PG1 | \ - WL1271_ACX_SW_INTR_WATCHDOG) +#define WL18XX_ACX_EVENTS_VECTOR (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_INIT_COMPLETE | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_CMD_COMPLETE | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA | \ + WL1271_ACX_SW_INTR_WATCHDOG) + +#define WL18XX_INTR_MASK (WL1271_ACX_INTR_WATCHDOG | \ + WL1271_ACX_INTR_EVENT_A | \ + WL1271_ACX_INTR_EVENT_B | \ + WL1271_ACX_INTR_HW_AVAILABLE | \ + WL1271_ACX_INTR_DATA | \ + WL1271_ACX_SW_INTR_WATCHDOG) struct wl18xx_acx_host_config_bitmap { struct acx_header header; diff --git a/drivers/net/wireless/ti/wl18xx/io.c b/drivers/net/wireless/ti/wl18xx/io.c index 598c057e722b..0c06ccfd1b8c 100644 --- a/drivers/net/wireless/ti/wl18xx/io.c +++ b/drivers/net/wireless/ti/wl18xx/io.c @@ -24,37 +24,52 @@ #include "io.h" -void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) +int wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val) { u32 tmp; + int ret; if (WARN_ON(addr % 2)) - return; + return -EINVAL; if ((addr % 4) == 0) { - tmp = wl1271_read32(wl, addr); + ret = wlcore_read32(wl, addr, &tmp); + if (ret < 0) + goto out; + tmp = (tmp & 0xffff0000) | val; - wl1271_write32(wl, addr, tmp); + ret = wlcore_write32(wl, addr, tmp); } else { - tmp = wl1271_read32(wl, addr - 2); + ret = wlcore_read32(wl, addr - 2, &tmp); + if (ret < 0) + goto out; + tmp = (tmp & 0xffff) | (val << 16); - wl1271_write32(wl, addr - 2, tmp); + ret = wlcore_write32(wl, addr - 2, tmp); } + +out: + return ret; } -u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr) +int wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out) { u32 val; + int ret; if (WARN_ON(addr % 2)) - return 0; + return -EINVAL; if ((addr % 4) == 0) { /* address is 4-bytes aligned */ - val = wl1271_read32(wl, addr); - return val & 0xffff; + ret = wlcore_read32(wl, addr, &val); + if (ret >= 0 && out) + *out = val & 0xffff; } else { - val = wl1271_read32(wl, addr - 2); - return (val & 0xffff0000) >> 16; + ret = wlcore_read32(wl, addr - 2, &val); + if (ret >= 0 && out) + *out = (val & 0xffff0000) >> 16; } + + return ret; } diff --git a/drivers/net/wireless/ti/wl18xx/io.h b/drivers/net/wireless/ti/wl18xx/io.h index be4e126ff617..c32ae30277df 100644 --- a/drivers/net/wireless/ti/wl18xx/io.h +++ b/drivers/net/wireless/ti/wl18xx/io.h @@ -22,7 +22,7 @@ #ifndef __WL18XX_IO_H__ #define __WL18XX_IO_H__ -void wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val); -u16 wl18xx_top_reg_read(struct wl1271 *wl, int addr); +int __must_check wl18xx_top_reg_write(struct wl1271 *wl, int addr, u16 val); +int __must_check wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out); #endif /* __WL18XX_IO_H__ */ diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index ed9c3650e08a..b378b34c4a6a 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -43,10 +43,11 @@ #define WL18XX_RX_CHECKSUM_MASK 0x40 -static char *ht_mode_param = "wide"; +static char *ht_mode_param = "default"; static char *board_type_param = "hdk"; static bool checksum_param = false; static bool enable_11a_param = true; +static int num_rx_desc_param = -1; /* phy paramters */ static int dc2dc_param = -1; @@ -368,10 +369,11 @@ static struct wlcore_conf wl18xx_conf = { .psm_entry_retries = 8, .psm_exit_retries = 16, .psm_entry_nullfunc_retries = 3, - .dynamic_ps_timeout = 200, + .dynamic_ps_timeout = 1500, .forced_ps = false, .keep_alive_interval = 55000, .max_listen_interval = 20, + .sta_sleep_auth = WL1271_PSM_ILLEGAL, }, .itrim = { .enable = false, @@ -606,24 +608,20 @@ static int wl18xx_identify_chip(struct wl1271 *wl) wl->plt_fw_name = WL18XX_FW_NAME; wl->quirks |= WLCORE_QUIRK_NO_ELP | WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | + WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN | + WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN | WLCORE_QUIRK_TX_PAD_LAST_FRAME; + wlcore_set_min_fw_ver(wl, WL18XX_CHIP_VER, WL18XX_IFTYPE_VER, + WL18XX_MAJOR_VER, WL18XX_SUBTYPE_VER, + WL18XX_MINOR_VER); break; case CHIP_ID_185x_PG10: - wl1271_debug(DEBUG_BOOT, "chip id 0x%x (185x PG10)", - wl->chip.id); - wl->sr_fw_name = WL18XX_FW_NAME; - /* wl18xx uses the same firmware for PLT */ - wl->plt_fw_name = WL18XX_FW_NAME; - wl->quirks |= WLCORE_QUIRK_NO_ELP | - WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED | - WLCORE_QUIRK_RX_BLOCKSIZE_ALIGN | - WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN; - - /* PG 1.0 has some problems with MCS_13, so disable it */ - wl->ht_cap[IEEE80211_BAND_2GHZ].mcs.rx_mask[1] &= ~BIT(5); + wl1271_warning("chip id 0x%x (185x PG10) is deprecated", + wl->chip.id); + ret = -ENODEV; + goto out; - break; default: wl1271_warning("unsupported chip id: 0x%x", wl->chip.id); ret = -ENODEV; @@ -634,123 +632,178 @@ out: return ret; } -static void wl18xx_set_clk(struct wl1271 *wl) +static int wl18xx_set_clk(struct wl1271 *wl) { - u32 clk_freq; + u16 clk_freq; + int ret; - wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + if (ret < 0) + goto out; /* TODO: PG2: apparently we need to read the clk type */ - clk_freq = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT); + ret = wl18xx_top_reg_read(wl, PRIMARY_CLK_DETECT, &clk_freq); + if (ret < 0) + goto out; + wl1271_debug(DEBUG_BOOT, "clock freq %d (%d, %d, %d, %d, %s)", clk_freq, wl18xx_clk_table[clk_freq].n, wl18xx_clk_table[clk_freq].m, wl18xx_clk_table[clk_freq].p, wl18xx_clk_table[clk_freq].q, wl18xx_clk_table[clk_freq].swallow ? "swallow" : "spit"); - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, wl18xx_clk_table[clk_freq].n); - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, wl18xx_clk_table[clk_freq].m); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_N, + wl18xx_clk_table[clk_freq].n); + if (ret < 0) + goto out; + + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_M, + wl18xx_clk_table[clk_freq].m); + if (ret < 0) + goto out; if (wl18xx_clk_table[clk_freq].swallow) { /* first the 16 lower bits */ - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1, - wl18xx_clk_table[clk_freq].q & - PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_1, + wl18xx_clk_table[clk_freq].q & + PLLSH_WCS_PLL_Q_FACTOR_CFG_1_MASK); + if (ret < 0) + goto out; + /* then the 16 higher bits, masked out */ - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2, - (wl18xx_clk_table[clk_freq].q >> 16) & - PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_Q_FACTOR_CFG_2, + (wl18xx_clk_table[clk_freq].q >> 16) & + PLLSH_WCS_PLL_Q_FACTOR_CFG_2_MASK); + if (ret < 0) + goto out; /* first the 16 lower bits */ - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1, - wl18xx_clk_table[clk_freq].p & - PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_1, + wl18xx_clk_table[clk_freq].p & + PLLSH_WCS_PLL_P_FACTOR_CFG_1_MASK); + if (ret < 0) + goto out; + /* then the 16 higher bits, masked out */ - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, - (wl18xx_clk_table[clk_freq].p >> 16) & - PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_P_FACTOR_CFG_2, + (wl18xx_clk_table[clk_freq].p >> 16) & + PLLSH_WCS_PLL_P_FACTOR_CFG_2_MASK); } else { - wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, - PLLSH_WCS_PLL_SWALLOW_EN_VAL2); + ret = wl18xx_top_reg_write(wl, PLLSH_WCS_PLL_SWALLOW_EN, + PLLSH_WCS_PLL_SWALLOW_EN_VAL2); } + +out: + return ret; } -static void wl18xx_boot_soft_reset(struct wl1271 *wl) +static int wl18xx_boot_soft_reset(struct wl1271 *wl) { + int ret; + /* disable Rx/Tx */ - wl1271_write32(wl, WL18XX_ENABLE, 0x0); + ret = wlcore_write32(wl, WL18XX_ENABLE, 0x0); + if (ret < 0) + goto out; /* disable auto calibration on start*/ - wl1271_write32(wl, WL18XX_SPARE_A2, 0xffff); + ret = wlcore_write32(wl, WL18XX_SPARE_A2, 0xffff); + +out: + return ret; } static int wl18xx_pre_boot(struct wl1271 *wl) { - wl18xx_set_clk(wl); + int ret; + + ret = wl18xx_set_clk(wl); + if (ret < 0) + goto out; /* Continue the ELP wake up sequence */ - wl1271_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + ret = wlcore_write32(wl, WL18XX_WELP_ARM_COMMAND, WELP_ARM_COMMAND_VAL); + if (ret < 0) + goto out; + udelay(500); - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + if (ret < 0) + goto out; /* Disable interrupts */ - wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, WL1271_ACX_INTR_ALL); + if (ret < 0) + goto out; - wl18xx_boot_soft_reset(wl); + ret = wl18xx_boot_soft_reset(wl); - return 0; +out: + return ret; } -static void wl18xx_pre_upload(struct wl1271 *wl) +static int wl18xx_pre_upload(struct wl1271 *wl) { u32 tmp; + int ret; - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + if (ret < 0) + goto out; /* TODO: check if this is all needed */ - wl1271_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND); + ret = wlcore_write32(wl, WL18XX_EEPROMLESS_IND, WL18XX_EEPROMLESS_IND); + if (ret < 0) + goto out; - tmp = wlcore_read_reg(wl, REG_CHIP_ID_B); + ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &tmp); + if (ret < 0) + goto out; wl1271_debug(DEBUG_BOOT, "chip id 0x%x", tmp); - tmp = wl1271_read32(wl, WL18XX_SCR_PAD2); + ret = wlcore_read32(wl, WL18XX_SCR_PAD2, &tmp); + +out: + return ret; } -static void wl18xx_set_mac_and_phy(struct wl1271 *wl) +static int wl18xx_set_mac_and_phy(struct wl1271 *wl) { struct wl18xx_priv *priv = wl->priv; - size_t len; + int ret; - /* the parameters struct is smaller for PG1 */ - if (wl->chip.id == CHIP_ID_185x_PG10) - len = offsetof(struct wl18xx_mac_and_phy_params, psat) + 1; - else - len = sizeof(struct wl18xx_mac_and_phy_params); + ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); + if (ret < 0) + goto out; - wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); - wl1271_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, len, - false); + ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, + sizeof(struct wl18xx_mac_and_phy_params), false); + +out: + return ret; } -static void wl18xx_enable_interrupts(struct wl1271 *wl) +static int wl18xx_enable_interrupts(struct wl1271 *wl) { u32 event_mask, intr_mask; + int ret; - if (wl->chip.id == CHIP_ID_185x_PG10) { - event_mask = WL18XX_ACX_EVENTS_VECTOR_PG1; - intr_mask = WL18XX_INTR_MASK_PG1; - } else { - event_mask = WL18XX_ACX_EVENTS_VECTOR_PG2; - intr_mask = WL18XX_INTR_MASK_PG2; - } + event_mask = WL18XX_ACX_EVENTS_VECTOR; + intr_mask = WL18XX_INTR_MASK; - wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask); + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, event_mask); + if (ret < 0) + goto out; wlcore_enable_interrupts(wl); - wlcore_write_reg(wl, REG_INTERRUPT_MASK, - WL1271_ACX_INTR_ALL & ~intr_mask); + + ret = wlcore_write_reg(wl, REG_INTERRUPT_MASK, + WL1271_ACX_INTR_ALL & ~intr_mask); + +out: + return ret; } static int wl18xx_boot(struct wl1271 *wl) @@ -761,25 +814,29 @@ static int wl18xx_boot(struct wl1271 *wl) if (ret < 0) goto out; - wl18xx_pre_upload(wl); + ret = wl18xx_pre_upload(wl); + if (ret < 0) + goto out; ret = wlcore_boot_upload_firmware(wl); if (ret < 0) goto out; - wl18xx_set_mac_and_phy(wl); + ret = wl18xx_set_mac_and_phy(wl); + if (ret < 0) + goto out; ret = wlcore_boot_run_firmware(wl); if (ret < 0) goto out; - wl18xx_enable_interrupts(wl); + ret = wl18xx_enable_interrupts(wl); out: return ret; } -static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, +static int wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, void *buf, size_t len) { struct wl18xx_priv *priv = wl->priv; @@ -787,13 +844,14 @@ static void wl18xx_trigger_cmd(struct wl1271 *wl, int cmd_box_addr, memcpy(priv->cmd_buf, buf, len); memset(priv->cmd_buf + len, 0, WL18XX_CMD_MAX_SIZE - len); - wl1271_write(wl, cmd_box_addr, priv->cmd_buf, WL18XX_CMD_MAX_SIZE, - false); + return wlcore_write(wl, cmd_box_addr, priv->cmd_buf, + WL18XX_CMD_MAX_SIZE, false); } -static void wl18xx_ack_event(struct wl1271 *wl) +static int wl18xx_ack_event(struct wl1271 *wl) { - wlcore_write_reg(wl, REG_INTERRUPT_TRIG, WL18XX_INTR_TRIG_EVENT_ACK); + return wlcore_write_reg(wl, REG_INTERRUPT_TRIG, + WL18XX_INTR_TRIG_EVENT_ACK); } static u32 wl18xx_calc_tx_blocks(struct wl1271 *wl, u32 len, u32 spare_blks) @@ -967,42 +1025,50 @@ static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - if ((wlvif->channel_type == NL80211_CHAN_HT40MINUS || - wlvif->channel_type == NL80211_CHAN_HT40PLUS) && - !strcmp(ht_mode_param, "wide")) { + struct wl18xx_priv *priv = wl->priv; + + if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || + wlvif->channel_type == NL80211_CHAN_HT40PLUS) { wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); + + /* sanity check - we don't support this */ + if (WARN_ON(wlvif->band != IEEE80211_BAND_5GHZ)) + return 0; + return CONF_TX_RATE_USE_WIDE_CHAN; - } else if (!strcmp(ht_mode_param, "mimo")) { + } else if (priv->conf.phy.number_of_assembled_ant2_4 >= 2 && + wlvif->band == IEEE80211_BAND_2GHZ) { wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); - /* - * PG 1.0 has some problems with MCS_13, so disable it - * - * TODO: instead of hacking this in here, we should - * make it more general and change a bit in the - * wlvif->rate_set instead. + * we don't care about HT channel here - if a peer doesn't + * support MIMO, we won't enable it in its rates */ - if (wl->chip.id == CHIP_ID_185x_PG10) - return CONF_TX_MIMO_RATES & ~CONF_HW_BIT_RATE_MCS_13; - return CONF_TX_MIMO_RATES; } else { return 0; } } -static s8 wl18xx_get_pg_ver(struct wl1271 *wl) +static int wl18xx_get_pg_ver(struct wl1271 *wl, s8 *ver) { u32 fuse; + int ret; - wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + if (ret < 0) + goto out; - fuse = wl1271_read32(wl, WL18XX_REG_FUSE_DATA_1_3); - fuse = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; + ret = wlcore_read32(wl, WL18XX_REG_FUSE_DATA_1_3, &fuse); + if (ret < 0) + goto out; + + if (ver) + *ver = (fuse & WL18XX_PG_VER_MASK) >> WL18XX_PG_VER_OFFSET; - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); - return (s8)fuse; +out: + return ret; } #define WL18XX_CONF_FILE_NAME "ti-connectivity/wl18xx-conf.bin" @@ -1021,8 +1087,7 @@ static int wl18xx_conf_init(struct wl1271 *wl, struct device *dev) } if (fw->size != WL18XX_CONF_SIZE) { - wl1271_error("configuration binary file size is wrong, " - "expected %ld got %zd", + wl1271_error("configuration binary file size is wrong, expected %zu got %zu", WL18XX_CONF_SIZE, fw->size); ret = -EINVAL; goto out; @@ -1069,26 +1134,41 @@ out: static int wl18xx_plt_init(struct wl1271 *wl) { - wl1271_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); + int ret; + + ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); + if (ret < 0) + return ret; return wl->ops->boot(wl); } -static void wl18xx_get_mac(struct wl1271 *wl) +static int wl18xx_get_mac(struct wl1271 *wl) { u32 mac1, mac2; + int ret; - wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_TOP_PRCM_ELP_SOC]); + if (ret < 0) + goto out; - mac1 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1); - mac2 = wl1271_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2); + ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_1, &mac1); + if (ret < 0) + goto out; + + ret = wlcore_read32(wl, WL18XX_REG_FUSE_BD_ADDR_2, &mac2); + if (ret < 0) + goto out; /* these are the two parts of the BD_ADDR */ wl->fuse_oui_addr = ((mac2 & 0xffff) << 8) + ((mac1 & 0xff000000) >> 24); wl->fuse_nic_addr = (mac1 & 0xffffff); - wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_DOWN]); + +out: + return ret; } static int wl18xx_handle_static_data(struct wl1271 *wl, @@ -1214,8 +1294,8 @@ static struct wlcore_ops wl18xx_ops = { .pre_pkt_send = wl18xx_pre_pkt_send, }; -/* HT cap appropriate for wide channels */ -static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = { +/* HT cap appropriate for wide channels in 2Ghz */ +static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_2ghz = { .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_DSSSCCK40, .ht_supported = true, @@ -1228,40 +1308,42 @@ static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap = { }, }; -/* HT cap appropriate for SISO 20 */ -static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { - .cap = IEEE80211_HT_CAP_SGI_20, +/* HT cap appropriate for wide channels in 5Ghz */ +static struct ieee80211_sta_ht_cap wl18xx_siso40_ht_cap_5ghz = { + .cap = IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_SUP_WIDTH_20_40, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .mcs = { .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - .rx_highest = cpu_to_le16(72), + .rx_highest = cpu_to_le16(150), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }; -/* HT cap appropriate for MIMO rates in 20mhz channel */ -static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { +/* HT cap appropriate for SISO 20 */ +static struct ieee80211_sta_ht_cap wl18xx_siso20_ht_cap = { .cap = IEEE80211_HT_CAP_SGI_20, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .mcs = { - .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, }, - .rx_highest = cpu_to_le16(144), + .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(72), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }; -static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_5ghz = { +/* HT cap appropriate for MIMO rates in 20mhz channel */ +static struct ieee80211_sta_ht_cap wl18xx_mimo_ht_cap_2ghz = { .cap = IEEE80211_HT_CAP_SGI_20, .ht_supported = true, .ampdu_factor = IEEE80211_HT_MAX_AMPDU_16K, .ampdu_density = IEEE80211_HT_MPDU_DENSITY_16, .mcs = { - .rx_mask = { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, }, - .rx_highest = cpu_to_le16(72), + .rx_mask = { 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, }, + .rx_highest = cpu_to_le16(144), .tx_params = IEEE80211_HT_MCS_TX_DEFINED, }, }; @@ -1286,7 +1368,7 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) wl->ptable = wl18xx_ptable; wl->rtable = wl18xx_rtable; wl->num_tx_desc = 32; - wl->num_rx_desc = 16; + wl->num_rx_desc = 32; wl->band_rate_to_idx = wl18xx_band_rate_to_idx; wl->hw_tx_rate_tbl_size = WL18XX_CONF_HW_RXTX_RATE_MAX; wl->hw_min_ht_rate = WL18XX_CONF_HW_RXTX_RATE_MCS0; @@ -1294,32 +1376,8 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) wl->stats.fw_stats_len = sizeof(struct wl18xx_acx_statistics); wl->static_data_priv_len = sizeof(struct wl18xx_static_data_priv); - if (!strcmp(ht_mode_param, "wide")) { - memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], - &wl18xx_siso40_ht_cap, - sizeof(wl18xx_siso40_ht_cap)); - memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], - &wl18xx_siso40_ht_cap, - sizeof(wl18xx_siso40_ht_cap)); - } else if (!strcmp(ht_mode_param, "mimo")) { - memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], - &wl18xx_mimo_ht_cap_2ghz, - sizeof(wl18xx_mimo_ht_cap_2ghz)); - memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], - &wl18xx_mimo_ht_cap_5ghz, - sizeof(wl18xx_mimo_ht_cap_5ghz)); - } else if (!strcmp(ht_mode_param, "siso20")) { - memcpy(&wl->ht_cap[IEEE80211_BAND_2GHZ], - &wl18xx_siso20_ht_cap, - sizeof(wl18xx_siso20_ht_cap)); - memcpy(&wl->ht_cap[IEEE80211_BAND_5GHZ], - &wl18xx_siso20_ht_cap, - sizeof(wl18xx_siso20_ht_cap)); - } else { - wl1271_error("invalid ht_mode '%s'", ht_mode_param); - ret = -EINVAL; - goto out_free; - } + if (num_rx_desc_param != -1) + wl->num_rx_desc = num_rx_desc_param; ret = wl18xx_conf_init(wl, &pdev->dev); if (ret < 0) @@ -1366,6 +1424,37 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) if (dc2dc_param != -1) priv->conf.phy.external_pa_dc2dc = dc2dc_param; + if (!strcmp(ht_mode_param, "default")) { + /* + * Only support mimo with multiple antennas. Fall back to + * siso20. + */ + if (priv->conf.phy.number_of_assembled_ant2_4 >= 2) + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, + &wl18xx_mimo_ht_cap_2ghz); + else + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, + &wl18xx_siso20_ht_cap); + + /* 5Ghz is always wide */ + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, + &wl18xx_siso40_ht_cap_5ghz); + } else if (!strcmp(ht_mode_param, "wide")) { + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, + &wl18xx_siso40_ht_cap_2ghz); + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, + &wl18xx_siso40_ht_cap_5ghz); + } else if (!strcmp(ht_mode_param, "siso20")) { + wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, + &wl18xx_siso20_ht_cap); + wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, + &wl18xx_siso20_ht_cap); + } else { + wl1271_error("invalid ht_mode '%s'", ht_mode_param); + ret = -EINVAL; + goto out_free; + } + if (!checksum_param) { wl18xx_ops.set_rx_csum = NULL; wl18xx_ops.init_vif = NULL; @@ -1410,7 +1499,7 @@ static void __exit wl18xx_exit(void) module_exit(wl18xx_exit); module_param_named(ht_mode, ht_mode_param, charp, S_IRUSR); -MODULE_PARM_DESC(ht_mode, "Force HT mode: wide (default), mimo or siso20"); +MODULE_PARM_DESC(ht_mode, "Force HT mode: wide or siso20"); module_param_named(board_type, board_type_param, charp, S_IRUSR); MODULE_PARM_DESC(board_type, "Board type: fpga, hdk (default), evb, com8 or " @@ -1458,6 +1547,11 @@ module_param_named(pwr_limit_reference_11_abg, MODULE_PARM_DESC(pwr_limit_reference_11_abg, "Power limit reference: u8 " "(default is 0xc8)"); +module_param_named(num_rx_desc, + num_rx_desc_param, int, S_IRUSR); +MODULE_PARM_DESC(num_rx_desc_param, + "Number of Rx descriptors: u8 (default is 32)"); + MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_FIRMWARE(WL18XX_FW_NAME); diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index bc67a4750615..6452396fa1d4 100644 --- a/drivers/net/wireless/ti/wl18xx/wl18xx.h +++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h @@ -24,6 +24,13 @@ #include "conf.h" +/* minimum FW required for driver */ +#define WL18XX_CHIP_VER 8 +#define WL18XX_IFTYPE_VER 2 +#define WL18XX_MAJOR_VER 0 +#define WL18XX_SUBTYPE_VER 0 +#define WL18XX_MINOR_VER 100 + #define WL18XX_CMD_MAX_SIZE 740 struct wl18xx_priv { diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index 54156b0b5c2d..d7b907e67170 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig @@ -1,7 +1,6 @@ config WLCORE tristate "TI wlcore support" depends on WL_TI && GENERIC_HARDIRQS && MAC80211 - depends on INET select FW_LOADER ---help--- This module contains the main code for TI WLAN chips. It abstracts diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index b9ec42c83757..ce108a736bd0 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -70,7 +70,7 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) struct acx_sleep_auth *auth; int ret; - wl1271_debug(DEBUG_ACX, "acx sleep auth"); + wl1271_debug(DEBUG_ACX, "acx sleep auth %d", sleep_auth); auth = kzalloc(sizeof(*auth), GFP_KERNEL); if (!auth) { @@ -81,7 +81,13 @@ int wl1271_acx_sleep_auth(struct wl1271 *wl, u8 sleep_auth) auth->sleep_auth = sleep_auth; ret = wl1271_cmd_configure(wl, ACX_SLEEP_AUTH, auth, sizeof(*auth)); + if (ret < 0) { + wl1271_error("could not configure sleep_auth to %d: %d", + sleep_auth, ret); + goto out; + } + wl->sleep_auth = sleep_auth; out: kfree(auth); return ret; diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index c0181258b722..d03215d6b3bd 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h @@ -118,6 +118,11 @@ enum wl1271_psm_mode { /* Extreme low power */ WL1271_PSM_ELP = 2, + + WL1271_PSM_MAX = WL1271_PSM_ELP, + + /* illegal out of band value of PSM mode */ + WL1271_PSM_ILLEGAL = 0xff }; struct acx_sleep_auth { diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 0fda500c01c9..375ea574eafb 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c @@ -33,16 +33,22 @@ #include "rx.h" #include "hw_ops.h" -static void wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) +static int wl1271_boot_set_ecpu_ctrl(struct wl1271 *wl, u32 flag) { u32 cpu_ctrl; + int ret; /* 10.5.0 run the firmware (I) */ - cpu_ctrl = wlcore_read_reg(wl, REG_ECPU_CONTROL); + ret = wlcore_read_reg(wl, REG_ECPU_CONTROL, &cpu_ctrl); + if (ret < 0) + goto out; /* 10.5.1 run the firmware (II) */ cpu_ctrl |= flag; - wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); + ret = wlcore_write_reg(wl, REG_ECPU_CONTROL, cpu_ctrl); + +out: + return ret; } static int wlcore_boot_parse_fw_ver(struct wl1271 *wl, @@ -75,6 +81,53 @@ out: return ret; } +static int wlcore_validate_fw_ver(struct wl1271 *wl) +{ + unsigned int *fw_ver = wl->chip.fw_ver; + unsigned int *min_ver = wl->min_fw_ver; + + /* the chip must be exactly equal */ + if (min_ver[FW_VER_CHIP] != fw_ver[FW_VER_CHIP]) + goto fail; + + /* always check the next digit if all previous ones are equal */ + + if (min_ver[FW_VER_IF_TYPE] < fw_ver[FW_VER_IF_TYPE]) + goto out; + else if (min_ver[FW_VER_IF_TYPE] > fw_ver[FW_VER_IF_TYPE]) + goto fail; + + if (min_ver[FW_VER_MAJOR] < fw_ver[FW_VER_MAJOR]) + goto out; + else if (min_ver[FW_VER_MAJOR] > fw_ver[FW_VER_MAJOR]) + goto fail; + + if (min_ver[FW_VER_SUBTYPE] < fw_ver[FW_VER_SUBTYPE]) + goto out; + else if (min_ver[FW_VER_SUBTYPE] > fw_ver[FW_VER_SUBTYPE]) + goto fail; + + if (min_ver[FW_VER_MINOR] < fw_ver[FW_VER_MINOR]) + goto out; + else if (min_ver[FW_VER_MINOR] > fw_ver[FW_VER_MINOR]) + goto fail; + +out: + return 0; + +fail: + wl1271_error("Your WiFi FW version (%u.%u.%u.%u.%u) is outdated.\n" + "Please use at least FW %u.%u.%u.%u.%u.\n" + "You can get more information at:\n" + "http://wireless.kernel.org/en/users/Drivers/wl12xx", + fw_ver[FW_VER_CHIP], fw_ver[FW_VER_IF_TYPE], + fw_ver[FW_VER_MAJOR], fw_ver[FW_VER_SUBTYPE], + fw_ver[FW_VER_MINOR], min_ver[FW_VER_CHIP], + min_ver[FW_VER_IF_TYPE], min_ver[FW_VER_MAJOR], + min_ver[FW_VER_SUBTYPE], min_ver[FW_VER_MINOR]); + return -EINVAL; +} + static int wlcore_boot_static_data(struct wl1271 *wl) { struct wl1271_static_data *static_data; @@ -87,12 +140,18 @@ static int wlcore_boot_static_data(struct wl1271 *wl) goto out; } - wl1271_read(wl, wl->cmd_box_addr, static_data, len, false); + ret = wlcore_read(wl, wl->cmd_box_addr, static_data, len, false); + if (ret < 0) + goto out_free; ret = wlcore_boot_parse_fw_ver(wl, static_data); if (ret < 0) goto out_free; + ret = wlcore_validate_fw_ver(wl); + if (ret < 0) + goto out_free; + ret = wlcore_handle_static_data(wl, static_data); if (ret < 0) goto out_free; @@ -109,6 +168,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, struct wlcore_partition_set partition; int addr, chunk_num, partition_limit; u8 *p, *chunk; + int ret; /* whal_FwCtrl_LoadFwImageSm() */ @@ -130,7 +190,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(&partition, &wl->ptable[PART_DOWN], sizeof(partition)); partition.mem.start = dest; - wlcore_set_partition(wl, &partition); + ret = wlcore_set_partition(wl, &partition); + if (ret < 0) + goto out; /* 10.1 set partition limit and chunk num */ chunk_num = 0; @@ -144,7 +206,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, partition_limit = chunk_num * CHUNK_SIZE + wl->ptable[PART_DOWN].mem.size; partition.mem.start = addr; - wlcore_set_partition(wl, &partition); + ret = wlcore_set_partition(wl, &partition); + if (ret < 0) + goto out; } /* 10.3 upload the chunk */ @@ -153,7 +217,9 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw chunk 0x%p to 0x%x", p, addr); - wl1271_write(wl, addr, chunk, CHUNK_SIZE, false); + ret = wlcore_write(wl, addr, chunk, CHUNK_SIZE, false); + if (ret < 0) + goto out; chunk_num++; } @@ -164,10 +230,11 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, memcpy(chunk, p, fw_data_len % CHUNK_SIZE); wl1271_debug(DEBUG_BOOT, "uploading fw last chunk (%zd B) 0x%p to 0x%x", fw_data_len % CHUNK_SIZE, p, addr); - wl1271_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); + ret = wlcore_write(wl, addr, chunk, fw_data_len % CHUNK_SIZE, false); +out: kfree(chunk); - return 0; + return ret; } int wlcore_boot_upload_firmware(struct wl1271 *wl) @@ -210,6 +277,7 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) int i; u32 dest_addr, val; u8 *nvs_ptr, *nvs_aligned; + int ret; if (wl->nvs == NULL) { wl1271_error("NVS file is needed during boot"); @@ -307,7 +375,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) wl1271_debug(DEBUG_BOOT, "nvs burst write 0x%x: 0x%x", dest_addr, val); - wl1271_write32(wl, dest_addr, val); + ret = wlcore_write32(wl, dest_addr, val); + if (ret < 0) + return ret; nvs_ptr += 4; dest_addr += 4; @@ -333,7 +403,9 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) nvs_len -= nvs_ptr - (u8 *)wl->nvs; /* Now we must set the partition correctly */ - wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + if (ret < 0) + return ret; /* Copy the NVS tables to a new block to ensure alignment */ nvs_aligned = kmemdup(nvs_ptr, nvs_len, GFP_KERNEL); @@ -341,11 +413,11 @@ int wlcore_boot_upload_nvs(struct wl1271 *wl) return -ENOMEM; /* And finally we upload the NVS tables */ - wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, - nvs_aligned, nvs_len, false); + ret = wlcore_write_data(wl, REG_CMD_MBOX_ADDRESS, nvs_aligned, nvs_len, + false); kfree(nvs_aligned); - return 0; + return ret; out_badnvs: wl1271_error("nvs data is malformed"); @@ -359,11 +431,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) u32 chip_id, intr; /* Make sure we have the boot partition */ - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + if (ret < 0) + return ret; - wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + ret = wl1271_boot_set_ecpu_ctrl(wl, ECPU_CONTROL_HALT); + if (ret < 0) + return ret; - chip_id = wlcore_read_reg(wl, REG_CHIP_ID_B); + ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &chip_id); + if (ret < 0) + return ret; wl1271_debug(DEBUG_BOOT, "chip id after firmware boot: 0x%x", chip_id); @@ -376,7 +454,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) loop = 0; while (loop++ < INIT_LOOP) { udelay(INIT_LOOP_DELAY); - intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); + if (ret < 0) + return ret; if (intr == 0xffffffff) { wl1271_error("error reading hardware complete " @@ -385,8 +465,10 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) } /* check that ACX_INTR_INIT_COMPLETE is enabled */ else if (intr & WL1271_ACX_INTR_INIT_COMPLETE) { - wlcore_write_reg(wl, REG_INTERRUPT_ACK, - WL1271_ACX_INTR_INIT_COMPLETE); + ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, + WL1271_ACX_INTR_INIT_COMPLETE); + if (ret < 0) + return ret; break; } } @@ -398,12 +480,17 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) } /* get hardware config command mail box */ - wl->cmd_box_addr = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR); + ret = wlcore_read_reg(wl, REG_COMMAND_MAILBOX_PTR, &wl->cmd_box_addr); + if (ret < 0) + return ret; wl1271_debug(DEBUG_MAILBOX, "cmd_box_addr 0x%x", wl->cmd_box_addr); /* get hardware config event mail box */ - wl->mbox_ptr[0] = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR); + ret = wlcore_read_reg(wl, REG_EVENT_MAILBOX_PTR, &wl->mbox_ptr[0]); + if (ret < 0) + return ret; + wl->mbox_ptr[1] = wl->mbox_ptr[0] + sizeof(struct event_mailbox); wl1271_debug(DEBUG_MAILBOX, "MBOX ptrs: 0x%x 0x%x", @@ -445,9 +532,9 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) } /* set the working partition to its "running" mode offset */ - wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_WORK]); /* firmware startup completed */ - return 0; + return ret; } EXPORT_SYMBOL_GPL(wlcore_boot_run_firmware); diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 885364ca4344..a23949cdaebc 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -39,6 +39,7 @@ #include "hw_ops.h" #define WL1271_CMD_FAST_POLL_COUNT 50 +#define WL1271_WAIT_EVENT_FAST_POLL_COUNT 20 /* * send command to firmware @@ -65,17 +66,24 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, WARN_ON(len % 4 != 0); WARN_ON(test_bit(WL1271_FLAG_IN_ELP, &wl->flags)); - wl1271_write(wl, wl->cmd_box_addr, buf, len, false); + ret = wlcore_write(wl, wl->cmd_box_addr, buf, len, false); + if (ret < 0) + goto fail; /* * TODO: we just need this because one bit is in a different * place. Is there any better way? */ - wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); + ret = wl->ops->trigger_cmd(wl, wl->cmd_box_addr, buf, len); + if (ret < 0) + goto fail; timeout = jiffies + msecs_to_jiffies(WL1271_COMMAND_TIMEOUT); - intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); + if (ret < 0) + goto fail; + while (!(intr & WL1271_ACX_INTR_CMD_COMPLETE)) { if (time_after(jiffies, timeout)) { wl1271_error("command complete timeout"); @@ -89,13 +97,18 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, else msleep(1); - intr = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR); + ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &intr); + if (ret < 0) + goto fail; } /* read back the status code of the command */ if (res_len == 0) res_len = sizeof(struct wl1271_cmd_header); - wl1271_read(wl, wl->cmd_box_addr, cmd, res_len, false); + + ret = wlcore_read(wl, wl->cmd_box_addr, cmd, res_len, false); + if (ret < 0) + goto fail; status = le16_to_cpu(cmd->status); if (status != CMD_STATUS_SUCCESS) { @@ -104,11 +117,14 @@ int wl1271_cmd_send(struct wl1271 *wl, u16 id, void *buf, size_t len, goto fail; } - wlcore_write_reg(wl, REG_INTERRUPT_ACK, WL1271_ACX_INTR_CMD_COMPLETE); + ret = wlcore_write_reg(wl, REG_INTERRUPT_ACK, + WL1271_ACX_INTR_CMD_COMPLETE); + if (ret < 0) + goto fail; + return 0; fail: - WARN_ON(1); wl12xx_queue_recovery_work(wl); return ret; } @@ -117,35 +133,50 @@ fail: * Poll the mailbox event field until any of the bits in the mask is set or a * timeout occurs (WL1271_EVENT_TIMEOUT in msecs) */ -static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) +static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, + u32 mask, bool *timeout) { u32 *events_vector; u32 event; - unsigned long timeout; + unsigned long timeout_time; + u16 poll_count = 0; int ret = 0; + *timeout = false; + events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA); if (!events_vector) return -ENOMEM; - timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); + timeout_time = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); do { - if (time_after(jiffies, timeout)) { + if (time_after(jiffies, timeout_time)) { wl1271_debug(DEBUG_CMD, "timeout waiting for event %d", (int)mask); - ret = -ETIMEDOUT; + *timeout = true; goto out; } - msleep(1); + poll_count++; + if (poll_count < WL1271_WAIT_EVENT_FAST_POLL_COUNT) + usleep_range(50, 51); + else + usleep_range(1000, 5000); /* read from both event fields */ - wl1271_read(wl, wl->mbox_ptr[0], events_vector, - sizeof(*events_vector), false); + ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector, + sizeof(*events_vector), false); + if (ret < 0) + goto out; + event = *events_vector & mask; - wl1271_read(wl, wl->mbox_ptr[1], events_vector, - sizeof(*events_vector), false); + + ret = wlcore_read(wl, wl->mbox_ptr[1], events_vector, + sizeof(*events_vector), false); + if (ret < 0) + goto out; + event |= *events_vector & mask; } while (!event); @@ -157,9 +188,10 @@ out: static int wl1271_cmd_wait_for_event(struct wl1271 *wl, u32 mask) { int ret; + bool timeout = false; - ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask); - if (ret != 0) { + ret = wl1271_cmd_wait_for_event_or_timeout(wl, mask, &timeout); + if (ret != 0 || timeout) { wl12xx_queue_recovery_work(wl); return ret; } @@ -981,12 +1013,14 @@ out: int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len) + const u8 *ie, size_t ie_len, bool sched_scan) { struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); struct sk_buff *skb; int ret; u32 rate; + u16 template_id_2_4 = CMD_TEMPL_CFG_PROBE_REQ_2_4; + u16 template_id_5 = CMD_TEMPL_CFG_PROBE_REQ_5; skb = ieee80211_probereq_get(wl->hw, vif, ssid, ssid_len, ie, ie_len); @@ -997,14 +1031,20 @@ int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len); + if (!sched_scan && + (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL)) { + template_id_2_4 = CMD_TEMPL_APP_PROBE_REQ_2_4; + template_id_5 = CMD_TEMPL_APP_PROBE_REQ_5; + } + rate = wl1271_tx_min_rate_get(wl, wlvif->bitrate_masks[band]); if (band == IEEE80211_BAND_2GHZ) ret = wl1271_cmd_template_set(wl, role_id, - CMD_TEMPL_CFG_PROBE_REQ_2_4, + template_id_2_4, skb->data, skb->len, 0, rate); else ret = wl1271_cmd_template_set(wl, role_id, - CMD_TEMPL_CFG_PROBE_REQ_5, + template_id_5, skb->data, skb->len, 0, rate); out: @@ -1412,6 +1452,7 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) { struct wl12xx_cmd_remove_peer *cmd; int ret; + bool timeout = false; wl1271_debug(DEBUG_CMD, "cmd remove peer %d", (int)hlid); @@ -1432,12 +1473,16 @@ int wl12xx_cmd_remove_peer(struct wl1271 *wl, u8 hlid) goto out_free; } + ret = wl1271_cmd_wait_for_event_or_timeout(wl, + PEER_REMOVE_COMPLETE_EVENT_ID, + &timeout); /* * We are ok with a timeout here. The event is sometimes not sent - * due to a firmware bug. + * due to a firmware bug. In case of another error (like SDIO timeout) + * queue a recovery. */ - wl1271_cmd_wait_for_event_or_timeout(wl, - PEER_REMOVE_COMPLETE_EVENT_ID); + if (ret) + wl12xx_queue_recovery_work(wl); out_free: kfree(cmd); @@ -1754,7 +1799,9 @@ int wl12xx_stop_dev(struct wl1271 *wl, struct wl12xx_vif *wlvif) return -EINVAL; /* flush all pending packets */ - wl1271_tx_work_locked(wl); + ret = wlcore_tx_work_locked(wl); + if (ret < 0) + goto out; if (test_bit(wlvif->dev_role_id, wl->roc_map)) { ret = wl12xx_croc(wl, wlvif->dev_role_id); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index 85171f2bf68e..d7d9f801e506 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -58,7 +58,7 @@ int wl1271_cmd_build_ps_poll(struct wl1271 *wl, struct wl12xx_vif *wlvif, int wl12xx_cmd_build_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, u8 band, const u8 *ssid, size_t ssid_len, - const u8 *ie, size_t ie_len); + const u8 *ie, size_t ie_len, bool sched_scan); struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl, struct wl12xx_vif *wlvif, struct sk_buff *skb); @@ -172,8 +172,8 @@ enum cmd_templ { CMD_TEMPL_PS_POLL, CMD_TEMPL_KLV, CMD_TEMPL_DISCONNECT, - CMD_TEMPL_PROBE_REQ_2_4, /* for firmware internal use only */ - CMD_TEMPL_PROBE_REQ_5, /* for firmware internal use only */ + CMD_TEMPL_APP_PROBE_REQ_2_4, + CMD_TEMPL_APP_PROBE_REQ_5, CMD_TEMPL_BAR, /* for firmware internal use only */ CMD_TEMPL_CTS, /* * For CTS-to-self (FastCTS) mechanism @@ -652,4 +652,25 @@ struct wl12xx_cmd_stop_channel_switch { struct wl1271_cmd_header header; } __packed; +/* Used to check radio status after calibration */ +#define MAX_TLV_LENGTH 500 +#define TEST_CMD_P2G_CAL 2 /* TX BiP */ + +struct wl1271_cmd_cal_p2g { + struct wl1271_cmd_header header; + + struct wl1271_cmd_test_header test; + + __le32 ver; + __le16 len; + u8 buf[MAX_TLV_LENGTH]; + u8 type; + u8 padding; + + __le16 radio_status; + + u8 sub_band_mask; + u8 padding2; +} __packed; + #endif /* __WL1271_CMD_H__ */ diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h index 03c635872335..d77224f2ac6b 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -951,6 +951,12 @@ struct conf_conn_settings { * Range: u16 */ u8 max_listen_interval; + + /* + * Default sleep authorization for a new STA interface. This determines + * whether we can go to ELP. + */ + u8 sta_sleep_auth; } __packed; enum { @@ -1276,7 +1282,7 @@ struct conf_hangover_settings { * version, the two LSB are the lower driver's private conf * version. */ -#define WLCORE_CONF_VERSION (0x0001 << 16) +#define WLCORE_CONF_VERSION (0x0002 << 16) #define WLCORE_CONF_MASK 0xffff0000 #define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \ sizeof(struct wlcore_conf)) diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c index 689a847005c9..80dbc5304fac 100644 --- a/drivers/net/wireless/ti/wlcore/debugfs.c +++ b/drivers/net/wireless/ti/wlcore/debugfs.c @@ -38,6 +38,8 @@ /* ms */ #define WL1271_DEBUGFS_STATS_LIFETIME 1000 +#define WLCORE_MAX_BLOCK_SIZE ((size_t)(4*PAGE_SIZE)) + /* debugfs macros idea from mac80211 */ int wl1271_format_buffer(char __user *userbuf, size_t count, loff_t *ppos, char *fmt, ...) @@ -963,6 +965,257 @@ static const struct file_operations fw_stats_raw_ops = { .llseek = default_llseek, }; +static ssize_t sleep_auth_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + + return wl1271_format_buffer(user_buf, count, + ppos, "%d\n", + wl->sleep_auth); +} + +static ssize_t sleep_auth_write(struct file *file, + const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + unsigned long value; + int ret; + + ret = kstrtoul_from_user(user_buf, count, 0, &value); + if (ret < 0) { + wl1271_warning("illegal value in sleep_auth"); + return -EINVAL; + } + + if (value < 0 || value > WL1271_PSM_MAX) { + wl1271_warning("sleep_auth must be between 0 and %d", + WL1271_PSM_MAX); + return -ERANGE; + } + + mutex_lock(&wl->mutex); + + wl->conf.conn.sta_sleep_auth = value; + + if (wl->state == WL1271_STATE_OFF) { + /* this will show up on "read" in case we are off */ + wl->sleep_auth = value; + goto out; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto out; + + ret = wl1271_acx_sleep_auth(wl, value); + if (ret < 0) + goto out_sleep; + +out_sleep: + wl1271_ps_elp_sleep(wl); +out: + mutex_unlock(&wl->mutex); + return count; +} + +static const struct file_operations sleep_auth_ops = { + .read = sleep_auth_read, + .write = sleep_auth_write, + .open = simple_open, + .llseek = default_llseek, +}; + +static ssize_t dev_mem_read(struct file *file, + char __user *user_buf, size_t count, + loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + struct wlcore_partition_set part, old_part; + size_t bytes = count; + int ret; + char *buf; + + /* only requests of dword-aligned size and offset are supported */ + if (bytes % 4) + return -EINVAL; + + if (*ppos % 4) + return -EINVAL; + + /* function should return in reasonable time */ + bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE); + + if (bytes == 0) + return -EINVAL; + + memset(&part, 0, sizeof(part)); + part.mem.start = file->f_pos; + part.mem.size = bytes; + + buf = kmalloc(bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + ret = -EFAULT; + goto skip_read; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto skip_read; + + /* store current partition and switch partition */ + memcpy(&old_part, &wl->curr_part, sizeof(old_part)); + ret = wlcore_set_partition(wl, &part); + if (ret < 0) + goto part_err; + + ret = wlcore_raw_read(wl, 0, buf, bytes, false); + if (ret < 0) + goto read_err; + +read_err: + /* recover partition */ + ret = wlcore_set_partition(wl, &old_part); + if (ret < 0) + goto part_err; + +part_err: + wl1271_ps_elp_sleep(wl); + +skip_read: + mutex_unlock(&wl->mutex); + + if (ret == 0) { + ret = copy_to_user(user_buf, buf, bytes); + if (ret < bytes) { + bytes -= ret; + *ppos += bytes; + ret = 0; + } else { + ret = -EFAULT; + } + } + + kfree(buf); + + return ((ret == 0) ? bytes : ret); +} + +static ssize_t dev_mem_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wl1271 *wl = file->private_data; + struct wlcore_partition_set part, old_part; + size_t bytes = count; + int ret; + char *buf; + + /* only requests of dword-aligned size and offset are supported */ + if (bytes % 4) + return -EINVAL; + + if (*ppos % 4) + return -EINVAL; + + /* function should return in reasonable time */ + bytes = min(bytes, WLCORE_MAX_BLOCK_SIZE); + + if (bytes == 0) + return -EINVAL; + + memset(&part, 0, sizeof(part)); + part.mem.start = file->f_pos; + part.mem.size = bytes; + + buf = kmalloc(bytes, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = copy_from_user(buf, user_buf, bytes); + if (ret) { + ret = -EFAULT; + goto err_out; + } + + mutex_lock(&wl->mutex); + + if (wl->state == WL1271_STATE_OFF) { + ret = -EFAULT; + goto skip_write; + } + + ret = wl1271_ps_elp_wakeup(wl); + if (ret < 0) + goto skip_write; + + /* store current partition and switch partition */ + memcpy(&old_part, &wl->curr_part, sizeof(old_part)); + ret = wlcore_set_partition(wl, &part); + if (ret < 0) + goto part_err; + + ret = wlcore_raw_write(wl, 0, buf, bytes, false); + if (ret < 0) + goto write_err; + +write_err: + /* recover partition */ + ret = wlcore_set_partition(wl, &old_part); + if (ret < 0) + goto part_err; + +part_err: + wl1271_ps_elp_sleep(wl); + +skip_write: + mutex_unlock(&wl->mutex); + + if (ret == 0) + *ppos += bytes; + +err_out: + kfree(buf); + + return ((ret == 0) ? bytes : ret); +} + +static loff_t dev_mem_seek(struct file *file, loff_t offset, int orig) +{ + loff_t ret; + + /* only requests of dword-aligned size and offset are supported */ + if (offset % 4) + return -EINVAL; + + switch (orig) { + case SEEK_SET: + file->f_pos = offset; + ret = file->f_pos; + break; + case SEEK_CUR: + file->f_pos += offset; + ret = file->f_pos; + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static const struct file_operations dev_mem_ops = { + .open = simple_open, + .read = dev_mem_read, + .write = dev_mem_write, + .llseek = dev_mem_seek, +}; + static int wl1271_debugfs_add_files(struct wl1271 *wl, struct dentry *rootdir) { @@ -988,6 +1241,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD(irq_blk_threshold, rootdir); DEBUGFS_ADD(irq_timeout, rootdir); DEBUGFS_ADD(fw_stats_raw, rootdir); + DEBUGFS_ADD(sleep_auth, rootdir); streaming = debugfs_create_dir("rx_streaming", rootdir); if (!streaming || IS_ERR(streaming)) @@ -996,6 +1250,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl, DEBUGFS_ADD_PREFIX(rx_streaming, interval, streaming); DEBUGFS_ADD_PREFIX(rx_streaming, always, streaming); + DEBUGFS_ADD_PREFIX(dev, mem, rootdir); return 0; diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index c976f0409865..48907054d493 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -105,6 +105,7 @@ static int wl1271_event_process(struct wl1271 *wl) u32 vector; bool disconnect_sta = false; unsigned long sta_bitmap = 0; + int ret; wl1271_event_mbox_dump(mbox); @@ -228,7 +229,9 @@ static int wl1271_event_process(struct wl1271 *wl) if ((vector & DUMMY_PACKET_EVENT_ID)) { wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID"); - wl1271_tx_dummy_packet(wl); + ret = wl1271_tx_dummy_packet(wl); + if (ret < 0) + return ret; } /* @@ -301,8 +304,10 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) return -EINVAL; /* first we read the mbox descriptor */ - wl1271_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, - sizeof(*wl->mbox), false); + ret = wlcore_read(wl, wl->mbox_ptr[mbox_num], wl->mbox, + sizeof(*wl->mbox), false); + if (ret < 0) + return ret; /* process the descriptor */ ret = wl1271_event_process(wl); @@ -313,7 +318,7 @@ int wl1271_event_handle(struct wl1271 *wl, u8 mbox_num) * TODO: we just need this because one bit is in a different * place. Is there any better way? */ - wl->ops->ack_event(wl); + ret = wl->ops->ack_event(wl); - return 0; + return ret; } diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h index 9e7787ba9610..2673d783ec1e 100644 --- a/drivers/net/wireless/ti/wlcore/hw_ops.h +++ b/drivers/net/wireless/ti/wlcore/hw_ops.h @@ -65,11 +65,13 @@ wlcore_hw_get_rx_buf_align(struct wl1271 *wl, u32 rx_desc) return wl->ops->get_rx_buf_align(wl, rx_desc); } -static inline void +static inline int wlcore_hw_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) { if (wl->ops->prepare_read) - wl->ops->prepare_read(wl, rx_desc, len); + return wl->ops->prepare_read(wl, rx_desc, len); + + return 0; } static inline u32 @@ -81,10 +83,12 @@ wlcore_hw_get_rx_packet_len(struct wl1271 *wl, void *rx_data, u32 data_len) return wl->ops->get_rx_packet_len(wl, rx_data, data_len); } -static inline void wlcore_hw_tx_delayed_compl(struct wl1271 *wl) +static inline int wlcore_hw_tx_delayed_compl(struct wl1271 *wl) { if (wl->ops->tx_delayed_compl) - wl->ops->tx_delayed_compl(wl); + return wl->ops->tx_delayed_compl(wl); + + return 0; } static inline void wlcore_hw_tx_immediate_compl(struct wl1271 *wl) diff --git a/drivers/net/wireless/ti/wlcore/ini.h b/drivers/net/wireless/ti/wlcore/ini.h index 4cf9ecc56212..d24fe3bbc672 100644 --- a/drivers/net/wireless/ti/wlcore/ini.h +++ b/drivers/net/wireless/ti/wlcore/ini.h @@ -172,7 +172,19 @@ struct wl128x_ini_fem_params_5 { /* NVS data structure */ #define WL1271_INI_NVS_SECTION_SIZE 468 -#define WL1271_INI_FEM_MODULE_COUNT 2 + +/* We have four FEM module types: 0-RFMD, 1-TQS, 2-SKW, 3-TQS_HP */ +#define WL1271_INI_FEM_MODULE_COUNT 4 + +/* + * In NVS we only store two FEM module entries - + * FEM modules 0,2,3 are stored in entry 0 + * FEM module 1 is stored in entry 1 + */ +#define WL12XX_NVS_FEM_MODULE_COUNT 2 + +#define WL12XX_FEM_TO_NVS_ENTRY(ini_fem_module) \ + ((ini_fem_module) == 1 ? 1 : 0) #define WL1271_INI_LEGACY_NVS_FILE_SIZE 800 @@ -188,13 +200,13 @@ struct wl1271_nvs_file { struct { struct wl1271_ini_fem_params_2 params; u8 padding; - } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT]; struct wl1271_ini_band_params_5 stat_radio_params_5; u8 padding3; struct { struct wl1271_ini_fem_params_5 params; u8 padding; - } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; + } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT]; } __packed; struct wl128x_nvs_file { @@ -209,12 +221,12 @@ struct wl128x_nvs_file { struct { struct wl128x_ini_fem_params_2 params; u8 padding; - } dyn_radio_params_2[WL1271_INI_FEM_MODULE_COUNT]; + } dyn_radio_params_2[WL12XX_NVS_FEM_MODULE_COUNT]; struct wl128x_ini_band_params_5 stat_radio_params_5; u8 padding3; struct { struct wl128x_ini_fem_params_5 params; u8 padding; - } dyn_radio_params_5[WL1271_INI_FEM_MODULE_COUNT]; + } dyn_radio_params_5[WL12XX_NVS_FEM_MODULE_COUNT]; } __packed; #endif diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 645abd4b660d..a3c867786df8 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -54,6 +54,22 @@ int wl1271_init_templates_config(struct wl1271 *wl) if (ret < 0) return ret; + if (wl->quirks & WLCORE_QUIRK_DUAL_PROBE_TMPL) { + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_APP_PROBE_REQ_2_4, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, + CMD_TEMPL_APP_PROBE_REQ_5, NULL, + WL1271_CMD_TEMPL_MAX_SIZE, + 0, WL1271_RATE_AUTOMATIC); + if (ret < 0) + return ret; + } + ret = wl1271_cmd_template_set(wl, WL12XX_INVALID_ROLE_ID, CMD_TEMPL_NULL_DATA, NULL, sizeof(struct wl12xx_null_data_template), @@ -554,29 +570,28 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif) bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); int ret, i; - /* - * consider all existing roles before configuring psm. - * TODO: reconfigure on interface removal. - */ - if (!wl->ap_count) { - if (is_ap) { - /* Configure for power always on */ + /* consider all existing roles before configuring psm. */ + + if (wl->ap_count == 0 && is_ap) { /* first AP */ + /* Configure for power always on */ + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + if (ret < 0) + return ret; + /* first STA, no APs */ + } else if (wl->sta_count == 0 && wl->ap_count == 0 && !is_ap) { + u8 sta_auth = wl->conf.conn.sta_sleep_auth; + /* Configure for power according to debugfs */ + if (sta_auth != WL1271_PSM_ILLEGAL) + ret = wl1271_acx_sleep_auth(wl, sta_auth); + /* Configure for power always on */ + else if (wl->quirks & WLCORE_QUIRK_NO_ELP) ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - return ret; - } else if (!wl->sta_count) { - if (wl->quirks & WLCORE_QUIRK_NO_ELP) { - /* Configure for power always on */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); - if (ret < 0) - return ret; - } else { - /* Configure for ELP power saving */ - ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); - if (ret < 0) - return ret; - } - } + /* Configure for ELP power saving */ + else + ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + + if (ret < 0) + return ret; } /* Mode specific init */ diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c index 7cd0081aede5..68e74eefd296 100644 --- a/drivers/net/wireless/ti/wlcore/io.c +++ b/drivers/net/wireless/ti/wlcore/io.c @@ -48,12 +48,24 @@ void wlcore_disable_interrupts(struct wl1271 *wl) } EXPORT_SYMBOL_GPL(wlcore_disable_interrupts); +void wlcore_disable_interrupts_nosync(struct wl1271 *wl) +{ + disable_irq_nosync(wl->irq); +} +EXPORT_SYMBOL_GPL(wlcore_disable_interrupts_nosync); + void wlcore_enable_interrupts(struct wl1271 *wl) { enable_irq(wl->irq); } EXPORT_SYMBOL_GPL(wlcore_enable_interrupts); +void wlcore_synchronize_interrupts(struct wl1271 *wl) +{ + synchronize_irq(wl->irq); +} +EXPORT_SYMBOL_GPL(wlcore_synchronize_interrupts); + int wlcore_translate_addr(struct wl1271 *wl, int addr) { struct wlcore_partition_set *part = &wl->curr_part; @@ -122,9 +134,11 @@ EXPORT_SYMBOL_GPL(wlcore_translate_addr); * | | * */ -void wlcore_set_partition(struct wl1271 *wl, - const struct wlcore_partition_set *p) +int wlcore_set_partition(struct wl1271 *wl, + const struct wlcore_partition_set *p) { + int ret; + /* copy partition info */ memcpy(&wl->curr_part, p, sizeof(*p)); @@ -137,28 +151,41 @@ void wlcore_set_partition(struct wl1271 *wl, wl1271_debug(DEBUG_IO, "mem3_start %08X mem3_size %08X", p->mem3.start, p->mem3.size); - wl1271_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); - wl1271_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); - wl1271_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); - wl1271_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); - wl1271_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); - wl1271_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + ret = wlcore_raw_write32(wl, HW_PART0_START_ADDR, p->mem.start); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART0_SIZE_ADDR, p->mem.size); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART1_START_ADDR, p->reg.start); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART1_SIZE_ADDR, p->reg.size); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART2_START_ADDR, p->mem2.start); + if (ret < 0) + goto out; + + ret = wlcore_raw_write32(wl, HW_PART2_SIZE_ADDR, p->mem2.size); + if (ret < 0) + goto out; + /* * We don't need the size of the last partition, as it is * automatically calculated based on the total memory size and * the sizes of the previous partitions. */ - wl1271_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); -} -EXPORT_SYMBOL_GPL(wlcore_set_partition); - -void wlcore_select_partition(struct wl1271 *wl, u8 part) -{ - wl1271_debug(DEBUG_IO, "setting partition %d", part); + ret = wlcore_raw_write32(wl, HW_PART3_START_ADDR, p->mem3.start); - wlcore_set_partition(wl, &wl->ptable[part]); +out: + return ret; } -EXPORT_SYMBOL_GPL(wlcore_select_partition); +EXPORT_SYMBOL_GPL(wlcore_set_partition); void wl1271_io_reset(struct wl1271 *wl) { diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index 8942954b56a0..259149f36fae 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -45,86 +45,122 @@ struct wl1271; void wlcore_disable_interrupts(struct wl1271 *wl); +void wlcore_disable_interrupts_nosync(struct wl1271 *wl); void wlcore_enable_interrupts(struct wl1271 *wl); +void wlcore_synchronize_interrupts(struct wl1271 *wl); void wl1271_io_reset(struct wl1271 *wl); void wl1271_io_init(struct wl1271 *wl); int wlcore_translate_addr(struct wl1271 *wl, int addr); /* Raw target IO, address is not translated */ -static inline void wl1271_raw_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr, + void *buf, size_t len, + bool fixed) { - wl->if_ops->write(wl->dev, addr, buf, len, fixed); + int ret; + + if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) + return -EIO; + + ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); + if (ret && wl->state != WL1271_STATE_OFF) + set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); + + return ret; } -static inline void wl1271_raw_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr, + void *buf, size_t len, + bool fixed) { - wl->if_ops->read(wl->dev, addr, buf, len, fixed); + int ret; + + if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) + return -EIO; + + ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); + if (ret && wl->state != WL1271_STATE_OFF) + set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); + + return ret; } -static inline void wlcore_raw_read_data(struct wl1271 *wl, int reg, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_raw_read_data(struct wl1271 *wl, int reg, + void *buf, size_t len, + bool fixed) { - wl1271_raw_read(wl, wl->rtable[reg], buf, len, fixed); + return wlcore_raw_read(wl, wl->rtable[reg], buf, len, fixed); } -static inline void wlcore_raw_write_data(struct wl1271 *wl, int reg, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_raw_write_data(struct wl1271 *wl, int reg, + void *buf, size_t len, + bool fixed) { - wl1271_raw_write(wl, wl->rtable[reg], buf, len, fixed); + return wlcore_raw_write(wl, wl->rtable[reg], buf, len, fixed); } -static inline u32 wl1271_raw_read32(struct wl1271 *wl, int addr) +static inline int __must_check wlcore_raw_read32(struct wl1271 *wl, int addr, + u32 *val) { - wl1271_raw_read(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + int ret; + + ret = wlcore_raw_read(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); + if (ret < 0) + return ret; + + if (val) + *val = le32_to_cpu(wl->buffer_32); - return le32_to_cpu(wl->buffer_32); + return 0; } -static inline void wl1271_raw_write32(struct wl1271 *wl, int addr, u32 val) +static inline int __must_check wlcore_raw_write32(struct wl1271 *wl, int addr, + u32 val) { wl->buffer_32 = cpu_to_le32(val); - wl1271_raw_write(wl, addr, &wl->buffer_32, - sizeof(wl->buffer_32), false); + return wlcore_raw_write(wl, addr, &wl->buffer_32, + sizeof(wl->buffer_32), false); } -static inline void wl1271_read(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_read(struct wl1271 *wl, int addr, + void *buf, size_t len, bool fixed) { int physical; physical = wlcore_translate_addr(wl, addr); - wl1271_raw_read(wl, physical, buf, len, fixed); + return wlcore_raw_read(wl, physical, buf, len, fixed); } -static inline void wl1271_write(struct wl1271 *wl, int addr, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_write(struct wl1271 *wl, int addr, + void *buf, size_t len, bool fixed) { int physical; physical = wlcore_translate_addr(wl, addr); - wl1271_raw_write(wl, physical, buf, len, fixed); + return wlcore_raw_write(wl, physical, buf, len, fixed); } -static inline void wlcore_write_data(struct wl1271 *wl, int reg, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_write_data(struct wl1271 *wl, int reg, + void *buf, size_t len, + bool fixed) { - wl1271_write(wl, wl->rtable[reg], buf, len, fixed); + return wlcore_write(wl, wl->rtable[reg], buf, len, fixed); } -static inline void wlcore_read_data(struct wl1271 *wl, int reg, void *buf, - size_t len, bool fixed) +static inline int __must_check wlcore_read_data(struct wl1271 *wl, int reg, + void *buf, size_t len, + bool fixed) { - wl1271_read(wl, wl->rtable[reg], buf, len, fixed); + return wlcore_read(wl, wl->rtable[reg], buf, len, fixed); } -static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, - void *buf, size_t len, bool fixed) +static inline int __must_check wlcore_read_hwaddr(struct wl1271 *wl, int hwaddr, + void *buf, size_t len, + bool fixed) { int physical; int addr; @@ -134,34 +170,47 @@ static inline void wl1271_read_hwaddr(struct wl1271 *wl, int hwaddr, physical = wlcore_translate_addr(wl, addr); - wl1271_raw_read(wl, physical, buf, len, fixed); + return wlcore_raw_read(wl, physical, buf, len, fixed); } -static inline u32 wl1271_read32(struct wl1271 *wl, int addr) +static inline int __must_check wlcore_read32(struct wl1271 *wl, int addr, + u32 *val) { - return wl1271_raw_read32(wl, wlcore_translate_addr(wl, addr)); + return wlcore_raw_read32(wl, wlcore_translate_addr(wl, addr), val); } -static inline void wl1271_write32(struct wl1271 *wl, int addr, u32 val) +static inline int __must_check wlcore_write32(struct wl1271 *wl, int addr, + u32 val) { - wl1271_raw_write32(wl, wlcore_translate_addr(wl, addr), val); + return wlcore_raw_write32(wl, wlcore_translate_addr(wl, addr), val); } -static inline u32 wlcore_read_reg(struct wl1271 *wl, int reg) +static inline int __must_check wlcore_read_reg(struct wl1271 *wl, int reg, + u32 *val) { - return wl1271_raw_read32(wl, - wlcore_translate_addr(wl, wl->rtable[reg])); + return wlcore_raw_read32(wl, + wlcore_translate_addr(wl, wl->rtable[reg]), + val); } -static inline void wlcore_write_reg(struct wl1271 *wl, int reg, u32 val) +static inline int __must_check wlcore_write_reg(struct wl1271 *wl, int reg, + u32 val) { - wl1271_raw_write32(wl, wlcore_translate_addr(wl, wl->rtable[reg]), val); + return wlcore_raw_write32(wl, + wlcore_translate_addr(wl, wl->rtable[reg]), + val); } static inline void wl1271_power_off(struct wl1271 *wl) { - wl->if_ops->power(wl->dev, false); - clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); + int ret; + + if (!test_bit(WL1271_FLAG_GPIO_POWER, &wl->flags)) + return; + + ret = wl->if_ops->power(wl->dev, false); + if (!ret) + clear_bit(WL1271_FLAG_GPIO_POWER, &wl->flags); } static inline int wl1271_power_on(struct wl1271 *wl) @@ -173,8 +222,8 @@ static inline int wl1271_power_on(struct wl1271 *wl) return ret; } -void wlcore_set_partition(struct wl1271 *wl, - const struct wlcore_partition_set *p); +int wlcore_set_partition(struct wl1271 *wl, + const struct wlcore_partition_set *p); bool wl1271_set_block_size(struct wl1271 *wl); @@ -182,6 +231,4 @@ bool wl1271_set_block_size(struct wl1271 *wl); int wl1271_tx_dummy_packet(struct wl1271 *wl); -void wlcore_select_partition(struct wl1271 *wl, u8 part); - #endif diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 1156e3f578c1..9f04b64dfa33 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -62,7 +62,7 @@ static bool no_recovery; static void __wl1271_op_remove_interface(struct wl1271 *wl, struct ieee80211_vif *vif, bool reset_tx_queues); -static void wl1271_op_stop(struct ieee80211_hw *hw); +static void wlcore_op_stop_locked(struct wl1271 *wl); static void wl1271_free_ap_keys(struct wl1271 *wl, struct wl12xx_vif *wlvif); static int wl12xx_set_authorized(struct wl1271 *wl, @@ -378,9 +378,9 @@ static void wl12xx_irq_update_links_status(struct wl1271 *wl, } } -static void wl12xx_fw_status(struct wl1271 *wl, - struct wl_fw_status_1 *status_1, - struct wl_fw_status_2 *status_2) +static int wlcore_fw_status(struct wl1271 *wl, + struct wl_fw_status_1 *status_1, + struct wl_fw_status_2 *status_2) { struct wl12xx_vif *wlvif; struct timespec ts; @@ -388,12 +388,15 @@ static void wl12xx_fw_status(struct wl1271 *wl, int avail, freed_blocks; int i; size_t status_len; + int ret; status_len = WLCORE_FW_STATUS_1_LEN(wl->num_rx_desc) + sizeof(*status_2) + wl->fw_status_priv_len; - wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1, - status_len, false); + ret = wlcore_raw_read_data(wl, REG_RAW_FW_STATUS_ADDR, status_1, + status_len, false); + if (ret < 0) + return ret; wl1271_debug(DEBUG_IRQ, "intr: 0x%x (fw_rx_counter = %d, " "drv_rx_counter = %d, tx_results_counter = %d)", @@ -462,6 +465,8 @@ static void wl12xx_fw_status(struct wl1271 *wl, getnstimeofday(&ts); wl->time_offset = (timespec_to_ns(&ts) >> 10) - (s64)le32_to_cpu(status_2->fw_localtime); + + return 0; } static void wl1271_flush_deferred_work(struct wl1271 *wl) @@ -489,20 +494,15 @@ static void wl1271_netstack_work(struct work_struct *work) #define WL1271_IRQ_MAX_LOOPS 256 -static irqreturn_t wl1271_irq(int irq, void *cookie) +static int wlcore_irq_locked(struct wl1271 *wl) { - int ret; + int ret = 0; u32 intr; int loopcount = WL1271_IRQ_MAX_LOOPS; - struct wl1271 *wl = (struct wl1271 *)cookie; bool done = false; unsigned int defer_count; unsigned long flags; - /* TX might be handled here, avoid redundant work */ - set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); - cancel_work_sync(&wl->tx_work); - /* * In case edge triggered interrupt must be used, we cannot iterate * more than once without introducing race conditions with the hardirq. @@ -510,8 +510,6 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) if (wl->platform_quirks & WL12XX_PLATFORM_QUIRK_EDGE_IRQ) loopcount = 1; - mutex_lock(&wl->mutex); - wl1271_debug(DEBUG_IRQ, "IRQ work"); if (unlikely(wl->state == WL1271_STATE_OFF)) @@ -530,7 +528,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) clear_bit(WL1271_FLAG_IRQ_RUNNING, &wl->flags); smp_mb__after_clear_bit(); - wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2); + ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2); + if (ret < 0) + goto out; wlcore_hw_tx_immediate_compl(wl); @@ -544,7 +544,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) if (unlikely(intr & WL1271_ACX_INTR_WATCHDOG)) { wl1271_error("HW watchdog interrupt received! starting recovery."); wl->watchdog_recovery = true; - wl12xx_queue_recovery_work(wl); + ret = -EIO; /* restarting the chip. ignore any other interrupt. */ goto out; @@ -554,7 +554,7 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) wl1271_error("SW watchdog interrupt received! " "starting recovery."); wl->watchdog_recovery = true; - wl12xx_queue_recovery_work(wl); + ret = -EIO; /* restarting the chip. ignore any other interrupt. */ goto out; @@ -563,7 +563,9 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) if (likely(intr & WL1271_ACX_INTR_DATA)) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_DATA"); - wl12xx_rx(wl, wl->fw_status_1); + ret = wlcore_rx(wl, wl->fw_status_1); + if (ret < 0) + goto out; /* Check if any tx blocks were freed */ spin_lock_irqsave(&wl->wl_lock, flags); @@ -574,13 +576,17 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) * In order to avoid starvation of the TX path, * call the work function directly. */ - wl1271_tx_work_locked(wl); + ret = wlcore_tx_work_locked(wl); + if (ret < 0) + goto out; } else { spin_unlock_irqrestore(&wl->wl_lock, flags); } /* check for tx results */ - wlcore_hw_tx_delayed_compl(wl); + ret = wlcore_hw_tx_delayed_compl(wl); + if (ret < 0) + goto out; /* Make sure the deferred queues don't get too long */ defer_count = skb_queue_len(&wl->deferred_tx_queue) + @@ -591,12 +597,16 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) if (intr & WL1271_ACX_INTR_EVENT_A) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_A"); - wl1271_event_handle(wl, 0); + ret = wl1271_event_handle(wl, 0); + if (ret < 0) + goto out; } if (intr & WL1271_ACX_INTR_EVENT_B) { wl1271_debug(DEBUG_IRQ, "WL1271_ACX_INTR_EVENT_B"); - wl1271_event_handle(wl, 1); + ret = wl1271_event_handle(wl, 1); + if (ret < 0) + goto out; } if (intr & WL1271_ACX_INTR_INIT_COMPLETE) @@ -610,6 +620,25 @@ static irqreturn_t wl1271_irq(int irq, void *cookie) wl1271_ps_elp_sleep(wl); out: + return ret; +} + +static irqreturn_t wlcore_irq(int irq, void *cookie) +{ + int ret; + unsigned long flags; + struct wl1271 *wl = cookie; + + /* TX might be handled here, avoid redundant work */ + set_bit(WL1271_FLAG_TX_PENDING, &wl->flags); + cancel_work_sync(&wl->tx_work); + + mutex_lock(&wl->mutex); + + ret = wlcore_irq_locked(wl); + if (ret) + wl12xx_queue_recovery_work(wl); + spin_lock_irqsave(&wl->wl_lock, flags); /* In case TX was not handled here, queue TX work */ clear_bit(WL1271_FLAG_TX_PENDING, &wl->flags); @@ -743,8 +772,13 @@ out: void wl12xx_queue_recovery_work(struct wl1271 *wl) { - if (!test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + WARN_ON(!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); + + /* Avoid a recursive recovery */ + if (!test_and_set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + wlcore_disable_interrupts_nosync(wl); ieee80211_queue_work(wl->hw, &wl->recovery_work); + } } size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) @@ -770,14 +804,17 @@ size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen) return len; } +#define WLCORE_FW_LOG_END 0x2000000 + static void wl12xx_read_fwlog_panic(struct wl1271 *wl) { u32 addr; - u32 first_addr; + u32 offset; + u32 end_of_log; u8 *block; + int ret; if ((wl->quirks & WLCORE_QUIRK_FWLOG_NOT_IMPLEMENTED) || - (wl->conf.fwlog.mode != WL12XX_FWLOG_ON_DEMAND) || (wl->conf.fwlog.mem_blocks == 0)) return; @@ -791,34 +828,47 @@ static void wl12xx_read_fwlog_panic(struct wl1271 *wl) * Make sure the chip is awake and the logger isn't active. * Do not send a stop fwlog command if the fw is hanged. */ - if (!wl1271_ps_elp_wakeup(wl) && !wl->watchdog_recovery) - wl12xx_cmd_stop_fwlog(wl); - else + if (wl1271_ps_elp_wakeup(wl)) goto out; + if (!wl->watchdog_recovery) + wl12xx_cmd_stop_fwlog(wl); /* Read the first memory block address */ - wl12xx_fw_status(wl, wl->fw_status_1, wl->fw_status_2); - first_addr = le32_to_cpu(wl->fw_status_2->log_start_addr); - if (!first_addr) + ret = wlcore_fw_status(wl, wl->fw_status_1, wl->fw_status_2); + if (ret < 0) + goto out; + + addr = le32_to_cpu(wl->fw_status_2->log_start_addr); + if (!addr) goto out; + if (wl->conf.fwlog.mode == WL12XX_FWLOG_CONTINUOUS) { + offset = sizeof(addr) + sizeof(struct wl1271_rx_descriptor); + end_of_log = WLCORE_FW_LOG_END; + } else { + offset = sizeof(addr); + end_of_log = addr; + } + /* Traverse the memory blocks linked list */ - addr = first_addr; do { memset(block, 0, WL12XX_HW_BLOCK_SIZE); - wl1271_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, - false); + ret = wlcore_read_hwaddr(wl, addr, block, WL12XX_HW_BLOCK_SIZE, + false); + if (ret < 0) + goto out; /* * Memory blocks are linked to one another. The first 4 bytes * of each memory block hold the hardware address of the next - * one. The last memory block points to the first one. + * one. The last memory block points to the first one in + * on demand mode and is equal to 0x2000000 in continuous mode. */ addr = le32_to_cpup((__le32 *)block); - if (!wl12xx_copy_fwlog(wl, block + sizeof(addr), - WL12XX_HW_BLOCK_SIZE - sizeof(addr))) + if (!wl12xx_copy_fwlog(wl, block + offset, + WL12XX_HW_BLOCK_SIZE - offset)) break; - } while (addr && (addr != first_addr)); + } while (addr && (addr != end_of_log)); wake_up_interruptible(&wl->fwlog_waitq); @@ -826,6 +876,34 @@ out: kfree(block); } +static void wlcore_print_recovery(struct wl1271 *wl) +{ + u32 pc = 0; + u32 hint_sts = 0; + int ret; + + wl1271_info("Hardware recovery in progress. FW ver: %s", + wl->chip.fw_ver_str); + + /* change partitions momentarily so we can read the FW pc */ + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + if (ret < 0) + return; + + ret = wlcore_read_reg(wl, REG_PC_ON_RECOVERY, &pc); + if (ret < 0) + return; + + ret = wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR, &hint_sts); + if (ret < 0) + return; + + wl1271_info("pc: 0x%x, hint_sts: 0x%08x", pc, hint_sts); + + wlcore_set_partition(wl, &wl->ptable[PART_WORK]); +} + + static void wl1271_recovery_work(struct work_struct *work) { struct wl1271 *wl = @@ -838,26 +916,16 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON || wl->plt) goto out_unlock; - /* Avoid a recursive recovery */ - set_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); - - wl12xx_read_fwlog_panic(wl); - - /* change partitions momentarily so we can read the FW pc */ - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); - wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x " - "hint_sts: 0x%08x", - wl->chip.fw_ver_str, - wlcore_read_reg(wl, REG_PC_ON_RECOVERY), - wlcore_read_reg(wl, REG_INTERRUPT_NO_CLEAR)); - wlcore_set_partition(wl, &wl->ptable[PART_WORK]); + if (!test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) { + wl12xx_read_fwlog_panic(wl); + wlcore_print_recovery(wl); + } BUG_ON(bug_on_recovery && !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)); if (no_recovery) { wl1271_info("No recovery (chosen on module load). Fw will remain stuck."); - clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); goto out_unlock; } @@ -888,11 +956,8 @@ static void wl1271_recovery_work(struct work_struct *work) vif = wl12xx_wlvif_to_vif(wlvif); __wl1271_op_remove_interface(wl, vif, false); } - wl->watchdog_recovery = false; - mutex_unlock(&wl->mutex); - wl1271_op_stop(wl->hw); - clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); + wlcore_op_stop_locked(wl); ieee80211_restart_hw(wl->hw); @@ -901,15 +966,16 @@ static void wl1271_recovery_work(struct work_struct *work) * to restart the HW. */ wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FW_RESTART); - return; + out_unlock: - wl->watchdog_recovery = false; + wl->watchdog_recovery = false; + clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags); mutex_unlock(&wl->mutex); } -static void wl1271_fw_wakeup(struct wl1271 *wl) +static int wlcore_fw_wakeup(struct wl1271 *wl) { - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); + return wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); } static int wl1271_setup(struct wl1271 *wl) @@ -945,13 +1011,21 @@ static int wl12xx_set_power_on(struct wl1271 *wl) wl1271_io_reset(wl); wl1271_io_init(wl); - wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + ret = wlcore_set_partition(wl, &wl->ptable[PART_BOOT]); + if (ret < 0) + goto fail; /* ELP module wake up */ - wl1271_fw_wakeup(wl); + ret = wlcore_fw_wakeup(wl); + if (ret < 0) + goto fail; out: return ret; + +fail: + wl1271_power_off(wl); + return ret; } static int wl12xx_chip_wakeup(struct wl1271 *wl, bool plt) @@ -1082,6 +1156,7 @@ int wl1271_plt_stop(struct wl1271 *wl) mutex_lock(&wl->mutex); wl1271_power_off(wl); wl->flags = 0; + wl->sleep_auth = WL1271_PSM_ILLEGAL; wl->state = WL1271_STATE_OFF; wl->plt = false; wl->rx_counter = 0; @@ -1136,7 +1211,9 @@ static void wl1271_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * The workqueue is slow to process the tx_queue and we need stop * the queue here, otherwise the queue will get too long. */ - if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK) { + if (wl->tx_queue_count[q] >= WL1271_TX_QUEUE_HIGH_WATERMARK && + !wlcore_is_queue_stopped_by_reason(wl, q, + WLCORE_QUEUE_STOP_REASON_WATERMARK)) { wl1271_debug(DEBUG_TX, "op_tx: stopping queues for q %d", q); wlcore_stop_queue_locked(wl, q, WLCORE_QUEUE_STOP_REASON_WATERMARK); @@ -1173,7 +1250,7 @@ int wl1271_tx_dummy_packet(struct wl1271 *wl) /* The FW is low on RX memory blocks, so send the dummy packet asap */ if (!test_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags)) - wl1271_tx_work_locked(wl); + return wlcore_tx_work_locked(wl); /* * If the FW TX is busy, TX work will be scheduled by the threaded @@ -1440,8 +1517,15 @@ static int wl1271_configure_wowlan(struct wl1271 *wl, int i, ret; if (!wow || wow->any || !wow->n_patterns) { - wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); - wl1271_rx_filter_clear_all(wl); + ret = wl1271_acx_default_rx_filter_enable(wl, 0, + FILTER_SIGNAL); + if (ret) + goto out; + + ret = wl1271_rx_filter_clear_all(wl); + if (ret) + goto out; + return 0; } @@ -1457,8 +1541,13 @@ static int wl1271_configure_wowlan(struct wl1271 *wl, } } - wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); - wl1271_rx_filter_clear_all(wl); + ret = wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); + if (ret) + goto out; + + ret = wl1271_rx_filter_clear_all(wl); + if (ret) + goto out; /* Translate WoWLAN patterns into filters */ for (i = 0; i < wow->n_patterns; i++) { @@ -1500,7 +1589,10 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) goto out; - wl1271_configure_wowlan(wl, wow); + ret = wl1271_configure_wowlan(wl, wow); + if (ret < 0) + goto out_sleep; + ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.suspend_wake_up_event, wl->conf.conn.suspend_listen_interval); @@ -1508,8 +1600,8 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) wl1271_error("suspend: set wake up conditions failed: %d", ret); +out_sleep: wl1271_ps_elp_sleep(wl); - out: return ret; @@ -1588,6 +1680,12 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); WARN_ON(!wow); + /* we want to perform the recovery before suspending */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) { + wl1271_warning("postponing suspend to perform recovery"); + return -EBUSY; + } + wl1271_tx_flush(wl); mutex_lock(&wl->mutex); @@ -1628,7 +1726,8 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif; unsigned long flags; - bool run_irq_work = false; + bool run_irq_work = false, pending_recovery; + int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 resume wow=%d", wl->wow_enabled); @@ -1644,17 +1743,37 @@ static int wl1271_op_resume(struct ieee80211_hw *hw) run_irq_work = true; spin_unlock_irqrestore(&wl->wl_lock, flags); + mutex_lock(&wl->mutex); + + /* test the recovery flag before calling any SDIO functions */ + pending_recovery = test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, + &wl->flags); + if (run_irq_work) { wl1271_debug(DEBUG_MAC80211, "run postponed irq_work directly"); - wl1271_irq(0, wl); + + /* don't talk to the HW if recovery is pending */ + if (!pending_recovery) { + ret = wlcore_irq_locked(wl); + if (ret) + wl12xx_queue_recovery_work(wl); + } + wlcore_enable_interrupts(wl); } - mutex_lock(&wl->mutex); + if (pending_recovery) { + wl1271_warning("queuing forgotten recovery on resume"); + ieee80211_queue_work(wl->hw, &wl->recovery_work); + goto out; + } + wl12xx_for_each_wlvif(wl, wlvif) { wl1271_configure_resume(wl, wlvif); } + +out: wl->wow_enabled = false; mutex_unlock(&wl->mutex); @@ -1680,29 +1799,15 @@ static int wl1271_op_start(struct ieee80211_hw *hw) return 0; } -static void wl1271_op_stop(struct ieee80211_hw *hw) +static void wlcore_op_stop_locked(struct wl1271 *wl) { - struct wl1271 *wl = hw->priv; int i; - wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); - - /* - * Interrupts must be disabled before setting the state to OFF. - * Otherwise, the interrupt handler might be called and exit without - * reading the interrupt status. - */ - wlcore_disable_interrupts(wl); - mutex_lock(&wl->mutex); if (wl->state == WL1271_STATE_OFF) { - mutex_unlock(&wl->mutex); + if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, + &wl->flags)) + wlcore_enable_interrupts(wl); - /* - * This will not necessarily enable interrupts as interrupts - * may have been disabled when op_stop was called. It will, - * however, balance the above call to disable_interrupts(). - */ - wlcore_enable_interrupts(wl); return; } @@ -1711,8 +1816,16 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) * functions don't perform further work. */ wl->state = WL1271_STATE_OFF; + + /* + * Use the nosync variant to disable interrupts, so the mutex could be + * held while doing so without deadlocking. + */ + wlcore_disable_interrupts_nosync(wl); + mutex_unlock(&wl->mutex); + wlcore_synchronize_interrupts(wl); wl1271_flush_deferred_work(wl); cancel_delayed_work_sync(&wl->scan_complete_work); cancel_work_sync(&wl->netstack_work); @@ -1726,6 +1839,13 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) mutex_lock(&wl->mutex); wl1271_power_off(wl); + /* + * In case a recovery was scheduled, interrupts were disabled to avoid + * an interrupt storm. Now that the power is down, it is safe to + * re-enable interrupts to balance the disable depth + */ + if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) + wlcore_enable_interrupts(wl); wl->band = IEEE80211_BAND_2GHZ; @@ -1740,6 +1860,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->ap_fw_ps_map = 0; wl->ap_ps_map = 0; wl->sched_scanning = false; + wl->sleep_auth = WL1271_PSM_ILLEGAL; memset(wl->roles_map, 0, sizeof(wl->roles_map)); memset(wl->links_map, 0, sizeof(wl->links_map)); memset(wl->roc_map, 0, sizeof(wl->roc_map)); @@ -1771,6 +1892,17 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) wl->tx_res_if = NULL; kfree(wl->target_mem_map); wl->target_mem_map = NULL; +} + +static void wlcore_op_stop(struct ieee80211_hw *hw) +{ + struct wl1271 *wl = hw->priv; + + wl1271_debug(DEBUG_MAC80211, "mac80211 stop"); + + mutex_lock(&wl->mutex); + + wlcore_op_stop_locked(wl); mutex_unlock(&wl->mutex); } @@ -2146,6 +2278,7 @@ static void __wl1271_op_remove_interface(struct wl1271 *wl, { struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); int i, ret; + bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); wl1271_debug(DEBUG_MAC80211, "mac80211 remove interface"); @@ -2226,11 +2359,25 @@ deinit: wlvif->role_id = WL12XX_INVALID_ROLE_ID; wlvif->dev_role_id = WL12XX_INVALID_ROLE_ID; - if (wlvif->bss_type == BSS_TYPE_AP_BSS) + if (is_ap) wl->ap_count--; else wl->sta_count--; + /* Last AP, have more stations. Configure according to STA. */ + if (wl->ap_count == 0 && is_ap && wl->sta_count) { + u8 sta_auth = wl->conf.conn.sta_sleep_auth; + /* Configure for power according to debugfs */ + if (sta_auth != WL1271_PSM_ILLEGAL) + wl1271_acx_sleep_auth(wl, sta_auth); + /* Configure for power always on */ + else if (wl->quirks & WLCORE_QUIRK_NO_ELP) + wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM); + /* Configure for ELP power saving */ + else + wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); + } + mutex_unlock(&wl->mutex); del_timer_sync(&wlvif->rx_streaming_timer); @@ -2448,12 +2595,16 @@ static int wl12xx_config_vif(struct wl1271 *wl, struct wl12xx_vif *wlvif, (wlvif->channel != channel) || (wlvif->channel_type != conf->channel_type))) { /* send all pending packets */ - wl1271_tx_work_locked(wl); + ret = wlcore_tx_work_locked(wl); + if (ret < 0) + return ret; + wlvif->band = conf->channel->band; wlvif->channel = channel; wlvif->channel_type = conf->channel_type; if (is_ap) { + wl1271_set_band_rate(wl, wlvif); ret = wl1271_init_ap_rates(wl, wlvif); if (ret < 0) wl1271_error("AP rate policy change failed %d", @@ -4090,16 +4241,13 @@ out: static int wl1271_op_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey) { - struct wl1271 *wl = hw->priv; struct ieee80211_conf *conf = &hw->conf; if (idx != 0) return -ENOENT; survey->channel = conf->channel; - survey->filled = SURVEY_INFO_NOISE_DBM; - survey->noise = wl->noise; - + survey->filled = 0; return 0; } @@ -4365,9 +4513,14 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw, case IEEE80211_AMPDU_RX_STOP: if (!(*ba_bitmap & BIT(tid))) { - ret = -EINVAL; - wl1271_error("no active RX BA session on tid: %d", + /* + * this happens on reconfig - so only output a debug + * message for now, and don't fail the function. + */ + wl1271_debug(DEBUG_MAC80211, + "no active RX BA session on tid: %d", tid); + ret = 0; break; } @@ -4416,7 +4569,7 @@ static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw, mutex_lock(&wl->mutex); - for (i = 0; i < IEEE80211_NUM_BANDS; i++) + for (i = 0; i < WLCORE_NUM_BANDS; i++) wlvif->bitrate_masks[i] = wl1271_tx_enabled_rates_get(wl, mask->control[i].legacy, @@ -4484,6 +4637,13 @@ out: mutex_unlock(&wl->mutex); } +static void wlcore_op_flush(struct ieee80211_hw *hw, bool drop) +{ + struct wl1271 *wl = hw->priv; + + wl1271_tx_flush(wl); +} + static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw) { struct wl1271 *wl = hw->priv; @@ -4646,7 +4806,7 @@ static struct ieee80211_supported_band wl1271_band_5ghz = { static const struct ieee80211_ops wl1271_ops = { .start = wl1271_op_start, - .stop = wl1271_op_stop, + .stop = wlcore_op_stop, .add_interface = wl1271_op_add_interface, .remove_interface = wl1271_op_remove_interface, .change_interface = wl12xx_op_change_interface, @@ -4674,6 +4834,7 @@ static const struct ieee80211_ops wl1271_ops = { .tx_frames_pending = wl1271_tx_frames_pending, .set_bitrate_mask = wl12xx_set_bitrate_mask, .channel_switch = wl12xx_op_channel_switch, + .flush = wlcore_op_flush, CFG80211_TESTMODE_CMD(wl1271_tm_cmd) }; @@ -4904,18 +5065,22 @@ static int wl12xx_get_hw_info(struct wl1271 *wl) if (ret < 0) goto out; - wl->chip.id = wlcore_read_reg(wl, REG_CHIP_ID_B); + ret = wlcore_read_reg(wl, REG_CHIP_ID_B, &wl->chip.id); + if (ret < 0) + goto out; wl->fuse_oui_addr = 0; wl->fuse_nic_addr = 0; - wl->hw_pg_ver = wl->ops->get_pg_ver(wl); + ret = wl->ops->get_pg_ver(wl, &wl->hw_pg_ver); + if (ret < 0) + goto out; if (wl->ops->get_mac) - wl->ops->get_mac(wl); + ret = wl->ops->get_mac(wl); - wl1271_power_off(wl); out: + wl1271_power_off(wl); return ret; } @@ -4976,6 +5141,29 @@ static void wl1271_unregister_hw(struct wl1271 *wl) } +static const struct ieee80211_iface_limit wlcore_iface_limits[] = { + { + .max = 2, + .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, + .types = BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_P2P_GO) | + BIT(NL80211_IFTYPE_P2P_CLIENT), + }, +}; + +static const struct ieee80211_iface_combination +wlcore_iface_combinations[] = { + { + .num_different_channels = 1, + .max_interfaces = 2, + .limits = wlcore_iface_limits, + .n_limits = ARRAY_SIZE(wlcore_iface_limits), + }, +}; + static int wl1271_init_ieee80211(struct wl1271 *wl) { static const u32 cipher_suites[] = { @@ -5069,6 +5257,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; + /* allowed interface combinations */ + wl->hw->wiphy->iface_combinations = wlcore_iface_combinations; + wl->hw->wiphy->n_iface_combinations = + ARRAY_SIZE(wlcore_iface_combinations); + SET_IEEE80211_DEV(wl->hw, wl->dev); wl->hw->sta_data_size = sizeof(struct wl1271_station); @@ -5140,6 +5333,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) wl->channel_type = NL80211_CHAN_NO_HT; wl->flags = 0; wl->sg_enabled = true; + wl->sleep_auth = WL1271_PSM_ILLEGAL; wl->hw_pg_ver = -1; wl->ap_ps_map = 0; wl->ap_fw_ps_map = 0; @@ -5313,7 +5507,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) else irqflags = IRQF_TRIGGER_HIGH | IRQF_ONESHOT; - ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wl1271_irq, + ret = request_threaded_irq(wl->irq, wl12xx_hardirq, wlcore_irq, irqflags, pdev->name, wl); if (ret < 0) { @@ -5321,6 +5515,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) goto out_free_hw; } +#ifdef CONFIG_PM ret = enable_irq_wake(wl->irq); if (!ret) { wl->irq_wake_enabled = true; @@ -5334,17 +5529,18 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) WL1271_RX_FILTER_MAX_PATTERN_SIZE; } } +#endif disable_irq(wl->irq); ret = wl12xx_get_hw_info(wl); if (ret < 0) { wl1271_error("couldn't get hw info"); - goto out; + goto out_irq; } ret = wl->ops->identify_chip(wl); if (ret < 0) - goto out; + goto out_irq; ret = wl1271_init_ieee80211(wl); if (ret) @@ -5358,7 +5554,7 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) ret = device_create_file(wl->dev, &dev_attr_bt_coex_state); if (ret < 0) { wl1271_error("failed to create sysfs file bt_coex_state"); - goto out_irq; + goto out_unreg; } /* Create sysfs file to get HW PG version */ @@ -5383,6 +5579,9 @@ out_hw_pg_ver: out_bt_coex_state: device_remove_file(wl->dev, &dev_attr_bt_coex_state); +out_unreg: + wl1271_unregister_hw(wl); + out_irq: free_irq(wl->irq, wl); diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c index 47e81b32f7da..46d36fd30eba 100644 --- a/drivers/net/wireless/ti/wlcore/ps.c +++ b/drivers/net/wireless/ti/wlcore/ps.c @@ -35,6 +35,7 @@ void wl1271_elp_work(struct work_struct *work) struct delayed_work *dwork; struct wl1271 *wl; struct wl12xx_vif *wlvif; + int ret; dwork = container_of(work, struct delayed_work, work); wl = container_of(dwork, struct wl1271, elp_work); @@ -63,7 +64,12 @@ void wl1271_elp_work(struct work_struct *work) } wl1271_debug(DEBUG_PSM, "chip to elp"); - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); + ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_SLEEP); + if (ret < 0) { + wl12xx_queue_recovery_work(wl); + goto out; + } + set_bit(WL1271_FLAG_IN_ELP, &wl->flags); out: @@ -76,7 +82,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl) struct wl12xx_vif *wlvif; u32 timeout; - if (wl->quirks & WLCORE_QUIRK_NO_ELP) + if (wl->sleep_auth != WL1271_PSM_ELP) return; /* we shouldn't get consecutive sleep requests */ @@ -135,7 +141,11 @@ int wl1271_ps_elp_wakeup(struct wl1271 *wl) wl->elp_compl = &compl; spin_unlock_irqrestore(&wl->wl_lock, flags); - wl1271_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); + ret = wlcore_raw_write32(wl, HW_ACCESS_ELP_CTRL_REG, ELPCTRL_WAKE_UP); + if (ret < 0) { + wl12xx_queue_recovery_work(wl); + goto err; + } if (!pending) { ret = wait_for_completion_timeout( diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 78200dcacfca..f55e2f9e7ac5 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -127,7 +127,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, } if (rx_align == WLCORE_RX_BUF_UNALIGNED) - reserved = NET_IP_ALIGN; + reserved = RX_BUF_ALIGN; /* the data read starts with the descriptor */ desc = (struct wl1271_rx_descriptor *) data; @@ -175,7 +175,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, */ memcpy(buf, data + sizeof(*desc), pkt_data_len); if (rx_align == WLCORE_RX_BUF_PADDED) - skb_pull(skb, NET_IP_ALIGN); + skb_pull(skb, RX_BUF_ALIGN); *hlid = desc->hlid; @@ -200,7 +200,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length, return is_data; } -void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) +int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) { unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; u32 buf_size; @@ -211,6 +211,7 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) u32 pkt_offset, des; u8 hlid; enum wl_rx_buf_align rx_align; + int ret = 0; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; @@ -234,9 +235,14 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) /* Read all available packets at once */ des = le32_to_cpu(status->rx_pkt_descs[drv_rx_counter]); - wlcore_hw_prepare_read(wl, des, buf_size); - wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, - buf_size, true); + ret = wlcore_hw_prepare_read(wl, des, buf_size); + if (ret < 0) + goto out; + + ret = wlcore_read_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, + buf_size, true); + if (ret < 0) + goto out; /* Split data into separate packets */ pkt_offset = 0; @@ -273,11 +279,17 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status) * Write the driver's packet counter to the FW. This is only required * for older hardware revisions */ - if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) - wl1271_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, - wl->rx_counter); + if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { + ret = wlcore_write32(wl, WL12XX_REG_RX_DRIVER_COUNTER, + wl->rx_counter); + if (ret < 0) + goto out; + } wl12xx_rearm_rx_streaming(wl, active_hlids); + +out: + return ret; } #ifdef CONFIG_PM @@ -306,14 +318,19 @@ int wl1271_rx_filter_enable(struct wl1271 *wl, return 0; } -void wl1271_rx_filter_clear_all(struct wl1271 *wl) +int wl1271_rx_filter_clear_all(struct wl1271 *wl) { - int i; + int i, ret = 0; for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) { if (!wl->rx_filter_enabled[i]) continue; - wl1271_rx_filter_enable(wl, i, 0, NULL); + ret = wl1271_rx_filter_enable(wl, i, 0, NULL); + if (ret) + goto out; } + +out: + return ret; } #endif /* CONFIG_PM */ diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index 9be780179456..71eba1899915 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -103,6 +103,12 @@ /* If set, the buffer was padded by the FW to be 4 bytes aligned */ #define RX_BUF_PADDED_PAYLOAD BIT(30) +/* + * Account for the padding inserted by the FW in case of RX_ALIGNMENT + * or for fixing alignment in case the packet wasn't aligned. + */ +#define RX_BUF_ALIGN 2 + /* Describes the alignment state of a Rx buffer */ enum wl_rx_buf_align { WLCORE_RX_BUF_ALIGNED, @@ -137,11 +143,11 @@ struct wl1271_rx_descriptor { u8 reserved; } __packed; -void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status_1 *status); +int wlcore_rx(struct wl1271 *wl, struct wl_fw_status_1 *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); int wl1271_rx_filter_enable(struct wl1271 *wl, int index, bool enable, struct wl12xx_rx_filter *filter); -void wl1271_rx_filter_clear_all(struct wl1271 *wl); +int wl1271_rx_filter_clear_all(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index d9daed53ceb7..dbeca1bfbb2c 100644 --- a/drivers/net/wireless/ti/wlcore/scan.c +++ b/drivers/net/wireless/ti/wlcore/scan.c @@ -226,7 +226,7 @@ static int wl1271_scan_send(struct wl1271 *wl, struct ieee80211_vif *vif, cmd->params.role_id, band, wl->scan.ssid, wl->scan.ssid_len, wl->scan.req->ie, - wl->scan.req->ie_len); + wl->scan.req->ie_len, false); if (ret < 0) { wl1271_error("PROBE request template failed"); goto out; @@ -633,7 +633,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl, for (j = 0; j < cmd->n_ssids; j++) if ((req->ssids[i].ssid_len == - req->ssids[j].ssid_len) && + cmd->ssids[j].len) && !memcmp(req->ssids[i].ssid, cmd->ssids[j].ssid, req->ssids[i].ssid_len)) { @@ -722,7 +722,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], - ies->len[band]); + ies->len[band], true); if (ret < 0) { wl1271_error("2.4GHz PROBE request template failed"); goto out; @@ -736,7 +736,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl, req->ssids[0].ssid, req->ssids[0].ssid_len, ies->ie[band], - ies->len[band]); + ies->len[band], true); if (ret < 0) { wl1271_error("5GHz PROBE request template failed"); goto out; @@ -766,7 +766,8 @@ int wl1271_scan_sched_scan_start(struct wl1271 *wl, struct wl12xx_vif *wlvif) if (wlvif->bss_type != BSS_TYPE_STA_BSS) return -EOPNOTSUPP; - if (test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) + if ((wl->quirks & WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN) && + test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags)) return -EBUSY; start = kzalloc(sizeof(*start), GFP_KERNEL); diff --git a/drivers/net/wireless/ti/wlcore/sdio.c b/drivers/net/wireless/ti/wlcore/sdio.c index c67ec482e445..73ace4b2604e 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -71,8 +71,8 @@ static void wl1271_sdio_set_block_size(struct device *child, sdio_release_host(func); } -static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, - size_t len, bool fixed) +static int __must_check wl12xx_sdio_raw_read(struct device *child, int addr, + void *buf, size_t len, bool fixed) { int ret; struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); @@ -103,12 +103,14 @@ static void wl12xx_sdio_raw_read(struct device *child, int addr, void *buf, sdio_release_host(func); - if (ret) + if (WARN_ON(ret)) dev_err(child->parent, "sdio read failed (%d)\n", ret); + + return ret; } -static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, - size_t len, bool fixed) +static int __must_check wl12xx_sdio_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) { int ret; struct wl12xx_sdio_glue *glue = dev_get_drvdata(child->parent); @@ -139,25 +141,30 @@ static void wl12xx_sdio_raw_write(struct device *child, int addr, void *buf, sdio_release_host(func); - if (ret) + if (WARN_ON(ret)) dev_err(child->parent, "sdio write failed (%d)\n", ret); + + return ret; } static int wl12xx_sdio_power_on(struct wl12xx_sdio_glue *glue) { int ret; struct sdio_func *func = dev_to_sdio_func(glue->dev); + struct mmc_card *card = func->card; - /* If enabled, tell runtime PM not to power off the card */ - if (pm_runtime_enabled(&func->dev)) { - ret = pm_runtime_get_sync(&func->dev); - if (ret < 0) - goto out; - } else { - /* Runtime PM is disabled: power up the card manually */ - ret = mmc_power_restore_host(func->card->host); - if (ret < 0) + ret = pm_runtime_get_sync(&card->dev); + if (ret) { + /* + * Runtime PM might be temporarily disabled, or the device + * might have a positive reference counter. Make sure it is + * really powered on. + */ + ret = mmc_power_restore_host(card->host); + if (ret < 0) { + pm_runtime_put_sync(&card->dev); goto out; + } } sdio_claim_host(func); @@ -172,20 +179,21 @@ static int wl12xx_sdio_power_off(struct wl12xx_sdio_glue *glue) { int ret; struct sdio_func *func = dev_to_sdio_func(glue->dev); + struct mmc_card *card = func->card; sdio_claim_host(func); sdio_disable_func(func); sdio_release_host(func); - /* Power off the card manually, even if runtime PM is enabled. */ - ret = mmc_power_save_host(func->card->host); + /* Power off the card manually in case it wasn't powered off above */ + ret = mmc_power_save_host(card->host); if (ret < 0) - return ret; + goto out; - /* If enabled, let runtime PM know the card is powered off */ - if (pm_runtime_enabled(&func->dev)) - ret = pm_runtime_put_sync(&func->dev); + /* Let runtime PM know the card is powered off */ + pm_runtime_put_sync(&card->dev); +out: return ret; } @@ -403,9 +411,3 @@ MODULE_PARM_DESC(dump, "Enable sdio read/write dumps."); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); -MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); -MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); -MODULE_FIRMWARE(WL127X_PLT_FW_NAME); -MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); -MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); -MODULE_FIRMWARE(WL128X_PLT_FW_NAME); diff --git a/drivers/net/wireless/ti/wlcore/spi.c b/drivers/net/wireless/ti/wlcore/spi.c index 553cd3cbb98c..8da4ed243ebc 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -193,8 +193,8 @@ static int wl12xx_spi_read_busy(struct device *child) return -ETIMEDOUT; } -static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, - size_t len, bool fixed) +static int __must_check wl12xx_spi_raw_read(struct device *child, int addr, + void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct wl1271 *wl = dev_get_drvdata(child); @@ -238,7 +238,7 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, if (!(busy_buf[WL1271_BUSY_WORD_CNT - 1] & 0x1) && wl12xx_spi_read_busy(child)) { memset(buf, 0, chunk_len); - return; + return 0; } spi_message_init(&m); @@ -256,10 +256,12 @@ static void wl12xx_spi_raw_read(struct device *child, int addr, void *buf, buf += chunk_len; len -= chunk_len; } + + return 0; } -static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, - size_t len, bool fixed) +static int __must_check wl12xx_spi_raw_write(struct device *child, int addr, + void *buf, size_t len, bool fixed) { struct wl12xx_spi_glue *glue = dev_get_drvdata(child->parent); struct spi_transfer t[2 * WSPI_MAX_NUM_OF_CHUNKS]; @@ -304,6 +306,8 @@ static void wl12xx_spi_raw_write(struct device *child, int addr, void *buf, } spi_sync(to_spi_device(glue->dev), &m); + + return 0; } static struct wl1271_if_operations spi_ops = { @@ -431,10 +435,4 @@ module_exit(wl1271_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>"); MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>"); -MODULE_FIRMWARE(WL127X_FW_NAME_SINGLE); -MODULE_FIRMWARE(WL127X_FW_NAME_MULTI); -MODULE_FIRMWARE(WL127X_PLT_FW_NAME); -MODULE_FIRMWARE(WL128X_FW_NAME_SINGLE); -MODULE_FIRMWARE(WL128X_FW_NAME_MULTI); -MODULE_FIRMWARE(WL128X_PLT_FW_NAME); MODULE_ALIAS("spi:wl1271"); diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index 0e59ea2cdd39..d6f57e2c03cf 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -40,7 +40,7 @@ enum wl1271_tm_commands { WL1271_TM_CMD_CONFIGURE, WL1271_TM_CMD_NVS_PUSH, /* Not in use. Keep to not break ABI */ WL1271_TM_CMD_SET_PLT_MODE, - WL1271_TM_CMD_RECOVER, + WL1271_TM_CMD_RECOVER, /* Not in use. Keep to not break ABI */ WL1271_TM_CMD_GET_MAC, __WL1271_TM_CMD_AFTER_LAST @@ -108,6 +108,20 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) } if (answer) { + /* If we got bip calibration answer print radio status */ + struct wl1271_cmd_cal_p2g *params = + (struct wl1271_cmd_cal_p2g *) buf; + + s16 radio_status = (s16) le16_to_cpu(params->radio_status); + + if (params->test.id == TEST_CMD_P2G_CAL && + radio_status < 0) + wl1271_warning("testmode cmd: radio status=%d", + radio_status); + else + wl1271_info("testmode cmd: radio status=%d", + radio_status); + len = nla_total_size(buf_len); skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); if (!skb) { @@ -258,15 +272,6 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) return ret; } -static int wl1271_tm_cmd_recover(struct wl1271 *wl, struct nlattr *tb[]) -{ - wl1271_debug(DEBUG_TESTMODE, "testmode cmd recover"); - - wl12xx_queue_recovery_work(wl); - - return 0; -} - static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) { struct sk_buff *skb; @@ -336,8 +341,6 @@ int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) return wl1271_tm_cmd_configure(wl, tb); case WL1271_TM_CMD_SET_PLT_MODE: return wl1271_tm_cmd_set_plt_mode(wl, tb); - case WL1271_TM_CMD_RECOVER: - return wl1271_tm_cmd_recover(wl, tb); case WL1271_TM_CMD_GET_MAC: return wl12xx_tm_cmd_get_mac(wl, tb); default: diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 6983e7a829d0..6a28aeecf004 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -305,11 +305,15 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, if (is_dummy || !wlvif) rate_idx = 0; else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { - /* if the packets are destined for AP (have a STA entry) - send them with AP rate policies, otherwise use default - basic rates */ + /* + * if the packets are destined for AP (have a STA entry) + * send them with AP rate policies (EAPOLs are an exception), + * otherwise use default basic rates + */ if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) rate_idx = wlvif->sta.p2p_rate_idx; + else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + rate_idx = wlvif->sta.basic_rate_idx; else if (control->control.sta) rate_idx = wlvif->sta.ap_rate_idx; else @@ -348,8 +352,10 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool is_dummy; bool is_gem = false; - if (!skb) + if (!skb) { + wl1271_error("discarding null skb"); return -EINVAL; + } info = IEEE80211_SKB_CB(skb); @@ -658,7 +664,17 @@ void wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) } } -void wl1271_tx_work_locked(struct wl1271 *wl) +/* + * Returns failure values only in case of failed bus ops within this function. + * wl1271_prepare_tx_frame retvals won't be returned in order to avoid + * triggering recovery by higher layers when not necessary. + * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery + * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame + * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING + * within prepare_tx_frame code but there's nothing we should do about those + * as well. + */ +int wlcore_tx_work_locked(struct wl1271 *wl) { struct wl12xx_vif *wlvif; struct sk_buff *skb; @@ -666,10 +682,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) u32 buf_offset = 0, last_len = 0; bool sent_packets = false; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; - int ret; + int ret = 0; + int bus_ret = 0; if (unlikely(wl->state == WL1271_STATE_OFF)) - return; + return 0; while ((skb = wl1271_skb_dequeue(wl))) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); @@ -690,8 +707,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); - wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); + bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, + wl->aggr_buf, buf_offset, true); + if (bus_ret < 0) + goto out; + sent_packets = true; buf_offset = 0; continue; @@ -727,8 +747,11 @@ void wl1271_tx_work_locked(struct wl1271 *wl) out_ack: if (buf_offset) { buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); - wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, - buf_offset, true); + bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, + buf_offset, true); + if (bus_ret < 0) + goto out; + sent_packets = true; } if (sent_packets) { @@ -736,13 +759,19 @@ out_ack: * Interrupt the firmware with the new packets. This is only * required for older hardware revisions */ - if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) - wl1271_write32(wl, WL12XX_HOST_WR_ACCESS, - wl->tx_packets_count); + if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { + bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS, + wl->tx_packets_count); + if (bus_ret < 0) + goto out; + } wl1271_handle_tx_low_watermark(wl); } wl12xx_rearm_rx_streaming(wl, active_hlids); + +out: + return bus_ret; } void wl1271_tx_work(struct work_struct *work) @@ -755,7 +784,11 @@ void wl1271_tx_work(struct work_struct *work) if (ret < 0) goto out; - wl1271_tx_work_locked(wl); + ret = wlcore_tx_work_locked(wl); + if (ret < 0) { + wl12xx_queue_recovery_work(wl); + goto out; + } wl1271_ps_elp_sleep(wl); out: @@ -877,22 +910,28 @@ static void wl1271_tx_complete_packet(struct wl1271 *wl, } /* Called upon reception of a TX complete interrupt */ -void wl1271_tx_complete(struct wl1271 *wl) +int wlcore_tx_complete(struct wl1271 *wl) { struct wl1271_acx_mem_map *memmap = (struct wl1271_acx_mem_map *)wl->target_mem_map; u32 count, fw_counter; u32 i; + int ret; /* read the tx results from the chipset */ - wl1271_read(wl, le32_to_cpu(memmap->tx_result), - wl->tx_res_if, sizeof(*wl->tx_res_if), false); + ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result), + wl->tx_res_if, sizeof(*wl->tx_res_if), false); + if (ret < 0) + goto out; + fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); /* write host counter to chipset (to ack) */ - wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + - offsetof(struct wl1271_tx_hw_res_if, - tx_result_host_counter), fw_counter); + ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) + + offsetof(struct wl1271_tx_hw_res_if, + tx_result_host_counter), fw_counter); + if (ret < 0) + goto out; count = fw_counter - wl->tx_results_count; wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); @@ -912,8 +951,11 @@ void wl1271_tx_complete(struct wl1271 *wl) wl->tx_results_count++; } + +out: + return ret; } -EXPORT_SYMBOL(wl1271_tx_complete); +EXPORT_SYMBOL(wlcore_tx_complete); void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) { diff --git a/drivers/net/wireless/ti/wlcore/tx.h b/drivers/net/wireless/ti/wlcore/tx.h index fa4be1b91135..1e939b016155 100644 --- a/drivers/net/wireless/ti/wlcore/tx.h +++ b/drivers/net/wireless/ti/wlcore/tx.h @@ -234,8 +234,8 @@ static inline int wl1271_tx_total_queue_count(struct wl1271 *wl) } void wl1271_tx_work(struct work_struct *work); -void wl1271_tx_work_locked(struct wl1271 *wl); -void wl1271_tx_complete(struct wl1271 *wl); +int wlcore_tx_work_locked(struct wl1271 *wl); +int wlcore_tx_complete(struct wl1271 *wl); void wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_tx_reset(struct wl1271 *wl); void wl1271_tx_flush(struct wl1271 *wl); diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 761a72f4b8d1..27ccc275a1c1 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -41,9 +41,9 @@ struct wlcore_ops { int (*identify_fw)(struct wl1271 *wl); int (*boot)(struct wl1271 *wl); int (*plt_init)(struct wl1271 *wl); - void (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, - void *buf, size_t len); - void (*ack_event)(struct wl1271 *wl); + int (*trigger_cmd)(struct wl1271 *wl, int cmd_box_addr, + void *buf, size_t len); + int (*ack_event)(struct wl1271 *wl); u32 (*calc_tx_blocks)(struct wl1271 *wl, u32 len, u32 spare_blks); void (*set_tx_desc_blocks)(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, @@ -53,17 +53,17 @@ struct wlcore_ops { struct sk_buff *skb); enum wl_rx_buf_align (*get_rx_buf_align)(struct wl1271 *wl, u32 rx_desc); - void (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); + int (*prepare_read)(struct wl1271 *wl, u32 rx_desc, u32 len); u32 (*get_rx_packet_len)(struct wl1271 *wl, void *rx_data, u32 data_len); - void (*tx_delayed_compl)(struct wl1271 *wl); + int (*tx_delayed_compl)(struct wl1271 *wl); void (*tx_immediate_compl)(struct wl1271 *wl); int (*hw_init)(struct wl1271 *wl); int (*init_vif)(struct wl1271 *wl, struct wl12xx_vif *wlvif); u32 (*sta_get_ap_rate_mask)(struct wl1271 *wl, struct wl12xx_vif *wlvif); - s8 (*get_pg_ver)(struct wl1271 *wl); - void (*get_mac)(struct wl1271 *wl); + int (*get_pg_ver)(struct wl1271 *wl, s8 *ver); + int (*get_mac)(struct wl1271 *wl); void (*set_tx_desc_csum)(struct wl1271 *wl, struct wl1271_tx_hw_descr *desc, struct sk_buff *skb); @@ -304,7 +304,7 @@ struct wl1271 { s8 noise; /* bands supported by this instance of wl12xx */ - struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; + struct ieee80211_supported_band bands[WLCORE_NUM_BANDS]; /* * wowlan trigger was configured during suspend. @@ -371,7 +371,7 @@ struct wl1271 { u8 hw_min_ht_rate; /* HW HT (11n) capabilities */ - struct ieee80211_sta_ht_cap ht_cap[IEEE80211_NUM_BANDS]; + struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS]; /* size of the private FW status data */ size_t fw_status_priv_len; @@ -387,6 +387,12 @@ struct wl1271 { /* mutex for protecting the tx_flush function */ struct mutex flush_mutex; + + /* sleep auth value currently configured to FW */ + int sleep_auth; + + /* the minimum FW version required for the driver to work */ + unsigned int min_fw_ver[NUM_FW_VER]; }; int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); @@ -398,6 +404,25 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, struct ieee80211_sta *sta, struct ieee80211_key_conf *key_conf); +static inline void +wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, + struct ieee80211_sta_ht_cap *ht_cap) +{ + memcpy(&wl->ht_cap[band], ht_cap, sizeof(*ht_cap)); +} + +static inline void +wlcore_set_min_fw_ver(struct wl1271 *wl, unsigned int chip, + unsigned int iftype, unsigned int major, + unsigned int subtype, unsigned int minor) +{ + wl->min_fw_ver[FW_VER_CHIP] = chip; + wl->min_fw_ver[FW_VER_IF_TYPE] = iftype; + wl->min_fw_ver[FW_VER_MAJOR] = major; + wl->min_fw_ver[FW_VER_SUBTYPE] = subtype; + wl->min_fw_ver[FW_VER_MINOR] = minor; +} + /* Firmware image load chunk size */ #define CHUNK_SIZE 16384 @@ -427,6 +452,12 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, /* extra header space is required for TKIP */ #define WLCORE_QUIRK_TKIP_HEADER_SPACE BIT(8) +/* Some firmwares not support sched scans while connected */ +#define WLCORE_QUIRK_NO_SCHED_SCAN_WHILE_CONN BIT(9) + +/* separate probe response templates for one-shot and sched scans */ +#define WLCORE_QUIRK_DUAL_PROBE_TMPL BIT(10) + /* TODO: move to the lower drivers when all usages are abstracted */ #define CHIP_ID_1271_PG10 (0x4030101) #define CHIP_ID_1271_PG20 (0x4030111) diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 8260b1e9288a..0187eef4fb07 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -35,15 +35,6 @@ #include "conf.h" #include "ini.h" -#define WL127X_FW_NAME_MULTI "ti-connectivity/wl127x-fw-4-mr.bin" -#define WL127X_FW_NAME_SINGLE "ti-connectivity/wl127x-fw-4-sr.bin" - -#define WL128X_FW_NAME_MULTI "ti-connectivity/wl128x-fw-4-mr.bin" -#define WL128X_FW_NAME_SINGLE "ti-connectivity/wl128x-fw-4-sr.bin" - -#define WL127X_PLT_FW_NAME "ti-connectivity/wl127x-fw-4-plt.bin" -#define WL128X_PLT_FW_NAME "ti-connectivity/wl128x-fw-4-plt.bin" - /* * wl127x and wl128x are using the same NVS file name. However, the * ini parameters between them are different. The driver validates @@ -71,6 +62,9 @@ #define WL12XX_INVALID_ROLE_ID 0xff #define WL12XX_INVALID_LINK_ID 0xff +/* the driver supports the 2.4Ghz and 5Ghz bands */ +#define WLCORE_NUM_BANDS 2 + #define WL12XX_MAX_RATE_POLICIES 16 /* Defined by FW as 0. Will not be freed or allocated. */ @@ -209,10 +203,10 @@ struct wl1271_scan { }; struct wl1271_if_operations { - void (*read)(struct device *child, int addr, void *buf, size_t len, - bool fixed); - void (*write)(struct device *child, int addr, void *buf, size_t len, - bool fixed); + int __must_check (*read)(struct device *child, int addr, void *buf, + size_t len, bool fixed); + int __must_check (*write)(struct device *child, int addr, void *buf, + size_t len, bool fixed); void (*reset)(struct device *child); void (*init)(struct device *child); int (*power)(struct device *child, bool enable); @@ -247,6 +241,7 @@ enum wl12xx_flags { WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, WL1271_FLAG_INTENDED_FW_RECOVERY, + WL1271_FLAG_IO_FAILED, }; enum wl12xx_vif_flags { @@ -368,7 +363,7 @@ struct wl12xx_vif { int channel; enum nl80211_channel_type channel_type; - u32 bitrate_masks[IEEE80211_NUM_BANDS]; + u32 bitrate_masks[WLCORE_NUM_BANDS]; u32 basic_rate_set; /* diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c index 1f74a77d040d..e7fd4938f9bc 100644 --- a/drivers/nfc/nfcwilink.c +++ b/drivers/nfc/nfcwilink.c @@ -535,9 +535,10 @@ static int nfcwilink_probe(struct platform_device *pdev) drv->pdev = pdev; protocols = NFC_PROTO_JEWEL_MASK - | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK - | NFC_PROTO_ISO14443_MASK - | NFC_PROTO_NFC_DEP_MASK; + | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK + | NFC_PROTO_ISO14443_MASK + | NFC_PROTO_ISO14443_B_MASK + | NFC_PROTO_NFC_DEP_MASK; drv->ndev = nci_allocate_device(&nfcwilink_ops, protocols, diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index 9ac829e22e73..d606f52fec84 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -38,9 +38,44 @@ #define SCM_VENDOR_ID 0x4E6 #define SCL3711_PRODUCT_ID 0x5591 +#define SONY_VENDOR_ID 0x054c +#define PASORI_PRODUCT_ID 0x02e1 + +#define PN533_QUIRKS_TYPE_A BIT(0) +#define PN533_QUIRKS_TYPE_F BIT(1) +#define PN533_QUIRKS_DEP BIT(2) +#define PN533_QUIRKS_RAW_EXCHANGE BIT(3) + +#define PN533_DEVICE_STD 0x1 +#define PN533_DEVICE_PASORI 0x2 + +#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\ + NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\ + NFC_PROTO_NFC_DEP_MASK |\ + NFC_PROTO_ISO14443_B_MASK) + +#define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \ + NFC_PROTO_MIFARE_MASK | \ + NFC_PROTO_FELICA_MASK | \ + NFC_PROTO_ISO14443_MASK | \ + NFC_PROTO_NFC_DEP_MASK) + static const struct usb_device_id pn533_table[] = { - { USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) }, - { USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = PN533_VENDOR_ID, + .idProduct = PN533_PRODUCT_ID, + .driver_info = PN533_DEVICE_STD, + }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = SCM_VENDOR_ID, + .idProduct = SCL3711_PRODUCT_ID, + .driver_info = PN533_DEVICE_STD, + }, + { .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = SONY_VENDOR_ID, + .idProduct = PASORI_PRODUCT_ID, + .driver_info = PN533_DEVICE_PASORI, + }, { } }; MODULE_DEVICE_TABLE(usb, pn533_table); @@ -72,6 +107,7 @@ MODULE_DEVICE_TABLE(usb, pn533_table); #define PN533_CMD_GET_FIRMWARE_VERSION 0x02 #define PN533_CMD_RF_CONFIGURATION 0x32 #define PN533_CMD_IN_DATA_EXCHANGE 0x40 +#define PN533_CMD_IN_COMM_THRU 0x42 #define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A #define PN533_CMD_IN_ATR 0x50 #define PN533_CMD_IN_RELEASE 0x52 @@ -109,6 +145,7 @@ struct pn533_fw_version { /* PN533_CMD_RF_CONFIGURATION */ #define PN533_CFGITEM_TIMING 0x02 #define PN533_CFGITEM_MAX_RETRIES 0x05 +#define PN533_CFGITEM_PASORI 0x82 #define PN533_CONFIG_TIMING_102 0xb #define PN533_CONFIG_TIMING_204 0xc @@ -344,6 +381,8 @@ struct pn533 { u8 tgt_available_prots; u8 tgt_active_prot; u8 tgt_mode; + + u32 device_type; }; struct pn533_frame { @@ -950,7 +989,7 @@ static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data, if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len)) return -EPROTO; - nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK; + nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_B_MASK; return 0; } @@ -1057,7 +1096,7 @@ static void pn533_poll_create_mod_list(struct pn533 *dev, if (im_protocols & NFC_PROTO_JEWEL_MASK) pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL); - if (im_protocols & NFC_PROTO_ISO14443_MASK) + if (im_protocols & NFC_PROTO_ISO14443_B_MASK) pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B); if (tm_protocols) @@ -1768,13 +1807,30 @@ static int pn533_build_tx_frame(struct pn533 *dev, struct sk_buff *skb, } if (target == true) { - skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); - out_frame = (struct pn533_frame *) skb->data; + switch (dev->device_type) { + case PN533_DEVICE_PASORI: + if (dev->tgt_active_prot == NFC_PROTO_FELICA) { + skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); + out_frame = (struct pn533_frame *) skb->data; + pn533_tx_frame_init(out_frame, + PN533_CMD_IN_COMM_THRU); + + break; + } + + default: + skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN); + out_frame = (struct pn533_frame *) skb->data; + pn533_tx_frame_init(out_frame, + PN533_CMD_IN_DATA_EXCHANGE); + tg = 1; + memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), + &tg, sizeof(u8)); + out_frame->datalen += sizeof(u8); + + break; + } - pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE); - tg = 1; - memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8)); - out_frame->datalen += sizeof(u8); } else { skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN - 1); out_frame = (struct pn533_frame *) skb->data; @@ -2101,7 +2157,28 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata, return rc; } -struct nfc_ops pn533_nfc_ops = { +static int pn533_fw_reset(struct pn533 *dev) +{ + int rc; + u8 *params; + + nfc_dev_dbg(&dev->interface->dev, "%s", __func__); + + pn533_tx_frame_init(dev->out_frame, 0x18); + + params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame); + params[0] = 0x1; + dev->out_frame->datalen += 1; + + pn533_tx_frame_finish(dev->out_frame); + + rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame, + dev->in_maxlen); + + return rc; +} + +static struct nfc_ops pn533_nfc_ops = { .dev_up = NULL, .dev_down = NULL, .dep_link_up = pn533_dep_link_up, @@ -2114,6 +2191,84 @@ struct nfc_ops pn533_nfc_ops = { .tm_send = pn533_tm_send, }; +static int pn533_setup(struct pn533 *dev) +{ + struct pn533_config_max_retries max_retries; + struct pn533_config_timing timing; + u8 pasori_cfg[3] = {0x08, 0x01, 0x08}; + int rc; + + switch (dev->device_type) { + case PN533_DEVICE_STD: + max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; + max_retries.mx_rty_psl = 2; + max_retries.mx_rty_passive_act = + PN533_CONFIG_MAX_RETRIES_NO_RETRY; + + timing.rfu = PN533_CONFIG_TIMING_102; + timing.atr_res_timeout = PN533_CONFIG_TIMING_204; + timing.dep_timeout = PN533_CONFIG_TIMING_409; + + break; + + case PN533_DEVICE_PASORI: + max_retries.mx_rty_atr = 0x2; + max_retries.mx_rty_psl = 0x1; + max_retries.mx_rty_passive_act = + PN533_CONFIG_MAX_RETRIES_NO_RETRY; + + timing.rfu = PN533_CONFIG_TIMING_102; + timing.atr_res_timeout = PN533_CONFIG_TIMING_102; + timing.dep_timeout = PN533_CONFIG_TIMING_204; + + break; + + default: + nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", + dev->device_type); + return -EINVAL; + } + + rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, + (u8 *)&max_retries, sizeof(max_retries)); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Error on setting MAX_RETRIES config"); + return rc; + } + + + rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, + (u8 *)&timing, sizeof(timing)); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Error on setting RF timings"); + return rc; + } + + switch (dev->device_type) { + case PN533_DEVICE_STD: + break; + + case PN533_DEVICE_PASORI: + pn533_fw_reset(dev); + + rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI, + pasori_cfg, 3); + if (rc) { + nfc_dev_err(&dev->interface->dev, + "Error while settings PASORI config"); + return rc; + } + + pn533_fw_reset(dev); + + break; + } + + return 0; +} + static int pn533_probe(struct usb_interface *interface, const struct usb_device_id *id) { @@ -2121,8 +2276,6 @@ static int pn533_probe(struct usb_interface *interface, struct pn533 *dev; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; - struct pn533_config_max_retries max_retries; - struct pn533_config_timing timing; int in_endpoint = 0; int out_endpoint = 0; int rc = -ENOMEM; @@ -2208,10 +2361,22 @@ static int pn533_probe(struct usb_interface *interface, nfc_dev_info(&dev->interface->dev, "NXP PN533 firmware ver %d.%d now" " attached", fw_ver->ver, fw_ver->rev); - protocols = NFC_PROTO_JEWEL_MASK - | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK - | NFC_PROTO_ISO14443_MASK - | NFC_PROTO_NFC_DEP_MASK; + dev->device_type = id->driver_info; + switch (dev->device_type) { + case PN533_DEVICE_STD: + protocols = PN533_ALL_PROTOCOLS; + break; + + case PN533_DEVICE_PASORI: + protocols = PN533_NO_TYPE_B_PROTOCOLS; + break; + + default: + nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n", + dev->device_type); + rc = -EINVAL; + goto destroy_wq; + } dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols, PN533_CMD_DATAEXCH_HEAD_LEN, @@ -2226,30 +2391,9 @@ static int pn533_probe(struct usb_interface *interface, if (rc) goto free_nfc_dev; - max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS; - max_retries.mx_rty_psl = 2; - max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY; - - rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES, - (u8 *) &max_retries, sizeof(max_retries)); - - if (rc) { - nfc_dev_err(&dev->interface->dev, "Error on setting MAX_RETRIES" - " config"); - goto unregister_nfc_dev; - } - - timing.rfu = PN533_CONFIG_TIMING_102; - timing.atr_res_timeout = PN533_CONFIG_TIMING_204; - timing.dep_timeout = PN533_CONFIG_TIMING_409; - - rc = pn533_set_configuration(dev, PN533_CFGITEM_TIMING, - (u8 *) &timing, sizeof(timing)); - if (rc) { - nfc_dev_err(&dev->interface->dev, - "Error on setting RF timings"); + rc = pn533_setup(dev); + if (rc) goto unregister_nfc_dev; - } return 0; diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c index 457eac35dc74..aa71807189ba 100644 --- a/drivers/nfc/pn544_hci.c +++ b/drivers/nfc/pn544_hci.c @@ -108,16 +108,22 @@ enum pn544_state { #define PN544_NFC_WI_MGMT_GATE 0xA1 -static u8 pn544_custom_gates[] = { - PN544_SYS_MGMT_GATE, - PN544_SWP_MGMT_GATE, - PN544_POLLING_LOOP_MGMT_GATE, - PN544_NFC_WI_MGMT_GATE, - PN544_RF_READER_F_GATE, - PN544_RF_READER_JEWEL_GATE, - PN544_RF_READER_ISO15693_GATE, - PN544_RF_READER_NFCIP1_INITIATOR_GATE, - PN544_RF_READER_NFCIP1_TARGET_GATE +static struct nfc_hci_gate pn544_gates[] = { + {NFC_HCI_ADMIN_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_LOOPBACK_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_ID_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_LINK_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_RF_READER_B_GATE, NFC_HCI_INVALID_PIPE}, + {NFC_HCI_RF_READER_A_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_SYS_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_SWP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_POLLING_LOOP_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_NFC_WI_MGMT_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_F_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_JEWEL_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_NFCIP1_INITIATOR_GATE, NFC_HCI_INVALID_PIPE}, + {PN544_RF_READER_NFCIP1_TARGET_GATE, NFC_HCI_INVALID_PIPE} }; /* Largest headroom needed for outgoing custom commands */ @@ -377,6 +383,9 @@ static int pn544_hci_open(struct nfc_shdlc *shdlc) r = pn544_hci_enable(info, HCI_MODE); + if (r == 0) + info->state = PN544_ST_READY; + out: mutex_unlock(&info->info_lock); return r; @@ -393,6 +402,8 @@ static void pn544_hci_close(struct nfc_shdlc *shdlc) pn544_hci_disable(info); + info->state = PN544_ST_COLD; + out: mutex_unlock(&info->info_lock); } @@ -844,10 +855,9 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, goto err_rti; } - init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); + init_data.gate_count = ARRAY_SIZE(pn544_gates); - memcpy(init_data.gates, pn544_custom_gates, - ARRAY_SIZE(pn544_custom_gates)); + memcpy(init_data.gates, pn544_gates, sizeof(pn544_gates)); /* * TODO: Session id must include the driver name + some bus addr @@ -859,6 +869,7 @@ static int __devinit pn544_hci_probe(struct i2c_client *client, NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK | + NFC_PROTO_ISO14443_B_MASK | NFC_PROTO_NFC_DEP_MASK; info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 8deaf6d050c3..03b2f30d2ace 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -70,6 +70,13 @@ struct bcma_host_ops { /* Core-ID values. */ #define BCMA_CORE_OOB_ROUTER 0x367 /* Out of band */ +#define BCMA_CORE_4706_CHIPCOMMON 0x500 +#define BCMA_CORE_4706_SOC_RAM 0x50E +#define BCMA_CORE_4706_MAC_GBIT 0x52D +#define BCMA_CORE_AMEMC 0x52E /* DDR1/2 memory controller core */ +#define BCMA_CORE_ALTA 0x534 /* I2S core */ +#define BCMA_CORE_4706_MAC_GBIT_COMMON 0x5DC +#define BCMA_CORE_DDR23_PHY 0x5DD #define BCMA_CORE_INVALID 0x700 #define BCMA_CORE_CHIPCOMMON 0x800 #define BCMA_CORE_ILINE20 0x801 @@ -130,6 +137,36 @@ struct bcma_host_ops { #define BCMA_MAX_NR_CORES 16 +/* Chip IDs of PCIe devices */ +#define BCMA_CHIP_ID_BCM4313 0x4313 +#define BCMA_CHIP_ID_BCM43224 43224 +#define BCMA_PKG_ID_BCM43224_FAB_CSM 0x8 +#define BCMA_PKG_ID_BCM43224_FAB_SMIC 0xa +#define BCMA_CHIP_ID_BCM43225 43225 +#define BCMA_CHIP_ID_BCM43227 43227 +#define BCMA_CHIP_ID_BCM43228 43228 +#define BCMA_CHIP_ID_BCM43421 43421 +#define BCMA_CHIP_ID_BCM43428 43428 +#define BCMA_CHIP_ID_BCM43431 43431 +#define BCMA_CHIP_ID_BCM43460 43460 +#define BCMA_CHIP_ID_BCM4331 0x4331 +#define BCMA_CHIP_ID_BCM6362 0x6362 +#define BCMA_CHIP_ID_BCM4360 0x4360 +#define BCMA_CHIP_ID_BCM4352 0x4352 + +/* Chip IDs of SoCs */ +#define BCMA_CHIP_ID_BCM4706 0x5300 +#define BCMA_CHIP_ID_BCM4716 0x4716 +#define BCMA_PKG_ID_BCM4716 8 +#define BCMA_PKG_ID_BCM4717 9 +#define BCMA_PKG_ID_BCM4718 10 +#define BCMA_CHIP_ID_BCM47162 47162 +#define BCMA_CHIP_ID_BCM4748 0x4748 +#define BCMA_CHIP_ID_BCM4749 0x4749 +#define BCMA_CHIP_ID_BCM5356 0x5356 +#define BCMA_CHIP_ID_BCM5357 0x5357 +#define BCMA_CHIP_ID_BCM53572 53572 + struct bcma_device { struct bcma_bus *bus; struct bcma_device_id id; diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index 8bbfe31fbac8..fbd0d49dc4d2 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -88,6 +88,11 @@ #define BCMA_CC_CHIPST_4313_OTP_PRESENT 2 #define BCMA_CC_CHIPST_4331_SPROM_PRESENT 2 #define BCMA_CC_CHIPST_4331_OTP_PRESENT 4 +#define BCMA_CC_CHIPST_4706_PKG_OPTION BIT(0) /* 0: full-featured package 1: low-cost package */ +#define BCMA_CC_CHIPST_4706_SFLASH_PRESENT BIT(1) /* 0: parallel, 1: serial flash is present */ +#define BCMA_CC_CHIPST_4706_SFLASH_TYPE BIT(2) /* 0: 8b-p/ST-s flash, 1: 16b-p/Atmal-s flash */ +#define BCMA_CC_CHIPST_4706_MIPS_BENDIAN BIT(3) /* 0: little, 1: big endian */ +#define BCMA_CC_CHIPST_4706_PCIE1_DISABLE BIT(5) /* PCIE1 enable strap pin */ #define BCMA_CC_JCMD 0x0030 /* Rev >= 10 only */ #define BCMA_CC_JCMD_START 0x80000000 #define BCMA_CC_JCMD_BUSY 0x80000000 @@ -280,6 +285,15 @@ /* 4706 PMU */ #define BCMA_CC_PMU4706_MAINPLL_PLL0 0 +#define BCMA_CC_PMU6_4706_PROCPLL_OFF 4 /* The CPU PLL */ +#define BCMA_CC_PMU6_4706_PROC_P2DIV_MASK 0x000f0000 +#define BCMA_CC_PMU6_4706_PROC_P2DIV_SHIFT 16 +#define BCMA_CC_PMU6_4706_PROC_P1DIV_MASK 0x0000f000 +#define BCMA_CC_PMU6_4706_PROC_P1DIV_SHIFT 12 +#define BCMA_CC_PMU6_4706_PROC_NDIV_INT_MASK 0x00000ff8 +#define BCMA_CC_PMU6_4706_PROC_NDIV_INT_SHIFT 3 +#define BCMA_CC_PMU6_4706_PROC_NDIV_MODE_MASK 0x00000007 +#define BCMA_CC_PMU6_4706_PROC_NDIV_MODE_SHIFT 0 /* ALP clock on pre-PMU chips */ #define BCMA_CC_PMU_ALP_CLOCK 20000000 @@ -308,6 +322,19 @@ #define BCMA_CC_PPL_PCHI_OFF 5 #define BCMA_CC_PPL_PCHI_MASK 0x0000003f +#define BCMA_CC_PMU_PLL_CTL0 0 +#define BCMA_CC_PMU_PLL_CTL1 1 +#define BCMA_CC_PMU_PLL_CTL2 2 +#define BCMA_CC_PMU_PLL_CTL3 3 +#define BCMA_CC_PMU_PLL_CTL4 4 +#define BCMA_CC_PMU_PLL_CTL5 5 + +#define BCMA_CC_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 +#define BCMA_CC_PMU1_PLL0_PC0_P1DIV_SHIFT 20 + +#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 +#define BCMA_CC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 + /* BCM4331 ChipControl numbers. */ #define BCMA_CHIPCTL_4331_BT_COEXIST BIT(0) /* 0 disable */ #define BCMA_CHIPCTL_4331_SECI BIT(1) /* 0 SECI is disabled (JATG functional) */ @@ -321,9 +348,18 @@ #define BCMA_CHIPCTL_4331_OVR_PIPEAUXPWRDOWN BIT(9) /* override core control on pipe_AuxPowerDown */ #define BCMA_CHIPCTL_4331_PCIE_AUXCLKEN BIT(10) /* pcie_auxclkenable */ #define BCMA_CHIPCTL_4331_PCIE_PIPE_PLLDOWN BIT(11) /* pcie_pipe_pllpowerdown */ +#define BCMA_CHIPCTL_4331_EXTPA_EN2 BIT(12) /* 0 ext pa disable, 1 ext pa enabled */ #define BCMA_CHIPCTL_4331_BT_SHD0_ON_GPIO4 BIT(16) /* enable bt_shd0 at gpio4 */ #define BCMA_CHIPCTL_4331_BT_SHD1_ON_GPIO5 BIT(17) /* enable bt_shd1 at gpio5 */ +/* 43224 chip-specific ChipControl register bits */ +#define BCMA_CCTRL_43224_GPIO_TOGGLE 0x8000 /* gpio[3:0] pins as btcoex or s/w gpio */ +#define BCMA_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ +#define BCMA_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ + +/* 4313 Chip specific ChipControl register bits */ +#define BCMA_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ + /* Data for the PMU, if available. * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU) */ @@ -411,5 +447,6 @@ extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, u32 set); extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask, u32 set); +extern void bcma_pmu_spuravoid_pllupdate(struct bcma_drv_cc *cc, int spuravoid); #endif /* LINUX_BCMA_DRIVER_CC_H_ */ diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index ce9af8918514..e02fc682bb68 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -47,6 +47,7 @@ #define IEEE80211_FCTL_MOREDATA 0x2000 #define IEEE80211_FCTL_PROTECTED 0x4000 #define IEEE80211_FCTL_ORDER 0x8000 +#define IEEE80211_FCTL_CTL_EXT 0x0f00 #define IEEE80211_SCTL_FRAG 0x000F #define IEEE80211_SCTL_SEQ 0xFFF0 @@ -54,6 +55,7 @@ #define IEEE80211_FTYPE_MGMT 0x0000 #define IEEE80211_FTYPE_CTL 0x0004 #define IEEE80211_FTYPE_DATA 0x0008 +#define IEEE80211_FTYPE_EXT 0x000c /* management */ #define IEEE80211_STYPE_ASSOC_REQ 0x0000 @@ -70,6 +72,7 @@ #define IEEE80211_STYPE_ACTION 0x00D0 /* control */ +#define IEEE80211_STYPE_CTL_EXT 0x0060 #define IEEE80211_STYPE_BACK_REQ 0x0080 #define IEEE80211_STYPE_BACK 0x0090 #define IEEE80211_STYPE_PSPOLL 0x00A0 @@ -97,6 +100,18 @@ #define IEEE80211_STYPE_QOS_CFPOLL 0x00E0 #define IEEE80211_STYPE_QOS_CFACKPOLL 0x00F0 +/* extension, added by 802.11ad */ +#define IEEE80211_STYPE_DMG_BEACON 0x0000 + +/* control extension - for IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTL_EXT */ +#define IEEE80211_CTL_EXT_POLL 0x2000 +#define IEEE80211_CTL_EXT_SPR 0x3000 +#define IEEE80211_CTL_EXT_GRANT 0x4000 +#define IEEE80211_CTL_EXT_DMG_CTS 0x5000 +#define IEEE80211_CTL_EXT_DMG_DTS 0x6000 +#define IEEE80211_CTL_EXT_SSW 0x8000 +#define IEEE80211_CTL_EXT_SSW_FBACK 0x9000 +#define IEEE80211_CTL_EXT_SSW_ACK 0xa000 /* miscellaneous IEEE 802.11 constants */ #define IEEE80211_MAX_FRAG_THRESHOLD 2352 @@ -568,6 +583,26 @@ struct ieee80211s_hdr { #define MESH_FLAGS_PS_DEEP 0x4 /** + * enum ieee80211_preq_flags - mesh PREQ element flags + * + * @IEEE80211_PREQ_PROACTIVE_PREP_FLAG: proactive PREP subfield + */ +enum ieee80211_preq_flags { + IEEE80211_PREQ_PROACTIVE_PREP_FLAG = 1<<2, +}; + +/** + * enum ieee80211_preq_target_flags - mesh PREQ element per target flags + * + * @IEEE80211_PREQ_TO_FLAG: target only subfield + * @IEEE80211_PREQ_USN_FLAG: unknown target HWMP sequence number subfield + */ +enum ieee80211_preq_target_flags { + IEEE80211_PREQ_TO_FLAG = 1<<0, + IEEE80211_PREQ_USN_FLAG = 1<<2, +}; + +/** * struct ieee80211_quiet_ie * * This structure refers to "Quiet information element" @@ -1072,6 +1107,73 @@ struct ieee80211_ht_operation { #define WLAN_HT_SMPS_CONTROL_STATIC 1 #define WLAN_HT_SMPS_CONTROL_DYNAMIC 3 +#define VHT_MCS_SUPPORTED_SET_SIZE 8 + +struct ieee80211_vht_capabilities { + __le32 vht_capabilities_info; + u8 vht_supported_mcs_set[VHT_MCS_SUPPORTED_SET_SIZE]; +} __packed; + +struct ieee80211_vht_operation { + u8 vht_op_info_chwidth; + u8 vht_op_info_chan_center_freq_seg1_idx; + u8 vht_op_info_chan_center_freq_seg2_idx; + __le16 vht_basic_mcs_set; +} __packed; + +/** + * struct ieee80211_vht_mcs_info - VHT MCS information + * @rx_mcs_map: RX MCS map 2 bits for each stream, total 8 streams + * @rx_highest: Indicates highest long GI VHT PPDU data rate + * STA can receive. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest RX data rate supported. + * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams + * @tx_highest: Indicates highest long GI VHT PPDU data rate + * STA can transmit. Rate expressed in units of 1 Mbps. + * If this field is 0 this value should not be used to + * consider the highest TX data rate supported. + */ +struct ieee80211_vht_mcs_info { + __le16 rx_mcs_map; + __le16 rx_highest; + __le16 tx_mcs_map; + __le16 tx_highest; +} __packed; + +#define IEEE80211_VHT_MCS_ZERO_TO_SEVEN_SUPPORT 0 +#define IEEE80211_VHT_MCS_ZERO_TO_EIGHT_SUPPORT 1 +#define IEEE80211_VHT_MCS_ZERO_TO_NINE_SUPPORT 2 +#define IEEE80211_VHT_MCS_NOT_SUPPORTED 3 + +/* 802.11ac VHT Capabilities */ +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_3895 0x00000000 +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_7991 0x00000001 +#define IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 0x00000002 +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ 0x00000004 +#define IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ 0x00000008 +#define IEEE80211_VHT_CAP_RXLDPC 0x00000010 +#define IEEE80211_VHT_CAP_SHORT_GI_80 0x00000020 +#define IEEE80211_VHT_CAP_SHORT_GI_160 0x00000040 +#define IEEE80211_VHT_CAP_TXSTBC 0x00000080 +#define IEEE80211_VHT_CAP_RXSTBC_1 0x00000100 +#define IEEE80211_VHT_CAP_RXSTBC_2 0x00000200 +#define IEEE80211_VHT_CAP_RXSTBC_3 0x00000300 +#define IEEE80211_VHT_CAP_RXSTBC_4 0x00000400 +#define IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE 0x00000800 +#define IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE 0x00001000 +#define IEEE80211_VHT_CAP_BEAMFORMER_ANTENNAS_MAX 0x00006000 +#define IEEE80211_VHT_CAP_SOUNDING_DIMENTION_MAX 0x00030000 +#define IEEE80211_VHT_CAP_MU_BEAMFORMER_CAPABLE 0x00080000 +#define IEEE80211_VHT_CAP_MU_BEAMFORMEE_CAPABLE 0x00100000 +#define IEEE80211_VHT_CAP_VHT_TXOP_PS 0x00200000 +#define IEEE80211_VHT_CAP_HTC_VHT 0x00400000 +#define IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT 0x00800000 +#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB 0x08000000 +#define IEEE80211_VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB 0x0c000000 +#define IEEE80211_VHT_CAP_RX_ANTENNA_PATTERN 0x10000000 +#define IEEE80211_VHT_CAP_TX_ANTENNA_PATTERN 0x20000000 + /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 @@ -1104,6 +1206,21 @@ struct ieee80211_ht_operation { #define WLAN_CAPABILITY_QOS (1<<9) #define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) #define WLAN_CAPABILITY_DSSS_OFDM (1<<13) + +/* DMG (60gHz) 802.11ad */ +/* type - bits 0..1 */ +#define WLAN_CAPABILITY_DMG_TYPE_IBSS (1<<0) /* Tx by: STA */ +#define WLAN_CAPABILITY_DMG_TYPE_PBSS (2<<0) /* Tx by: PCP */ +#define WLAN_CAPABILITY_DMG_TYPE_AP (3<<0) /* Tx by: AP */ + +#define WLAN_CAPABILITY_DMG_CBAP_ONLY (1<<2) +#define WLAN_CAPABILITY_DMG_CBAP_SOURCE (1<<3) +#define WLAN_CAPABILITY_DMG_PRIVACY (1<<4) +#define WLAN_CAPABILITY_DMG_ECPAC (1<<5) + +#define WLAN_CAPABILITY_DMG_SPECTRUM_MGMT (1<<8) +#define WLAN_CAPABILITY_DMG_RADIO_MEASURE (1<<12) + /* measurement */ #define IEEE80211_SPCT_MSR_RPRT_MODE_LATE (1<<0) #define IEEE80211_SPCT_MSR_RPRT_MODE_INCAPABLE (1<<1) @@ -1113,7 +1230,6 @@ struct ieee80211_ht_operation { #define IEEE80211_SPCT_MSR_RPRT_TYPE_CCA 1 #define IEEE80211_SPCT_MSR_RPRT_TYPE_RPI 2 - /* 802.11g ERP information element */ #define WLAN_ERP_NON_ERP_PRESENT (1<<0) #define WLAN_ERP_USE_PROTECTION (1<<1) @@ -1125,6 +1241,16 @@ enum { WLAN_ERP_PREAMBLE_LONG = 1, }; +/* Band ID, 802.11ad #8.4.1.45 */ +enum { + IEEE80211_BANDID_TV_WS = 0, /* TV white spaces */ + IEEE80211_BANDID_SUB1 = 1, /* Sub-1 GHz (excluding TV white spaces) */ + IEEE80211_BANDID_2G = 2, /* 2.4 GHz */ + IEEE80211_BANDID_3G = 3, /* 3.6 GHz */ + IEEE80211_BANDID_5G = 4, /* 4.9 and 5 GHz */ + IEEE80211_BANDID_60G = 5, /* 60 GHz */ +}; + /* Status codes */ enum ieee80211_statuscode { WLAN_STATUS_SUCCESS = 0, @@ -1176,6 +1302,17 @@ enum ieee80211_statuscode { WLAN_STATUS_ANTI_CLOG_REQUIRED = 76, WLAN_STATUS_FCG_NOT_SUPP = 78, WLAN_STATUS_STA_NO_TBTT = 78, + /* 802.11ad */ + WLAN_STATUS_REJECTED_WITH_SUGGESTED_CHANGES = 39, + WLAN_STATUS_REJECTED_FOR_DELAY_PERIOD = 47, + WLAN_STATUS_REJECT_WITH_SCHEDULE = 83, + WLAN_STATUS_PENDING_ADMITTING_FST_SESSION = 86, + WLAN_STATUS_PERFORMING_FST_NOW = 87, + WLAN_STATUS_PENDING_GAP_IN_BA_WINDOW = 88, + WLAN_STATUS_REJECT_U_PID_SETTING = 89, + WLAN_STATUS_REJECT_DSE_BAND = 96, + WLAN_STATUS_DENIED_WITH_SUGGESTED_BAND_AND_CHANNEL = 99, + WLAN_STATUS_DENIED_DUE_TO_SPECTRUM_MANAGEMENT = 103, }; @@ -1332,6 +1469,43 @@ enum ieee80211_eid { WLAN_EID_DSE_REGISTERED_LOCATION = 58, WLAN_EID_SUPPORTED_REGULATORY_CLASSES = 59, WLAN_EID_EXT_CHANSWITCH_ANN = 60, + + WLAN_EID_VHT_CAPABILITY = 191, + WLAN_EID_VHT_OPERATION = 192, + + /* 802.11ad */ + WLAN_EID_NON_TX_BSSID_CAP = 83, + WLAN_EID_WAKEUP_SCHEDULE = 143, + WLAN_EID_EXT_SCHEDULE = 144, + WLAN_EID_STA_AVAILABILITY = 145, + WLAN_EID_DMG_TSPEC = 146, + WLAN_EID_DMG_AT = 147, + WLAN_EID_DMG_CAP = 148, + WLAN_EID_DMG_OPERATION = 151, + WLAN_EID_DMG_BSS_PARAM_CHANGE = 152, + WLAN_EID_DMG_BEAM_REFINEMENT = 153, + WLAN_EID_CHANNEL_MEASURE_FEEDBACK = 154, + WLAN_EID_AWAKE_WINDOW = 157, + WLAN_EID_MULTI_BAND = 158, + WLAN_EID_ADDBA_EXT = 159, + WLAN_EID_NEXT_PCP_LIST = 160, + WLAN_EID_PCP_HANDOVER = 161, + WLAN_EID_DMG_LINK_MARGIN = 162, + WLAN_EID_SWITCHING_STREAM = 163, + WLAN_EID_SESSION_TRANSITION = 164, + WLAN_EID_DYN_TONE_PAIRING_REPORT = 165, + WLAN_EID_CLUSTER_REPORT = 166, + WLAN_EID_RELAY_CAP = 167, + WLAN_EID_RELAY_XFER_PARAM_SET = 168, + WLAN_EID_BEAM_LINK_MAINT = 169, + WLAN_EID_MULTIPLE_MAC_ADDR = 170, + WLAN_EID_U_PID = 171, + WLAN_EID_DMG_LINK_ADAPT_ACK = 172, + WLAN_EID_QUIET_PERIOD_REQ = 175, + WLAN_EID_QUIET_PERIOD_RESP = 177, + WLAN_EID_EPAC_POLICY = 182, + WLAN_EID_CLISTER_TIME_OFF = 183, + WLAN_EID_ANTENNA_SECTOR_ID_PATTERN = 190, }; /* Action category code */ @@ -1348,7 +1522,10 @@ enum ieee80211_category { WLAN_CATEGORY_MESH_ACTION = 13, WLAN_CATEGORY_MULTIHOP_ACTION = 14, WLAN_CATEGORY_SELF_PROTECTED = 15, + WLAN_CATEGORY_DMG = 16, WLAN_CATEGORY_WMM = 17, + WLAN_CATEGORY_FST = 18, + WLAN_CATEGORY_UNPROT_DMG = 20, WLAN_CATEGORY_VENDOR_SPECIFIC_PROTECTED = 126, WLAN_CATEGORY_VENDOR_SPECIFIC = 127, }; @@ -1443,7 +1620,7 @@ enum ieee80211_tdls_actioncode { * * @IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET: the default synchronization method * @IEEE80211_SYNC_METHOD_VENDOR: a vendor specific synchronization method - * that will be specified in a vendor specific information element + * that will be specified in a vendor specific information element */ enum { IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET = 1, @@ -1455,7 +1632,7 @@ enum { * * @IEEE80211_PATH_PROTOCOL_HWMP: the default path selection protocol * @IEEE80211_PATH_PROTOCOL_VENDOR: a vendor specific protocol that will - * be specified in a vendor specific information element + * be specified in a vendor specific information element */ enum { IEEE80211_PATH_PROTOCOL_HWMP = 1, @@ -1467,13 +1644,35 @@ enum { * * @IEEE80211_PATH_METRIC_AIRTIME: the default path selection metric * @IEEE80211_PATH_METRIC_VENDOR: a vendor specific metric that will be - * specified in a vendor specific information element + * specified in a vendor specific information element */ enum { IEEE80211_PATH_METRIC_AIRTIME = 1, IEEE80211_PATH_METRIC_VENDOR = 255, }; +/** + * enum ieee80211_root_mode_identifier - root mesh STA mode identifier + * + * These attribute are used by dot11MeshHWMPRootMode to set root mesh STA mode + * + * @IEEE80211_ROOTMODE_NO_ROOT: the mesh STA is not a root mesh STA (default) + * @IEEE80211_ROOTMODE_ROOT: the mesh STA is a root mesh STA if greater than + * this value + * @IEEE80211_PROACTIVE_PREQ_NO_PREP: the mesh STA is a root mesh STA supports + * the proactive PREQ with proactive PREP subfield set to 0 + * @IEEE80211_PROACTIVE_PREQ_WITH_PREP: the mesh STA is a root mesh STA + * supports the proactive PREQ with proactive PREP subfield set to 1 + * @IEEE80211_PROACTIVE_RANN: the mesh STA is a root mesh STA supports + * the proactive RANN + */ +enum ieee80211_root_mode_identifier { + IEEE80211_ROOTMODE_NO_ROOT = 0, + IEEE80211_ROOTMODE_ROOT = 1, + IEEE80211_PROACTIVE_PREQ_NO_PREP = 2, + IEEE80211_PROACTIVE_PREQ_WITH_PREP = 3, + IEEE80211_PROACTIVE_RANN = 4, +}; /* * IEEE 802.11-2007 7.3.2.9 Country information element @@ -1574,6 +1773,7 @@ enum ieee80211_sa_query_action { #define WLAN_CIPHER_SUITE_CCMP 0x000FAC04 #define WLAN_CIPHER_SUITE_WEP104 0x000FAC05 #define WLAN_CIPHER_SUITE_AES_CMAC 0x000FAC06 +#define WLAN_CIPHER_SUITE_GCMP 0x000FAC08 #define WLAN_CIPHER_SUITE_SMS4 0x00147201 @@ -1589,6 +1789,10 @@ enum ieee80211_sa_query_action { #define WLAN_OUI_WFA 0x506f9a #define WLAN_OUI_TYPE_WFA_P2P 9 +#define WLAN_OUI_MICROSOFT 0x0050f2 +#define WLAN_OUI_TYPE_MICROSOFT_WPA 1 +#define WLAN_OUI_TYPE_MICROSOFT_WMM 2 +#define WLAN_OUI_TYPE_MICROSOFT_WPS 4 /* * WMM/802.11e Tspec Element diff --git a/include/linux/nfc.h b/include/linux/nfc.h index f4e6dd915b1c..6189f27e305b 100644 --- a/include/linux/nfc.h +++ b/include/linux/nfc.h @@ -136,8 +136,9 @@ enum nfc_attrs { #define NFC_PROTO_FELICA 3 #define NFC_PROTO_ISO14443 4 #define NFC_PROTO_NFC_DEP 5 +#define NFC_PROTO_ISO14443_B 6 -#define NFC_PROTO_MAX 6 +#define NFC_PROTO_MAX 7 /* NFC communication modes */ #define NFC_COMM_ACTIVE 0 @@ -149,11 +150,12 @@ enum nfc_attrs { #define NFC_RF_NONE 2 /* NFC protocols masks used in bitsets */ -#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) -#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) -#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) -#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) -#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) +#define NFC_PROTO_JEWEL_MASK (1 << NFC_PROTO_JEWEL) +#define NFC_PROTO_MIFARE_MASK (1 << NFC_PROTO_MIFARE) +#define NFC_PROTO_FELICA_MASK (1 << NFC_PROTO_FELICA) +#define NFC_PROTO_ISO14443_MASK (1 << NFC_PROTO_ISO14443) +#define NFC_PROTO_NFC_DEP_MASK (1 << NFC_PROTO_NFC_DEP) +#define NFC_PROTO_ISO14443_B_MASK (1 << NFC_PROTO_ISO14443_B) struct sockaddr_nfc { sa_family_t sa_family; diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 970afdf5a605..e791487ead37 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -277,6 +277,12 @@ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to * NL80211_CMD_GET_SURVEY and on the "scan" multicast group) * + * @NL80211_CMD_SET_PMKSA: Add a PMKSA cache entry, using %NL80211_ATTR_MAC + * (for the BSSID) and %NL80211_ATTR_PMKID. + * @NL80211_CMD_DEL_PMKSA: Delete a PMKSA cache entry, using %NL80211_ATTR_MAC + * (for the BSSID) and %NL80211_ATTR_PMKID. + * @NL80211_CMD_FLUSH_PMKSA: Flush all PMKSA cache entries. + * * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain * has been changed and provides details of the request information * that caused the change such as who initiated the regulatory request @@ -456,6 +462,10 @@ * the frame. * @NL80211_CMD_ACTION_TX_STATUS: Alias for @NL80211_CMD_FRAME_TX_STATUS for * backward compatibility. + * + * @NL80211_CMD_SET_POWER_SAVE: Set powersave, using %NL80211_ATTR_PS_STATE + * @NL80211_CMD_GET_POWER_SAVE: Get powersave status in %NL80211_ATTR_PS_STATE + * * @NL80211_CMD_SET_CQM: Connection quality monitor configuration. This command * is used to configure connection quality monitoring notification trigger * levels. @@ -761,6 +771,9 @@ enum nl80211_commands { * @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * + * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices + * that don't have a netdev (u64) + * * @NL80211_ATTR_MAC: MAC address (various uses) * * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of @@ -771,6 +784,13 @@ enum nl80211_commands { * section 7.3.2.25.1, e.g. 0x000FAC04) * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and * CCMP keys, each six bytes in little endian + * @NL80211_ATTR_KEY_DEFAULT: Flag attribute indicating the key is default key + * @NL80211_ATTR_KEY_DEFAULT_MGMT: Flag attribute indicating the key is the + * default management key + * @NL80211_ATTR_CIPHER_SUITES_PAIRWISE: For crypto settings for connect or + * other commands, indicates which pairwise cipher suites are used + * @NL80211_ATTR_CIPHER_SUITE_GROUP: For crypto settings for connect or + * other commands, indicates which group cipher suite is used * * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing @@ -1006,6 +1026,8 @@ enum nl80211_commands { * @NL80211_ATTR_ACK: Flag attribute indicating that the frame was * acknowledged by the recipient. * + * @NL80211_ATTR_PS_STATE: powersave state, using &enum nl80211_ps_state values. + * * @NL80211_ATTR_CQM: connection quality monitor configuration in a * nested attribute with %NL80211_ATTR_CQM_* sub-attributes. * @@ -1063,7 +1085,7 @@ enum nl80211_commands { * flag isn't set, the frame will be rejected. This is also used as an * nl80211 capability flag. * - * @NL80211_ATTR_BSS_HTOPMODE: HT operation mode (u16) + * @NL80211_ATTR_BSS_HT_OPMODE: HT operation mode (u16) * * @NL80211_ATTR_KEY_DEFAULT_TYPES: A nested attribute containing flags * attributes, specifying what a key should be set as default as. @@ -1087,10 +1109,10 @@ enum nl80211_commands { * indicate which WoW triggers should be enabled. This is also * used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN * triggers. - + * * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan * cycles, in msecs. - + * * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more * sets of attributes to match during scheduled scans. Only BSSs * that match any of the sets will be reported. These are @@ -1117,7 +1139,7 @@ enum nl80211_commands { * are managed in software: interfaces of these types aren't subject to * any restrictions in their number or combinations. * - * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information + * @NL80211_ATTR_REKEY_DATA: nested attribute containing the information * necessary for GTK rekeying in the device, see &enum nl80211_rekey_data. * * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan, @@ -1184,7 +1206,6 @@ enum nl80211_commands { * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from * &enum nl80211_feature_flags and is advertised in wiphy information. * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe - * * requests while operating in AP-mode. * This attribute holds a bitmap of the supported protocols for * offloading (see &enum nl80211_probe_resp_offload_support_attr). @@ -1475,6 +1496,8 @@ enum nl80211_attrs { NL80211_ATTR_BG_SCAN_PERIOD, + NL80211_ATTR_WDEV, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1524,6 +1547,9 @@ enum nl80211_attrs { #define NL80211_MIN_REMAIN_ON_CHANNEL_TIME 10 +/* default RSSI threshold for scan results if none specified. */ +#define NL80211_SCAN_RSSI_THOLD_OFF -300 + /** * enum nl80211_iftype - (virtual) interface types * @@ -1617,12 +1643,20 @@ struct nl80211_sta_flag_update { * * These attribute types are used with %NL80211_STA_INFO_TXRATE * when getting information about the bitrate of a station. + * There are 2 attributes for bitrate, a legacy one that represents + * a 16-bit value, and new one that represents a 32-bit value. + * If the rate value fits into 16 bit, both attributes are reported + * with the same value. If the rate is too high to fit into 16 bits + * (>6.5535Gbps) only 32-bit attribute is included. + * User space tools encouraged to use the 32-bit attribute and fall + * back to the 16-bit one for compatibility with older kernels. * * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval + * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s) * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined * @__NL80211_RATE_INFO_AFTER_LAST: internal use */ @@ -1632,6 +1666,7 @@ enum nl80211_rate_info { NL80211_RATE_INFO_MCS, NL80211_RATE_INFO_40_MHZ_WIDTH, NL80211_RATE_INFO_SHORT_GI, + NL80211_RATE_INFO_BITRATE32, /* keep last */ __NL80211_RATE_INFO_AFTER_LAST, @@ -1792,6 +1827,9 @@ enum nl80211_mpath_info { * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n + * @NL80211_BAND_ATTR_VHT_MCS_SET: 32-byte attribute containing the MCS set as + * defined in 802.11ac + * @NL80211_BAND_ATTR_VHT_CAPA: VHT capabilities, as in the HT information IE * @NL80211_BAND_ATTR_MAX: highest band attribute currently defined * @__NL80211_BAND_ATTR_AFTER_LAST: internal use */ @@ -1805,6 +1843,9 @@ enum nl80211_band_attr { NL80211_BAND_ATTR_HT_AMPDU_FACTOR, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + NL80211_BAND_ATTR_VHT_MCS_SET, + NL80211_BAND_ATTR_VHT_CAPA, + /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 @@ -1956,6 +1997,8 @@ enum nl80211_reg_rule_attr { * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching, * only report BSS with matching SSID. + * @NL80211_SCHED_SCAN_MATCH_ATTR_RSSI: RSSI threshold (in dBm) for reporting a + * BSS in scan results. Filtering is turned off if not specified. * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter * attribute number currently defined * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use @@ -1963,7 +2006,8 @@ enum nl80211_reg_rule_attr { enum nl80211_sched_scan_match_attr { __NL80211_SCHED_SCAN_MATCH_ATTR_INVALID, - NL80211_ATTR_SCHED_SCAN_MATCH_SSID, + NL80211_SCHED_SCAN_MATCH_ATTR_SSID, + NL80211_SCHED_SCAN_MATCH_ATTR_RSSI, /* keep last */ __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST, @@ -1971,6 +2015,9 @@ enum nl80211_sched_scan_match_attr { __NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1 }; +/* only for backward compatibility */ +#define NL80211_ATTR_SCHED_SCAN_MATCH_SSID NL80211_SCHED_SCAN_MATCH_ATTR_SSID + /** * enum nl80211_reg_rule_flags - regulatory rule flags * @@ -2090,78 +2137,91 @@ enum nl80211_mntr_flags { * @__NL80211_MESHCONF_INVALID: internal use * * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in - * millisecond units, used by the Peer Link Open message + * millisecond units, used by the Peer Link Open message * * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in - * millisecond units, used by the peer link management to close a peer link + * millisecond units, used by the peer link management to close a peer link * * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in - * millisecond units + * millisecond units * * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed - * on this mesh interface + * on this mesh interface * * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link - * open retries that can be sent to establish a new peer link instance in a - * mesh + * open retries that can be sent to establish a new peer link instance in a + * mesh * * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh - * point. + * point. * * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically - * open peer links when we detect compatible mesh peers. + * open peer links when we detect compatible mesh peers. * * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames - * containing a PREQ that an MP can send to a particular destination (path - * target) + * containing a PREQ that an MP can send to a particular destination (path + * target) * * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths - * (in milliseconds) + * (in milliseconds) * * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait - * until giving up on a path discovery (in milliseconds) + * until giving up on a path discovery (in milliseconds) * * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh - * points receiving a PREQ shall consider the forwarding information from the - * root to be valid. (TU = time unit) + * points receiving a PREQ shall consider the forwarding information from + * the root to be valid. (TU = time unit) * * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in - * TUs) during which an MP can send only one action frame containing a PREQ - * reference element + * TUs) during which an MP can send only one action frame containing a PREQ + * reference element * * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) - * that it takes for an HWMP information element to propagate across the mesh + * that it takes for an HWMP information element to propagate across the + * mesh * * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not * * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a - * source mesh point for path selection elements. + * source mesh point for path selection elements. * * @NL80211_MESHCONF_HWMP_RANN_INTERVAL: The interval of time (in TUs) between - * root announcements are transmitted. + * root announcements are transmitted. * * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has - * access to a broader network beyond the MBSS. This is done via Root - * Announcement frames. + * access to a broader network beyond the MBSS. This is done via Root + * Announcement frames. * * @NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL: The minimum interval of time (in - * TUs) during which a mesh STA can send only one Action frame containing a - * PERR element. + * TUs) during which a mesh STA can send only one Action frame containing a + * PERR element. * * @NL80211_MESHCONF_FORWARDING: set Mesh STA as forwarding or non-forwarding - * or forwarding entity (default is TRUE - forwarding entity) + * or forwarding entity (default is TRUE - forwarding entity) * * @NL80211_MESHCONF_RSSI_THRESHOLD: RSSI threshold in dBm. This specifies the - * threshold for average signal strength of candidate station to establish - * a peer link. - * - * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute + * threshold for average signal strength of candidate station to establish + * a peer link. * * @NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR: maximum number of neighbors - * to synchronize to for 11s default synchronization method (see 11C.12.2.2) + * to synchronize to for 11s default synchronization method + * (see 11C.12.2.2) * * @NL80211_MESHCONF_HT_OPMODE: set mesh HT protection mode. * + * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute + * + * @NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT: The time (in TUs) for + * which mesh STAs receiving a proactive PREQ shall consider the forwarding + * information to the root mesh STA to be valid. + * + * @NL80211_MESHCONF_HWMP_ROOT_INTERVAL: The interval of time (in TUs) between + * proactive PREQs are transmitted. + * + * @NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL: The minimum interval of time + * (in TUs) during which a mesh STA can send only one Action frame + * containing a PREQ element for root path confirmation. + * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { @@ -2188,6 +2248,9 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_RSSI_THRESHOLD, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, NL80211_MESHCONF_HT_OPMODE, + NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, + NL80211_MESHCONF_HWMP_ROOT_INTERVAL, + NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -2203,34 +2266,36 @@ enum nl80211_meshconf_params { * @__NL80211_MESH_SETUP_INVALID: Internal use * * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a - * vendor specific path selection algorithm or disable it to use the default - * HWMP. + * vendor specific path selection algorithm or disable it to use the + * default HWMP. * * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a - * vendor specific path metric or disable it to use the default Airtime - * metric. + * vendor specific path metric or disable it to use the default Airtime + * metric. * * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a - * robust security network ie, or a vendor specific information element that - * vendors will use to identify the path selection methods and metrics in use. + * robust security network ie, or a vendor specific information element + * that vendors will use to identify the path selection methods and + * metrics in use. * * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication - * daemon will be authenticating mesh candidates. + * daemon will be authenticating mesh candidates. * * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication - * daemon will be securing peer link frames. AMPE is a secured version of Mesh - * Peering Management (MPM) and is implemented with the assistance of a - * userspace daemon. When this flag is set, the kernel will send peer - * management frames to a userspace daemon that will implement AMPE - * functionality (security capabilities selection, key confirmation, and key - * management). When the flag is unset (default), the kernel can autonomously - * complete (unsecured) mesh peering without the need of a userspace daemon. - * - * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number + * daemon will be securing peer link frames. AMPE is a secured version of + * Mesh Peering Management (MPM) and is implemented with the assistance of + * a userspace daemon. When this flag is set, the kernel will send peer + * management frames to a userspace daemon that will implement AMPE + * functionality (security capabilities selection, key confirmation, and + * key management). When the flag is unset (default), the kernel can + * autonomously complete (unsecured) mesh peering without the need of a + * userspace daemon. * * @NL80211_MESH_SETUP_ENABLE_VENDOR_SYNC: Enable this option to use a - * vendor specific synchronization method or disable it to use the default - * neighbor offset synchronization + * vendor specific synchronization method or disable it to use the default + * neighbor offset synchronization + * + * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number * * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use */ @@ -2494,12 +2559,19 @@ enum nl80211_tx_rate_attributes { * enum nl80211_band - Frequency band * @NL80211_BAND_2GHZ: 2.4 GHz ISM band * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) + * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) */ enum nl80211_band { NL80211_BAND_2GHZ, NL80211_BAND_5GHZ, + NL80211_BAND_60GHZ, }; +/** + * enum nl80211_ps_state - powersave state + * @NL80211_PS_DISABLED: powersave is disabled + * @NL80211_PS_ENABLED: powersave is enabled + */ enum nl80211_ps_state { NL80211_PS_DISABLED, NL80211_PS_ENABLED, diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h new file mode 100644 index 000000000000..6a76e0a0705e --- /dev/null +++ b/include/net/bluetooth/a2mp.h @@ -0,0 +1,126 @@ +/* + Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved. + Copyright (c) 2011,2012 Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 and + only version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#ifndef __A2MP_H +#define __A2MP_H + +#include <net/bluetooth/l2cap.h> + +#define A2MP_FEAT_EXT 0x8000 + +struct amp_mgr { + struct l2cap_conn *l2cap_conn; + struct l2cap_chan *a2mp_chan; + struct kref kref; + __u8 ident; + __u8 handle; + unsigned long flags; +}; + +struct a2mp_cmd { + __u8 code; + __u8 ident; + __le16 len; + __u8 data[0]; +} __packed; + +/* A2MP command codes */ +#define A2MP_COMMAND_REJ 0x01 +struct a2mp_cmd_rej { + __le16 reason; + __u8 data[0]; +} __packed; + +#define A2MP_DISCOVER_REQ 0x02 +struct a2mp_discov_req { + __le16 mtu; + __le16 ext_feat; +} __packed; + +struct a2mp_cl { + __u8 id; + __u8 type; + __u8 status; +} __packed; + +#define A2MP_DISCOVER_RSP 0x03 +struct a2mp_discov_rsp { + __le16 mtu; + __le16 ext_feat; + struct a2mp_cl cl[0]; +} __packed; + +#define A2MP_CHANGE_NOTIFY 0x04 +#define A2MP_CHANGE_RSP 0x05 + +#define A2MP_GETINFO_REQ 0x06 +struct a2mp_info_req { + __u8 id; +} __packed; + +#define A2MP_GETINFO_RSP 0x07 +struct a2mp_info_rsp { + __u8 id; + __u8 status; + __le32 total_bw; + __le32 max_bw; + __le32 min_latency; + __le16 pal_cap; + __le16 assoc_size; +} __packed; + +#define A2MP_GETAMPASSOC_REQ 0x08 +struct a2mp_amp_assoc_req { + __u8 id; +} __packed; + +#define A2MP_GETAMPASSOC_RSP 0x09 +struct a2mp_amp_assoc_rsp { + __u8 id; + __u8 status; + __u8 amp_assoc[0]; +} __packed; + +#define A2MP_CREATEPHYSLINK_REQ 0x0A +#define A2MP_DISCONNPHYSLINK_REQ 0x0C +struct a2mp_physlink_req { + __u8 local_id; + __u8 remote_id; + __u8 amp_assoc[0]; +} __packed; + +#define A2MP_CREATEPHYSLINK_RSP 0x0B +#define A2MP_DISCONNPHYSLINK_RSP 0x0D +struct a2mp_physlink_rsp { + __u8 local_id; + __u8 remote_id; + __u8 status; +} __packed; + +/* A2MP response status */ +#define A2MP_STATUS_SUCCESS 0x00 +#define A2MP_STATUS_INVALID_CTRL_ID 0x01 +#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02 +#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02 +#define A2MP_STATUS_COLLISION_OCCURED 0x03 +#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04 +#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05 +#define A2MP_STATUS_SECURITY_VIOLATION 0x06 + +void amp_mgr_get(struct amp_mgr *mgr); +int amp_mgr_put(struct amp_mgr *mgr); +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, + struct sk_buff *skb); + +#endif /* __A2MP_H */ diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 961669b648fd..565d4bee1e49 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -1,4 +1,4 @@ -/* +/* BlueZ - Bluetooth protocol stack for Linux Copyright (C) 2000-2001 Qualcomm Incorporated @@ -12,22 +12,19 @@ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS + ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, + COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS SOFTWARE IS DISCLAIMED. */ #ifndef __BLUETOOTH_H #define __BLUETOOTH_H -#include <asm/types.h> -#include <asm/byteorder.h> -#include <linux/list.h> #include <linux/poll.h> #include <net/sock.h> @@ -168,8 +165,8 @@ typedef struct { #define BDADDR_LE_PUBLIC 0x01 #define BDADDR_LE_RANDOM 0x02 -#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) -#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) +#define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0} }) +#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff} }) /* Copy, swap, convert BD Address */ static inline int bacmp(bdaddr_t *ba1, bdaddr_t *ba2) @@ -215,7 +212,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); int bt_sock_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); -uint bt_sock_poll(struct file * file, struct socket *sock, poll_table *wait); +uint bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait); int bt_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int bt_sock_wait_state(struct sock *sk, int state, unsigned long timeo); @@ -225,12 +222,12 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); /* Skb helpers */ struct l2cap_ctrl { - unsigned int sframe : 1, - poll : 1, - final : 1, - fcs : 1, - sar : 2, - super : 2; + unsigned int sframe:1, + poll:1, + final:1, + fcs:1, + sar:2, + super:2; __u16 reqseq; __u16 txseq; __u8 retries; @@ -249,7 +246,8 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how) { struct sk_buff *skb; - if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) { + skb = alloc_skb(len + BT_SKB_RESERVE, how); + if (skb) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } @@ -261,7 +259,8 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, { struct sk_buff *skb; - if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { + skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err); + if (skb) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 66a7b579e31c..2a6b0b8b7120 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -30,6 +30,9 @@ #define HCI_MAX_EVENT_SIZE 260 #define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4) +#define HCI_LINK_KEY_SIZE 16 +#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE) + /* HCI dev events */ #define HCI_DEV_REG 1 #define HCI_DEV_UNREG 2 @@ -56,9 +59,12 @@ #define HCI_BREDR 0x00 #define HCI_AMP 0x01 +/* First BR/EDR Controller shall have ID = 0 */ +#define HCI_BREDR_ID 0 + /* HCI device quirks */ enum { - HCI_QUIRK_NO_RESET, + HCI_QUIRK_RESET_ON_CLOSE, HCI_QUIRK_RAW_DEVICE, HCI_QUIRK_FIXUP_BUFFER_SIZE }; @@ -133,10 +139,8 @@ enum { #define HCIINQUIRY _IOR('H', 240, int) /* HCI timeouts */ -#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */ #define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ #define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ -#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ #define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ #define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */ @@ -371,7 +375,7 @@ struct hci_cp_reject_conn_req { #define HCI_OP_LINK_KEY_REPLY 0x040b struct hci_cp_link_key_reply { bdaddr_t bdaddr; - __u8 link_key[16]; + __u8 link_key[HCI_LINK_KEY_SIZE]; } __packed; #define HCI_OP_LINK_KEY_NEG_REPLY 0x040c @@ -523,6 +527,28 @@ struct hci_cp_io_capability_neg_reply { __u8 reason; } __packed; +#define HCI_OP_CREATE_PHY_LINK 0x0435 +struct hci_cp_create_phy_link { + __u8 phy_handle; + __u8 key_len; + __u8 key_type; + __u8 key[HCI_AMP_LINK_KEY_SIZE]; +} __packed; + +#define HCI_OP_ACCEPT_PHY_LINK 0x0436 +struct hci_cp_accept_phy_link { + __u8 phy_handle; + __u8 key_len; + __u8 key_type; + __u8 key[HCI_AMP_LINK_KEY_SIZE]; +} __packed; + +#define HCI_OP_DISCONN_PHY_LINK 0x0437 +struct hci_cp_disconn_phy_link { + __u8 phy_handle; + __u8 reason; +} __packed; + #define HCI_OP_SNIFF_MODE 0x0803 struct hci_cp_sniff_mode { __le16 handle; @@ -818,6 +844,31 @@ struct hci_rp_read_local_amp_info { __le32 be_flush_to; } __packed; +#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a +struct hci_cp_read_local_amp_assoc { + __u8 phy_handle; + __le16 len_so_far; + __le16 max_len; +} __packed; +struct hci_rp_read_local_amp_assoc { + __u8 status; + __u8 phy_handle; + __le16 rem_len; + __u8 frag[0]; +} __packed; + +#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b +struct hci_cp_write_remote_amp_assoc { + __u8 phy_handle; + __le16 len_so_far; + __le16 rem_len; + __u8 frag[0]; +} __packed; +struct hci_rp_write_remote_amp_assoc { + __u8 status; + __u8 phy_handle; +} __packed; + #define HCI_OP_LE_SET_EVENT_MASK 0x2001 struct hci_cp_le_set_event_mask { __u8 mask[8]; @@ -1048,7 +1099,7 @@ struct hci_ev_link_key_req { #define HCI_EV_LINK_KEY_NOTIFY 0x18 struct hci_ev_link_key_notify { bdaddr_t bdaddr; - __u8 link_key[16]; + __u8 link_key[HCI_LINK_KEY_SIZE]; __u8 key_type; } __packed; @@ -1144,6 +1195,12 @@ struct extended_inquiry_info { __u8 data[240]; } __packed; +#define HCI_EV_KEY_REFRESH_COMPLETE 0x30 +struct hci_ev_key_refresh_complete { + __u8 status; + __le16 handle; +} __packed; + #define HCI_EV_IO_CAPA_REQUEST 0x31 struct hci_ev_io_capa_request { bdaddr_t bdaddr; @@ -1190,6 +1247,39 @@ struct hci_ev_le_meta { __u8 subevent; } __packed; +#define HCI_EV_PHY_LINK_COMPLETE 0x40 +struct hci_ev_phy_link_complete { + __u8 status; + __u8 phy_handle; +} __packed; + +#define HCI_EV_CHANNEL_SELECTED 0x41 +struct hci_ev_channel_selected { + __u8 phy_handle; +} __packed; + +#define HCI_EV_DISCONN_PHY_LINK_COMPLETE 0x42 +struct hci_ev_disconn_phy_link_complete { + __u8 status; + __u8 phy_handle; + __u8 reason; +} __packed; + +#define HCI_EV_LOGICAL_LINK_COMPLETE 0x45 +struct hci_ev_logical_link_complete { + __u8 status; + __le16 handle; + __u8 phy_handle; + __u8 flow_spec_id; +} __packed; + +#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE 0x46 +struct hci_ev_disconn_logical_link_complete { + __u8 status; + __le16 handle; + __u8 reason; +} __packed; + #define HCI_EV_NUM_COMP_BLOCKS 0x48 struct hci_comp_blocks_info { __le16 handle; @@ -1290,7 +1380,6 @@ struct hci_sco_hdr { __u8 dlen; } __packed; -#include <linux/skbuff.h> static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb) { return (struct hci_event_hdr *) skb->data; @@ -1307,12 +1396,12 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) } /* Command opcode pack/unpack */ -#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10)) +#define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10))) #define hci_opcode_ogf(op) (op >> 10) #define hci_opcode_ocf(op) (op & 0x03ff) /* ACL handle and flags pack/unpack */ -#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12)) +#define hci_handle_pack(h, f) ((__u16) ((h & 0x0fff)|(f << 12))) #define hci_handle(h) (h & 0x0fff) #define hci_flags(h) (h >> 12) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9fc7728f94e4..20fd57367ddc 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -25,7 +25,6 @@ #ifndef __HCI_CORE_H #define __HCI_CORE_H -#include <linux/interrupt.h> #include <net/bluetooth/hci.h> /* HCI priority */ @@ -65,7 +64,7 @@ struct discovery_state { DISCOVERY_RESOLVING, DISCOVERY_STOPPING, } state; - struct list_head all; /* All devices found during inquiry */ + struct list_head all; /* All devices found during inquiry */ struct list_head unknown; /* Name state not known */ struct list_head resolve; /* Name needs to be resolved */ __u32 timestamp; @@ -105,7 +104,7 @@ struct link_key { struct list_head list; bdaddr_t bdaddr; u8 type; - u8 val[16]; + u8 val[HCI_LINK_KEY_SIZE]; u8 pin_len; }; @@ -333,6 +332,7 @@ struct hci_conn { void *l2cap_data; void *sco_data; void *smp_conn; + struct amp_mgr *amp_mgr; struct hci_conn *link; @@ -360,7 +360,8 @@ extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status); extern int l2cap_disconn_ind(struct hci_conn *hcon); extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason); extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt); -extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); +extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, + u16 flags); extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr); extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status); @@ -429,8 +430,8 @@ enum { static inline bool hci_conn_ssp_enabled(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && - test_bit(HCI_CONN_SSP_ENABLED, &conn->flags)); + return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) && + test_bit(HCI_CONN_SSP_ENABLED, &conn->flags); } static inline void hci_conn_hash_init(struct hci_dev *hdev) @@ -640,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data) dev_set_drvdata(&hdev->dev, data); } +/* hci_dev_list shall be locked */ +static inline uint8_t __hci_num_ctrl(void) +{ + uint8_t count = 0; + struct list_head *p; + + list_for_each(p, &hci_dev_list) { + count++; + } + + return count; +} + struct hci_dev *hci_dev_get(int index); struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst); @@ -661,7 +675,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg); int hci_get_auth_info(struct hci_dev *hdev, void __user *arg); int hci_inquiry(void __user *arg); -struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr); +struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, + bdaddr_t *bdaddr); int hci_blacklist_clear(struct hci_dev *hdev); int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type); diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 1c7d1cd5e679..d80e3f0691b4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -40,11 +40,11 @@ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ #define L2CAP_DEFAULT_ACK_TO 200 -#define L2CAP_LE_DEFAULT_MTU 23 #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF #define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */ +#define L2CAP_LE_MIN_MTU 23 #define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) #define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) @@ -52,6 +52,8 @@ #define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000) #define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000) +#define L2CAP_A2MP_DEFAULT_MTU 670 + /* L2CAP socket address */ struct sockaddr_l2 { sa_family_t l2_family; @@ -229,9 +231,14 @@ struct l2cap_conn_rsp { __le16 status; } __packed; +/* protocol/service multiplexer (PSM) */ +#define L2CAP_PSM_SDP 0x0001 +#define L2CAP_PSM_RFCOMM 0x0003 + /* channel indentifier */ #define L2CAP_CID_SIGNALING 0x0001 #define L2CAP_CID_CONN_LESS 0x0002 +#define L2CAP_CID_A2MP 0x0003 #define L2CAP_CID_LE_DATA 0x0004 #define L2CAP_CID_LE_SIGNALING 0x0005 #define L2CAP_CID_SMP 0x0006 @@ -271,6 +278,9 @@ struct l2cap_conf_rsp { #define L2CAP_CONF_PENDING 0x0004 #define L2CAP_CONF_EFS_REJECT 0x0005 +/* configuration req/rsp continuation flag */ +#define L2CAP_CONF_FLAG_CONTINUATION 0x0001 + struct l2cap_conf_opt { __u8 type; __u8 len; @@ -419,11 +429,6 @@ struct l2cap_seq_list { #define L2CAP_SEQ_LIST_CLEAR 0xFFFF #define L2CAP_SEQ_LIST_TAIL 0x8000 -struct srej_list { - __u16 tx_seq; - struct list_head list; -}; - struct l2cap_chan { struct sock *sk; @@ -475,14 +480,12 @@ struct l2cap_chan { __u16 expected_ack_seq; __u16 expected_tx_seq; __u16 buffer_seq; - __u16 buffer_seq_srej; __u16 srej_save_reqseq; __u16 last_acked_seq; __u16 frames_sent; __u16 unacked_frames; __u8 retry_count; __u16 srej_queue_next; - __u8 num_acked; __u16 sdu_len; struct sk_buff *sdu; struct sk_buff *sdu_last_frag; @@ -515,7 +518,6 @@ struct l2cap_chan { struct sk_buff_head srej_q; struct l2cap_seq_list srej_list; struct l2cap_seq_list retrans_list; - struct list_head srej_l; struct list_head list; struct list_head global_l; @@ -528,10 +530,14 @@ struct l2cap_chan { struct l2cap_ops { char *name; - struct l2cap_chan *(*new_connection) (void *data); - int (*recv) (void *data, struct sk_buff *skb); - void (*close) (void *data); - void (*state_change) (void *data, int state); + struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan); + int (*recv) (struct l2cap_chan * chan, + struct sk_buff *skb); + void (*teardown) (struct l2cap_chan *chan, int err); + void (*close) (struct l2cap_chan *chan); + void (*state_change) (struct l2cap_chan *chan, + int state); + void (*ready) (struct l2cap_chan *chan); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, unsigned long len, int nb); }; @@ -575,6 +581,7 @@ struct l2cap_conn { #define L2CAP_CHAN_RAW 1 #define L2CAP_CHAN_CONN_LESS 2 #define L2CAP_CHAN_CONN_ORIENTED 3 +#define L2CAP_CHAN_CONN_FIX_A2MP 4 /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) @@ -597,6 +604,7 @@ enum { CONF_EWS_RECV, CONF_LOC_CONF_PEND, CONF_REM_CONF_PEND, + CONF_NOT_COMPLETE, }; #define L2CAP_CONF_MAX_CONF_REQ 2 @@ -713,11 +721,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t)) #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer) -#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \ - msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); #define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer) -#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \ - msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); #define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer) #define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \ msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); @@ -736,173 +740,17 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq) return (seq + 1) % (chan->tx_win_max + 1); } -static inline int l2cap_tx_window_full(struct l2cap_chan *ch) -{ - int sub; - - sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64; - - if (sub < 0) - sub += 64; - - return sub == ch->remote_tx_win; -} - -static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >> - L2CAP_EXT_CTRL_REQSEQ_SHIFT; - else - return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; -} - -static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq) +static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan) { - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) & - L2CAP_EXT_CTRL_REQSEQ; - else - return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ; + return NULL; } -static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl) +static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err) { - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >> - L2CAP_EXT_CTRL_TXSEQ_SHIFT; - else - return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; } -static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq) +static inline void l2cap_chan_no_ready(struct l2cap_chan *chan) { - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) & - L2CAP_EXT_CTRL_TXSEQ; - else - return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ; -} - -static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE; - else - return ctrl & L2CAP_CTRL_FRAME_TYPE; -} - -static inline __u32 __set_sframe(struct l2cap_chan *chan) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return L2CAP_EXT_CTRL_FRAME_TYPE; - else - return L2CAP_CTRL_FRAME_TYPE; -} - -static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; - else - return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; -} - -static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR; - else - return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR; -} - -static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl) -{ - return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START; -} - -static inline __u32 __get_sar_mask(struct l2cap_chan *chan) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return L2CAP_EXT_CTRL_SAR; - else - return L2CAP_CTRL_SAR; -} - -static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >> - L2CAP_EXT_CTRL_SUPER_SHIFT; - else - return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; -} - -static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) & - L2CAP_EXT_CTRL_SUPERVISE; - else - return (super << L2CAP_CTRL_SUPER_SHIFT) & - L2CAP_CTRL_SUPERVISE; -} - -static inline __u32 __set_ctrl_final(struct l2cap_chan *chan) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return L2CAP_EXT_CTRL_FINAL; - else - return L2CAP_CTRL_FINAL; -} - -static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return ctrl & L2CAP_EXT_CTRL_FINAL; - else - return ctrl & L2CAP_CTRL_FINAL; -} - -static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return L2CAP_EXT_CTRL_POLL; - else - return L2CAP_CTRL_POLL; -} - -static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return ctrl & L2CAP_EXT_CTRL_POLL; - else - return ctrl & L2CAP_CTRL_POLL; -} - -static inline __u32 __get_control(struct l2cap_chan *chan, void *p) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return get_unaligned_le32(p); - else - return get_unaligned_le16(p); -} - -static inline void __put_control(struct l2cap_chan *chan, __u32 control, - void *p) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return put_unaligned_le32(control, p); - else - return put_unaligned_le16(control, p); -} - -static inline __u8 __ctrl_size(struct l2cap_chan *chan) -{ - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE; - else - return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE; } extern bool disable_ertm; @@ -926,5 +774,8 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); void l2cap_chan_set_defaults(struct l2cap_chan *chan); +int l2cap_ertm_init(struct l2cap_chan *chan); +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); +void l2cap_chan_del(struct l2cap_chan *chan, int err); #endif /* __L2CAP_H */ diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 7319f25250b6..5a67165f3b19 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -70,11 +70,13 @@ * * @IEEE80211_BAND_2GHZ: 2.4GHz ISM band * @IEEE80211_BAND_5GHZ: around 5GHz band (4.9-5.7) + * @IEEE80211_BAND_60GHZ: around 60 GHz band (58.32 - 64.80 GHz) * @IEEE80211_NUM_BANDS: number of defined bands */ enum ieee80211_band { IEEE80211_BAND_2GHZ = NL80211_BAND_2GHZ, IEEE80211_BAND_5GHZ = NL80211_BAND_5GHZ, + IEEE80211_BAND_60GHZ = NL80211_BAND_60GHZ, /* keep last */ IEEE80211_NUM_BANDS @@ -211,6 +213,22 @@ struct ieee80211_sta_ht_cap { }; /** + * struct ieee80211_sta_vht_cap - STA's VHT capabilities + * + * This structure describes most essential parameters needed + * to describe 802.11ac VHT capabilities for an STA. + * + * @vht_supported: is VHT supported by the STA + * @cap: VHT capabilities map as described in 802.11ac spec + * @vht_mcs: Supported VHT MCS rates + */ +struct ieee80211_sta_vht_cap { + bool vht_supported; + u32 cap; /* use IEEE80211_VHT_CAP_ */ + struct ieee80211_vht_mcs_info vht_mcs; +}; + +/** * struct ieee80211_supported_band - frequency band definition * * This structure describes a frequency band a wiphy @@ -233,6 +251,7 @@ struct ieee80211_supported_band { int n_channels; int n_bitrates; struct ieee80211_sta_ht_cap ht_cap; + struct ieee80211_sta_vht_cap vht_cap; }; /* @@ -561,11 +580,13 @@ enum station_info_flags { * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval + * @RATE_INFO_FLAGS_60G: 60gHz MCS */ enum rate_info_flags { RATE_INFO_FLAGS_MCS = 1<<0, RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, RATE_INFO_FLAGS_SHORT_GI = 1<<2, + RATE_INFO_FLAGS_60G = 1<<3, }; /** @@ -627,10 +648,10 @@ struct sta_bss_parameters { * @llid: mesh local link id * @plid: mesh peer link id * @plink_state: mesh peer link state - * @signal: the signal strength, type depends on the wiphy's signal_type - NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. - * @signal_avg: avg signal strength, type depends on the wiphy's signal_type - NOTE: For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. + * @signal: The signal strength, type depends on the wiphy's signal_type. + * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. + * @signal_avg: Average signal strength, type depends on the wiphy's signal_type. + * For CFG80211_SIGNAL_TYPE_MBM, value is expressed in _dBm_. * @txrate: current unicast bitrate from this station * @rxrate: current unicast bitrate to this station * @rx_packets: packets received from this station @@ -790,43 +811,95 @@ struct bss_parameters { int ht_opmode; }; -/* +/** * struct mesh_config - 802.11s mesh configuration * * These parameters can be changed while the mesh is active. + * + * @dot11MeshRetryTimeout: the initial retry timeout in millisecond units used + * by the Mesh Peering Open message + * @dot11MeshConfirmTimeout: the initial retry timeout in millisecond units + * used by the Mesh Peering Open message + * @dot11MeshHoldingTimeout: the confirm timeout in millisecond units used by + * the mesh peering management to close a mesh peering + * @dot11MeshMaxPeerLinks: the maximum number of peer links allowed on this + * mesh interface + * @dot11MeshMaxRetries: the maximum number of peer link open retries that can + * be sent to establish a new peer link instance in a mesh + * @dot11MeshTTL: the value of TTL field set at a source mesh STA + * @element_ttl: the value of TTL field set at a mesh STA for path selection + * elements + * @auto_open_plinks: whether we should automatically open peer links when we + * detect compatible mesh peers + * @dot11MeshNbrOffsetMaxNeighbor: the maximum number of neighbors to + * synchronize to for 11s default synchronization method + * @dot11MeshHWMPmaxPREQretries: the number of action frames containing a PREQ + * that an originator mesh STA can send to a particular path target + * @path_refresh_time: how frequently to refresh mesh paths in milliseconds + * @min_discovery_timeout: the minimum length of time to wait until giving up on + * a path discovery in milliseconds + * @dot11MeshHWMPactivePathTimeout: the time (in TUs) for which mesh STAs + * receiving a PREQ shall consider the forwarding information from the + * root to be valid. (TU = time unit) + * @dot11MeshHWMPpreqMinInterval: the minimum interval of time (in TUs) during + * which a mesh STA can send only one action frame containing a PREQ + * element + * @dot11MeshHWMPperrMinInterval: the minimum interval of time (in TUs) during + * which a mesh STA can send only one Action frame containing a PERR + * element + * @dot11MeshHWMPnetDiameterTraversalTime: the interval of time (in TUs) that + * it takes for an HWMP information element to propagate across the mesh + * @dot11MeshHWMPRootMode: the configuration of a mesh STA as root mesh STA + * @dot11MeshHWMPRannInterval: the interval of time (in TUs) between root + * announcements are transmitted + * @dot11MeshGateAnnouncementProtocol: whether to advertise that this mesh + * station has access to a broader network beyond the MBSS. (This is + * missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol set to true + * only means that the station will announce others it's a mesh gate, but + * not necessarily using the gate announcement protocol. Still keeping the + * same nomenclature to be in sync with the spec) + * @dot11MeshForwarding: whether the Mesh STA is forwarding or non-forwarding + * entity (default is TRUE - forwarding entity) + * @rssi_threshold: the threshold for average signal strength of candidate + * station to establish a peer link + * @ht_opmode: mesh HT protection mode + * + * @dot11MeshHWMPactivePathToRootTimeout: The time (in TUs) for which mesh STAs + * receiving a proactive PREQ shall consider the forwarding information to + * the root mesh STA to be valid. + * + * @dot11MeshHWMProotInterval: The interval of time (in TUs) between proactive + * PREQs are transmitted. + * @dot11MeshHWMPconfirmationInterval: The minimum interval of time (in TUs) + * during which a mesh STA can send only one Action frame containing + * a PREQ element for root path confirmation. */ struct mesh_config { - /* Timeouts in ms */ - /* Mesh plink management parameters */ u16 dot11MeshRetryTimeout; u16 dot11MeshConfirmTimeout; u16 dot11MeshHoldingTimeout; u16 dot11MeshMaxPeerLinks; - u8 dot11MeshMaxRetries; - u8 dot11MeshTTL; - /* ttl used in path selection information elements */ - u8 element_ttl; + u8 dot11MeshMaxRetries; + u8 dot11MeshTTL; + u8 element_ttl; bool auto_open_plinks; - /* neighbor offset synchronization */ u32 dot11MeshNbrOffsetMaxNeighbor; - /* HWMP parameters */ - u8 dot11MeshHWMPmaxPREQretries; + u8 dot11MeshHWMPmaxPREQretries; u32 path_refresh_time; u16 min_discovery_timeout; u32 dot11MeshHWMPactivePathTimeout; u16 dot11MeshHWMPpreqMinInterval; u16 dot11MeshHWMPperrMinInterval; u16 dot11MeshHWMPnetDiameterTraversalTime; - u8 dot11MeshHWMPRootMode; + u8 dot11MeshHWMPRootMode; u16 dot11MeshHWMPRannInterval; - /* This is missnamed in draft 12.0: dot11MeshGateAnnouncementProtocol - * set to true only means that the station will announce others it's a - * mesh gate, but not necessarily using the gate announcement protocol. - * Still keeping the same nomenclature to be in sync with the spec. */ - bool dot11MeshGateAnnouncementProtocol; + bool dot11MeshGateAnnouncementProtocol; bool dot11MeshForwarding; s32 rssi_threshold; u16 ht_opmode; + u32 dot11MeshHWMPactivePathToRootTimeout; + u16 dot11MeshHWMProotInterval; + u16 dot11MeshHWMPconfirmationInterval; }; /** @@ -926,7 +999,7 @@ struct cfg80211_ssid { * @ie_len: length of ie in octets * @rates: bitmap of rates to advertise for each band * @wiphy: the wiphy this was for - * @dev: the interface + * @wdev: the wireless device to scan for * @aborted: (internal) scan request was notified as aborted * @no_cck: used to send probe requests at non CCK rate in 2GHz band */ @@ -939,9 +1012,10 @@ struct cfg80211_scan_request { u32 rates[IEEE80211_NUM_BANDS]; + struct wireless_dev *wdev; + /* internal */ struct wiphy *wiphy; - struct net_device *dev; bool aborted; bool no_cck; @@ -975,6 +1049,7 @@ struct cfg80211_match_set { * @wiphy: the wiphy this was for * @dev: the interface * @channels: channels to scan + * @rssi_thold: don't report scan results below this threshold (in s32 dBm) */ struct cfg80211_sched_scan_request { struct cfg80211_ssid *ssids; @@ -985,6 +1060,7 @@ struct cfg80211_sched_scan_request { size_t ie_len; struct cfg80211_match_set *match_sets; int n_match_sets; + s32 rssi_thold; /* internal */ struct wiphy *wiphy; @@ -1360,10 +1436,10 @@ struct cfg80211_gtk_rekey_data { * * @add_virtual_intf: create a new virtual interface with the given name, * must set the struct wireless_dev's iftype. Beware: You must create - * the new netdev in the wiphy's network namespace! Returns the netdev, - * or an ERR_PTR. + * the new netdev in the wiphy's network namespace! Returns the struct + * wireless_dev, or an ERR_PTR. * - * @del_virtual_intf: remove the virtual interface determined by ifindex. + * @del_virtual_intf: remove the virtual interface * * @change_virtual_intf: change type/configuration of virtual interface, * keep the struct wireless_dev's iftype updated. @@ -1428,9 +1504,8 @@ struct cfg80211_gtk_rekey_data { * interfaces are active this callback should reject the configuration. * If no interfaces are active or the device is down, the channel should * be stored for when a monitor interface becomes active. - * @get_channel: Get the current operating channel, should return %NULL if - * there's no single defined operating channel if for example the - * device implements channel hopping for multi-channel virtual interfaces. + * @set_monitor_enabled: Notify driver that there are only monitor + * interfaces running. * * @scan: Request to do a scan. If returning zero, the scan request is given * the driver, and will be valid until passed to cfg80211_scan_done(). @@ -1543,12 +1618,13 @@ struct cfg80211_ops { int (*resume)(struct wiphy *wiphy); void (*set_wakeup)(struct wiphy *wiphy, bool enabled); - struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params); - int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); + struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); + int (*del_virtual_intf)(struct wiphy *wiphy, + struct wireless_dev *wdev); int (*change_virtual_intf)(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, @@ -1625,7 +1701,7 @@ struct cfg80211_ops { struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); - int (*scan)(struct wiphy *wiphy, struct net_device *dev, + int (*scan)(struct wiphy *wiphy, struct cfg80211_scan_request *request); int (*auth)(struct wiphy *wiphy, struct net_device *dev, @@ -1679,23 +1755,23 @@ struct cfg80211_ops { int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); int (*remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie); int (*cancel_remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie); - int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev, + int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie); int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie); int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, @@ -1706,7 +1782,7 @@ struct cfg80211_ops { s32 rssi_thold, u32 rssi_hyst); void (*mgmt_frame_register)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg); int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); @@ -1737,15 +1813,14 @@ struct cfg80211_ops { struct net_device *dev, u16 noack_map); - struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy, - enum nl80211_channel_type *type); - int (*get_et_sset_count)(struct wiphy *wiphy, struct net_device *dev, int sset); void (*get_et_stats)(struct wiphy *wiphy, struct net_device *dev, struct ethtool_stats *stats, u64 *data); void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, u32 sset, u8 *data); + + void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled); }; /* @@ -2099,7 +2174,9 @@ struct wiphy { char fw_version[ETHTOOL_BUSINFO_LEN]; u32 hw_version; +#ifdef CONFIG_PM struct wiphy_wowlan_support wowlan; +#endif u16 max_remain_on_channel_duration; @@ -2266,17 +2343,25 @@ struct cfg80211_internal_bss; struct cfg80211_cached_keys; /** - * struct wireless_dev - wireless per-netdev state + * struct wireless_dev - wireless device state + * + * For netdevs, this structure must be allocated by the driver + * that uses the ieee80211_ptr field in struct net_device (this + * is intentional so it can be allocated along with the netdev.) + * It need not be registered then as netdev registration will + * be intercepted by cfg80211 to see the new wireless device. * - * This structure must be allocated by the driver/stack - * that uses the ieee80211_ptr field in struct net_device - * (this is intentional so it can be allocated along with - * the netdev.) + * For non-netdev uses, it must also be allocated by the driver + * in response to the cfg80211 callbacks that require it, as + * there's no netdev registration in that case it may not be + * allocated outside of callback operations that return it. * * @wiphy: pointer to hardware description * @iftype: interface type * @list: (private) Used to collect the interfaces - * @netdev: (private) Used to reference back to the netdev + * @netdev: (private) Used to reference back to the netdev, may be %NULL + * @identifier: (private) Identifier used in nl80211 to identify this + * wireless device if it has no netdev * @current_bss: (private) Used by the internal configuration code * @channel: (private) Used by the internal configuration code to track * the user-set AP, monitor and WDS channel @@ -2308,6 +2393,8 @@ struct wireless_dev { struct list_head list; struct net_device *netdev; + u32 identifier; + struct list_head mgmt_registrations; spinlock_t mgmt_registrations_lock; @@ -2335,6 +2422,11 @@ struct wireless_dev { struct ieee80211_channel *preset_chan; enum nl80211_channel_type preset_chantype; + /* for AP and mesh channel tracking */ + struct ieee80211_channel *channel; + + bool ibss_fixed; + bool ps; int ps_timeout; @@ -3189,7 +3281,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, /** * cfg80211_ready_on_channel - notification of remain_on_channel start - * @dev: network device + * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) * @channel_type: Channel type @@ -3197,21 +3289,20 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, * channel * @gfp: allocation flags */ -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, +void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); /** * cfg80211_remain_on_channel_expired - remain_on_channel duration expired - * @dev: network device + * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) * @channel_type: Channel type * @gfp: allocation flags */ -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, +void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp); @@ -3239,7 +3330,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); /** * cfg80211_rx_mgmt - notification of received, unprocessed management frame - * @dev: network device + * @wdev: wireless device receiving the frame * @freq: Frequency on which the frame was received in MHz * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) @@ -3254,12 +3345,12 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * This function is called whenever an Action frame is received for a station * mode interface, but is not processed in kernel. */ -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, +bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame - * @dev: network device + * @wdev: wireless device receiving the frame * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() * @buf: Management frame (header + body) * @len: length of the frame data @@ -3270,7 +3361,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the * transmission attempt. */ -void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, +void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp); @@ -3409,7 +3500,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, * * return 0 if MCS index >= 32 */ -u16 cfg80211_calculate_bitrate(struct rate_info *rate); +u32 cfg80211_calculate_bitrate(struct rate_info *rate); /* Logging, debugging and troubleshooting/diagnostic helpers. */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index d152f54064fd..bb86aa6f98dd 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -233,8 +233,10 @@ enum ieee80211_rssi_event { * valid in station mode only while @assoc is true and if also * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf * @ps_dtim_period) - * @last_tsf: last beacon's/probe response's TSF timestamp (could be old + * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old * as it may have been received during scanning long ago) + * @sync_device_ts: the device timestamp corresponding to the sync_tsf, + * the driver/device can use this to calculate synchronisation * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp * @basic_rates: bitmap of basic rates, each bit stands for an @@ -281,7 +283,8 @@ struct ieee80211_bss_conf { u8 dtim_period; u16 beacon_int; u16 assoc_capability; - u64 last_tsf; + u64 sync_tsf; + u32 sync_device_ts; u32 basic_rates; int mcast_rate[IEEE80211_NUM_BANDS]; u16 ht_operation_mode; @@ -475,7 +478,7 @@ enum mac80211_rate_control_flags { #define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 /* maximum number of rate stages */ -#define IEEE80211_TX_MAX_RATES 5 +#define IEEE80211_TX_MAX_RATES 4 /** * struct ieee80211_tx_rate - rate selection/status @@ -563,11 +566,11 @@ struct ieee80211_tx_info { } control; struct { struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; - u8 ampdu_ack_len; int ack_signal; + u8 ampdu_ack_len; u8 ampdu_len; u8 antenna; - /* 14 bytes free */ + /* 21 bytes free */ } status; struct { struct ieee80211_tx_rate driver_rates[ @@ -634,7 +637,7 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) info->status.rates[i].count = 0; BUILD_BUG_ON( - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + offsetof(struct ieee80211_tx_info, status.ack_signal) != 20); memset(&info->status.ampdu_ack_len, 0, sizeof(struct ieee80211_tx_info) - offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); @@ -696,6 +699,8 @@ enum mac80211_rx_flags { * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. + * @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use + * it but can store it and pass it back to the driver for synchronisation * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz * @signal: signal strength when receiving this frame, either in dBm, in dB or @@ -709,13 +714,14 @@ enum mac80211_rx_flags { */ struct ieee80211_rx_status { u64 mactime; - enum ieee80211_band band; - int freq; - int signal; - int antenna; - int rate_idx; - int flag; - unsigned int rx_flags; + u32 device_timestamp; + u16 flag; + u16 freq; + u8 rate_idx; + u8 rx_flags; + u8 band; + u8 antenna; + s8 signal; }; /** @@ -1896,19 +1902,6 @@ enum ieee80211_rate_control_changed { * The low-level driver should send the frame out based on * configuration in the TX control data. This handler should, * preferably, never fail and stop queues appropriately. - * This must be implemented if @tx_frags is not. - * Must be atomic. - * - * @tx_frags: Called to transmit multiple fragments of a single MSDU. - * This handler must consume all fragments, sending out some of - * them only is useless and it can't ask for some of them to be - * queued again. If the frame is not fragmented the queue has a - * single SKB only. To avoid issues with the networking stack - * when TX status is reported the frames should be removed from - * the skb queue. - * If this is used, the tx_info @vif and @sta pointers will be - * invalid -- you must not use them in that case. - * This must be implemented if @tx isn't. * Must be atomic. * * @start: Called before the first netdevice attached to the hardware @@ -1945,6 +1938,11 @@ enum ieee80211_rate_control_changed { * to also unregister the device. If it returns 1, then mac80211 * will also go through the regular complete restart on resume. * + * @set_wakeup: Enable or disable wakeup when WoWLAN configuration is + * modified. The reason is that device_set_wakeup_enable() is + * supposed to be called when the configuration changes, not only + * in suspend(). + * * @add_interface: Called when a netdevice attached to the hardware is * enabled. Because it is not called for monitor mode devices, @start * and @stop must be implemented. @@ -2249,11 +2247,24 @@ enum ieee80211_rate_control_changed { * @get_et_strings: Ethtool API to get a set of strings to describe stats * and perhaps other supported types of ethtool data-sets. * + * @get_rssi: Get current signal strength in dBm, the function is optional + * and can sleep. + * + * @mgd_prepare_tx: Prepare for transmitting a management frame for association + * before associated. In multi-channel scenarios, a virtual interface is + * bound to a channel before it is associated, but as it isn't associated + * yet it need not necessarily be given airtime, in particular since any + * transmission to a P2P GO needs to be synchronized against the GO's + * powersave state. mac80211 will call this function before transmitting a + * management frame prior to having successfully associated to allow the + * driver to give it channel time for the transmission, to get a response + * and to be able to synchronize with the GO. + * The callback will be called before each transmission and upon return + * mac80211 will transmit the frame right away. + * The callback is optional and can (should!) sleep. */ struct ieee80211_ops { void (*tx)(struct ieee80211_hw *hw, struct sk_buff *skb); - void (*tx_frags)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, - struct ieee80211_sta *sta, struct sk_buff_head *skbs); int (*start)(struct ieee80211_hw *hw); void (*stop)(struct ieee80211_hw *hw); #ifdef CONFIG_PM @@ -2388,6 +2399,11 @@ struct ieee80211_ops { void (*get_et_strings)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u32 sset, u8 *data); + int (*get_rssi)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, s8 *rssi_dbm); + + void (*mgd_prepare_tx)(struct ieee80211_hw *hw, + struct ieee80211_vif *vif); }; /** @@ -2974,6 +2990,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, * ieee80211_generic_frame_duration - Calculate the duration field for a frame * @hw: pointer obtained from ieee80211_alloc_hw(). * @vif: &struct ieee80211_vif pointer from the add_interface callback. + * @band: the band to calculate the frame duration on * @frame_len: the length of the frame. * @rate: the rate at which the frame is going to be transmitted. * @@ -3581,22 +3598,6 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_mode); /** - * ieee80211_key_removed - disable hw acceleration for key - * @key_conf: The key hw acceleration should be disabled for - * - * This allows drivers to indicate that the given key has been - * removed from hardware acceleration, due to a new key that - * was added. Don't use this if the key can continue to be used - * for TX, if the key restriction is on RX only it is permitted - * to keep the key for TX only and not call this function. - * - * Due to locking constraints, it may only be called during - * @set_key. This function must be allowed to sleep, and the - * key it tries to disable may still be used until it returns. - */ -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf); - -/** * ieee80211_ready_on_channel - notification of remain-on-channel start * @hw: pointer as obtained from ieee80211_alloc_hw() */ @@ -3821,12 +3822,6 @@ void ieee80211_enable_rssi_reports(struct ieee80211_vif *vif, void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif); -int ieee80211_add_srates_ie(struct ieee80211_vif *vif, - struct sk_buff *skb, bool need_basic); - -int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, - struct sk_buff *skb, bool need_basic); - /** * ieee80211_ave_rssi - report the average rssi for the specified interface * @@ -3837,28 +3832,4 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, */ int ieee80211_ave_rssi(struct ieee80211_vif *vif); -/* Extra debugging macros */ - -#ifdef CONFIG_MAC80211_HT_DEBUG -#define ht_vdbg(fmt, ...) \ - pr_debug(fmt, ##__VA_ARGS__) -#else -#define ht_vdbg(fmt, ...) \ -do { \ - if (0) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) -#endif - -#ifdef CONFIG_MAC80211_IBSS_DEBUG -#define ibss_vdbg(fmt, ...) \ - pr_debug(fmt, ##__VA_ARGS__) -#else -#define ibss_vdbg(fmt, ...) \ -do { \ - if (0) \ - pr_debug(fmt, ##__VA_ARGS__); \ -} while (0) -#endif - #endif /* MAC80211_H */ diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index e30e6a869714..f5169b04f082 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -44,10 +44,20 @@ struct nfc_hci_ops { struct nfc_target *target); }; -#define NFC_HCI_MAX_CUSTOM_GATES 15 +/* Pipes */ +#define NFC_HCI_INVALID_PIPE 0x80 +#define NFC_HCI_LINK_MGMT_PIPE 0x00 +#define NFC_HCI_ADMIN_PIPE 0x01 + +struct nfc_hci_gate { + u8 gate; + u8 pipe; +}; + +#define NFC_HCI_MAX_CUSTOM_GATES 50 struct nfc_hci_init_data { u8 gate_count; - u8 gates[NFC_HCI_MAX_CUSTOM_GATES]; + struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES]; char session_id[9]; }; @@ -112,6 +122,8 @@ void nfc_hci_unregister_device(struct nfc_hci_dev *hdev); void nfc_hci_set_clientdata(struct nfc_hci_dev *hdev, void *clientdata); void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev); +void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err); + /* Host IDs */ #define NFC_HCI_HOST_CONTROLLER_ID 0x00 #define NFC_HCI_TERMINAL_HOST_ID 0x01 @@ -180,7 +192,8 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb); /* connecting to gates and sending hci instructions */ -int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate); +int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, + u8 pipe); int nfc_hci_disconnect_gate(struct nfc_hci_dev *hdev, u8 gate); int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev); int nfc_hci_get_param(struct nfc_hci_dev *hdev, u8 gate, u8 idx, diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 180964b954ab..6431f5e39022 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -204,4 +204,6 @@ int nfc_tm_activated(struct nfc_dev *dev, u32 protocol, u8 comm_mode, int nfc_tm_deactivated(struct nfc_dev *dev); int nfc_tm_data_received(struct nfc_dev *dev, struct sk_buff *skb); +void nfc_driver_failure(struct nfc_dev *dev, int err); + #endif /* __NET_NFC_H */ diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile index 2dc5a5700f53..fa6d94a4602a 100644 --- a/net/bluetooth/Makefile +++ b/net/bluetooth/Makefile @@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP) += cmtp/ obj-$(CONFIG_BT_HIDP) += hidp/ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ - hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o + hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ + a2mp.o diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c new file mode 100644 index 000000000000..fb93250b3938 --- /dev/null +++ b/net/bluetooth/a2mp.c @@ -0,0 +1,568 @@ +/* + Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved. + Copyright (c) 2011,2012 Intel Corp. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 and + only version 2 as published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. +*/ + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> +#include <net/bluetooth/l2cap.h> +#include <net/bluetooth/a2mp.h> + +/* A2MP build & send command helper functions */ +static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data) +{ + struct a2mp_cmd *cmd; + int plen; + + plen = sizeof(*cmd) + len; + cmd = kzalloc(plen, GFP_KERNEL); + if (!cmd) + return NULL; + + cmd->code = code; + cmd->ident = ident; + cmd->len = cpu_to_le16(len); + + memcpy(cmd->data, data, len); + + return cmd; +} + +static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, + void *data) +{ + struct l2cap_chan *chan = mgr->a2mp_chan; + struct a2mp_cmd *cmd; + u16 total_len = len + sizeof(*cmd); + struct kvec iv; + struct msghdr msg; + + cmd = __a2mp_build(code, ident, len, data); + if (!cmd) + return; + + iv.iov_base = cmd; + iv.iov_len = total_len; + + memset(&msg, 0, sizeof(msg)); + + msg.msg_iov = (struct iovec *) &iv; + msg.msg_iovlen = 1; + + l2cap_chan_send(chan, &msg, total_len, 0); + + kfree(cmd); +} + +static inline void __a2mp_cl_bredr(struct a2mp_cl *cl) +{ + cl->id = 0; + cl->type = 0; + cl->status = 1; +} + +/* hci_dev_list shall be locked */ +static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl) +{ + int i = 0; + struct hci_dev *hdev; + + __a2mp_cl_bredr(cl); + + list_for_each_entry(hdev, &hci_dev_list, list) { + /* Iterate through AMP controllers */ + if (hdev->id == HCI_BREDR_ID) + continue; + + /* Starting from second entry */ + if (++i >= num_ctrl) + return; + + cl[i].id = hdev->id; + cl[i].type = hdev->amp_type; + cl[i].status = hdev->amp_status; + } +} + +/* Processing A2MP messages */ +static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_cmd_rej *rej = (void *) skb->data; + + if (le16_to_cpu(hdr->len) < sizeof(*rej)) + return -EINVAL; + + BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason)); + + skb_pull(skb, sizeof(*rej)); + + return 0; +} + +static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_discov_req *req = (void *) skb->data; + u16 len = le16_to_cpu(hdr->len); + struct a2mp_discov_rsp *rsp; + u16 ext_feat; + u8 num_ctrl; + + if (len < sizeof(*req)) + return -EINVAL; + + skb_pull(skb, sizeof(*req)); + + ext_feat = le16_to_cpu(req->ext_feat); + + BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat); + + /* check that packet is not broken for now */ + while (ext_feat & A2MP_FEAT_EXT) { + if (len < sizeof(ext_feat)) + return -EINVAL; + + ext_feat = get_unaligned_le16(skb->data); + BT_DBG("efm 0x%4.4x", ext_feat); + len -= sizeof(ext_feat); + skb_pull(skb, sizeof(ext_feat)); + } + + read_lock(&hci_dev_list_lock); + + num_ctrl = __hci_num_ctrl(); + len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp); + rsp = kmalloc(len, GFP_ATOMIC); + if (!rsp) { + read_unlock(&hci_dev_list_lock); + return -ENOMEM; + } + + rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU); + rsp->ext_feat = 0; + + __a2mp_add_cl(mgr, rsp->cl, num_ctrl); + + read_unlock(&hci_dev_list_lock); + + a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp); + + kfree(rsp); + return 0; +} + +static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_cl *cl = (void *) skb->data; + + while (skb->len >= sizeof(*cl)) { + BT_DBG("Controller id %d type %d status %d", cl->id, cl->type, + cl->status); + cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl)); + } + + /* TODO send A2MP_CHANGE_RSP */ + + return 0; +} + +static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_info_req *req = (void *) skb->data; + struct a2mp_info_rsp rsp; + struct hci_dev *hdev; + + if (le16_to_cpu(hdr->len) < sizeof(*req)) + return -EINVAL; + + BT_DBG("id %d", req->id); + + rsp.id = req->id; + rsp.status = A2MP_STATUS_INVALID_CTRL_ID; + + hdev = hci_dev_get(req->id); + if (hdev && hdev->amp_type != HCI_BREDR) { + rsp.status = 0; + rsp.total_bw = cpu_to_le32(hdev->amp_total_bw); + rsp.max_bw = cpu_to_le32(hdev->amp_max_bw); + rsp.min_latency = cpu_to_le32(hdev->amp_min_latency); + rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap); + rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size); + } + + if (hdev) + hci_dev_put(hdev); + + a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp); + + skb_pull(skb, sizeof(*req)); + return 0; +} + +static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_amp_assoc_req *req = (void *) skb->data; + struct hci_dev *hdev; + + if (le16_to_cpu(hdr->len) < sizeof(*req)) + return -EINVAL; + + BT_DBG("id %d", req->id); + + hdev = hci_dev_get(req->id); + if (!hdev || hdev->amp_type == HCI_BREDR) { + struct a2mp_amp_assoc_rsp rsp; + rsp.id = req->id; + rsp.status = A2MP_STATUS_INVALID_CTRL_ID; + + a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp), + &rsp); + goto clean; + } + + /* Placeholder for HCI Read AMP Assoc */ + +clean: + if (hdev) + hci_dev_put(hdev); + + skb_pull(skb, sizeof(*req)); + return 0; +} + +static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_physlink_req *req = (void *) skb->data; + + struct a2mp_physlink_rsp rsp; + struct hci_dev *hdev; + + if (le16_to_cpu(hdr->len) < sizeof(*req)) + return -EINVAL; + + BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id); + + rsp.local_id = req->remote_id; + rsp.remote_id = req->local_id; + + hdev = hci_dev_get(req->remote_id); + if (!hdev || hdev->amp_type != HCI_AMP) { + rsp.status = A2MP_STATUS_INVALID_CTRL_ID; + goto send_rsp; + } + + /* TODO process physlink create */ + + rsp.status = A2MP_STATUS_SUCCESS; + +send_rsp: + if (hdev) + hci_dev_put(hdev); + + a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp), + &rsp); + + skb_pull(skb, le16_to_cpu(hdr->len)); + return 0; +} + +static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + struct a2mp_physlink_req *req = (void *) skb->data; + struct a2mp_physlink_rsp rsp; + struct hci_dev *hdev; + + if (le16_to_cpu(hdr->len) < sizeof(*req)) + return -EINVAL; + + BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id); + + rsp.local_id = req->remote_id; + rsp.remote_id = req->local_id; + rsp.status = A2MP_STATUS_SUCCESS; + + hdev = hci_dev_get(req->local_id); + if (!hdev) { + rsp.status = A2MP_STATUS_INVALID_CTRL_ID; + goto send_rsp; + } + + /* TODO Disconnect Phys Link here */ + + hci_dev_put(hdev); + +send_rsp: + a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp); + + skb_pull(skb, sizeof(*req)); + return 0; +} + +static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb, + struct a2mp_cmd *hdr) +{ + BT_DBG("ident %d code %d", hdr->ident, hdr->code); + + skb_pull(skb, le16_to_cpu(hdr->len)); + return 0; +} + +/* Handle A2MP signalling */ +static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) +{ + struct a2mp_cmd *hdr = (void *) skb->data; + struct amp_mgr *mgr = chan->data; + int err = 0; + + amp_mgr_get(mgr); + + while (skb->len >= sizeof(*hdr)) { + struct a2mp_cmd *hdr = (void *) skb->data; + u16 len = le16_to_cpu(hdr->len); + + BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len); + + skb_pull(skb, sizeof(*hdr)); + + if (len > skb->len || !hdr->ident) { + err = -EINVAL; + break; + } + + mgr->ident = hdr->ident; + + switch (hdr->code) { + case A2MP_COMMAND_REJ: + a2mp_command_rej(mgr, skb, hdr); + break; + + case A2MP_DISCOVER_REQ: + err = a2mp_discover_req(mgr, skb, hdr); + break; + + case A2MP_CHANGE_NOTIFY: + err = a2mp_change_notify(mgr, skb, hdr); + break; + + case A2MP_GETINFO_REQ: + err = a2mp_getinfo_req(mgr, skb, hdr); + break; + + case A2MP_GETAMPASSOC_REQ: + err = a2mp_getampassoc_req(mgr, skb, hdr); + break; + + case A2MP_CREATEPHYSLINK_REQ: + err = a2mp_createphyslink_req(mgr, skb, hdr); + break; + + case A2MP_DISCONNPHYSLINK_REQ: + err = a2mp_discphyslink_req(mgr, skb, hdr); + break; + + case A2MP_CHANGE_RSP: + case A2MP_DISCOVER_RSP: + case A2MP_GETINFO_RSP: + case A2MP_GETAMPASSOC_RSP: + case A2MP_CREATEPHYSLINK_RSP: + case A2MP_DISCONNPHYSLINK_RSP: + err = a2mp_cmd_rsp(mgr, skb, hdr); + break; + + default: + BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code); + err = -EINVAL; + break; + } + } + + if (err) { + struct a2mp_cmd_rej rej; + rej.reason = __constant_cpu_to_le16(0); + + BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err); + + a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej), + &rej); + } + + /* Always free skb and return success error code to prevent + from sending L2CAP Disconnect over A2MP channel */ + kfree_skb(skb); + + amp_mgr_put(mgr); + + return 0; +} + +static void a2mp_chan_close_cb(struct l2cap_chan *chan) +{ + l2cap_chan_destroy(chan); +} + +static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state) +{ + struct amp_mgr *mgr = chan->data; + + if (!mgr) + return; + + BT_DBG("chan %p state %s", chan, state_to_string(state)); + + chan->state = state; + + switch (state) { + case BT_CLOSED: + if (mgr) + amp_mgr_put(mgr); + break; + } +} + +static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan, + unsigned long len, int nb) +{ + return bt_skb_alloc(len, GFP_KERNEL); +} + +static struct l2cap_ops a2mp_chan_ops = { + .name = "L2CAP A2MP channel", + .recv = a2mp_chan_recv_cb, + .close = a2mp_chan_close_cb, + .state_change = a2mp_chan_state_change_cb, + .alloc_skb = a2mp_chan_alloc_skb_cb, + + /* Not implemented for A2MP */ + .new_connection = l2cap_chan_no_new_connection, + .teardown = l2cap_chan_no_teardown, + .ready = l2cap_chan_no_ready, +}; + +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn) +{ + struct l2cap_chan *chan; + int err; + + chan = l2cap_chan_create(); + if (!chan) + return NULL; + + BT_DBG("chan %p", chan); + + chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP; + chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; + + chan->ops = &a2mp_chan_ops; + + l2cap_chan_set_defaults(chan); + chan->remote_max_tx = chan->max_tx; + chan->remote_tx_win = chan->tx_win; + + chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO; + chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO; + + skb_queue_head_init(&chan->tx_q); + + chan->mode = L2CAP_MODE_ERTM; + + err = l2cap_ertm_init(chan); + if (err < 0) { + l2cap_chan_del(chan, 0); + return NULL; + } + + chan->conf_state = 0; + + l2cap_chan_add(conn, chan); + + chan->remote_mps = chan->omtu; + chan->mps = chan->omtu; + + chan->state = BT_CONNECTED; + + return chan; +} + +/* AMP Manager functions */ +void amp_mgr_get(struct amp_mgr *mgr) +{ + BT_DBG("mgr %p", mgr); + + kref_get(&mgr->kref); +} + +static void amp_mgr_destroy(struct kref *kref) +{ + struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref); + + BT_DBG("mgr %p", mgr); + + kfree(mgr); +} + +int amp_mgr_put(struct amp_mgr *mgr) +{ + BT_DBG("mgr %p", mgr); + + return kref_put(&mgr->kref, &_mgr_destroy); +} + +static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn) +{ + struct amp_mgr *mgr; + struct l2cap_chan *chan; + + mgr = kzalloc(sizeof(*mgr), GFP_KERNEL); + if (!mgr) + return NULL; + + BT_DBG("conn %p mgr %p", conn, mgr); + + mgr->l2cap_conn = conn; + + chan = a2mp_chan_open(conn); + if (!chan) { + kfree(mgr); + return NULL; + } + + mgr->a2mp_chan = chan; + chan->data = mgr; + + conn->hcon->amp_mgr = mgr; + + kref_init(&mgr->kref); + + return mgr; +} + +struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, + struct sk_buff *skb) +{ + struct amp_mgr *mgr; + + mgr = amp_mgr_create(conn); + if (!mgr) { + BT_ERR("Could not create AMP manager"); + return NULL; + } + + BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan); + + return mgr->a2mp_chan; +} diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 3e18af4dadc4..f7db5792ec64 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -25,18 +25,7 @@ /* Bluetooth address family and sockets. */ #include <linux/module.h> - -#include <linux/types.h> -#include <linux/list.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/skbuff.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <net/sock.h> #include <asm/ioctls.h> -#include <linux/kmod.h> #include <net/bluetooth/bluetooth.h> @@ -418,7 +407,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent) return 0; } -unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait) +unsigned int bt_sock_poll(struct file *file, struct socket *sock, + poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask = 0; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 031d7d656754..4a6620bc1570 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -26,26 +26,9 @@ */ #include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/freezer.h> -#include <linux/errno.h> -#include <linux/net.h> -#include <linux/slab.h> #include <linux/kthread.h> -#include <net/sock.h> - -#include <linux/socket.h> #include <linux/file.h> - -#include <linux/netdevice.h> #include <linux/etherdevice.h> -#include <linux/skbuff.h> - #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -306,7 +289,7 @@ static u8 __bnep_rx_hlen[] = { ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ }; -static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) +static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) { struct net_device *dev = s->dev; struct sk_buff *nskb; @@ -404,7 +387,7 @@ static u8 __bnep_tx_types[] = { BNEP_COMPRESSED }; -static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb) +static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb) { struct ethhdr *eh = (void *) skb->data; struct socket *sock = s->sock; diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index bc4086480d97..98f86f91d47c 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -25,16 +25,8 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/module.h> -#include <linux/slab.h> - -#include <linux/socket.h> -#include <linux/netdevice.h> +#include <linux/export.h> #include <linux/etherdevice.h> -#include <linux/skbuff.h> -#include <linux/wait.h> - -#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -128,7 +120,7 @@ static void bnep_net_timeout(struct net_device *dev) } #ifdef CONFIG_BT_BNEP_MC_FILTER -static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s) +static int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s) { struct ethhdr *eh = (void *) skb->data; @@ -140,7 +132,7 @@ static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s #ifdef CONFIG_BT_BNEP_PROTO_FILTER /* Determine ether protocol. Based on eth_type_trans. */ -static inline u16 bnep_net_eth_proto(struct sk_buff *skb) +static u16 bnep_net_eth_proto(struct sk_buff *skb) { struct ethhdr *eh = (void *) skb->data; u16 proto = ntohs(eh->h_proto); @@ -154,7 +146,7 @@ static inline u16 bnep_net_eth_proto(struct sk_buff *skb) return ETH_P_802_2; } -static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s) +static int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s) { u16 proto = bnep_net_eth_proto(skb); struct bnep_proto_filter *f = s->proto_filter; diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 180bfc45810d..5e5f5b410e0b 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -24,24 +24,8 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/skbuff.h> -#include <linux/socket.h> -#include <linux/ioctl.h> +#include <linux/export.h> #include <linux/file.h> -#include <linux/init.h> -#include <linux/compat.h> -#include <linux/gfp.h> -#include <linux/uaccess.h> -#include <net/sock.h> - #include "bnep.h" diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 3f18a6ed9731..2fcced377e50 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -24,24 +24,11 @@ /* Bluetooth HCI connection handling. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/interrupt.h> -#include <net/sock.h> - -#include <linux/uaccess.h> -#include <asm/unaligned.h> +#include <linux/export.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> +#include <net/bluetooth/a2mp.h> static void hci_le_connect(struct hci_conn *conn) { @@ -54,15 +41,15 @@ static void hci_le_connect(struct hci_conn *conn) conn->sec_level = BT_SECURITY_LOW; memset(&cp, 0, sizeof(cp)); - cp.scan_interval = cpu_to_le16(0x0060); - cp.scan_window = cpu_to_le16(0x0030); + cp.scan_interval = __constant_cpu_to_le16(0x0060); + cp.scan_window = __constant_cpu_to_le16(0x0030); bacpy(&cp.peer_addr, &conn->dst); cp.peer_addr_type = conn->dst_type; - cp.conn_interval_min = cpu_to_le16(0x0028); - cp.conn_interval_max = cpu_to_le16(0x0038); - cp.supervision_timeout = cpu_to_le16(0x002a); - cp.min_ce_len = cpu_to_le16(0x0000); - cp.max_ce_len = cpu_to_le16(0x0000); + cp.conn_interval_min = __constant_cpu_to_le16(0x0028); + cp.conn_interval_max = __constant_cpu_to_le16(0x0038); + cp.supervision_timeout = __constant_cpu_to_le16(0x002a); + cp.min_ce_len = __constant_cpu_to_le16(0x0000); + cp.max_ce_len = __constant_cpu_to_le16(0x0000); hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); } @@ -99,7 +86,7 @@ void hci_acl_connect(struct hci_conn *conn) cp.pscan_rep_mode = ie->data.pscan_rep_mode; cp.pscan_mode = ie->data.pscan_mode; cp.clock_offset = ie->data.clock_offset | - cpu_to_le16(0x8000); + __constant_cpu_to_le16(0x8000); } memcpy(conn->dev_class, ie->data.dev_class, 3); @@ -175,9 +162,9 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) cp.handle = cpu_to_le16(handle); cp.pkt_type = cpu_to_le16(conn->pkt_type); - cp.tx_bandwidth = cpu_to_le32(0x00001f40); - cp.rx_bandwidth = cpu_to_le32(0x00001f40); - cp.max_latency = cpu_to_le16(0xffff); + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.max_latency = __constant_cpu_to_le16(0xffff); cp.voice_setting = cpu_to_le16(hdev->voice_setting); cp.retrans_effort = 0xff; @@ -185,7 +172,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) } void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, - u16 latency, u16 to_multiplier) + u16 latency, u16 to_multiplier) { struct hci_cp_le_conn_update cp; struct hci_dev *hdev = conn->hdev; @@ -197,15 +184,14 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, cp.conn_interval_max = cpu_to_le16(max); cp.conn_latency = cpu_to_le16(latency); cp.supervision_timeout = cpu_to_le16(to_multiplier); - cp.min_ce_len = cpu_to_le16(0x0001); - cp.max_ce_len = cpu_to_le16(0x0001); + cp.min_ce_len = __constant_cpu_to_le16(0x0001); + cp.max_ce_len = __constant_cpu_to_le16(0x0001); hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); } -EXPORT_SYMBOL(hci_le_conn_update); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], - __u8 ltk[16]) + __u8 ltk[16]) { struct hci_dev *hdev = conn->hdev; struct hci_cp_le_start_enc cp; @@ -221,7 +207,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp); } -EXPORT_SYMBOL(hci_le_start_enc); /* Device _must_ be locked */ void hci_sco_setup(struct hci_conn *conn, __u8 status) @@ -247,7 +232,7 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) static void hci_conn_timeout(struct work_struct *work) { struct hci_conn *conn = container_of(work, struct hci_conn, - disc_work.work); + disc_work.work); __u8 reason; BT_DBG("conn %p state %s", conn, state_to_string(conn->state)); @@ -295,9 +280,9 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { struct hci_cp_sniff_subrate cp; cp.handle = cpu_to_le16(conn->handle); - cp.max_latency = cpu_to_le16(0); - cp.min_remote_timeout = cpu_to_le16(0); - cp.min_local_timeout = cpu_to_le16(0); + cp.max_latency = __constant_cpu_to_le16(0); + cp.min_remote_timeout = __constant_cpu_to_le16(0); + cp.min_local_timeout = __constant_cpu_to_le16(0); hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); } @@ -306,8 +291,8 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) cp.handle = cpu_to_le16(conn->handle); cp.max_interval = cpu_to_le16(hdev->sniff_max_interval); cp.min_interval = cpu_to_le16(hdev->sniff_min_interval); - cp.attempt = cpu_to_le16(4); - cp.timeout = cpu_to_le16(1); + cp.attempt = __constant_cpu_to_le16(4); + cp.timeout = __constant_cpu_to_le16(1); hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); } } @@ -327,7 +312,7 @@ static void hci_conn_auto_accept(unsigned long arg) struct hci_dev *hdev = conn->hdev; hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), - &conn->dst); + &conn->dst); } struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) @@ -376,7 +361,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, - (unsigned long) conn); + (unsigned long) conn); atomic_set(&conn->refcnt, 0); @@ -425,9 +410,11 @@ int hci_conn_del(struct hci_conn *conn) } } - hci_chan_list_flush(conn); + if (conn->amp_mgr) + amp_mgr_put(conn->amp_mgr); + hci_conn_hash_del(hdev, conn); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); @@ -454,7 +441,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) read_lock(&hci_dev_list_lock); list_for_each_entry(d, &hci_dev_list, list) { - if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags)) + if (!test_bit(HCI_UP, &d->flags) || + test_bit(HCI_RAW, &d->flags)) continue; /* Simple routing: @@ -495,6 +483,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, if (type == LE_LINK) { le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); if (!le) { + le = hci_conn_hash_lookup_state(hdev, LE_LINK, + BT_CONNECT); + if (le) + return ERR_PTR(-EBUSY); + le = hci_conn_add(hdev, LE_LINK, dst); if (!le) return ERR_PTR(-ENOMEM); @@ -545,7 +538,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, hci_conn_hold(sco); if (acl->state == BT_CONNECTED && - (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { + (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { set_bit(HCI_CONN_POWER_SAVE, &acl->flags); hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); @@ -560,7 +553,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, return sco; } -EXPORT_SYMBOL(hci_connect); /* Check link security requirement */ int hci_conn_check_link_mode(struct hci_conn *conn) @@ -572,7 +564,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn) return 1; } -EXPORT_SYMBOL(hci_conn_check_link_mode); /* Authenticate remote device */ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) @@ -600,7 +591,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, - sizeof(cp), &cp); + sizeof(cp), &cp); if (conn->key_type != 0xff) set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); } @@ -618,7 +609,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) cp.handle = cpu_to_le16(conn->handle); cp.encrypt = 0x01; hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), - &cp); + &cp); } } @@ -648,8 +639,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* An unauthenticated combination key has sufficient security for security level 1 and 2. */ if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && - (sec_level == BT_SECURITY_MEDIUM || - sec_level == BT_SECURITY_LOW)) + (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) goto encrypt; /* A combination key has always sufficient security for the security @@ -657,8 +647,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) is generated using maximum PIN code length (16). For pre 2.1 units. */ if (conn->key_type == HCI_LK_COMBINATION && - (sec_level != BT_SECURITY_HIGH || - conn->pin_length == 16)) + (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16)) goto encrypt; auth: @@ -701,12 +690,11 @@ int hci_conn_change_link_key(struct hci_conn *conn) struct hci_cp_change_conn_link_key cp; cp.handle = cpu_to_le16(conn->handle); hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, - sizeof(cp), &cp); + sizeof(cp), &cp); } return 0; } -EXPORT_SYMBOL(hci_conn_change_link_key); /* Switch role */ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) @@ -752,7 +740,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) timer: if (hdev->idle_timeout > 0) mod_timer(&conn->idle_timer, - jiffies + msecs_to_jiffies(hdev->idle_timeout)); + jiffies + msecs_to_jiffies(hdev->idle_timeout)); } /* Drop all connection on the device */ @@ -802,7 +790,7 @@ EXPORT_SYMBOL(hci_conn_put_device); int hci_get_conn_list(void __user *arg) { - register struct hci_conn *c; + struct hci_conn *c; struct hci_conn_list_req req, *cl; struct hci_conn_info *ci; struct hci_dev *hdev; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 411ace8e647b..08994ecc3b6a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -25,28 +25,10 @@ /* Bluetooth HCI core. */ -#include <linux/jiffies.h> -#include <linux/module.h> -#include <linux/kmod.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/rfkill.h> -#include <linux/timer.h> -#include <linux/crypto.h> -#include <net/sock.h> +#include <linux/export.h> +#include <linux/idr.h> -#include <linux/uaccess.h> -#include <asm/unaligned.h> +#include <linux/rfkill.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -65,6 +47,9 @@ DEFINE_RWLOCK(hci_dev_list_lock); LIST_HEAD(hci_cb_list); DEFINE_RWLOCK(hci_cb_list_lock); +/* HCI ID Numbering */ +static DEFINE_IDA(hci_index_ida); + /* ---- HCI notifications ---- */ static void hci_notify(struct hci_dev *hdev, int event) @@ -124,8 +109,9 @@ static void hci_req_cancel(struct hci_dev *hdev, int err) } /* Execute request and wait for completion. */ -static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), - unsigned long opt, __u32 timeout) +static int __hci_request(struct hci_dev *hdev, + void (*req)(struct hci_dev *hdev, unsigned long opt), + unsigned long opt, __u32 timeout) { DECLARE_WAITQUEUE(wait, current); int err = 0; @@ -166,8 +152,9 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, return err; } -static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt), - unsigned long opt, __u32 timeout) +static int hci_request(struct hci_dev *hdev, + void (*req)(struct hci_dev *hdev, unsigned long opt), + unsigned long opt, __u32 timeout) { int ret; @@ -202,7 +189,7 @@ static void bredr_init(struct hci_dev *hdev) /* Mandatory initialization */ /* Reset */ - if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { + if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } @@ -235,7 +222,7 @@ static void bredr_init(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type); /* Connection accept timeout ~20 secs */ - param = cpu_to_le16(0x7d00); + param = __constant_cpu_to_le16(0x7d00); hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); bacpy(&cp.bdaddr, BDADDR_ANY); @@ -417,7 +404,8 @@ static void inquiry_cache_flush(struct hci_dev *hdev) INIT_LIST_HEAD(&cache->resolve); } -struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr) +struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, + bdaddr_t *bdaddr) { struct discovery_state *cache = &hdev->discovery; struct inquiry_entry *e; @@ -478,7 +466,7 @@ void hci_inquiry_cache_update_resolve(struct hci_dev *hdev, list_for_each_entry(p, &cache->resolve, list) { if (p->name_state != NAME_PENDING && - abs(p->data.rssi) >= abs(ie->data.rssi)) + abs(p->data.rssi) >= abs(ie->data.rssi)) break; pos = &p->list; } @@ -503,7 +491,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, *ssp = true; if (ie->name_state == NAME_NEEDED && - data->rssi != ie->data.rssi) { + data->rssi != ie->data.rssi) { ie->data.rssi = data->rssi; hci_inquiry_cache_update_resolve(hdev, ie); } @@ -527,7 +515,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, update: if (name_known && ie->name_state != NAME_KNOWN && - ie->name_state != NAME_PENDING) { + ie->name_state != NAME_PENDING) { ie->name_state = NAME_KNOWN; list_del(&ie->list); } @@ -605,8 +593,7 @@ int hci_inquiry(void __user *arg) hci_dev_lock(hdev); if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX || - inquiry_cache_empty(hdev) || - ir.flags & IREQ_CACHE_FLUSH) { + inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) { inquiry_cache_flush(hdev); do_inquiry = 1; } @@ -620,7 +607,9 @@ int hci_inquiry(void __user *arg) goto done; } - /* for unlimited number of responses we will use buffer with 255 entries */ + /* for unlimited number of responses we will use buffer with + * 255 entries + */ max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp; /* cache_dump can't sleep. Therefore we allocate temp buffer and then @@ -641,7 +630,7 @@ int hci_inquiry(void __user *arg) if (!copy_to_user(ptr, &ir, sizeof(ir))) { ptr += sizeof(ir); if (copy_to_user(ptr, buf, sizeof(struct inquiry_info) * - ir.num_rsp)) + ir.num_rsp)) err = -EFAULT; } else err = -EFAULT; @@ -702,11 +691,11 @@ int hci_dev_open(__u16 dev) hdev->init_last_cmd = 0; ret = __hci_request(hdev, hci_init_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); if (lmp_host_le_capable(hdev)) ret = __hci_request(hdev, hci_le_init_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); clear_bit(HCI_INIT, &hdev->flags); } @@ -791,10 +780,10 @@ static int hci_dev_do_close(struct hci_dev *hdev) skb_queue_purge(&hdev->cmd_q); atomic_set(&hdev->cmd_cnt, 1); if (!test_bit(HCI_RAW, &hdev->flags) && - test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { + test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); __hci_request(hdev, hci_reset_req, 0, - msecs_to_jiffies(250)); + msecs_to_jiffies(250)); clear_bit(HCI_INIT, &hdev->flags); } @@ -884,7 +873,7 @@ int hci_dev_reset(__u16 dev) if (!test_bit(HCI_RAW, &hdev->flags)) ret = __hci_request(hdev, hci_reset_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); done: hci_req_unlock(hdev); @@ -924,7 +913,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) switch (cmd) { case HCISETAUTH: err = hci_request(hdev, hci_auth_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETENCRYPT: @@ -936,23 +925,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) if (!test_bit(HCI_AUTH, &hdev->flags)) { /* Auth must be enabled first */ err = hci_request(hdev, hci_auth_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); if (err) break; } err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETSCAN: err = hci_request(hdev, hci_scan_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETLINKPOL: err = hci_request(hdev, hci_linkpol_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + msecs_to_jiffies(HCI_INIT_TIMEOUT)); break; case HCISETLINKMODE: @@ -1103,7 +1092,7 @@ static void hci_power_on(struct work_struct *work) if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) schedule_delayed_work(&hdev->power_off, - msecs_to_jiffies(AUTO_OFF_TIMEOUT)); + msecs_to_jiffies(AUTO_OFF_TIMEOUT)); if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); @@ -1112,7 +1101,7 @@ static void hci_power_on(struct work_struct *work) static void hci_power_off(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, - power_off.work); + power_off.work); BT_DBG("%s", hdev->name); @@ -1193,7 +1182,7 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) } static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, - u8 key_type, u8 old_key_type) + u8 key_type, u8 old_key_type) { /* Legacy key */ if (key_type < 0x03) @@ -1234,7 +1223,7 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) list_for_each_entry(k, &hdev->long_term_keys, list) { if (k->ediv != ediv || - memcmp(rand, k->rand, sizeof(k->rand))) + memcmp(rand, k->rand, sizeof(k->rand))) continue; return k; @@ -1242,7 +1231,6 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) return NULL; } -EXPORT_SYMBOL(hci_find_ltk); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type) @@ -1251,12 +1239,11 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, list_for_each_entry(k, &hdev->long_term_keys, list) if (addr_type == k->bdaddr_type && - bacmp(bdaddr, &k->bdaddr) == 0) + bacmp(bdaddr, &k->bdaddr) == 0) return k; return NULL; } -EXPORT_SYMBOL(hci_find_ltk_by_addr); int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) @@ -1283,15 +1270,14 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, * combination key for legacy pairing even when there's no * previous key */ if (type == HCI_LK_CHANGED_COMBINATION && - (!conn || conn->remote_auth == 0xff) && - old_key_type == 0xff) { + (!conn || conn->remote_auth == 0xff) && old_key_type == 0xff) { type = HCI_LK_COMBINATION; if (conn) conn->key_type = type; } bacpy(&key->bdaddr, bdaddr); - memcpy(key->val, val, 16); + memcpy(key->val, val, HCI_LINK_KEY_SIZE); key->pin_len = pin_len; if (type == HCI_LK_CHANGED_COMBINATION) @@ -1540,6 +1526,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt) memset(&cp, 0, sizeof(cp)); cp.enable = 1; + cp.filter_dup = 1; hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); } @@ -1707,41 +1694,39 @@ EXPORT_SYMBOL(hci_free_dev); /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { - struct list_head *head, *p; int id, error; if (!hdev->open || !hdev->close) return -EINVAL; - write_lock(&hci_dev_list_lock); - /* Do not allow HCI_AMP devices to register at index 0, * so the index can be used as the AMP controller ID. */ - id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; - head = &hci_dev_list; - - /* Find first available device id */ - list_for_each(p, &hci_dev_list) { - int nid = list_entry(p, struct hci_dev, list)->id; - if (nid > id) - break; - if (nid == id) - id++; - head = p; + switch (hdev->dev_type) { + case HCI_BREDR: + id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL); + break; + case HCI_AMP: + id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL); + break; + default: + return -EINVAL; } + if (id < 0) + return id; + sprintf(hdev->name, "hci%d", id); hdev->id = id; BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - list_add(&hdev->list, head); - + write_lock(&hci_dev_list_lock); + list_add(&hdev->list, &hci_dev_list); write_unlock(&hci_dev_list_lock); hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND | - WQ_MEM_RECLAIM, 1); + WQ_MEM_RECLAIM, 1); if (!hdev->workqueue) { error = -ENOMEM; goto err; @@ -1752,7 +1737,8 @@ int hci_register_dev(struct hci_dev *hdev) goto err_wqueue; hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev, - RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev); + RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, + hdev); if (hdev->rfkill) { if (rfkill_register(hdev->rfkill) < 0) { rfkill_destroy(hdev->rfkill); @@ -1772,6 +1758,7 @@ int hci_register_dev(struct hci_dev *hdev) err_wqueue: destroy_workqueue(hdev->workqueue); err: + ida_simple_remove(&hci_index_ida, hdev->id); write_lock(&hci_dev_list_lock); list_del(&hdev->list); write_unlock(&hci_dev_list_lock); @@ -1783,12 +1770,14 @@ EXPORT_SYMBOL(hci_register_dev); /* Unregister HCI device */ void hci_unregister_dev(struct hci_dev *hdev) { - int i; + int i, id; BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); set_bit(HCI_UNREGISTER, &hdev->dev_flags); + id = hdev->id; + write_lock(&hci_dev_list_lock); list_del(&hdev->list); write_unlock(&hci_dev_list_lock); @@ -1799,7 +1788,7 @@ void hci_unregister_dev(struct hci_dev *hdev) kfree_skb(hdev->reassembly[i]); if (!test_bit(HCI_INIT, &hdev->flags) && - !test_bit(HCI_SETUP, &hdev->dev_flags)) { + !test_bit(HCI_SETUP, &hdev->dev_flags)) { hci_dev_lock(hdev); mgmt_index_removed(hdev); hci_dev_unlock(hdev); @@ -1829,6 +1818,8 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_dev_unlock(hdev); hci_dev_put(hdev); + + ida_simple_remove(&hci_index_ida, id); } EXPORT_SYMBOL(hci_unregister_dev); @@ -1853,7 +1844,7 @@ int hci_recv_frame(struct sk_buff *skb) { struct hci_dev *hdev = (struct hci_dev *) skb->dev; if (!hdev || (!test_bit(HCI_UP, &hdev->flags) - && !test_bit(HCI_INIT, &hdev->flags))) { + && !test_bit(HCI_INIT, &hdev->flags))) { kfree_skb(skb); return -ENXIO; } @@ -1872,7 +1863,7 @@ int hci_recv_frame(struct sk_buff *skb) EXPORT_SYMBOL(hci_recv_frame); static int hci_reassembly(struct hci_dev *hdev, int type, void *data, - int count, __u8 index) + int count, __u8 index) { int len = 0; int hlen = 0; @@ -1881,7 +1872,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, struct bt_skb_cb *scb; if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || - index >= NUM_REASSEMBLY) + index >= NUM_REASSEMBLY) return -EILSEQ; skb = hdev->reassembly[index]; @@ -2023,7 +2014,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) type = bt_cb(skb)->pkt_type; rem = hci_reassembly(hdev, type, data, count, - STREAM_REASSEMBLY); + STREAM_REASSEMBLY); if (rem < 0) return rem; @@ -2157,7 +2148,7 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) } static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, - struct sk_buff *skb, __u16 flags) + struct sk_buff *skb, __u16 flags) { struct hci_dev *hdev = conn->hdev; struct sk_buff *list; @@ -2216,7 +2207,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) queue_work(hdev->workqueue, &hdev->tx_work); } -EXPORT_SYMBOL(hci_send_acl); /* Send SCO data */ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) @@ -2239,12 +2229,12 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb) skb_queue_tail(&conn->data_q, skb); queue_work(hdev->workqueue, &hdev->tx_work); } -EXPORT_SYMBOL(hci_send_sco); /* ---- HCI TX task (outgoing data) ---- */ /* HCI Connection scheduler */ -static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote) +static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, + int *quote) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL, *c; @@ -2303,7 +2293,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int return conn; } -static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) +static void hci_link_tx_to(struct hci_dev *hdev, __u8 type) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *c; @@ -2316,16 +2306,16 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type) list_for_each_entry_rcu(c, &h->list, list) { if (c->type == type && c->sent) { BT_ERR("%s killing stalled connection %s", - hdev->name, batostr(&c->dst)); - hci_acl_disconn(c, 0x13); + hdev->name, batostr(&c->dst)); + hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM); } } rcu_read_unlock(); } -static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, - int *quote) +static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, + int *quote) { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_chan *chan = NULL; @@ -2442,7 +2432,7 @@ static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type) skb->priority = HCI_PRIO_MAX - 1; BT_DBG("chan %p skb %p promoted to %d", chan, skb, - skb->priority); + skb->priority); } if (hci_conn_num(hdev, type) == num) @@ -2459,18 +2449,18 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb) return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len); } -static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt) +static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) { if (!test_bit(HCI_RAW, &hdev->flags)) { /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!cnt && time_after(jiffies, hdev->acl_last_tx + - msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) + msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) hci_link_tx_to(hdev, ACL_LINK); } } -static inline void hci_sched_acl_pkt(struct hci_dev *hdev) +static void hci_sched_acl_pkt(struct hci_dev *hdev) { unsigned int cnt = hdev->acl_cnt; struct hci_chan *chan; @@ -2480,11 +2470,11 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) __check_timeout(hdev, cnt); while (hdev->acl_cnt && - (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { + (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { u32 priority = (skb_peek(&chan->data_q))->priority; while (quote-- && (skb = skb_peek(&chan->data_q))) { BT_DBG("chan %p skb %p len %d priority %u", chan, skb, - skb->len, skb->priority); + skb->len, skb->priority); /* Stop if priority has changed */ if (skb->priority < priority) @@ -2508,7 +2498,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev) hci_prio_recalculate(hdev, ACL_LINK); } -static inline void hci_sched_acl_blk(struct hci_dev *hdev) +static void hci_sched_acl_blk(struct hci_dev *hdev) { unsigned int cnt = hdev->block_cnt; struct hci_chan *chan; @@ -2518,13 +2508,13 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev) __check_timeout(hdev, cnt); while (hdev->block_cnt > 0 && - (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { + (chan = hci_chan_sent(hdev, ACL_LINK, "e))) { u32 priority = (skb_peek(&chan->data_q))->priority; while (quote > 0 && (skb = skb_peek(&chan->data_q))) { int blocks; BT_DBG("chan %p skb %p len %d priority %u", chan, skb, - skb->len, skb->priority); + skb->len, skb->priority); /* Stop if priority has changed */ if (skb->priority < priority) @@ -2537,7 +2527,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev) return; hci_conn_enter_active_mode(chan->conn, - bt_cb(skb)->force_active); + bt_cb(skb)->force_active); hci_send_frame(skb); hdev->acl_last_tx = jiffies; @@ -2554,7 +2544,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev) hci_prio_recalculate(hdev, ACL_LINK); } -static inline void hci_sched_acl(struct hci_dev *hdev) +static void hci_sched_acl(struct hci_dev *hdev) { BT_DBG("%s", hdev->name); @@ -2573,7 +2563,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev) } /* Schedule SCO */ -static inline void hci_sched_sco(struct hci_dev *hdev) +static void hci_sched_sco(struct hci_dev *hdev) { struct hci_conn *conn; struct sk_buff *skb; @@ -2596,7 +2586,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev) } } -static inline void hci_sched_esco(struct hci_dev *hdev) +static void hci_sched_esco(struct hci_dev *hdev) { struct hci_conn *conn; struct sk_buff *skb; @@ -2607,7 +2597,8 @@ static inline void hci_sched_esco(struct hci_dev *hdev) if (!hci_conn_num(hdev, ESCO_LINK)) return; - while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) { + while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, + "e))) { while (quote-- && (skb = skb_dequeue(&conn->data_q))) { BT_DBG("skb %p len %d", skb, skb->len); hci_send_frame(skb); @@ -2619,7 +2610,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev) } } -static inline void hci_sched_le(struct hci_dev *hdev) +static void hci_sched_le(struct hci_dev *hdev) { struct hci_chan *chan; struct sk_buff *skb; @@ -2634,7 +2625,7 @@ static inline void hci_sched_le(struct hci_dev *hdev) /* LE tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!hdev->le_cnt && hdev->le_pkts && - time_after(jiffies, hdev->le_last_tx + HZ * 45)) + time_after(jiffies, hdev->le_last_tx + HZ * 45)) hci_link_tx_to(hdev, LE_LINK); } @@ -2644,7 +2635,7 @@ static inline void hci_sched_le(struct hci_dev *hdev) u32 priority = (skb_peek(&chan->data_q))->priority; while (quote-- && (skb = skb_peek(&chan->data_q))) { BT_DBG("chan %p skb %p len %d priority %u", chan, skb, - skb->len, skb->priority); + skb->len, skb->priority); /* Stop if priority has changed */ if (skb->priority < priority) @@ -2676,7 +2667,7 @@ static void hci_tx_work(struct work_struct *work) struct sk_buff *skb; BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt, - hdev->sco_cnt, hdev->le_cnt); + hdev->sco_cnt, hdev->le_cnt); /* Schedule queues and send stuff to HCI driver */ @@ -2696,7 +2687,7 @@ static void hci_tx_work(struct work_struct *work) /* ----- HCI RX task (incoming data processing) ----- */ /* ACL data packet */ -static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_acl_hdr *hdr = (void *) skb->data; struct hci_conn *conn; @@ -2708,7 +2699,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) flags = hci_flags(handle); handle = hci_handle(handle); - BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags); + BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, + handle, flags); hdev->stat.acl_rx++; @@ -2732,14 +2724,14 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) return; } else { BT_ERR("%s ACL packet for unknown connection handle %d", - hdev->name, handle); + hdev->name, handle); } kfree_skb(skb); } /* SCO data packet */ -static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_sco_hdr *hdr = (void *) skb->data; struct hci_conn *conn; @@ -2763,7 +2755,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) return; } else { BT_ERR("%s SCO packet for unknown connection handle %d", - hdev->name, handle); + hdev->name, handle); } kfree_skb(skb); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 4eefb7f65cf6..1ba929c05d0d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -24,20 +24,7 @@ /* Bluetooth HCI event handling. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/interrupt.h> -#include <net/sock.h> - -#include <linux/uaccess.h> +#include <linux/export.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -95,7 +82,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_check_pending(hdev); } -static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, + struct sk_buff *skb) { BT_DBG("%s", hdev->name); } @@ -166,7 +154,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } -static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_read_def_link_policy(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_rp_read_def_link_policy *rp = (void *) skb->data; @@ -178,7 +167,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk hdev->link_policy = __le16_to_cpu(rp->policy); } -static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_write_def_link_policy(struct hci_dev *hdev, + struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); void *sent; @@ -329,7 +319,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) if (hdev->discov_timeout > 0) { int to = msecs_to_jiffies(hdev->discov_timeout * 1000); queue_delayed_work(hdev->workqueue, &hdev->discov_off, - to); + to); } } else if (old_iscan) mgmt_discoverable(hdev, 0); @@ -358,7 +348,7 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) memcpy(hdev->dev_class, rp->dev_class, 3); BT_DBG("%s class 0x%.2x%.2x%.2x", hdev->name, - hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); + hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); } static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) @@ -406,7 +396,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); } -static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_write_voice_setting(struct hci_dev *hdev, + struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); __u16 setting; @@ -473,7 +464,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev) return 1; if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 && - hdev->lmp_subver == 0x0757) + hdev->lmp_subver == 0x0757) return 1; if (hdev->manufacturer == 15) { @@ -486,7 +477,7 @@ static u8 hci_get_inquiry_mode(struct hci_dev *hdev) } if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 && - hdev->lmp_subver == 0x1805) + hdev->lmp_subver == 0x1805) return 1; return 0; @@ -566,7 +557,7 @@ static void hci_setup(struct hci_dev *hdev) if (hdev->hci_ver > BLUETOOTH_VER_1_1) hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); - if (hdev->features[6] & LMP_SIMPLE_PAIR) { + if (lmp_ssp_capable(hdev)) { if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) { u8 mode = 0x01; hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, @@ -618,8 +609,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver); BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, - hdev->manufacturer, - hdev->hci_ver, hdev->hci_rev); + hdev->manufacturer, hdev->hci_ver, hdev->hci_rev); if (test_bit(HCI_INIT, &hdev->flags)) hci_setup(hdev); @@ -646,7 +636,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev) hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp); } -static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_read_local_commands(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_rp_read_local_commands *rp = (void *) skb->data; @@ -664,7 +655,8 @@ done: hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status); } -static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cc_read_local_features(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_rp_read_local_features *rp = (void *) skb->data; @@ -713,10 +705,10 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5); BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name, - hdev->features[0], hdev->features[1], - hdev->features[2], hdev->features[3], - hdev->features[4], hdev->features[5], - hdev->features[6], hdev->features[7]); + hdev->features[0], hdev->features[1], + hdev->features[2], hdev->features[3], + hdev->features[4], hdev->features[5], + hdev->features[6], hdev->features[7]); } static void hci_set_le_support(struct hci_dev *hdev) @@ -736,7 +728,7 @@ static void hci_set_le_support(struct hci_dev *hdev) } static void hci_cc_read_local_ext_features(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_local_ext_features *rp = (void *) skb->data; @@ -762,7 +754,7 @@ done: } static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_flow_control_mode *rp = (void *) skb->data; @@ -798,9 +790,8 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) hdev->acl_cnt = hdev->acl_pkts; hdev->sco_cnt = hdev->sco_pkts; - BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, - hdev->acl_mtu, hdev->acl_pkts, - hdev->sco_mtu, hdev->sco_pkts); + BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu, + hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts); } static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) @@ -816,7 +807,7 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_read_data_block_size(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_data_block_size *rp = (void *) skb->data; @@ -832,7 +823,7 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev, hdev->block_cnt = hdev->num_blocks; BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu, - hdev->block_cnt, hdev->block_len); + hdev->block_cnt, hdev->block_len); hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status); } @@ -847,7 +838,7 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_read_local_amp_info(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_local_amp_info *rp = (void *) skb->data; @@ -871,7 +862,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, } static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -890,7 +881,7 @@ static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -900,7 +891,7 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, } static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data; @@ -959,7 +950,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(HCI_MGMT, &hdev->dev_flags)) mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr, - rp->status); + rp->status); hci_dev_unlock(hdev); } @@ -1000,7 +991,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; @@ -1031,7 +1022,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; @@ -1047,7 +1038,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, } static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_rp_read_local_oob_data *rp = (void *) skb->data; @@ -1076,7 +1067,7 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) } static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, - struct sk_buff *skb) + struct sk_buff *skb) { struct hci_cp_le_set_scan_enable *cp; __u8 status = *((__u8 *) skb->data); @@ -1156,8 +1147,8 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status); } -static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_cc_write_le_host_supported(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); @@ -1176,13 +1167,13 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev, } if (test_bit(HCI_MGMT, &hdev->dev_flags) && - !test_bit(HCI_INIT, &hdev->flags)) + !test_bit(HCI_INIT, &hdev->flags)) mgmt_le_enable_complete(hdev, sent->le, status); hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status); } -static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) +static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); @@ -1203,7 +1194,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) hci_dev_unlock(hdev); } -static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) +static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) { struct hci_cp_create_conn *cp; struct hci_conn *conn; @@ -1333,7 +1324,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) } static int hci_outgoing_auth_needed(struct hci_dev *hdev, - struct hci_conn *conn) + struct hci_conn *conn) { if (conn->state != BT_CONFIG || !conn->out) return 0; @@ -1343,15 +1334,14 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev, /* Only request authentication for SSP connections or non-SSP * devices with sec_level HIGH or if MITM protection is requested */ - if (!hci_conn_ssp_enabled(conn) && - conn->pending_sec_level != BT_SECURITY_HIGH && - !(conn->auth_type & 0x01)) + if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) && + conn->pending_sec_level != BT_SECURITY_HIGH) return 0; return 1; } -static inline int hci_resolve_name(struct hci_dev *hdev, +static int hci_resolve_name(struct hci_dev *hdev, struct inquiry_entry *e) { struct hci_cp_remote_name_req cp; @@ -1638,7 +1628,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr); BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->peer_addr), - conn); + conn); if (status) { if (conn && conn->state == BT_CONNECT) { @@ -1668,7 +1658,7 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) BT_DBG("%s status 0x%x", hdev->name, status); } -static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); struct discovery_state *discov = &hdev->discovery; @@ -1708,7 +1698,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct inquiry_data data; struct inquiry_info *info = (void *) (skb->data + 1); @@ -1745,7 +1735,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_unlock(hdev); } -static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -1823,18 +1813,18 @@ unlock: hci_conn_check_pending(hdev); } -static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_conn_request *ev = (void *) skb->data; int mask = hdev->link_mode; - BT_DBG("%s bdaddr %s type 0x%x", hdev->name, - batostr(&ev->bdaddr), ev->link_type); + BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr), + ev->link_type); mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); if ((mask & HCI_LM_ACCEPT) && - !hci_blacklist_lookup(hdev, &ev->bdaddr)) { + !hci_blacklist_lookup(hdev, &ev->bdaddr)) { /* Connection accepted */ struct inquiry_entry *ie; struct hci_conn *conn; @@ -1845,7 +1835,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk if (ie) memcpy(ie->data.dev_class, ev->dev_class, 3); - conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, + &ev->bdaddr); if (!conn) { conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr); if (!conn) { @@ -1878,9 +1869,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk bacpy(&cp.bdaddr, &ev->bdaddr); cp.pkt_type = cpu_to_le16(conn->pkt_type); - cp.tx_bandwidth = cpu_to_le32(0x00001f40); - cp.rx_bandwidth = cpu_to_le32(0x00001f40); - cp.max_latency = cpu_to_le16(0xffff); + cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40); + cp.max_latency = __constant_cpu_to_le16(0xffff); cp.content_format = cpu_to_le16(hdev->voice_setting); cp.retrans_effort = 0xff; @@ -1897,7 +1888,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk } } -static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_disconn_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -1914,10 +1905,10 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->state = BT_CLOSED; if (test_and_clear_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags) && - (conn->type == ACL_LINK || conn->type == LE_LINK)) { + (conn->type == ACL_LINK || conn->type == LE_LINK)) { if (ev->status != 0) mgmt_disconnect_failed(hdev, &conn->dst, conn->type, - conn->dst_type, ev->status); + conn->dst_type, ev->status); else mgmt_device_disconnected(hdev, &conn->dst, conn->type, conn->dst_type); @@ -1934,7 +1925,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_auth_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -1949,7 +1940,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s if (!ev->status) { if (!hci_conn_ssp_enabled(conn) && - test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { + test_bit(HCI_CONN_REAUTH_PEND, &conn->flags)) { BT_INFO("re-auth of legacy device is not possible."); } else { conn->link_mode |= HCI_LM_AUTH; @@ -1969,7 +1960,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), - &cp); + &cp); } else { conn->state = BT_CONNECTED; hci_proto_connect_cfm(conn, ev->status); @@ -1989,7 +1980,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s cp.handle = ev->handle; cp.encrypt = 0x01; hci_send_cmd(hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), - &cp); + &cp); } else { clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); hci_encrypt_cfm(conn, ev->status, 0x00); @@ -2000,7 +1991,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_remote_name *ev = (void *) skb->data; struct hci_conn *conn; @@ -2039,7 +2030,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_encrypt_change *ev = (void *) skb->data; struct hci_conn *conn; @@ -2082,7 +2073,8 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_change_link_key_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_change_link_key_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -2104,7 +2096,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct hci_dev_unlock(hdev); } -static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_remote_features_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_remote_features *ev = (void *) skb->data; struct hci_conn *conn; @@ -2128,7 +2121,7 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff cp.handle = ev->handle; cp.page = 0x01; hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES, - sizeof(cp), &cp); + sizeof(cp), &cp); goto unlock; } @@ -2153,17 +2146,18 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); } -static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_qos_setup_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) { BT_DBG("%s", hdev->name); } -static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_cmd_complete *ev = (void *) skb->data; __u16 opcode; @@ -2384,7 +2378,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk } } -static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_cmd_status *ev = (void *) skb->data; __u16 opcode; @@ -2465,7 +2459,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) } } -static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_role_change *ev = (void *) skb->data; struct hci_conn *conn; @@ -2491,7 +2485,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_unlock(hdev); } -static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_num_comp_pkts *ev = (void *) skb->data; int i; @@ -2502,7 +2496,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s } if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) + - ev->num_hndl * sizeof(struct hci_comp_pkts_info)) { + ev->num_hndl * sizeof(struct hci_comp_pkts_info)) { BT_DBG("%s bad parameters", hdev->name); return; } @@ -2557,8 +2551,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s queue_work(hdev->workqueue, &hdev->tx_work); } -static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_num_comp_blocks *ev = (void *) skb->data; int i; @@ -2569,13 +2562,13 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, } if (skb->len < sizeof(*ev) || skb->len < sizeof(*ev) + - ev->num_hndl * sizeof(struct hci_comp_blocks_info)) { + ev->num_hndl * sizeof(struct hci_comp_blocks_info)) { BT_DBG("%s bad parameters", hdev->name); return; } BT_DBG("%s num_blocks %d num_hndl %d", hdev->name, ev->num_blocks, - ev->num_hndl); + ev->num_hndl); for (i = 0; i < ev->num_hndl; i++) { struct hci_comp_blocks_info *info = &ev->handles[i]; @@ -2607,7 +2600,7 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev, queue_work(hdev->workqueue, &hdev->tx_work); } -static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_mode_change *ev = (void *) skb->data; struct hci_conn *conn; @@ -2621,7 +2614,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb conn->mode = ev->mode; conn->interval = __le16_to_cpu(ev->interval); - if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { + if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, + &conn->flags)) { if (conn->mode == HCI_CM_ACTIVE) set_bit(HCI_CONN_POWER_SAVE, &conn->flags); else @@ -2635,7 +2629,7 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb hci_dev_unlock(hdev); } -static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_pin_code_req *ev = (void *) skb->data; struct hci_conn *conn; @@ -2656,7 +2650,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff if (!test_bit(HCI_PAIRABLE, &hdev->dev_flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, - sizeof(ev->bdaddr), &ev->bdaddr); + sizeof(ev->bdaddr), &ev->bdaddr); else if (test_bit(HCI_MGMT, &hdev->dev_flags)) { u8 secure; @@ -2672,7 +2666,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_link_key_req *ev = (void *) skb->data; struct hci_cp_link_key_reply cp; @@ -2689,15 +2683,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff key = hci_find_link_key(hdev, &ev->bdaddr); if (!key) { BT_DBG("%s link key not found for %s", hdev->name, - batostr(&ev->bdaddr)); + batostr(&ev->bdaddr)); goto not_found; } BT_DBG("%s found key type %u for %s", hdev->name, key->type, - batostr(&ev->bdaddr)); + batostr(&ev->bdaddr)); if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && - key->type == HCI_LK_DEBUG_COMBINATION) { + key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; } @@ -2705,16 +2699,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn) { if (key->type == HCI_LK_UNAUTH_COMBINATION && - conn->auth_type != 0xff && - (conn->auth_type & 0x01)) { + conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; } if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && - conn->pending_sec_level == BT_SECURITY_HIGH) { - BT_DBG("%s ignoring key unauthenticated for high \ - security", hdev->name); + conn->pending_sec_level == BT_SECURITY_HIGH) { + BT_DBG("%s ignoring key unauthenticated for high security", + hdev->name); goto not_found; } @@ -2723,7 +2716,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff } bacpy(&cp.bdaddr, &ev->bdaddr); - memcpy(cp.link_key, key->val, 16); + memcpy(cp.link_key, key->val, HCI_LINK_KEY_SIZE); hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp); @@ -2736,7 +2729,7 @@ not_found: hci_dev_unlock(hdev); } -static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_link_key_notify *ev = (void *) skb->data; struct hci_conn *conn; @@ -2760,12 +2753,12 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff if (test_bit(HCI_LINK_KEYS, &hdev->dev_flags)) hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, - ev->key_type, pin_len); + ev->key_type, pin_len); hci_dev_unlock(hdev); } -static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_clock_offset *ev = (void *) skb->data; struct hci_conn *conn; @@ -2788,7 +2781,7 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk hci_dev_unlock(hdev); } -static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_pkt_type_change *ev = (void *) skb->data; struct hci_conn *conn; @@ -2804,7 +2797,7 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff hci_dev_unlock(hdev); } -static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_pscan_rep_mode *ev = (void *) skb->data; struct inquiry_entry *ie; @@ -2822,7 +2815,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_unlock(hdev); } -static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct inquiry_data data; int num_rsp = *((__u8 *) skb->data); @@ -2881,7 +2875,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct hci_dev_unlock(hdev); } -static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_remote_ext_features_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_remote_ext_features *ev = (void *) skb->data; struct hci_conn *conn; @@ -2929,7 +2924,8 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_sync_conn_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_sync_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -2984,19 +2980,20 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb) { BT_DBG("%s", hdev->name); } -static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_sniff_subrate *ev = (void *) skb->data; BT_DBG("%s status %d", hdev->name, ev->status); } -static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct inquiry_data data; struct extended_inquiry_info *info = (void *) (skb->data + 1); @@ -3043,7 +3040,51 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_unlock(hdev); } -static inline u8 hci_get_auth_req(struct hci_conn *conn) +static void hci_key_refresh_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_key_refresh_complete *ev = (void *) skb->data; + struct hci_conn *conn; + + BT_DBG("%s status %u handle %u", hdev->name, ev->status, + __le16_to_cpu(ev->handle)); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (!conn) + goto unlock; + + if (!ev->status) + conn->sec_level = conn->pending_sec_level; + + clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); + + if (ev->status && conn->state == BT_CONNECTED) { + hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE); + hci_conn_put(conn); + goto unlock; + } + + if (conn->state == BT_CONFIG) { + if (!ev->status) + conn->state = BT_CONNECTED; + + hci_proto_connect_cfm(conn, ev->status); + hci_conn_put(conn); + } else { + hci_auth_cfm(conn, ev->status); + + hci_conn_hold(conn); + conn->disc_timeout = HCI_DISCONN_TIMEOUT; + hci_conn_put(conn); + } + +unlock: + hci_dev_unlock(hdev); +} + +static u8 hci_get_auth_req(struct hci_conn *conn) { /* If remote requests dedicated bonding follow that lead */ if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) { @@ -3062,7 +3103,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn) return conn->auth_type; } -static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_io_capa_request *ev = (void *) skb->data; struct hci_conn *conn; @@ -3081,7 +3122,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff goto unlock; if (test_bit(HCI_PAIRABLE, &hdev->dev_flags) || - (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { + (conn->remote_auth & ~0x01) == HCI_AT_NO_BONDING) { struct hci_cp_io_capability_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); @@ -3092,14 +3133,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff conn->auth_type = hci_get_auth_req(conn); cp.authentication = conn->auth_type; - if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) && - hci_find_remote_oob_data(hdev, &conn->dst)) + if (hci_find_remote_oob_data(hdev, &conn->dst) && + (conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags))) cp.oob_data = 0x01; else cp.oob_data = 0x00; hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, - sizeof(cp), &cp); + sizeof(cp), &cp); } else { struct hci_cp_io_capability_neg_reply cp; @@ -3107,14 +3148,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED; hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, - sizeof(cp), &cp); + sizeof(cp), &cp); } unlock: hci_dev_unlock(hdev); } -static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_io_capa_reply *ev = (void *) skb->data; struct hci_conn *conn; @@ -3136,8 +3177,8 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_user_confirm_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; int loc_mitm, rem_mitm, confirm_hint = 0; @@ -3165,13 +3206,13 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { BT_DBG("Rejecting request: remote device can't provide MITM"); hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, - sizeof(ev->bdaddr), &ev->bdaddr); + sizeof(ev->bdaddr), &ev->bdaddr); goto unlock; } /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == 0x03) && - (!rem_mitm || conn->io_capability == 0x03)) { + (!rem_mitm || conn->io_capability == 0x03)) { /* If we're not the initiators request authorization to * proceed from user space (mgmt_user_confirm with @@ -3183,7 +3224,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, } BT_DBG("Auto-accept of user confirmation with %ums delay", - hdev->auto_accept_delay); + hdev->auto_accept_delay); if (hdev->auto_accept_delay > 0) { int delay = msecs_to_jiffies(hdev->auto_accept_delay); @@ -3192,7 +3233,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, } hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, - sizeof(ev->bdaddr), &ev->bdaddr); + sizeof(ev->bdaddr), &ev->bdaddr); goto unlock; } @@ -3204,8 +3245,8 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_user_passkey_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_user_passkey_req *ev = (void *) skb->data; @@ -3219,7 +3260,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev, hci_dev_unlock(hdev); } -static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_simple_pair_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_simple_pair_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -3247,7 +3289,8 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_remote_host_features_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_remote_host_features *ev = (void *) skb->data; struct inquiry_entry *ie; @@ -3263,8 +3306,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ hci_dev_unlock(hdev); } -static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_remote_oob_data_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) { struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; struct oob_data *data; @@ -3285,20 +3328,20 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), - &cp); + &cp); } else { struct hci_cp_remote_oob_data_neg_reply cp; bacpy(&cp.bdaddr, &ev->bdaddr); hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), - &cp); + &cp); } unlock: hci_dev_unlock(hdev); } -static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; @@ -3307,6 +3350,19 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff hci_dev_lock(hdev); + if (ev->status) { + conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); + if (!conn) + goto unlock; + + mgmt_connect_failed(hdev, &conn->dst, conn->type, + conn->dst_type, ev->status); + hci_proto_connect_cfm(conn, ev->status); + conn->state = BT_CLOSED; + hci_conn_del(conn); + goto unlock; + } + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr); if (!conn) { conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr); @@ -3319,15 +3375,6 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->dst_type = ev->bdaddr_type; } - if (ev->status) { - mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, - conn->dst_type, ev->status); - hci_proto_connect_cfm(conn, ev->status); - conn->state = BT_CLOSED; - hci_conn_del(conn); - goto unlock; - } - if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags)) mgmt_device_connected(hdev, &ev->bdaddr, conn->type, conn->dst_type, 0, NULL, 0, NULL); @@ -3345,8 +3392,7 @@ unlock: hci_dev_unlock(hdev); } -static inline void hci_le_adv_report_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) { u8 num_reports = skb->data[0]; void *ptr = &skb->data[1]; @@ -3367,8 +3413,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, hci_dev_unlock(hdev); } -static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, - struct sk_buff *skb) +static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_ltk_req *ev = (void *) skb->data; struct hci_cp_le_ltk_reply cp; @@ -3411,7 +3456,7 @@ not_found: hci_dev_unlock(hdev); } -static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) +static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_meta *le_ev = (void *) skb->data; @@ -3559,6 +3604,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_extended_inquiry_result_evt(hdev, skb); break; + case HCI_EV_KEY_REFRESH_COMPLETE: + hci_key_refresh_complete_evt(hdev, skb); + break; + case HCI_EV_IO_CAPA_REQUEST: hci_io_capa_request_evt(hdev, skb); break; diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index 5914623f426a..a7f04de03d79 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -24,25 +24,7 @@ /* Bluetooth HCI sockets. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/skbuff.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/compat.h> -#include <linux/socket.h> -#include <linux/ioctl.h> -#include <net/sock.h> - -#include <linux/uaccess.h> +#include <linux/export.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -113,11 +95,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) flt = &hci_pi(sk)->filter; if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ? - 0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask)) + 0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), + &flt->type_mask)) continue; if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) { - register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); + int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS); if (!hci_test_bit(evt, &flt->event_mask)) continue; @@ -240,7 +223,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb) struct hci_mon_hdr *hdr; /* Create a private copy with headroom */ - skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC); + skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, + GFP_ATOMIC); if (!skb_copy) continue; @@ -495,7 +479,8 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg) } /* Ioctls that require bound socket */ -static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg) +static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, + unsigned long arg) { struct hci_dev *hdev = hci_pi(sk)->hdev; @@ -540,7 +525,8 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign } } -static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg) { struct sock *sk = sock->sk; void __user *argp = (void __user *) arg; @@ -601,7 +587,8 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a } } -static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len) +static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, + int addr_len) { struct sockaddr_hci haddr; struct sock *sk = sock->sk; @@ -690,7 +677,8 @@ done: return err; } -static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) +static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, + int *addr_len, int peer) { struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr; struct sock *sk = sock->sk; @@ -711,13 +699,15 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add return 0; } -static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) +static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, + struct sk_buff *skb) { __u32 mask = hci_pi(sk)->cmsg_mask; if (mask & HCI_CMSG_DIR) { int incoming = bt_cb(skb)->incoming; - put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming); + put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), + &incoming); } if (mask & HCI_CMSG_TSTAMP) { @@ -747,7 +737,7 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_ } static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock, - struct msghdr *msg, size_t len, int flags) + struct msghdr *msg, size_t len, int flags) { int noblock = flags & MSG_DONTWAIT; struct sock *sk = sock->sk; @@ -857,8 +847,9 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock, u16 ocf = hci_opcode_ocf(opcode); if (((ogf > HCI_SFLT_MAX_OGF) || - !hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) && - !capable(CAP_NET_RAW)) { + !hci_test_bit(ocf & HCI_FLT_OCF_BITS, + &hci_sec_filter.ocf_mask[ogf])) && + !capable(CAP_NET_RAW)) { err = -EPERM; goto drop; } @@ -891,7 +882,8 @@ drop: goto done; } -static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len) +static int hci_sock_setsockopt(struct socket *sock, int level, int optname, + char __user *optval, unsigned int len) { struct hci_ufilter uf = { .opcode = 0 }; struct sock *sk = sock->sk; @@ -973,7 +965,8 @@ done: return err; } -static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) +static int hci_sock_getsockopt(struct socket *sock, int level, int optname, + char __user *optval, int __user *optlen) { struct hci_ufilter uf; struct sock *sk = sock->sk; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 937f3187eafa..a20e61c3653d 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -1,10 +1,6 @@ /* Bluetooth HCI driver model support. */ -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> #include <linux/debugfs.h> -#include <linux/seq_file.h> #include <linux/module.h> #include <net/bluetooth/bluetooth.h> @@ -31,27 +27,30 @@ static inline char *link_typetostr(int type) } } -static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_link_type(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", link_typetostr(conn->type)); } -static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_link_address(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "%s\n", batostr(&conn->dst)); } -static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_link_features(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_conn *conn = to_hci_conn(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", - conn->features[0], conn->features[1], - conn->features[2], conn->features[3], - conn->features[4], conn->features[5], - conn->features[6], conn->features[7]); + conn->features[0], conn->features[1], + conn->features[2], conn->features[3], + conn->features[4], conn->features[5], + conn->features[6], conn->features[7]); } #define LINK_ATTR(_name, _mode, _show, _store) \ @@ -185,19 +184,22 @@ static inline char *host_typetostr(int type) } } -static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_bus(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_bustostr(hdev->bus)); } -static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_type(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type)); } -static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_name(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); char name[HCI_MAX_NAME_LENGTH + 1]; @@ -210,55 +212,64 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char return sprintf(buf, "%s\n", name); } -static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_class(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); - return sprintf(buf, "0x%.2x%.2x%.2x\n", - hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]); + return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2], + hdev->dev_class[1], hdev->dev_class[0]); } -static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_address(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%s\n", batostr(&hdev->bdaddr)); } -static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_features(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n", - hdev->features[0], hdev->features[1], - hdev->features[2], hdev->features[3], - hdev->features[4], hdev->features[5], - hdev->features[6], hdev->features[7]); + hdev->features[0], hdev->features[1], + hdev->features[2], hdev->features[3], + hdev->features[4], hdev->features[5], + hdev->features[6], hdev->features[7]); } -static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_manufacturer(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->manufacturer); } -static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_hci_version(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_ver); } -static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_hci_revision(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->hci_rev); } -static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_idle_timeout(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->idle_timeout); } -static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_idle_timeout(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct hci_dev *hdev = to_hci_dev(dev); unsigned int val; @@ -276,13 +287,16 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a return count; } -static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_sniff_max_interval(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_max_interval); } -static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_sniff_max_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct hci_dev *hdev = to_hci_dev(dev); u16 val; @@ -300,13 +314,16 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib return count; } -static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf) +static ssize_t show_sniff_min_interval(struct device *dev, + struct device_attribute *attr, char *buf) { struct hci_dev *hdev = to_hci_dev(dev); return sprintf(buf, "%d\n", hdev->sniff_min_interval); } -static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +static ssize_t store_sniff_min_interval(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct hci_dev *hdev = to_hci_dev(dev); u16 val; @@ -335,11 +352,11 @@ static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL); static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL); static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, - show_idle_timeout, store_idle_timeout); + show_idle_timeout, store_idle_timeout); static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, - show_sniff_max_interval, store_sniff_max_interval); + show_sniff_max_interval, store_sniff_max_interval); static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, - show_sniff_min_interval, store_sniff_min_interval); + show_sniff_min_interval, store_sniff_min_interval); static struct attribute *bt_host_attrs[] = { &dev_attr_bus.attr, @@ -455,8 +472,8 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid) memcpy(&data5, &uuid[14], 2); seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n", - ntohl(data0), ntohs(data1), ntohs(data2), - ntohs(data3), ntohl(data4), ntohs(data5)); + ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3), + ntohl(data4), ntohs(data5)); } static int uuids_show(struct seq_file *f, void *p) @@ -513,7 +530,7 @@ static int auto_accept_delay_get(void *data, u64 *val) } DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get, - auto_accept_delay_set, "%llu\n"); + auto_accept_delay_set, "%llu\n"); void hci_init_sysfs(struct hci_dev *hdev) { @@ -547,15 +564,15 @@ int hci_add_sysfs(struct hci_dev *hdev) return 0; debugfs_create_file("inquiry_cache", 0444, hdev->debugfs, - hdev, &inquiry_cache_fops); + hdev, &inquiry_cache_fops); debugfs_create_file("blacklist", 0444, hdev->debugfs, - hdev, &blacklist_fops); + hdev, &blacklist_fops); debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev, - &auto_accept_delay_fops); + &auto_accept_delay_fops); return 0; } diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 2c20d765b394..ccd985da6518 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -21,27 +21,8 @@ */ #include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/freezer.h> -#include <linux/fcntl.h> -#include <linux/skbuff.h> -#include <linux/socket.h> -#include <linux/ioctl.h> #include <linux/file.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/mutex.h> #include <linux/kthread.h> -#include <net/sock.h> - -#include <linux/input.h> -#include <linux/hid.h> #include <linux/hidraw.h> #include <net/bluetooth/bluetooth.h> @@ -244,7 +225,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb) } static int __hidp_send_ctrl_message(struct hidp_session *session, - unsigned char hdr, unsigned char *data, int size) + unsigned char hdr, unsigned char *data, + int size) { struct sk_buff *skb; @@ -268,7 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session, return 0; } -static inline int hidp_send_ctrl_message(struct hidp_session *session, +static int hidp_send_ctrl_message(struct hidp_session *session, unsigned char hdr, unsigned char *data, int size) { int err; @@ -471,7 +453,7 @@ static void hidp_set_timer(struct hidp_session *session) mod_timer(&session->timer, jiffies + HZ * session->idle_to); } -static inline void hidp_del_timer(struct hidp_session *session) +static void hidp_del_timer(struct hidp_session *session) { if (session->idle_to > 0) del_timer(&session->timer); diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 73a32d705c1f..18b3f6892a36 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -20,22 +20,8 @@ SOFTWARE IS DISCLAIMED. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/skbuff.h> -#include <linux/socket.h> -#include <linux/ioctl.h> +#include <linux/export.h> #include <linux/file.h> -#include <linux/init.h> -#include <linux/compat.h> -#include <linux/gfp.h> -#include <net/sock.h> #include "hidp.h" diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 24f144b72a96..d42dfdc83ebb 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -30,32 +30,14 @@ #include <linux/module.h> -#include <linux/types.h> -#include <linux/capability.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/socket.h> -#include <linux/skbuff.h> -#include <linux/list.h> -#include <linux/device.h> #include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/uaccess.h> #include <linux/crc16.h> -#include <net/sock.h> - -#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> #include <net/bluetooth/smp.h> +#include <net/bluetooth/a2mp.h> bool disable_ertm; @@ -73,6 +55,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); +static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, + struct sk_buff_head *skbs, u8 event); + /* ---- L2CAP channels ---- */ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) @@ -196,7 +181,7 @@ static void __l2cap_state_change(struct l2cap_chan *chan, int state) state_to_string(state)); chan->state = state; - chan->ops->state_change(chan->data, state); + chan->ops->state_change(chan, state); } static void l2cap_state_change(struct l2cap_chan *chan, int state) @@ -224,6 +209,37 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) release_sock(sk); } +static void __set_retrans_timer(struct l2cap_chan *chan) +{ + if (!delayed_work_pending(&chan->monitor_timer) && + chan->retrans_timeout) { + l2cap_set_timer(chan, &chan->retrans_timer, + msecs_to_jiffies(chan->retrans_timeout)); + } +} + +static void __set_monitor_timer(struct l2cap_chan *chan) +{ + __clear_retrans_timer(chan); + if (chan->monitor_timeout) { + l2cap_set_timer(chan, &chan->monitor_timer, + msecs_to_jiffies(chan->monitor_timeout)); + } +} + +static struct sk_buff *l2cap_ertm_seq_in_queue(struct sk_buff_head *head, + u16 seq) +{ + struct sk_buff *skb; + + skb_queue_walk(head, skb) { + if (bt_cb(skb)->control.txseq == seq) + return skb; + } + + return NULL; +} + /* ---- L2CAP sequence number lists ---- */ /* For ERTM, ordered lists of sequence numbers must be tracked for @@ -366,7 +382,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_unlock(chan); - chan->ops->close(chan->data); + chan->ops->close(chan); mutex_unlock(&conn->chan_lock); l2cap_chan_put(chan); @@ -392,6 +408,9 @@ struct l2cap_chan *l2cap_chan_create(void) atomic_set(&chan->refcnt, 1); + /* This flag is cleared in l2cap_chan_ready() */ + set_bit(CONF_NOT_COMPLETE, &chan->conf_state); + BT_DBG("chan %p", chan); return chan; @@ -430,7 +449,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) case L2CAP_CHAN_CONN_ORIENTED: if (conn->hcon->type == LE_LINK) { /* LE connection */ - chan->omtu = L2CAP_LE_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; chan->scid = L2CAP_CID_LE_DATA; chan->dcid = L2CAP_CID_LE_DATA; } else { @@ -447,6 +466,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) chan->omtu = L2CAP_DEFAULT_MTU; break; + case L2CAP_CHAN_CONN_FIX_A2MP: + chan->scid = L2CAP_CID_A2MP; + chan->dcid = L2CAP_CID_A2MP; + chan->omtu = L2CAP_A2MP_DEFAULT_MTU; + chan->imtu = L2CAP_A2MP_DEFAULT_MTU; + break; + default: /* Raw socket can send/recv signalling messages only */ chan->scid = L2CAP_CID_SIGNALING; @@ -466,18 +492,16 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) list_add(&chan->list, &conn->chan_l); } -static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); mutex_unlock(&conn->chan_lock); } -static void l2cap_chan_del(struct l2cap_chan *chan, int err) +void l2cap_chan_del(struct l2cap_chan *chan, int err) { - struct sock *sk = chan->sk; struct l2cap_conn *conn = chan->conn; - struct sock *parent = bt_sk(sk)->parent; __clear_chan_timer(chan); @@ -490,34 +514,22 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_chan_put(chan); chan->conn = NULL; - hci_conn_put(conn->hcon); - } - - lock_sock(sk); - - __l2cap_state_change(chan, BT_CLOSED); - sock_set_flag(sk, SOCK_ZAPPED); - - if (err) - __l2cap_chan_set_err(chan, err); - if (parent) { - bt_accept_unlink(sk); - parent->sk_data_ready(parent, 0); - } else - sk->sk_state_change(sk); + if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP) + hci_conn_put(conn->hcon); + } - release_sock(sk); + if (chan->ops->teardown) + chan->ops->teardown(chan, err); - if (!(test_bit(CONF_OUTPUT_DONE, &chan->conf_state) && - test_bit(CONF_INPUT_DONE, &chan->conf_state))) + if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state)) return; - skb_queue_purge(&chan->tx_q); - - if (chan->mode == L2CAP_MODE_ERTM) { - struct srej_list *l, *tmp; + switch(chan->mode) { + case L2CAP_MODE_BASIC: + break; + case L2CAP_MODE_ERTM: __clear_retrans_timer(chan); __clear_monitor_timer(chan); __clear_ack_timer(chan); @@ -526,30 +538,15 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_seq_list_free(&chan->srej_list); l2cap_seq_list_free(&chan->retrans_list); - list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { - list_del(&l->list); - kfree(l); - } - } -} - -static void l2cap_chan_cleanup_listen(struct sock *parent) -{ - struct sock *sk; - - BT_DBG("parent %p", parent); - - /* Close not yet accepted channels */ - while ((sk = bt_accept_dequeue(parent, NULL))) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - l2cap_chan_lock(chan); - __clear_chan_timer(chan); - l2cap_chan_close(chan, ECONNRESET); - l2cap_chan_unlock(chan); + /* fall through */ - chan->ops->close(chan->data); + case L2CAP_MODE_STREAMING: + skb_queue_purge(&chan->tx_q); + break; } + + return; } void l2cap_chan_close(struct l2cap_chan *chan, int reason) @@ -562,12 +559,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) switch (chan->state) { case BT_LISTEN: - lock_sock(sk); - l2cap_chan_cleanup_listen(sk); - - __l2cap_state_change(chan, BT_CLOSED); - sock_set_flag(sk, SOCK_ZAPPED); - release_sock(sk); + if (chan->ops->teardown) + chan->ops->teardown(chan, 0); break; case BT_CONNECTED: @@ -595,7 +588,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); } @@ -609,9 +602,8 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) break; default: - lock_sock(sk); - sock_set_flag(sk, SOCK_ZAPPED); - release_sock(sk); + if (chan->ops->teardown) + chan->ops->teardown(chan, 0); break; } } @@ -627,7 +619,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) default: return HCI_AT_NO_BONDING; } - } else if (chan->psm == cpu_to_le16(0x0001)) { + } else if (chan->psm == __constant_cpu_to_le16(L2CAP_PSM_SDP)) { if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; @@ -773,9 +765,11 @@ static inline void __unpack_control(struct l2cap_chan *chan, if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { __unpack_extended_control(get_unaligned_le32(skb->data), &bt_cb(skb)->control); + skb_pull(skb, L2CAP_EXT_CTRL_SIZE); } else { __unpack_enhanced_control(get_unaligned_le16(skb->data), &bt_cb(skb)->control); + skb_pull(skb, L2CAP_ENH_CTRL_SIZE); } } @@ -830,66 +824,102 @@ static inline void __pack_control(struct l2cap_chan *chan, } } -static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) +static inline unsigned int __ertm_hdr_size(struct l2cap_chan *chan) { - struct sk_buff *skb; - struct l2cap_hdr *lh; - struct l2cap_conn *conn = chan->conn; - int count, hlen; - - if (chan->state != BT_CONNECTED) - return; - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - hlen = L2CAP_EXT_HDR_SIZE; + return L2CAP_EXT_HDR_SIZE; else - hlen = L2CAP_ENH_HDR_SIZE; + return L2CAP_ENH_HDR_SIZE; +} + +static struct sk_buff *l2cap_create_sframe_pdu(struct l2cap_chan *chan, + u32 control) +{ + struct sk_buff *skb; + struct l2cap_hdr *lh; + int hlen = __ertm_hdr_size(chan); if (chan->fcs == L2CAP_FCS_CRC16) hlen += L2CAP_FCS_SIZE; - BT_DBG("chan %p, control 0x%8.8x", chan, control); + skb = bt_skb_alloc(hlen, GFP_KERNEL); - count = min_t(unsigned int, conn->mtu, hlen); - - control |= __set_sframe(chan); - - if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) - control |= __set_ctrl_final(chan); - - if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state)) - control |= __set_ctrl_poll(chan); - - skb = bt_skb_alloc(count, GFP_ATOMIC); if (!skb) - return; + return ERR_PTR(-ENOMEM); lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + put_unaligned_le32(control, skb_put(skb, L2CAP_EXT_CTRL_SIZE)); + else + put_unaligned_le16(control, skb_put(skb, L2CAP_ENH_CTRL_SIZE)); if (chan->fcs == L2CAP_FCS_CRC16) { - u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE); + u16 fcs = crc16(0, (u8 *)skb->data, skb->len); put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); } skb->priority = HCI_PRIO_MAX; - l2cap_do_send(chan, skb); + return skb; } -static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control) +static void l2cap_send_sframe(struct l2cap_chan *chan, + struct l2cap_ctrl *control) { - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); + struct sk_buff *skb; + u32 control_field; + + BT_DBG("chan %p, control %p", chan, control); + + if (!control->sframe) + return; + + if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) && + !control->poll) + control->final = 1; + + if (control->super == L2CAP_SUPER_RR) + clear_bit(CONN_RNR_SENT, &chan->conn_state); + else if (control->super == L2CAP_SUPER_RNR) set_bit(CONN_RNR_SENT, &chan->conn_state); - } else - control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); - control |= __set_reqseq(chan, chan->buffer_seq); + if (control->super != L2CAP_SUPER_SREJ) { + chan->last_acked_seq = control->reqseq; + __clear_ack_timer(chan); + } + + BT_DBG("reqseq %d, final %d, poll %d, super %d", control->reqseq, + control->final, control->poll, control->super); + + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + control_field = __pack_extended_control(control); + else + control_field = __pack_enhanced_control(control); - l2cap_send_sframe(chan, control); + skb = l2cap_create_sframe_pdu(chan, control_field); + if (!IS_ERR(skb)) + l2cap_do_send(chan, skb); +} + +static void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, bool poll) +{ + struct l2cap_ctrl control; + + BT_DBG("chan %p, poll %d", chan, poll); + + memset(&control, 0, sizeof(control)); + control.sframe = 1; + control.poll = poll; + + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) + control.super = L2CAP_SUPER_RNR; + else + control.super = L2CAP_SUPER_RR; + + control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &control); } static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) @@ -914,25 +944,13 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan) static void l2cap_chan_ready(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - struct sock *parent; - - lock_sock(sk); - - parent = bt_sk(sk)->parent; - - BT_DBG("sk %p, parent %p", sk, parent); - + /* This clears all conf flags, including CONF_NOT_COMPLETE */ chan->conf_state = 0; __clear_chan_timer(chan); - __l2cap_state_change(chan, BT_CONNECTED); - sk->sk_state_change(sk); + chan->state = BT_CONNECTED; - if (parent) - parent->sk_data_ready(parent, 0); - - release_sock(sk); + chan->ops->ready(chan); } static void l2cap_do_start(struct l2cap_chan *chan) @@ -953,7 +971,7 @@ static void l2cap_do_start(struct l2cap_chan *chan) l2cap_send_conn_req(chan); } else { struct l2cap_info_req req; - req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); @@ -995,6 +1013,11 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c __clear_ack_timer(chan); } + if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + __l2cap_state_change(chan, BT_DISCONN); + return; + } + req.dcid = cpu_to_le16(chan->dcid); req.scid = cpu_to_le16(chan->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), @@ -1053,20 +1076,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; - rsp.result = cpu_to_le16(L2CAP_CR_PEND); - rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND); if (parent) parent->sk_data_ready(parent, 0); } else { __l2cap_state_change(chan, BT_CONFIG); - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); } release_sock(sk); } else { - rsp.result = cpu_to_le16(L2CAP_CR_PEND); - rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHEN_PEND); } l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -1150,13 +1173,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) lock_sock(parent); - /* Check for backlog size */ - if (sk_acceptq_is_full(parent)) { - BT_DBG("backlog full %d", parent->sk_ack_backlog); - goto clean; - } - - chan = pchan->ops->new_connection(pchan->data); + chan = pchan->ops->new_connection(pchan); if (!chan) goto clean; @@ -1171,10 +1188,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) l2cap_chan_add(conn, chan); - __set_chan_timer(chan, sk->sk_sndtimeo); - - __l2cap_state_change(chan, BT_CONNECTED); - parent->sk_data_ready(parent, 0); + l2cap_chan_ready(chan); clean: release_sock(parent); @@ -1198,6 +1212,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) l2cap_chan_lock(chan); + if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) { + l2cap_chan_unlock(chan); + continue; + } + if (conn->hcon->type == LE_LINK) { if (smp_conn_security(conn, chan->sec_level)) l2cap_chan_ready(chan); @@ -1270,7 +1289,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_chan_unlock(chan); - chan->ops->close(chan->data); + chan->ops->close(chan); l2cap_chan_put(chan); } @@ -1295,7 +1314,12 @@ static void security_timeout(struct work_struct *work) struct l2cap_conn *conn = container_of(work, struct l2cap_conn, security_timer.work); - l2cap_conn_del(conn->hcon, ETIMEDOUT); + BT_DBG("conn %p", conn); + + if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->flags)) { + smp_chan_destroy(conn); + l2cap_conn_del(conn->hcon, ETIMEDOUT); + } } static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) @@ -1439,21 +1463,17 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, goto done; } - lock_sock(sk); - - switch (sk->sk_state) { + switch (chan->state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: /* Already connecting */ err = 0; - release_sock(sk); goto done; case BT_CONNECTED: /* Already connected */ err = -EISCONN; - release_sock(sk); goto done; case BT_OPEN: @@ -1463,13 +1483,12 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, default: err = -EBADFD; - release_sock(sk); goto done; } /* Set destination address and psm */ + lock_sock(sk); bacpy(&bt_sk(sk)->dst, dst); - release_sock(sk); chan->psm = psm; @@ -1571,23 +1590,20 @@ int __l2cap_wait_ack(struct sock *sk) static void l2cap_monitor_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, - monitor_timer.work); + monitor_timer.work); BT_DBG("chan %p", chan); l2cap_chan_lock(chan); - if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + if (!chan->conn) { l2cap_chan_unlock(chan); l2cap_chan_put(chan); return; } - chan->retry_count++; - __set_monitor_timer(chan); + l2cap_tx(chan, NULL, NULL, L2CAP_EV_MONITOR_TO); - l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); l2cap_chan_unlock(chan); l2cap_chan_put(chan); } @@ -1595,234 +1611,293 @@ static void l2cap_monitor_timeout(struct work_struct *work) static void l2cap_retrans_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, - retrans_timer.work); + retrans_timer.work); BT_DBG("chan %p", chan); l2cap_chan_lock(chan); - chan->retry_count = 1; - __set_monitor_timer(chan); - - set_bit(CONN_WAIT_F, &chan->conn_state); - - l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); + if (!chan->conn) { + l2cap_chan_unlock(chan); + l2cap_chan_put(chan); + return; + } + l2cap_tx(chan, NULL, NULL, L2CAP_EV_RETRANS_TO); l2cap_chan_unlock(chan); l2cap_chan_put(chan); } -static void l2cap_drop_acked_frames(struct l2cap_chan *chan) +static void l2cap_streaming_send(struct l2cap_chan *chan, + struct sk_buff_head *skbs) { struct sk_buff *skb; + struct l2cap_ctrl *control; - while ((skb = skb_peek(&chan->tx_q)) && - chan->unacked_frames) { - if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) - break; + BT_DBG("chan %p, skbs %p", chan, skbs); - skb = skb_dequeue(&chan->tx_q); - kfree_skb(skb); + skb_queue_splice_tail_init(skbs, &chan->tx_q); - chan->unacked_frames--; - } + while (!skb_queue_empty(&chan->tx_q)) { - if (!chan->unacked_frames) - __clear_retrans_timer(chan); -} + skb = skb_dequeue(&chan->tx_q); -static void l2cap_streaming_send(struct l2cap_chan *chan) -{ - struct sk_buff *skb; - u32 control; - u16 fcs; + bt_cb(skb)->control.retries = 1; + control = &bt_cb(skb)->control; + + control->reqseq = 0; + control->txseq = chan->next_tx_seq; - while ((skb = skb_dequeue(&chan->tx_q))) { - control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); - control |= __set_txseq(chan, chan->next_tx_seq); - control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); - __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); + __pack_control(chan, control, skb); if (chan->fcs == L2CAP_FCS_CRC16) { - fcs = crc16(0, (u8 *)skb->data, - skb->len - L2CAP_FCS_SIZE); - put_unaligned_le16(fcs, - skb->data + skb->len - L2CAP_FCS_SIZE); + u16 fcs = crc16(0, (u8 *) skb->data, skb->len); + put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); } l2cap_do_send(chan, skb); + BT_DBG("Sent txseq %d", (int)control->txseq); + chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); + chan->frames_sent++; } } -static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) +static int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; - u16 fcs; - u32 control; + struct l2cap_ctrl *control; + int sent = 0; - skb = skb_peek(&chan->tx_q); - if (!skb) - return; + BT_DBG("chan %p", chan); - while (bt_cb(skb)->control.txseq != tx_seq) { - if (skb_queue_is_last(&chan->tx_q, skb)) - return; + if (chan->state != BT_CONNECTED) + return -ENOTCONN; - skb = skb_queue_next(&chan->tx_q, skb); - } + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; - if (bt_cb(skb)->control.retries == chan->remote_max_tx && - chan->remote_max_tx) { - l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - return; - } + while (chan->tx_send_head && + chan->unacked_frames < chan->remote_tx_win && + chan->tx_state == L2CAP_TX_STATE_XMIT) { - tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->control.retries++; + skb = chan->tx_send_head; - control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); - control &= __get_sar_mask(chan); + bt_cb(skb)->control.retries = 1; + control = &bt_cb(skb)->control; - if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) - control |= __set_ctrl_final(chan); + if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) + control->final = 1; - control |= __set_reqseq(chan, chan->buffer_seq); - control |= __set_txseq(chan, tx_seq); + control->reqseq = chan->buffer_seq; + chan->last_acked_seq = chan->buffer_seq; + control->txseq = chan->next_tx_seq; - __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); + __pack_control(chan, control, skb); - if (chan->fcs == L2CAP_FCS_CRC16) { - fcs = crc16(0, (u8 *)tx_skb->data, - tx_skb->len - L2CAP_FCS_SIZE); - put_unaligned_le16(fcs, - tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE); + if (chan->fcs == L2CAP_FCS_CRC16) { + u16 fcs = crc16(0, (u8 *) skb->data, skb->len); + put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE)); + } + + /* Clone after data has been modified. Data is assumed to be + read-only (for locking purposes) on cloned sk_buffs. + */ + tx_skb = skb_clone(skb, GFP_KERNEL); + + if (!tx_skb) + break; + + __set_retrans_timer(chan); + + chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); + chan->unacked_frames++; + chan->frames_sent++; + sent++; + + if (skb_queue_is_last(&chan->tx_q, skb)) + chan->tx_send_head = NULL; + else + chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); + + l2cap_do_send(chan, tx_skb); + BT_DBG("Sent txseq %d", (int)control->txseq); } - l2cap_do_send(chan, tx_skb); + BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent, + (int) chan->unacked_frames, skb_queue_len(&chan->tx_q)); + + return sent; } -static int l2cap_ertm_send(struct l2cap_chan *chan) +static void l2cap_ertm_resend(struct l2cap_chan *chan) { - struct sk_buff *skb, *tx_skb; - u16 fcs; - u32 control; - int nsent = 0; + struct l2cap_ctrl control; + struct sk_buff *skb; + struct sk_buff *tx_skb; + u16 seq; - if (chan->state != BT_CONNECTED) - return -ENOTCONN; + BT_DBG("chan %p", chan); if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) - return 0; + return; - while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { + while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) { + seq = l2cap_seq_list_pop(&chan->retrans_list); - if (bt_cb(skb)->control.retries == chan->remote_max_tx && - chan->remote_max_tx) { - l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); - break; + skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq); + if (!skb) { + BT_DBG("Error: Can't retransmit seq %d, frame missing", + seq); + continue; } - tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->control.retries++; + control = bt_cb(skb)->control; - control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); - control &= __get_sar_mask(chan); + if (chan->max_tx != 0 && + bt_cb(skb)->control.retries > chan->max_tx) { + BT_DBG("Retry limit exceeded (%d)", chan->max_tx); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + l2cap_seq_list_clear(&chan->retrans_list); + break; + } + control.reqseq = chan->buffer_seq; if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state)) - control |= __set_ctrl_final(chan); + control.final = 1; + else + control.final = 0; + + if (skb_cloned(skb)) { + /* Cloned sk_buffs are read-only, so we need a + * writeable copy + */ + tx_skb = skb_copy(skb, GFP_ATOMIC); + } else { + tx_skb = skb_clone(skb, GFP_ATOMIC); + } - control |= __set_reqseq(chan, chan->buffer_seq); - control |= __set_txseq(chan, chan->next_tx_seq); - control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); + if (!tx_skb) { + l2cap_seq_list_clear(&chan->retrans_list); + break; + } - __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); + /* Update skb contents */ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + put_unaligned_le32(__pack_extended_control(&control), + tx_skb->data + L2CAP_HDR_SIZE); + } else { + put_unaligned_le16(__pack_enhanced_control(&control), + tx_skb->data + L2CAP_HDR_SIZE); + } if (chan->fcs == L2CAP_FCS_CRC16) { - fcs = crc16(0, (u8 *)skb->data, - tx_skb->len - L2CAP_FCS_SIZE); - put_unaligned_le16(fcs, skb->data + - tx_skb->len - L2CAP_FCS_SIZE); + u16 fcs = crc16(0, (u8 *) tx_skb->data, tx_skb->len); + put_unaligned_le16(fcs, skb_put(tx_skb, + L2CAP_FCS_SIZE)); } l2cap_do_send(chan, tx_skb); - __set_retrans_timer(chan); - - bt_cb(skb)->control.txseq = chan->next_tx_seq; + BT_DBG("Resent txseq %d", control.txseq); - chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - - if (bt_cb(skb)->control.retries == 1) { - chan->unacked_frames++; - - if (!nsent++) - __clear_ack_timer(chan); - } - - chan->frames_sent++; - - if (skb_queue_is_last(&chan->tx_q, skb)) - chan->tx_send_head = NULL; - else - chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); + chan->last_acked_seq = chan->buffer_seq; } - - return nsent; } -static int l2cap_retransmit_frames(struct l2cap_chan *chan) +static void l2cap_retransmit(struct l2cap_chan *chan, + struct l2cap_ctrl *control) { - int ret; + BT_DBG("chan %p, control %p", chan, control); - if (!skb_queue_empty(&chan->tx_q)) - chan->tx_send_head = chan->tx_q.next; - - chan->next_tx_seq = chan->expected_ack_seq; - ret = l2cap_ertm_send(chan); - return ret; + l2cap_seq_list_append(&chan->retrans_list, control->reqseq); + l2cap_ertm_resend(chan); } -static void __l2cap_send_ack(struct l2cap_chan *chan) +static void l2cap_retransmit_all(struct l2cap_chan *chan, + struct l2cap_ctrl *control) { - u32 control = 0; + struct sk_buff *skb; - control |= __set_reqseq(chan, chan->buffer_seq); + BT_DBG("chan %p, control %p", chan, control); - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - set_bit(CONN_RNR_SENT, &chan->conn_state); - l2cap_send_sframe(chan, control); - return; - } + if (control->poll) + set_bit(CONN_SEND_FBIT, &chan->conn_state); + + l2cap_seq_list_clear(&chan->retrans_list); - if (l2cap_ertm_send(chan) > 0) + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) return; - control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); - l2cap_send_sframe(chan, control); + if (chan->unacked_frames) { + skb_queue_walk(&chan->tx_q, skb) { + if (bt_cb(skb)->control.txseq == control->reqseq || + skb == chan->tx_send_head) + break; + } + + skb_queue_walk_from(&chan->tx_q, skb) { + if (skb == chan->tx_send_head) + break; + + l2cap_seq_list_append(&chan->retrans_list, + bt_cb(skb)->control.txseq); + } + + l2cap_ertm_resend(chan); + } } static void l2cap_send_ack(struct l2cap_chan *chan) { - __clear_ack_timer(chan); - __l2cap_send_ack(chan); -} + struct l2cap_ctrl control; + u16 frames_to_ack = __seq_offset(chan, chan->buffer_seq, + chan->last_acked_seq); + int threshold; -static void l2cap_send_srejtail(struct l2cap_chan *chan) -{ - struct srej_list *tail; - u32 control; + BT_DBG("chan %p last_acked_seq %d buffer_seq %d", + chan, chan->last_acked_seq, chan->buffer_seq); - control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); - control |= __set_ctrl_final(chan); + memset(&control, 0, sizeof(control)); + control.sframe = 1; - tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); - control |= __set_reqseq(chan, tail->tx_seq); + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state) && + chan->rx_state == L2CAP_RX_STATE_RECV) { + __clear_ack_timer(chan); + control.super = L2CAP_SUPER_RNR; + control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &control); + } else { + if (!test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) { + l2cap_ertm_send(chan); + /* If any i-frames were sent, they included an ack */ + if (chan->buffer_seq == chan->last_acked_seq) + frames_to_ack = 0; + } - l2cap_send_sframe(chan, control); + /* Ack now if the tx window is 3/4ths full. + * Calculate without mul or div + */ + threshold = chan->tx_win; + threshold += threshold << 1; + threshold >>= 2; + + BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack, + threshold); + + if (frames_to_ack >= threshold) { + __clear_ack_timer(chan); + control.super = L2CAP_SUPER_RR; + control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &control); + frames_to_ack = 0; + } + + if (frames_to_ack) + __set_ack_timer(chan); + } } static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, @@ -1951,10 +2026,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (!conn) return ERR_PTR(-ENOTCONN); - if (test_bit(FLAG_EXT_CTRL, &chan->flags)) - hlen = L2CAP_EXT_HDR_SIZE; - else - hlen = L2CAP_ENH_HDR_SIZE; + hlen = __ertm_hdr_size(chan); if (sdulen) hlen += L2CAP_SDULEN_SIZE; @@ -1974,7 +2046,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); + /* Control header is populated later */ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + put_unaligned_le32(0, skb_put(skb, L2CAP_EXT_CTRL_SIZE)); + else + put_unaligned_le16(0, skb_put(skb, L2CAP_ENH_CTRL_SIZE)); if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); @@ -1985,9 +2061,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, return ERR_PTR(err); } - if (chan->fcs == L2CAP_FCS_CRC16) - put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); - + bt_cb(skb)->control.fcs = chan->fcs; bt_cb(skb)->control.retries = 0; return skb; } @@ -1999,7 +2073,6 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, struct sk_buff *skb; u16 sdu_len; size_t pdu_len; - int err = 0; u8 sar; BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); @@ -2015,7 +2088,10 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); /* Adjust for largest possible L2CAP overhead. */ - pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE; + if (chan->fcs) + pdu_len -= L2CAP_FCS_SIZE; + + pdu_len -= __ertm_hdr_size(chan); /* Remote device may have requested smaller PDUs */ pdu_len = min_t(size_t, pdu_len, chan->remote_mps); @@ -2055,7 +2131,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, } } - return err; + return 0; } int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, @@ -2117,17 +2193,12 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, if (err) break; - if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL) - chan->tx_send_head = seg_queue.next; - skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) - err = l2cap_ertm_send(chan); + l2cap_tx(chan, NULL, &seg_queue, L2CAP_EV_DATA_REQUEST); else - l2cap_streaming_send(chan); + l2cap_streaming_send(chan, &seg_queue); - if (err >= 0) - err = len; + err = len; /* If the skbs were not queued for sending, they'll still be in * seg_queue and need to be purged. @@ -2143,6 +2214,296 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, return err; } +static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) +{ + struct l2cap_ctrl control; + u16 seq; + + BT_DBG("chan %p, txseq %d", chan, txseq); + + memset(&control, 0, sizeof(control)); + control.sframe = 1; + control.super = L2CAP_SUPER_SREJ; + + for (seq = chan->expected_tx_seq; seq != txseq; + seq = __next_seq(chan, seq)) { + if (!l2cap_ertm_seq_in_queue(&chan->srej_q, seq)) { + control.reqseq = seq; + l2cap_send_sframe(chan, &control); + l2cap_seq_list_append(&chan->srej_list, seq); + } + } + + chan->expected_tx_seq = __next_seq(chan, txseq); +} + +static void l2cap_send_srej_tail(struct l2cap_chan *chan) +{ + struct l2cap_ctrl control; + + BT_DBG("chan %p", chan); + + if (chan->srej_list.tail == L2CAP_SEQ_LIST_CLEAR) + return; + + memset(&control, 0, sizeof(control)); + control.sframe = 1; + control.super = L2CAP_SUPER_SREJ; + control.reqseq = chan->srej_list.tail; + l2cap_send_sframe(chan, &control); +} + +static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq) +{ + struct l2cap_ctrl control; + u16 initial_head; + u16 seq; + + BT_DBG("chan %p, txseq %d", chan, txseq); + + memset(&control, 0, sizeof(control)); + control.sframe = 1; + control.super = L2CAP_SUPER_SREJ; + + /* Capture initial list head to allow only one pass through the list. */ + initial_head = chan->srej_list.head; + + do { + seq = l2cap_seq_list_pop(&chan->srej_list); + if (seq == txseq || seq == L2CAP_SEQ_LIST_CLEAR) + break; + + control.reqseq = seq; + l2cap_send_sframe(chan, &control); + l2cap_seq_list_append(&chan->srej_list, seq); + } while (chan->srej_list.head != initial_head); +} + +static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) +{ + struct sk_buff *acked_skb; + u16 ackseq; + + BT_DBG("chan %p, reqseq %d", chan, reqseq); + + if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq) + return; + + BT_DBG("expected_ack_seq %d, unacked_frames %d", + chan->expected_ack_seq, chan->unacked_frames); + + for (ackseq = chan->expected_ack_seq; ackseq != reqseq; + ackseq = __next_seq(chan, ackseq)) { + + acked_skb = l2cap_ertm_seq_in_queue(&chan->tx_q, ackseq); + if (acked_skb) { + skb_unlink(acked_skb, &chan->tx_q); + kfree_skb(acked_skb); + chan->unacked_frames--; + } + } + + chan->expected_ack_seq = reqseq; + + if (chan->unacked_frames == 0) + __clear_retrans_timer(chan); + + BT_DBG("unacked_frames %d", (int) chan->unacked_frames); +} + +static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan) +{ + BT_DBG("chan %p", chan); + + chan->expected_tx_seq = chan->buffer_seq; + l2cap_seq_list_clear(&chan->srej_list); + skb_queue_purge(&chan->srej_q); + chan->rx_state = L2CAP_RX_STATE_RECV; +} + +static void l2cap_tx_state_xmit(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff_head *skbs, u8 event) +{ + BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs, + event); + + switch (event) { + case L2CAP_EV_DATA_REQUEST: + if (chan->tx_send_head == NULL) + chan->tx_send_head = skb_peek(skbs); + + skb_queue_splice_tail_init(skbs, &chan->tx_q); + l2cap_ertm_send(chan); + break; + case L2CAP_EV_LOCAL_BUSY_DETECTED: + BT_DBG("Enter LOCAL_BUSY"); + set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + + if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) { + /* The SREJ_SENT state must be aborted if we are to + * enter the LOCAL_BUSY state. + */ + l2cap_abort_rx_srej_sent(chan); + } + + l2cap_send_ack(chan); + + break; + case L2CAP_EV_LOCAL_BUSY_CLEAR: + BT_DBG("Exit LOCAL_BUSY"); + clear_bit(CONN_LOCAL_BUSY, &chan->conn_state); + + if (test_bit(CONN_RNR_SENT, &chan->conn_state)) { + struct l2cap_ctrl local_control; + + memset(&local_control, 0, sizeof(local_control)); + local_control.sframe = 1; + local_control.super = L2CAP_SUPER_RR; + local_control.poll = 1; + local_control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &local_control); + + chan->retry_count = 1; + __set_monitor_timer(chan); + chan->tx_state = L2CAP_TX_STATE_WAIT_F; + } + break; + case L2CAP_EV_RECV_REQSEQ_AND_FBIT: + l2cap_process_reqseq(chan, control->reqseq); + break; + case L2CAP_EV_EXPLICIT_POLL: + l2cap_send_rr_or_rnr(chan, 1); + chan->retry_count = 1; + __set_monitor_timer(chan); + __clear_ack_timer(chan); + chan->tx_state = L2CAP_TX_STATE_WAIT_F; + break; + case L2CAP_EV_RETRANS_TO: + l2cap_send_rr_or_rnr(chan, 1); + chan->retry_count = 1; + __set_monitor_timer(chan); + chan->tx_state = L2CAP_TX_STATE_WAIT_F; + break; + case L2CAP_EV_RECV_FBIT: + /* Nothing to process */ + break; + default: + break; + } +} + +static void l2cap_tx_state_wait_f(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff_head *skbs, u8 event) +{ + BT_DBG("chan %p, control %p, skbs %p, event %d", chan, control, skbs, + event); + + switch (event) { + case L2CAP_EV_DATA_REQUEST: + if (chan->tx_send_head == NULL) + chan->tx_send_head = skb_peek(skbs); + /* Queue data, but don't send. */ + skb_queue_splice_tail_init(skbs, &chan->tx_q); + break; + case L2CAP_EV_LOCAL_BUSY_DETECTED: + BT_DBG("Enter LOCAL_BUSY"); + set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + + if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) { + /* The SREJ_SENT state must be aborted if we are to + * enter the LOCAL_BUSY state. + */ + l2cap_abort_rx_srej_sent(chan); + } + + l2cap_send_ack(chan); + + break; + case L2CAP_EV_LOCAL_BUSY_CLEAR: + BT_DBG("Exit LOCAL_BUSY"); + clear_bit(CONN_LOCAL_BUSY, &chan->conn_state); + + if (test_bit(CONN_RNR_SENT, &chan->conn_state)) { + struct l2cap_ctrl local_control; + memset(&local_control, 0, sizeof(local_control)); + local_control.sframe = 1; + local_control.super = L2CAP_SUPER_RR; + local_control.poll = 1; + local_control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &local_control); + + chan->retry_count = 1; + __set_monitor_timer(chan); + chan->tx_state = L2CAP_TX_STATE_WAIT_F; + } + break; + case L2CAP_EV_RECV_REQSEQ_AND_FBIT: + l2cap_process_reqseq(chan, control->reqseq); + + /* Fall through */ + + case L2CAP_EV_RECV_FBIT: + if (control && control->final) { + __clear_monitor_timer(chan); + if (chan->unacked_frames > 0) + __set_retrans_timer(chan); + chan->retry_count = 0; + chan->tx_state = L2CAP_TX_STATE_XMIT; + BT_DBG("recv fbit tx_state 0x2.2%x", chan->tx_state); + } + break; + case L2CAP_EV_EXPLICIT_POLL: + /* Ignore */ + break; + case L2CAP_EV_MONITOR_TO: + if (chan->max_tx == 0 || chan->retry_count < chan->max_tx) { + l2cap_send_rr_or_rnr(chan, 1); + __set_monitor_timer(chan); + chan->retry_count++; + } else { + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); + } + break; + default: + break; + } +} + +static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control, + struct sk_buff_head *skbs, u8 event) +{ + BT_DBG("chan %p, control %p, skbs %p, event %d, state %d", + chan, control, skbs, event, chan->tx_state); + + switch (chan->tx_state) { + case L2CAP_TX_STATE_XMIT: + l2cap_tx_state_xmit(chan, control, skbs, event); + break; + case L2CAP_TX_STATE_WAIT_F: + l2cap_tx_state_wait_f(chan, control, skbs, event); + break; + default: + /* Ignore event */ + break; + } +} + +static void l2cap_pass_to_tx(struct l2cap_chan *chan, + struct l2cap_ctrl *control) +{ + BT_DBG("chan %p, control %p", chan, control); + l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_REQSEQ_AND_FBIT); +} + +static void l2cap_pass_to_tx_fbit(struct l2cap_chan *chan, + struct l2cap_ctrl *control) +{ + BT_DBG("chan %p, control %p", chan, control); + l2cap_tx(chan, control, NULL, L2CAP_EV_RECV_FBIT); +} + /* Copy frame to all raw sockets on that connection */ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { @@ -2165,7 +2526,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (!nskb) continue; - if (chan->ops->recv(chan->data, nskb)) + if (chan->ops->recv(chan, nskb)) kfree_skb(nskb); } @@ -2195,9 +2556,9 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, lh->len = cpu_to_le16(L2CAP_CMD_HDR_SIZE + dlen); if (conn->hcon->type == LE_LINK) - lh->cid = cpu_to_le16(L2CAP_CID_LE_SIGNALING); + lh->cid = __constant_cpu_to_le16(L2CAP_CID_LE_SIGNALING); else - lh->cid = cpu_to_le16(L2CAP_CID_SIGNALING); + lh->cid = __constant_cpu_to_le16(L2CAP_CID_SIGNALING); cmd = (struct l2cap_cmd_hdr *) skb_put(skb, L2CAP_CMD_HDR_SIZE); cmd->code = code; @@ -2309,8 +2670,8 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) efs.stype = chan->local_stype; efs.msdu = cpu_to_le16(chan->local_msdu); efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime); - efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT); - efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO); + efs.acc_lat = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT); + efs.flush_to = __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO); break; case L2CAP_MODE_STREAMING: @@ -2333,20 +2694,24 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan) static void l2cap_ack_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, - ack_timer.work); + ack_timer.work); + u16 frames_to_ack; BT_DBG("chan %p", chan); l2cap_chan_lock(chan); - __l2cap_send_ack(chan); + frames_to_ack = __seq_offset(chan, chan->buffer_seq, + chan->last_acked_seq); - l2cap_chan_unlock(chan); + if (frames_to_ack) + l2cap_send_rr_or_rnr(chan, 0); + l2cap_chan_unlock(chan); l2cap_chan_put(chan); } -static inline int l2cap_ertm_init(struct l2cap_chan *chan) +int l2cap_ertm_init(struct l2cap_chan *chan) { int err; @@ -2355,7 +2720,6 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan) chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; - chan->num_acked = 0; chan->frames_sent = 0; chan->last_acked_seq = 0; chan->sdu = NULL; @@ -2376,12 +2740,15 @@ static inline int l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); - INIT_LIST_HEAD(&chan->srej_l); err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); if (err < 0) return err; - return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); + err = l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); + if (err < 0) + l2cap_seq_list_free(&chan->srej_list); + + return err; } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -2507,6 +2874,7 @@ done: break; case L2CAP_MODE_STREAMING: + l2cap_txwin_setup(chan); rfc.mode = L2CAP_MODE_STREAMING; rfc.txwin_size = 0; rfc.max_transmit = 0; @@ -2537,7 +2905,7 @@ done: } req->dcid = cpu_to_le16(chan->dcid); - req->flags = cpu_to_le16(0); + req->flags = __constant_cpu_to_le16(0); return ptr - data; } @@ -2757,7 +3125,7 @@ done: } rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); - rsp->flags = cpu_to_le16(0x0000); + rsp->flags = __constant_cpu_to_le16(0); return ptr - data; } @@ -2856,7 +3224,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi } req->dcid = cpu_to_le16(chan->dcid); - req->flags = cpu_to_le16(0x0000); + req->flags = __constant_cpu_to_le16(0); return ptr - data; } @@ -2883,8 +3251,8 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); @@ -2910,20 +3278,22 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); - switch (type) { - case L2CAP_CONF_RFC: - if (olen == sizeof(rfc)) - memcpy(&rfc, (void *)val, olen); - goto done; - } + if (type != L2CAP_CONF_RFC) + continue; + + if (olen != sizeof(rfc)) + break; + + memcpy(&rfc, (void *)val, olen); + goto done; } /* Use sane default values in case a misbehaving remote device * did not send an RFC option. */ rfc.mode = chan->mode; - rfc.retrans_timeout = cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc.monitor_timeout = cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); + rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); + rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); rfc.max_pdu_size = cpu_to_le16(chan->imtu); BT_ERR("Expected RFC option was not found, using defaults"); @@ -2986,7 +3356,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ - if (psm != cpu_to_le16(0x0001) && + if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) && !hci_conn_check_link_mode(conn->hcon)) { conn->disc_reason = HCI_ERROR_AUTH_FAILURE; result = L2CAP_CR_SEC_BLOCK; @@ -2995,25 +3365,16 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd result = L2CAP_CR_NO_MEM; - /* Check for backlog size */ - if (sk_acceptq_is_full(parent)) { - BT_DBG("backlog full %d", parent->sk_ack_backlog); + /* Check if we already have channel with that dcid */ + if (__l2cap_get_chan_by_dcid(conn, scid)) goto response; - } - chan = pchan->ops->new_connection(pchan->data); + chan = pchan->ops->new_connection(pchan); if (!chan) goto response; sk = chan->sk; - /* Check if we already have channel with that dcid */ - if (__l2cap_get_chan_by_dcid(conn, scid)) { - sock_set_flag(sk, SOCK_ZAPPED); - chan->ops->close(chan->data); - goto response; - } - hci_conn_hold(conn->hcon); bacpy(&bt_sk(sk)->src, conn->src); @@ -3067,7 +3428,7 @@ sendresp: if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) { struct l2cap_info_req info; - info.type = cpu_to_le16(L2CAP_IT_FEAT_MASK); + info.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT; conn->info_ident = l2cap_get_ident(conn); @@ -3189,7 +3550,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; - rej.reason = cpu_to_le16(L2CAP_REJ_INVALID_CID); + rej.reason = __constant_cpu_to_le16(L2CAP_REJ_INVALID_CID); rej.scid = cpu_to_le16(chan->scid); rej.dcid = cpu_to_le16(chan->dcid); @@ -3211,11 +3572,11 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr memcpy(chan->conf_req + chan->conf_len, req->data, len); chan->conf_len += len; - if (flags & 0x0001) { + if (flags & L2CAP_CONF_FLAG_CONTINUATION) { /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, - L2CAP_CONF_SUCCESS, 0x0001), rsp); + L2CAP_CONF_SUCCESS, flags), rsp); goto unlock; } @@ -3238,8 +3599,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) { set_default_fcs(chan); - l2cap_state_change(chan, BT_CONNECTED); - if (chan->mode == L2CAP_MODE_ERTM || chan->mode == L2CAP_MODE_STREAMING) err = l2cap_ertm_init(chan); @@ -3271,7 +3630,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(chan, rsp, - L2CAP_CONF_SUCCESS, 0x0000), rsp); + L2CAP_CONF_SUCCESS, flags), rsp); } unlock: @@ -3362,7 +3721,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto done; } - if (flags & 0x01) + if (flags & L2CAP_CONF_FLAG_CONTINUATION) goto done; set_bit(CONF_INPUT_DONE, &chan->conf_state); @@ -3370,7 +3729,6 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (test_bit(CONF_OUTPUT_DONE, &chan->conf_state)) { set_default_fcs(chan); - l2cap_state_change(chan, BT_CONNECTED); if (chan->mode == L2CAP_MODE_ERTM || chan->mode == L2CAP_MODE_STREAMING) err = l2cap_ertm_init(chan); @@ -3424,7 +3782,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd l2cap_chan_unlock(chan); - chan->ops->close(chan->data); + chan->ops->close(chan); l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); @@ -3458,7 +3816,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd l2cap_chan_unlock(chan); - chan->ops->close(chan->data); + chan->ops->close(chan); l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); @@ -3479,8 +3837,8 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm u8 buf[8]; u32 feat_mask = l2cap_feat_mask; struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf; - rsp->type = cpu_to_le16(L2CAP_IT_FEAT_MASK); - rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); + rsp->type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK); + rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS); if (!disable_ertm) feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING | L2CAP_FEAT_FCS; @@ -3500,15 +3858,15 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm else l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP; - rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); - rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS); + rsp->type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN); + rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS); memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan)); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf), buf); } else { struct l2cap_info_rsp rsp; rsp.type = cpu_to_le16(type); - rsp.result = cpu_to_le16(L2CAP_IR_NOTSUPP); + rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP); l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp), &rsp); } @@ -3548,7 +3906,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm if (conn->feat_mask & L2CAP_FEAT_FIXED_CHAN) { struct l2cap_info_req req; - req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN); + req.type = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN); conn->info_ident = l2cap_get_ident(conn); @@ -3783,9 +4141,9 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn, err = l2cap_check_conn_param(min, max, latency, to_multiplier); if (err) - rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); + rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_REJECTED); else - rsp.result = cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); + rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED); l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP, sizeof(rsp), &rsp); @@ -3933,7 +4291,7 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, BT_ERR("Wrong link type (%d)", err); /* FIXME: Map err to a valid reason */ - rej.reason = cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); + rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD); l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej); } @@ -3965,65 +4323,38 @@ static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb) return 0; } -static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) +static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) { - u32 control = 0; + struct l2cap_ctrl control; - chan->frames_sent = 0; + BT_DBG("chan %p", chan); - control |= __set_reqseq(chan, chan->buffer_seq); + memset(&control, 0, sizeof(control)); + control.sframe = 1; + control.final = 1; + control.reqseq = chan->buffer_seq; + set_bit(CONN_SEND_FBIT, &chan->conn_state); if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR); - l2cap_send_sframe(chan, control); - set_bit(CONN_RNR_SENT, &chan->conn_state); + control.super = L2CAP_SUPER_RNR; + l2cap_send_sframe(chan, &control); } - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) - l2cap_retransmit_frames(chan); + if (test_and_clear_bit(CONN_REMOTE_BUSY, &chan->conn_state) && + chan->unacked_frames > 0) + __set_retrans_timer(chan); + /* Send pending iframes */ l2cap_ertm_send(chan); if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) && - chan->frames_sent == 0) { - control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); - l2cap_send_sframe(chan, control); - } -} - -static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar) -{ - struct sk_buff *next_skb; - int tx_seq_offset, next_tx_seq_offset; - - bt_cb(skb)->control.txseq = tx_seq; - bt_cb(skb)->control.sar = sar; - - next_skb = skb_peek(&chan->srej_q); - - tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); - - while (next_skb) { - if (bt_cb(next_skb)->control.txseq == tx_seq) - return -EINVAL; - - next_tx_seq_offset = __seq_offset(chan, - bt_cb(next_skb)->control.txseq, chan->buffer_seq); - - if (next_tx_seq_offset > tx_seq_offset) { - __skb_queue_before(&chan->srej_q, next_skb, skb); - return 0; - } - - if (skb_queue_is_last(&chan->srej_q, next_skb)) - next_skb = NULL; - else - next_skb = skb_queue_next(&chan->srej_q, next_skb); + test_bit(CONN_SEND_FBIT, &chan->conn_state)) { + /* F-bit wasn't sent in an s-frame or i-frame yet, so + * send it now. + */ + control.super = L2CAP_SUPER_RR; + l2cap_send_sframe(chan, &control); } - - __skb_queue_tail(&chan->srej_q, skb); - - return 0; } static void append_skb_frag(struct sk_buff *skb, @@ -4045,16 +4376,17 @@ static void append_skb_frag(struct sk_buff *skb, skb->truesize += new_frag->truesize; } -static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control) +static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, + struct l2cap_ctrl *control) { int err = -EINVAL; - switch (__get_ctrl_sar(chan, control)) { + switch (control->sar) { case L2CAP_SAR_UNSEGMENTED: if (chan->sdu) break; - err = chan->ops->recv(chan->data, skb); + err = chan->ops->recv(chan, skb); break; case L2CAP_SAR_START: @@ -4104,7 +4436,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3 if (chan->sdu->len != chan->sdu_len) break; - err = chan->ops->recv(chan->data, chan->sdu); + err = chan->ops->recv(chan, chan->sdu); if (!err) { /* Reassembly complete */ @@ -4126,448 +4458,609 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u3 return err; } -static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) +void l2cap_chan_busy(struct l2cap_chan *chan, int busy) { - BT_DBG("chan %p, Enter local busy", chan); + u8 event; - set_bit(CONN_LOCAL_BUSY, &chan->conn_state); - l2cap_seq_list_clear(&chan->srej_list); + if (chan->mode != L2CAP_MODE_ERTM) + return; - __set_ack_timer(chan); + event = busy ? L2CAP_EV_LOCAL_BUSY_DETECTED : L2CAP_EV_LOCAL_BUSY_CLEAR; + l2cap_tx(chan, NULL, NULL, event); } -static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan) +static int l2cap_rx_queued_iframes(struct l2cap_chan *chan) { - u32 control; - - if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) - goto done; + int err = 0; + /* Pass sequential frames to l2cap_reassemble_sdu() + * until a gap is encountered. + */ - control = __set_reqseq(chan, chan->buffer_seq); - control |= __set_ctrl_poll(chan); - control |= __set_ctrl_super(chan, L2CAP_SUPER_RR); - l2cap_send_sframe(chan, control); - chan->retry_count = 1; + BT_DBG("chan %p", chan); - __clear_retrans_timer(chan); - __set_monitor_timer(chan); + while (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + struct sk_buff *skb; + BT_DBG("Searching for skb with txseq %d (queue len %d)", + chan->buffer_seq, skb_queue_len(&chan->srej_q)); - set_bit(CONN_WAIT_F, &chan->conn_state); + skb = l2cap_ertm_seq_in_queue(&chan->srej_q, chan->buffer_seq); -done: - clear_bit(CONN_LOCAL_BUSY, &chan->conn_state); - clear_bit(CONN_RNR_SENT, &chan->conn_state); + if (!skb) + break; - BT_DBG("chan %p, Exit local busy", chan); -} + skb_unlink(skb, &chan->srej_q); + chan->buffer_seq = __next_seq(chan, chan->buffer_seq); + err = l2cap_reassemble_sdu(chan, skb, &bt_cb(skb)->control); + if (err) + break; + } -void l2cap_chan_busy(struct l2cap_chan *chan, int busy) -{ - if (chan->mode == L2CAP_MODE_ERTM) { - if (busy) - l2cap_ertm_enter_local_busy(chan); - else - l2cap_ertm_exit_local_busy(chan); + if (skb_queue_empty(&chan->srej_q)) { + chan->rx_state = L2CAP_RX_STATE_RECV; + l2cap_send_ack(chan); } + + return err; } -static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) +static void l2cap_handle_srej(struct l2cap_chan *chan, + struct l2cap_ctrl *control) { struct sk_buff *skb; - u32 control; - while ((skb = skb_peek(&chan->srej_q)) && - !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - int err; + BT_DBG("chan %p, control %p", chan, control); - if (bt_cb(skb)->control.txseq != tx_seq) - break; + if (control->reqseq == chan->next_tx_seq) { + BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + return; + } - skb = skb_dequeue(&chan->srej_q); - control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); - err = l2cap_reassemble_sdu(chan, skb, control); + skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq); - if (err < 0) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - break; - } + if (skb == NULL) { + BT_DBG("Seq %d not available for retransmission", + control->reqseq); + return; + } - chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej); - tx_seq = __next_seq(chan, tx_seq); + if (chan->max_tx != 0 && bt_cb(skb)->control.retries >= chan->max_tx) { + BT_DBG("Retry limit exceeded (%d)", chan->max_tx); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + return; } -} -static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq) -{ - struct srej_list *l, *tmp; - u32 control; + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { - if (l->tx_seq == tx_seq) { - list_del(&l->list); - kfree(l); - return; + if (control->poll) { + l2cap_pass_to_tx(chan, control); + + set_bit(CONN_SEND_FBIT, &chan->conn_state); + l2cap_retransmit(chan, control); + l2cap_ertm_send(chan); + + if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) { + set_bit(CONN_SREJ_ACT, &chan->conn_state); + chan->srej_save_reqseq = control->reqseq; + } + } else { + l2cap_pass_to_tx_fbit(chan, control); + + if (control->final) { + if (chan->srej_save_reqseq != control->reqseq || + !test_and_clear_bit(CONN_SREJ_ACT, + &chan->conn_state)) + l2cap_retransmit(chan, control); + } else { + l2cap_retransmit(chan, control); + if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) { + set_bit(CONN_SREJ_ACT, &chan->conn_state); + chan->srej_save_reqseq = control->reqseq; + } } - control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); - control |= __set_reqseq(chan, l->tx_seq); - l2cap_send_sframe(chan, control); - list_del(&l->list); - list_add_tail(&l->list, &chan->srej_l); } } -static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) +static void l2cap_handle_rej(struct l2cap_chan *chan, + struct l2cap_ctrl *control) { - struct srej_list *new; - u32 control; - - while (tx_seq != chan->expected_tx_seq) { - control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); - control |= __set_reqseq(chan, chan->expected_tx_seq); - l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); - l2cap_send_sframe(chan, control); + struct sk_buff *skb; - new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); - if (!new) - return -ENOMEM; + BT_DBG("chan %p, control %p", chan, control); - new->tx_seq = chan->expected_tx_seq; + if (control->reqseq == chan->next_tx_seq) { + BT_DBG("Invalid reqseq %d, disconnecting", control->reqseq); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + return; + } - chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); + skb = l2cap_ertm_seq_in_queue(&chan->tx_q, control->reqseq); - list_add_tail(&new->list, &chan->srej_l); + if (chan->max_tx && skb && + bt_cb(skb)->control.retries >= chan->max_tx) { + BT_DBG("Retry limit exceeded (%d)", chan->max_tx); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + return; } - chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - return 0; + l2cap_pass_to_tx(chan, control); + + if (control->final) { + if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) + l2cap_retransmit_all(chan, control); + } else { + l2cap_retransmit_all(chan, control); + l2cap_ertm_send(chan); + if (chan->tx_state == L2CAP_TX_STATE_WAIT_F) + set_bit(CONN_REJ_ACT, &chan->conn_state); + } } -static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) +static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq) { - u16 tx_seq = __get_txseq(chan, rx_control); - u16 req_seq = __get_reqseq(chan, rx_control); - u8 sar = __get_ctrl_sar(chan, rx_control); - int tx_seq_offset, expected_tx_seq_offset; - int num_to_ack = (chan->tx_win/6) + 1; - int err = 0; + BT_DBG("chan %p, txseq %d", chan, txseq); - BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len, - tx_seq, rx_control); + BT_DBG("last_acked_seq %d, expected_tx_seq %d", chan->last_acked_seq, + chan->expected_tx_seq); - if (__is_ctrl_final(chan, rx_control) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - __clear_monitor_timer(chan); - if (chan->unacked_frames > 0) - __set_retrans_timer(chan); - clear_bit(CONN_WAIT_F, &chan->conn_state); - } + if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) { + if (__seq_offset(chan, txseq, chan->last_acked_seq) >= + chan->tx_win) { + /* See notes below regarding "double poll" and + * invalid packets. + */ + if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) { + BT_DBG("Invalid/Ignore - after SREJ"); + return L2CAP_TXSEQ_INVALID_IGNORE; + } else { + BT_DBG("Invalid - in window after SREJ sent"); + return L2CAP_TXSEQ_INVALID; + } + } - chan->expected_ack_seq = req_seq; - l2cap_drop_acked_frames(chan); + if (chan->srej_list.head == txseq) { + BT_DBG("Expected SREJ"); + return L2CAP_TXSEQ_EXPECTED_SREJ; + } - tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); + if (l2cap_ertm_seq_in_queue(&chan->srej_q, txseq)) { + BT_DBG("Duplicate SREJ - txseq already stored"); + return L2CAP_TXSEQ_DUPLICATE_SREJ; + } - /* invalid tx_seq */ - if (tx_seq_offset >= chan->tx_win) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - goto drop; + if (l2cap_seq_list_contains(&chan->srej_list, txseq)) { + BT_DBG("Unexpected SREJ - not requested"); + return L2CAP_TXSEQ_UNEXPECTED_SREJ; + } } - if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { - if (!test_bit(CONN_RNR_SENT, &chan->conn_state)) - l2cap_send_ack(chan); - goto drop; + if (chan->expected_tx_seq == txseq) { + if (__seq_offset(chan, txseq, chan->last_acked_seq) >= + chan->tx_win) { + BT_DBG("Invalid - txseq outside tx window"); + return L2CAP_TXSEQ_INVALID; + } else { + BT_DBG("Expected"); + return L2CAP_TXSEQ_EXPECTED; + } } - if (tx_seq == chan->expected_tx_seq) - goto expected; + if (__seq_offset(chan, txseq, chan->last_acked_seq) < + __seq_offset(chan, chan->expected_tx_seq, + chan->last_acked_seq)){ + BT_DBG("Duplicate - expected_tx_seq later than txseq"); + return L2CAP_TXSEQ_DUPLICATE; + } + + if (__seq_offset(chan, txseq, chan->last_acked_seq) >= chan->tx_win) { + /* A source of invalid packets is a "double poll" condition, + * where delays cause us to send multiple poll packets. If + * the remote stack receives and processes both polls, + * sequence numbers can wrap around in such a way that a + * resent frame has a sequence number that looks like new data + * with a sequence gap. This would trigger an erroneous SREJ + * request. + * + * Fortunately, this is impossible with a tx window that's + * less than half of the maximum sequence number, which allows + * invalid frames to be safely ignored. + * + * With tx window sizes greater than half of the tx window + * maximum, the frame is invalid and cannot be ignored. This + * causes a disconnect. + */ + + if (chan->tx_win <= ((chan->tx_win_max + 1) >> 1)) { + BT_DBG("Invalid/Ignore - txseq outside tx window"); + return L2CAP_TXSEQ_INVALID_IGNORE; + } else { + BT_DBG("Invalid - txseq outside tx window"); + return L2CAP_TXSEQ_INVALID; + } + } else { + BT_DBG("Unexpected - txseq indicates missing frames"); + return L2CAP_TXSEQ_UNEXPECTED; + } +} - if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - struct srej_list *first; +static int l2cap_rx_state_recv(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff *skb, u8 event) +{ + int err = 0; + bool skb_in_use = 0; - first = list_first_entry(&chan->srej_l, - struct srej_list, list); - if (tx_seq == first->tx_seq) { - l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); - l2cap_check_srej_gap(chan, tx_seq); + BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, + event); - list_del(&first->list); - kfree(first); + switch (event) { + case L2CAP_EV_RECV_IFRAME: + switch (l2cap_classify_txseq(chan, control->txseq)) { + case L2CAP_TXSEQ_EXPECTED: + l2cap_pass_to_tx(chan, control); - if (list_empty(&chan->srej_l)) { - chan->buffer_seq = chan->buffer_seq_srej; - clear_bit(CONN_SREJ_SENT, &chan->conn_state); - l2cap_send_ack(chan); - BT_DBG("chan %p, Exit SREJ_SENT", chan); + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + BT_DBG("Busy, discarding expected seq %d", + control->txseq); + break; } - } else { - struct srej_list *l; - /* duplicated tx_seq */ - if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) - goto drop; + chan->expected_tx_seq = __next_seq(chan, + control->txseq); + + chan->buffer_seq = chan->expected_tx_seq; + skb_in_use = 1; + + err = l2cap_reassemble_sdu(chan, skb, control); + if (err) + break; - list_for_each_entry(l, &chan->srej_l, list) { - if (l->tx_seq == tx_seq) { - l2cap_resend_srejframe(chan, tx_seq); - return 0; + if (control->final) { + if (!test_and_clear_bit(CONN_REJ_ACT, + &chan->conn_state)) { + control->final = 0; + l2cap_retransmit_all(chan, control); + l2cap_ertm_send(chan); } } - err = l2cap_send_srejframe(chan, tx_seq); - if (err < 0) { - l2cap_send_disconn_req(chan->conn, chan, -err); - return err; + if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) + l2cap_send_ack(chan); + break; + case L2CAP_TXSEQ_UNEXPECTED: + l2cap_pass_to_tx(chan, control); + + /* Can't issue SREJ frames in the local busy state. + * Drop this frame, it will be seen as missing + * when local busy is exited. + */ + if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { + BT_DBG("Busy, discarding unexpected seq %d", + control->txseq); + break; } - } - } else { - expected_tx_seq_offset = __seq_offset(chan, - chan->expected_tx_seq, chan->buffer_seq); - - /* duplicated tx_seq */ - if (tx_seq_offset < expected_tx_seq_offset) - goto drop; - set_bit(CONN_SREJ_SENT, &chan->conn_state); + /* There was a gap in the sequence, so an SREJ + * must be sent for each missing frame. The + * current frame is stored for later use. + */ + skb_queue_tail(&chan->srej_q, skb); + skb_in_use = 1; + BT_DBG("Queued %p (queue len %d)", skb, + skb_queue_len(&chan->srej_q)); - BT_DBG("chan %p, Enter SREJ", chan); + clear_bit(CONN_SREJ_ACT, &chan->conn_state); + l2cap_seq_list_clear(&chan->srej_list); + l2cap_send_srej(chan, control->txseq); - INIT_LIST_HEAD(&chan->srej_l); - chan->buffer_seq_srej = chan->buffer_seq; + chan->rx_state = L2CAP_RX_STATE_SREJ_SENT; + break; + case L2CAP_TXSEQ_DUPLICATE: + l2cap_pass_to_tx(chan, control); + break; + case L2CAP_TXSEQ_INVALID_IGNORE: + break; + case L2CAP_TXSEQ_INVALID: + default: + l2cap_send_disconn_req(chan->conn, chan, + ECONNRESET); + break; + } + break; + case L2CAP_EV_RECV_RR: + l2cap_pass_to_tx(chan, control); + if (control->final) { + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - __skb_queue_head_init(&chan->srej_q); - l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); + if (!test_and_clear_bit(CONN_REJ_ACT, + &chan->conn_state)) { + control->final = 0; + l2cap_retransmit_all(chan, control); + } - /* Set P-bit only if there are some I-frames to ack. */ - if (__clear_ack_timer(chan)) - set_bit(CONN_SEND_PBIT, &chan->conn_state); + l2cap_ertm_send(chan); + } else if (control->poll) { + l2cap_send_i_or_rr_or_rnr(chan); + } else { + if (test_and_clear_bit(CONN_REMOTE_BUSY, + &chan->conn_state) && + chan->unacked_frames) + __set_retrans_timer(chan); - err = l2cap_send_srejframe(chan, tx_seq); - if (err < 0) { - l2cap_send_disconn_req(chan->conn, chan, -err); - return err; + l2cap_ertm_send(chan); } + break; + case L2CAP_EV_RECV_RNR: + set_bit(CONN_REMOTE_BUSY, &chan->conn_state); + l2cap_pass_to_tx(chan, control); + if (control && control->poll) { + set_bit(CONN_SEND_FBIT, &chan->conn_state); + l2cap_send_rr_or_rnr(chan, 0); + } + __clear_retrans_timer(chan); + l2cap_seq_list_clear(&chan->retrans_list); + break; + case L2CAP_EV_RECV_REJ: + l2cap_handle_rej(chan, control); + break; + case L2CAP_EV_RECV_SREJ: + l2cap_handle_srej(chan, control); + break; + default: + break; } - return 0; - -expected: - chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); - - if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - bt_cb(skb)->control.txseq = tx_seq; - bt_cb(skb)->control.sar = sar; - __skb_queue_tail(&chan->srej_q, skb); - return 0; - } - - err = l2cap_reassemble_sdu(chan, skb, rx_control); - chan->buffer_seq = __next_seq(chan, chan->buffer_seq); - if (err < 0) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - return err; + if (skb && !skb_in_use) { + BT_DBG("Freeing %p", skb); + kfree_skb(skb); } - if (__is_ctrl_final(chan, rx_control)) { - if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) - l2cap_retransmit_frames(chan); - } + return err; +} +static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff *skb, u8 event) +{ + int err = 0; + u16 txseq = control->txseq; + bool skb_in_use = 0; + + BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb, + event); + + switch (event) { + case L2CAP_EV_RECV_IFRAME: + switch (l2cap_classify_txseq(chan, txseq)) { + case L2CAP_TXSEQ_EXPECTED: + /* Keep frame for reassembly later */ + l2cap_pass_to_tx(chan, control); + skb_queue_tail(&chan->srej_q, skb); + skb_in_use = 1; + BT_DBG("Queued %p (queue len %d)", skb, + skb_queue_len(&chan->srej_q)); + + chan->expected_tx_seq = __next_seq(chan, txseq); + break; + case L2CAP_TXSEQ_EXPECTED_SREJ: + l2cap_seq_list_pop(&chan->srej_list); - chan->num_acked = (chan->num_acked + 1) % num_to_ack; - if (chan->num_acked == num_to_ack - 1) - l2cap_send_ack(chan); - else - __set_ack_timer(chan); + l2cap_pass_to_tx(chan, control); + skb_queue_tail(&chan->srej_q, skb); + skb_in_use = 1; + BT_DBG("Queued %p (queue len %d)", skb, + skb_queue_len(&chan->srej_q)); - return 0; + err = l2cap_rx_queued_iframes(chan); + if (err) + break; -drop: - kfree_skb(skb); - return 0; -} + break; + case L2CAP_TXSEQ_UNEXPECTED: + /* Got a frame that can't be reassembled yet. + * Save it for later, and send SREJs to cover + * the missing frames. + */ + skb_queue_tail(&chan->srej_q, skb); + skb_in_use = 1; + BT_DBG("Queued %p (queue len %d)", skb, + skb_queue_len(&chan->srej_q)); + + l2cap_pass_to_tx(chan, control); + l2cap_send_srej(chan, control->txseq); + break; + case L2CAP_TXSEQ_UNEXPECTED_SREJ: + /* This frame was requested with an SREJ, but + * some expected retransmitted frames are + * missing. Request retransmission of missing + * SREJ'd frames. + */ + skb_queue_tail(&chan->srej_q, skb); + skb_in_use = 1; + BT_DBG("Queued %p (queue len %d)", skb, + skb_queue_len(&chan->srej_q)); + + l2cap_pass_to_tx(chan, control); + l2cap_send_srej_list(chan, control->txseq); + break; + case L2CAP_TXSEQ_DUPLICATE_SREJ: + /* We've already queued this frame. Drop this copy. */ + l2cap_pass_to_tx(chan, control); + break; + case L2CAP_TXSEQ_DUPLICATE: + /* Expecting a later sequence number, so this frame + * was already received. Ignore it completely. + */ + break; + case L2CAP_TXSEQ_INVALID_IGNORE: + break; + case L2CAP_TXSEQ_INVALID: + default: + l2cap_send_disconn_req(chan->conn, chan, + ECONNRESET); + break; + } + break; + case L2CAP_EV_RECV_RR: + l2cap_pass_to_tx(chan, control); + if (control->final) { + clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); -static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control) -{ - BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, - __get_reqseq(chan, rx_control), rx_control); + if (!test_and_clear_bit(CONN_REJ_ACT, + &chan->conn_state)) { + control->final = 0; + l2cap_retransmit_all(chan, control); + } - chan->expected_ack_seq = __get_reqseq(chan, rx_control); - l2cap_drop_acked_frames(chan); + l2cap_ertm_send(chan); + } else if (control->poll) { + if (test_and_clear_bit(CONN_REMOTE_BUSY, + &chan->conn_state) && + chan->unacked_frames) { + __set_retrans_timer(chan); + } - if (__is_ctrl_poll(chan, rx_control)) { - set_bit(CONN_SEND_FBIT, &chan->conn_state); - if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - (chan->unacked_frames > 0)) + set_bit(CONN_SEND_FBIT, &chan->conn_state); + l2cap_send_srej_tail(chan); + } else { + if (test_and_clear_bit(CONN_REMOTE_BUSY, + &chan->conn_state) && + chan->unacked_frames) __set_retrans_timer(chan); - clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - l2cap_send_srejtail(chan); + l2cap_send_ack(chan); + } + break; + case L2CAP_EV_RECV_RNR: + set_bit(CONN_REMOTE_BUSY, &chan->conn_state); + l2cap_pass_to_tx(chan, control); + if (control->poll) { + l2cap_send_srej_tail(chan); } else { - l2cap_send_i_or_rr_or_rnr(chan); + struct l2cap_ctrl rr_control; + memset(&rr_control, 0, sizeof(rr_control)); + rr_control.sframe = 1; + rr_control.super = L2CAP_SUPER_RR; + rr_control.reqseq = chan->buffer_seq; + l2cap_send_sframe(chan, &rr_control); } - } else if (__is_ctrl_final(chan, rx_control)) { - clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - - if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) - l2cap_retransmit_frames(chan); - - } else { - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - (chan->unacked_frames > 0)) - __set_retrans_timer(chan); + break; + case L2CAP_EV_RECV_REJ: + l2cap_handle_rej(chan, control); + break; + case L2CAP_EV_RECV_SREJ: + l2cap_handle_srej(chan, control); + break; + } - clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) - l2cap_send_ack(chan); - else - l2cap_ertm_send(chan); + if (skb && !skb_in_use) { + BT_DBG("Freeing %p", skb); + kfree_skb(skb); } + + return err; } -static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control) +static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq) { - u16 tx_seq = __get_reqseq(chan, rx_control); + /* Make sure reqseq is for a packet that has been sent but not acked */ + u16 unacked; - BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); - - clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - - chan->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan); - - if (__is_ctrl_final(chan, rx_control)) { - if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state)) - l2cap_retransmit_frames(chan); - } else { - l2cap_retransmit_frames(chan); - - if (test_bit(CONN_WAIT_F, &chan->conn_state)) - set_bit(CONN_REJ_ACT, &chan->conn_state); - } + unacked = __seq_offset(chan, chan->next_tx_seq, chan->expected_ack_seq); + return __seq_offset(chan, chan->next_tx_seq, reqseq) <= unacked; } -static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control) -{ - u16 tx_seq = __get_reqseq(chan, rx_control); - - BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); - clear_bit(CONN_REMOTE_BUSY, &chan->conn_state); - - if (__is_ctrl_poll(chan, rx_control)) { - chan->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan); - - set_bit(CONN_SEND_FBIT, &chan->conn_state); - l2cap_retransmit_one_frame(chan, tx_seq); +static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, + struct sk_buff *skb, u8 event) +{ + int err = 0; - l2cap_ertm_send(chan); + BT_DBG("chan %p, control %p, skb %p, event %d, state %d", chan, + control, skb, event, chan->rx_state); - if (test_bit(CONN_WAIT_F, &chan->conn_state)) { - chan->srej_save_reqseq = tx_seq; - set_bit(CONN_SREJ_ACT, &chan->conn_state); + if (__valid_reqseq(chan, control->reqseq)) { + switch (chan->rx_state) { + case L2CAP_RX_STATE_RECV: + err = l2cap_rx_state_recv(chan, control, skb, event); + break; + case L2CAP_RX_STATE_SREJ_SENT: + err = l2cap_rx_state_srej_sent(chan, control, skb, + event); + break; + default: + /* shut it down */ + break; } - } else if (__is_ctrl_final(chan, rx_control)) { - if (test_bit(CONN_SREJ_ACT, &chan->conn_state) && - chan->srej_save_reqseq == tx_seq) - clear_bit(CONN_SREJ_ACT, &chan->conn_state); - else - l2cap_retransmit_one_frame(chan, tx_seq); } else { - l2cap_retransmit_one_frame(chan, tx_seq); - if (test_bit(CONN_WAIT_F, &chan->conn_state)) { - chan->srej_save_reqseq = tx_seq; - set_bit(CONN_SREJ_ACT, &chan->conn_state); - } + BT_DBG("Invalid reqseq %d (next_tx_seq %d, expected_ack_seq %d", + control->reqseq, chan->next_tx_seq, + chan->expected_ack_seq); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); } + + return err; } -static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control) +static int l2cap_stream_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control, + struct sk_buff *skb) { - u16 tx_seq = __get_reqseq(chan, rx_control); + int err = 0; - BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control); + BT_DBG("chan %p, control %p, skb %p, state %d", chan, control, skb, + chan->rx_state); - set_bit(CONN_REMOTE_BUSY, &chan->conn_state); - chan->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan); + if (l2cap_classify_txseq(chan, control->txseq) == + L2CAP_TXSEQ_EXPECTED) { + l2cap_pass_to_tx(chan, control); - if (__is_ctrl_poll(chan, rx_control)) - set_bit(CONN_SEND_FBIT, &chan->conn_state); + BT_DBG("buffer_seq %d->%d", chan->buffer_seq, + __next_seq(chan, chan->buffer_seq)); - if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - __clear_retrans_timer(chan); - if (__is_ctrl_poll(chan, rx_control)) - l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); - return; - } + chan->buffer_seq = __next_seq(chan, chan->buffer_seq); - if (__is_ctrl_poll(chan, rx_control)) { - l2cap_send_srejtail(chan); + l2cap_reassemble_sdu(chan, skb, control); } else { - rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR); - l2cap_send_sframe(chan, rx_control); - } -} - -static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb) -{ - BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len); + if (chan->sdu) { + kfree_skb(chan->sdu); + chan->sdu = NULL; + } + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; - if (__is_ctrl_final(chan, rx_control) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - __clear_monitor_timer(chan); - if (chan->unacked_frames > 0) - __set_retrans_timer(chan); - clear_bit(CONN_WAIT_F, &chan->conn_state); + if (skb) { + BT_DBG("Freeing %p", skb); + kfree_skb(skb); + } } - switch (__get_ctrl_super(chan, rx_control)) { - case L2CAP_SUPER_RR: - l2cap_data_channel_rrframe(chan, rx_control); - break; - - case L2CAP_SUPER_REJ: - l2cap_data_channel_rejframe(chan, rx_control); - break; - - case L2CAP_SUPER_SREJ: - l2cap_data_channel_srejframe(chan, rx_control); - break; - - case L2CAP_SUPER_RNR: - l2cap_data_channel_rnrframe(chan, rx_control); - break; - } + chan->last_acked_seq = control->txseq; + chan->expected_tx_seq = __next_seq(chan, control->txseq); - kfree_skb(skb); - return 0; + return err; } -static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) +static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) { - u32 control; - u16 req_seq; - int len, next_tx_seq_offset, req_seq_offset; + struct l2cap_ctrl *control = &bt_cb(skb)->control; + u16 len; + u8 event; __unpack_control(chan, skb); - control = __get_control(chan, skb->data); - skb_pull(skb, __ctrl_size(chan)); len = skb->len; /* * We can just drop the corrupted I-frame here. * Receiver will miss it and start proper recovery - * procedures and ask retransmission. + * procedures and ask for retransmission. */ if (l2cap_check_fcs(chan, skb)) goto drop; - if (__is_sar_start(chan, control) && !__is_sframe(chan, control)) + if (!control->sframe && control->sar == L2CAP_SAR_START) len -= L2CAP_SDULEN_SIZE; if (chan->fcs == L2CAP_FCS_CRC16) @@ -4578,34 +5071,57 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) goto drop; } - req_seq = __get_reqseq(chan, control); - - req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq); + if (!control->sframe) { + int err; - next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq, - chan->expected_ack_seq); + BT_DBG("iframe sar %d, reqseq %d, final %d, txseq %d", + control->sar, control->reqseq, control->final, + control->txseq); - /* check for invalid req-seq */ - if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - goto drop; - } - - if (!__is_sframe(chan, control)) { - if (len < 0) { - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); + /* Validate F-bit - F=0 always valid, F=1 only + * valid in TX WAIT_F + */ + if (control->final && chan->tx_state != L2CAP_TX_STATE_WAIT_F) goto drop; + + if (chan->mode != L2CAP_MODE_STREAMING) { + event = L2CAP_EV_RECV_IFRAME; + err = l2cap_rx(chan, control, skb, event); + } else { + err = l2cap_stream_rx(chan, control, skb); } - l2cap_data_channel_iframe(chan, control, skb); + if (err) + l2cap_send_disconn_req(chan->conn, chan, + ECONNRESET); } else { + const u8 rx_func_to_event[4] = { + L2CAP_EV_RECV_RR, L2CAP_EV_RECV_REJ, + L2CAP_EV_RECV_RNR, L2CAP_EV_RECV_SREJ + }; + + /* Only I-frames are expected in streaming mode */ + if (chan->mode == L2CAP_MODE_STREAMING) + goto drop; + + BT_DBG("sframe reqseq %d, final %d, poll %d, super %d", + control->reqseq, control->final, control->poll, + control->super); + if (len != 0) { BT_ERR("%d", len); l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } - l2cap_data_channel_sframe(chan, control, skb); + /* Validate F and P bits */ + if (control->final && (control->poll || + chan->tx_state != L2CAP_TX_STATE_WAIT_F)) + goto drop; + + event = rx_func_to_event[control->super]; + if (l2cap_rx(chan, control, skb, event)) + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); } return 0; @@ -4615,19 +5131,27 @@ drop: return 0; } -static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) +static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid, + struct sk_buff *skb) { struct l2cap_chan *chan; - u32 control; - u16 tx_seq; - int len; chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { - BT_DBG("unknown cid 0x%4.4x", cid); - /* Drop packet and return */ - kfree_skb(skb); - return 0; + if (cid == L2CAP_CID_A2MP) { + chan = a2mp_channel_create(conn, skb); + if (!chan) { + kfree_skb(skb); + return; + } + + l2cap_chan_lock(chan); + } else { + BT_DBG("unknown cid 0x%4.4x", cid); + /* Drop packet and return */ + kfree_skb(skb); + return; + } } BT_DBG("chan %p, len %d", chan, skb->len); @@ -4645,49 +5169,13 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (chan->imtu < skb->len) goto drop; - if (!chan->ops->recv(chan->data, skb)) + if (!chan->ops->recv(chan, skb)) goto done; break; case L2CAP_MODE_ERTM: - l2cap_ertm_data_rcv(chan, skb); - - goto done; - case L2CAP_MODE_STREAMING: - control = __get_control(chan, skb->data); - skb_pull(skb, __ctrl_size(chan)); - len = skb->len; - - if (l2cap_check_fcs(chan, skb)) - goto drop; - - if (__is_sar_start(chan, control)) - len -= L2CAP_SDULEN_SIZE; - - if (chan->fcs == L2CAP_FCS_CRC16) - len -= L2CAP_FCS_SIZE; - - if (len > chan->mps || len < 0 || __is_sframe(chan, control)) - goto drop; - - tx_seq = __get_txseq(chan, control); - - if (chan->expected_tx_seq != tx_seq) { - /* Frame(s) missing - must discard partial SDU */ - kfree_skb(chan->sdu); - chan->sdu = NULL; - chan->sdu_last_frag = NULL; - chan->sdu_len = 0; - - /* TODO: Notify userland of missing data */ - } - - chan->expected_tx_seq = __next_seq(chan, tx_seq); - - if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE) - l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); - + l2cap_data_rcv(chan, skb); goto done; default: @@ -4700,11 +5188,10 @@ drop: done: l2cap_chan_unlock(chan); - - return 0; } -static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) +static void l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, + struct sk_buff *skb) { struct l2cap_chan *chan; @@ -4720,17 +5207,15 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str if (chan->imtu < skb->len) goto drop; - if (!chan->ops->recv(chan->data, skb)) - return 0; + if (!chan->ops->recv(chan, skb)) + return; drop: kfree_skb(skb); - - return 0; } -static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, - struct sk_buff *skb) +static void l2cap_att_channel(struct l2cap_conn *conn, u16 cid, + struct sk_buff *skb) { struct l2cap_chan *chan; @@ -4746,13 +5231,11 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, if (chan->imtu < skb->len) goto drop; - if (!chan->ops->recv(chan->data, skb)) - return 0; + if (!chan->ops->recv(chan, skb)) + return; drop: kfree_skb(skb); - - return 0; } static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) @@ -4780,7 +5263,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) case L2CAP_CID_CONN_LESS: psm = get_unaligned((__le16 *) skb->data); - skb_pull(skb, 2); + skb_pull(skb, L2CAP_PSMLEN_SIZE); l2cap_conless_channel(conn, psm, skb); break; @@ -4974,6 +5457,17 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) rsp.status = cpu_to_le16(stat); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (!test_bit(CONF_REQ_SENT, &chan->conf_state) && + res == L2CAP_CR_SUCCESS) { + char buf[128]; + set_bit(CONF_REQ_SENT, &chan->conf_state); + l2cap_send_cmd(conn, l2cap_get_ident(conn), + L2CAP_CONF_REQ, + l2cap_build_conf_req(chan, buf), + buf); + chan->num_conf_req++; + } } l2cap_chan_unlock(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 3bb1611b9d48..a4bb27e8427e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -27,7 +27,6 @@ /* Bluetooth L2CAP sockets. */ -#include <linux/security.h> #include <linux/export.h> #include <net/bluetooth/bluetooth.h> @@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (err < 0) goto done; - if (__le16_to_cpu(la.l2_psm) == 0x0001 || - __le16_to_cpu(la.l2_psm) == 0x0003) + if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP || + __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM) chan->sec_level = BT_SECURITY_SDP; bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); @@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch return err; } +static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu) +{ + switch (chan->scid) { + case L2CAP_CID_LE_DATA: + if (mtu < L2CAP_LE_MIN_MTU) + return false; + break; + + default: + if (mtu < L2CAP_DEFAULT_MIN_MTU) + return false; + } + + return true; +} + static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; @@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } + if (!l2cap_valid_mtu(chan, opts.imtu)) { + err = -EINVAL; + break; + } + chan->mode = opts.mode; switch (chan->mode) { case L2CAP_MODE_BASIC: @@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock) return err; } -static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) +static void l2cap_sock_cleanup_listen(struct sock *parent) { - struct sock *sk, *parent = data; + struct sock *sk; + + BT_DBG("parent %p", parent); + + /* Close not yet accepted channels */ + while ((sk = bt_accept_dequeue(parent, NULL))) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + l2cap_chan_lock(chan); + __clear_chan_timer(chan); + l2cap_chan_close(chan, ECONNRESET); + l2cap_chan_unlock(chan); + + l2cap_sock_kill(sk); + } +} + +static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan) +{ + struct sock *sk, *parent = chan->data; + + /* Check for backlog size */ + if (sk_acceptq_is_full(parent)) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); + return NULL; + } sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP, GFP_ATOMIC); @@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data) return l2cap_pi(sk)->chan; } -static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb) +static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb) { int err; - struct sock *sk = data; + struct sock *sk = chan->data; struct l2cap_pinfo *pi = l2cap_pi(sk); lock_sock(sk); @@ -925,16 +970,57 @@ done: return err; } -static void l2cap_sock_close_cb(void *data) +static void l2cap_sock_close_cb(struct l2cap_chan *chan) { - struct sock *sk = data; + struct sock *sk = chan->data; l2cap_sock_kill(sk); } -static void l2cap_sock_state_change_cb(void *data, int state) +static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err) { - struct sock *sk = data; + struct sock *sk = chan->data; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; + + sock_set_flag(sk, SOCK_ZAPPED); + + switch (chan->state) { + case BT_OPEN: + case BT_BOUND: + case BT_CLOSED: + break; + case BT_LISTEN: + l2cap_sock_cleanup_listen(sk); + sk->sk_state = BT_CLOSED; + chan->state = BT_CLOSED; + + break; + default: + sk->sk_state = BT_CLOSED; + chan->state = BT_CLOSED; + + sk->sk_err = err; + + if (parent) { + bt_accept_unlink(sk); + parent->sk_data_ready(parent, 0); + } else { + sk->sk_state_change(sk); + } + + break; + } + + release_sock(sk); +} + +static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state) +{ + struct sock *sk = chan->data; sk->sk_state = state; } @@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, return skb; } +static void l2cap_sock_ready_cb(struct l2cap_chan *chan) +{ + struct sock *sk = chan->data; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; + + BT_DBG("sk %p, parent %p", sk, parent); + + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + + if (parent) + parent->sk_data_ready(parent, 0); + + release_sock(sk); +} + static struct l2cap_ops l2cap_chan_ops = { .name = "L2CAP Socket Interface", .new_connection = l2cap_sock_new_connection_cb, .recv = l2cap_sock_recv_cb, .close = l2cap_sock_close_cb, + .teardown = l2cap_sock_teardown_cb, .state_change = l2cap_sock_state_change_cb, + .ready = l2cap_sock_ready_cb, .alloc_skb = l2cap_sock_alloc_skb_cb, }; diff --git a/net/bluetooth/lib.c b/net/bluetooth/lib.c index 506628876f36..e1c97527e16c 100644 --- a/net/bluetooth/lib.c +++ b/net/bluetooth/lib.c @@ -26,12 +26,7 @@ #define pr_fmt(fmt) "Bluetooth: " fmt -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/stddef.h> -#include <linux/string.h> -#include <asm/errno.h> +#include <linux/export.h> #include <net/bluetooth/bluetooth.h> diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 25d220776079..a6e0f3d8da6c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -24,8 +24,6 @@ /* Bluetooth HCI Management interface */ -#include <linux/kernel.h> -#include <linux/uaccess.h> #include <linux/module.h> #include <asm/unaligned.h> @@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, } static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev, - void (*cb)(struct pending_cmd *cmd, void *data), + void (*cb)(struct pending_cmd *cmd, + void *data), void *data) { struct list_head *p, *n; @@ -871,7 +870,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || - mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { + mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_BUSY); goto failed; @@ -978,7 +977,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, } if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) || - mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { + mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE, MGMT_STATUS_BUSY); goto failed; @@ -1001,7 +1000,7 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data, scan = 0; if (test_bit(HCI_ISCAN, &hdev->flags) && - hdev->discov_timeout > 0) + hdev->discov_timeout > 0) cancel_delayed_work(&hdev->discov_off); } @@ -1056,7 +1055,7 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data, bool changed = false; if (!!cp->val != test_bit(HCI_LINK_SECURITY, - &hdev->dev_flags)) { + &hdev->dev_flags)) { change_bit(HCI_LINK_SECURITY, &hdev->dev_flags); changed = true; } @@ -1317,7 +1316,7 @@ static bool enable_service_cache(struct hci_dev *hdev) } static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_remove_uuid *cp = data; struct pending_cmd *cmd; @@ -1442,7 +1441,7 @@ unlock: } static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, - u16 len) + u16 len) { struct mgmt_cp_load_link_keys *cp = data; u16 key_count, expected_len; @@ -1454,13 +1453,13 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, sizeof(struct mgmt_link_key_info); if (expected_len != len) { BT_ERR("load_link_keys: expected %u bytes, got %u bytes", - len, expected_len); + len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, MGMT_STATUS_INVALID_PARAMS); } BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys, - key_count); + key_count); hci_dev_lock(hdev); @@ -1535,10 +1534,10 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, if (cp->disconnect) { if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, - &cp->addr.bdaddr); + &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, - &cp->addr.bdaddr); + &cp->addr.bdaddr); } else { conn = NULL; } @@ -1594,11 +1593,12 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, } if (cp->addr.type == BDADDR_BREDR) - conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, + &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); - if (!conn) { + if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) { err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT, MGMT_STATUS_NOT_CONNECTED); goto failed; @@ -1813,7 +1813,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, - hdev->io_capability); + hdev->io_capability); hci_dev_unlock(hdev); @@ -1821,7 +1821,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, 0); } -static inline struct pending_cmd *find_pairing(struct hci_conn *conn) +static struct pending_cmd *find_pairing(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; struct pending_cmd *cmd; @@ -1873,6 +1873,22 @@ static void pairing_complete_cb(struct hci_conn *conn, u8 status) pairing_complete(cmd, mgmt_status(status)); } +static void le_connect_complete_cb(struct hci_conn *conn, u8 status) +{ + struct pending_cmd *cmd; + + BT_DBG("status %u", status); + + if (!status) + return; + + cmd = find_pairing(conn); + if (!cmd) + BT_DBG("Unable to find a pending command"); + else + pairing_complete(cmd, mgmt_status(status)); +} + static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -1911,8 +1927,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, rp.addr.type = cp->addr.type; if (IS_ERR(conn)) { + int status; + + if (PTR_ERR(conn) == -EBUSY) + status = MGMT_STATUS_BUSY; + else + status = MGMT_STATUS_CONNECT_FAILED; + err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE, - MGMT_STATUS_CONNECT_FAILED, &rp, + status, &rp, sizeof(rp)); goto unlock; } @@ -1934,6 +1957,8 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, /* For LE, just connecting isn't a proof that the pairing finished */ if (cp->addr.type == BDADDR_BREDR) conn->connect_cfm_cb = pairing_complete_cb; + else + conn->connect_cfm_cb = le_connect_complete_cb; conn->security_cfm_cb = pairing_complete_cb; conn->disconn_cfm_cb = pairing_complete_cb; @@ -1941,7 +1966,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, cmd->user_data = conn; if (conn->state == BT_CONNECTED && - hci_conn_security(conn, sec_level, auth_type)) + hci_conn_security(conn, sec_level, auth_type)) pairing_complete(cmd, 0); err = 0; @@ -2238,7 +2263,7 @@ unlock: } static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) + void *data, u16 len) { struct mgmt_cp_remove_remote_oob_data *cp = data; u8 status; @@ -2407,7 +2432,7 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, case DISCOVERY_RESOLVING: e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, - NAME_PENDING); + NAME_PENDING); if (!e) { mgmt_pending_remove(cmd); err = cmd_complete(sk, hdev->id, @@ -2629,7 +2654,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, sizeof(struct mgmt_ltk_info); if (expected_len != len) { BT_ERR("load_keys: expected %u bytes, got %u bytes", - len, expected_len); + len, expected_len); return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, EINVAL); } @@ -2754,7 +2779,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if (opcode >= ARRAY_SIZE(mgmt_handlers) || - mgmt_handlers[opcode].func == NULL) { + mgmt_handlers[opcode].func == NULL) { BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, MGMT_STATUS_UNKNOWN_COMMAND); @@ -2762,7 +2787,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } if ((hdev && opcode < MGMT_OP_READ_INFO) || - (!hdev && opcode >= MGMT_OP_READ_INFO)) { + (!hdev && opcode >= MGMT_OP_READ_INFO)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_INDEX); goto done; @@ -2771,7 +2796,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) handler = &mgmt_handlers[opcode]; if ((handler->var_len && len < handler->data_len) || - (!handler->var_len && len != handler->data_len)) { + (!handler->var_len && len != handler->data_len)) { err = cmd_status(sk, index, opcode, MGMT_STATUS_INVALID_PARAMS); goto done; @@ -2955,7 +2980,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bacpy(&ev.key.addr.bdaddr, &key->bdaddr); ev.key.addr.type = BDADDR_BREDR; ev.key.type = key->type; - memcpy(ev.key.val, key->val, 16); + memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE); ev.key.pin_len = key->pin_len; return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL); @@ -3090,7 +3115,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, mgmt_pending_remove(cmd); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, - hdev); + hdev); return err; } @@ -3180,7 +3205,7 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, } int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type) + u8 link_type, u8 addr_type) { struct mgmt_ev_user_passkey_request ev; @@ -3194,8 +3219,8 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, } static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, - u8 link_type, u8 addr_type, u8 status, - u8 opcode) + u8 link_type, u8 addr_type, u8 status, + u8 opcode) { struct pending_cmd *cmd; struct mgmt_rp_user_confirm_reply rp; @@ -3226,7 +3251,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_CONFIRM_NEG_REPLY); + status, + MGMT_OP_USER_CONFIRM_NEG_REPLY); } int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, @@ -3240,7 +3266,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u8 addr_type, u8 status) { return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type, - status, MGMT_OP_USER_PASSKEY_NEG_REPLY); + status, + MGMT_OP_USER_PASSKEY_NEG_REPLY); } int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 8a602388f1e7..c75107ef8920 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -26,22 +26,8 @@ */ #include <linux/module.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/signal.h> -#include <linux/init.h> -#include <linux/wait.h> -#include <linux/device.h> #include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/net.h> -#include <linux/mutex.h> #include <linux/kthread.h> -#include <linux/slab.h> - -#include <net/sock.h> -#include <linux/uaccess.h> #include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> @@ -115,14 +101,14 @@ static void rfcomm_session_del(struct rfcomm_session *s); #define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1) #define __get_rpn_parity(line) (((line) >> 3) & 0x7) -static inline void rfcomm_schedule(void) +static void rfcomm_schedule(void) { if (!rfcomm_thread) return; wake_up_process(rfcomm_thread); } -static inline void rfcomm_session_put(struct rfcomm_session *s) +static void rfcomm_session_put(struct rfcomm_session *s) { if (atomic_dec_and_test(&s->refcnt)) rfcomm_session_del(s); @@ -227,7 +213,7 @@ static int rfcomm_l2sock_create(struct socket **sock) return err; } -static inline int rfcomm_check_security(struct rfcomm_dlc *d) +static int rfcomm_check_security(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; @@ -1750,7 +1736,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s) /* Send data queued for the DLC. * Return number of frames left in the queue. */ -static inline int rfcomm_process_tx(struct rfcomm_dlc *d) +static int rfcomm_process_tx(struct rfcomm_dlc *d) { struct sk_buff *skb; int err; @@ -1798,7 +1784,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d) return skb_queue_len(&d->tx_queue); } -static inline void rfcomm_process_dlcs(struct rfcomm_session *s) +static void rfcomm_process_dlcs(struct rfcomm_session *s) { struct rfcomm_dlc *d; struct list_head *p, *n; @@ -1858,7 +1844,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s) } } -static inline void rfcomm_process_rx(struct rfcomm_session *s) +static void rfcomm_process_rx(struct rfcomm_session *s) { struct socket *sock = s->sock; struct sock *sk = sock->sk; @@ -1883,7 +1869,7 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s) } } -static inline void rfcomm_accept_connection(struct rfcomm_session *s) +static void rfcomm_accept_connection(struct rfcomm_session *s) { struct socket *sock = s->sock, *nsock; int err; @@ -1917,7 +1903,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) sock_release(nsock); } -static inline void rfcomm_check_connection(struct rfcomm_session *s) +static void rfcomm_check_connection(struct rfcomm_session *s) { struct sock *sk = s->sock->sk; @@ -1941,7 +1927,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) } } -static inline void rfcomm_process_sessions(void) +static void rfcomm_process_sessions(void) { struct list_head *p, *n; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index e8707debb864..7e1e59645c05 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -25,27 +25,8 @@ * RFCOMM sockets. */ -#include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/socket.h> -#include <linux/skbuff.h> -#include <linux/list.h> -#include <linux/device.h> +#include <linux/export.h> #include <linux/debugfs.h> -#include <linux/seq_file.h> -#include <linux/security.h> -#include <net/sock.h> - -#include <linux/uaccess.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d1820ff14aee..cb960773c002 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -31,11 +31,6 @@ #include <linux/tty_driver.h> #include <linux/tty_flip.h> -#include <linux/capability.h> -#include <linux/slab.h> -#include <linux/skbuff.h> -#include <linux/workqueue.h> - #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/rfcomm.h> @@ -132,7 +127,7 @@ static struct rfcomm_dev *__rfcomm_dev_get(int id) return NULL; } -static inline struct rfcomm_dev *rfcomm_dev_get(int id) +static struct rfcomm_dev *rfcomm_dev_get(int id) { struct rfcomm_dev *dev; @@ -345,7 +340,7 @@ static void rfcomm_wfree(struct sk_buff *skb) tty_port_put(&dev->port); } -static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) +static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev) { tty_port_get(&dev->port); atomic_add(skb->truesize, &dev->wmem_alloc); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index cbdd313659a7..40bbe25dcff7 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -25,26 +25,8 @@ /* Bluetooth SCO sockets. */ #include <linux/module.h> - -#include <linux/types.h> -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/poll.h> -#include <linux/fcntl.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/socket.h> -#include <linux/skbuff.h> -#include <linux/device.h> #include <linux/debugfs.h> #include <linux/seq_file.h> -#include <linux/list.h> -#include <linux/security.h> -#include <net/sock.h> - -#include <linux/uaccess.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> @@ -123,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon) return conn; } -static inline struct sock *sco_chan_get(struct sco_conn *conn) +static struct sock *sco_chan_get(struct sco_conn *conn) { struct sock *sk = NULL; sco_conn_lock(conn); @@ -157,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err) return 0; } -static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent) +static int sco_chan_add(struct sco_conn *conn, struct sock *sk, + struct sock *parent) { int err = 0; @@ -228,7 +211,7 @@ done: return err; } -static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) +static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) { struct sco_conn *conn = sco_pi(sk)->conn; struct sk_buff *skb; @@ -254,7 +237,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) return len; } -static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) +static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) { struct sock *sk = sco_chan_get(conn); @@ -523,7 +506,7 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen goto done; err = bt_sock_wait_state(sk, BT_CONNECTED, - sock_sndtimeo(sk, flags & O_NONBLOCK)); + sock_sndtimeo(sk, flags & O_NONBLOCK)); done: release_sock(sk); @@ -788,7 +771,7 @@ static int sco_sock_shutdown(struct socket *sock, int how) if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime) err = bt_sock_wait_state(sk, BT_CLOSED, - sk->sk_lingertime); + sk->sk_lingertime); } release_sock(sk); return err; @@ -878,7 +861,7 @@ static void sco_conn_ready(struct sco_conn *conn) bh_lock_sock(parent); sk = sco_sock_alloc(sock_net(parent), NULL, - BTPROTO_SCO, GFP_ATOMIC); + BTPROTO_SCO, GFP_ATOMIC); if (!sk) { bh_unlock_sock(parent); goto done; @@ -907,7 +890,7 @@ done: /* ----- SCO interface with lower layer (HCI) ----- */ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) { - register struct sock *sk; + struct sock *sk; struct hlist_node *node; int lm = 0; @@ -920,7 +903,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) || - !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { + !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm |= HCI_LM_ACCEPT; break; } @@ -981,7 +964,7 @@ static int sco_debugfs_show(struct seq_file *f, void *p) sk_for_each(sk, node, &sco_sk_list.head) { seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src), - batostr(&bt_sk(sk)->dst), sk->sk_state); + batostr(&bt_sk(sk)->dst), sk->sk_state); } read_unlock(&sco_sk_list.lock); @@ -1044,8 +1027,8 @@ int __init sco_init(void) } if (bt_debugfs) { - sco_debugfs = debugfs_create_file("sco", 0444, - bt_debugfs, NULL, &sco_debugfs_fops); + sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs, + NULL, &sco_debugfs_fops); if (!sco_debugfs) BT_ERR("Failed to create SCO debug file"); } diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index 6fc7c4708f3e..16ef0dc85a0a 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -20,14 +20,15 @@ SOFTWARE IS DISCLAIMED. */ +#include <linux/crypto.h> +#include <linux/scatterlist.h> +#include <crypto/b128ops.h> + #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include <net/bluetooth/l2cap.h> #include <net/bluetooth/mgmt.h> #include <net/bluetooth/smp.h> -#include <linux/crypto.h> -#include <linux/scatterlist.h> -#include <crypto/b128ops.h> #define SMP_TIMEOUT msecs_to_jiffies(30000) @@ -648,7 +649,7 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb) auth |= (req->auth_req | rsp->auth_req) & SMP_AUTH_MITM; - ret = tk_request(conn, 0, auth, rsp->io_capability, req->io_capability); + ret = tk_request(conn, 0, auth, req->io_capability, rsp->io_capability); if (ret) return SMP_UNSPECIFIED; @@ -703,7 +704,7 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb) return 0; } -static u8 smp_ltk_encrypt(struct l2cap_conn *conn) +static u8 smp_ltk_encrypt(struct l2cap_conn *conn, u8 sec_level) { struct smp_ltk *key; struct hci_conn *hcon = conn->hcon; @@ -712,6 +713,9 @@ static u8 smp_ltk_encrypt(struct l2cap_conn *conn) if (!key) return 0; + if (sec_level > BT_SECURITY_MEDIUM && !key->authenticated) + return 0; + if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->flags)) return 1; @@ -732,7 +736,7 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb) hcon->pending_sec_level = authreq_to_seclevel(rp->auth_req); - if (smp_ltk_encrypt(conn)) + if (smp_ltk_encrypt(conn, hcon->pending_sec_level)) return 0; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) @@ -771,7 +775,7 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level) return 1; if (hcon->link_mode & HCI_LM_MASTER) - if (smp_ltk_encrypt(conn)) + if (smp_ltk_encrypt(conn, sec_level)) goto done; if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->flags)) diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 8d249d705980..63af25458fda 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -107,6 +107,19 @@ config MAC80211_DEBUGFS Say N unless you know you need this. +config MAC80211_MESSAGE_TRACING + bool "Trace all mac80211 debug messages" + depends on MAC80211 + ---help--- + Select this option to have mac80211 register the + mac80211_msg trace subsystem with tracepoints to + collect all debugging messages, independent of + printing them into the kernel log. + + The overhead in this option is that all the messages + need to be present in the binary and formatted at + runtime for tracing. + menuconfig MAC80211_DEBUG_MENU bool "Select mac80211 debugging features" depends on MAC80211 @@ -140,26 +153,35 @@ config MAC80211_VERBOSE_DEBUG Do not select this option. -config MAC80211_HT_DEBUG - bool "Verbose HT debugging" +config MAC80211_MLME_DEBUG + bool "Verbose managed MLME output" depends on MAC80211_DEBUG_MENU ---help--- - This option enables 802.11n High Throughput features - debug tracing output. - - It should not be selected on production systems as some + Selecting this option causes mac80211 to print out + debugging messages for the managed-mode MLME. It + should not be selected on production systems as some of the messages are remotely triggerable. Do not select this option. -config MAC80211_TKIP_DEBUG - bool "Verbose TKIP debugging" +config MAC80211_STA_DEBUG + bool "Verbose station debugging" depends on MAC80211_DEBUG_MENU ---help--- Selecting this option causes mac80211 to print out - very verbose TKIP debugging messages. It should not - be selected on production systems as those messages - are remotely triggerable. + debugging messages for station addition/removal. + + Do not select this option. + +config MAC80211_HT_DEBUG + bool "Verbose HT debugging" + depends on MAC80211_DEBUG_MENU + ---help--- + This option enables 802.11n High Throughput features + debug tracing output. + + It should not be selected on production systems as some + of the messages are remotely triggerable. Do not select this option. @@ -174,7 +196,7 @@ config MAC80211_IBSS_DEBUG Do not select this option. -config MAC80211_VERBOSE_PS_DEBUG +config MAC80211_PS_DEBUG bool "Verbose powersave mode debugging" depends on MAC80211_DEBUG_MENU ---help--- @@ -186,7 +208,7 @@ config MAC80211_VERBOSE_PS_DEBUG Do not select this option. -config MAC80211_VERBOSE_MPL_DEBUG +config MAC80211_MPL_DEBUG bool "Verbose mesh peer link debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -199,7 +221,7 @@ config MAC80211_VERBOSE_MPL_DEBUG Do not select this option. -config MAC80211_VERBOSE_MPATH_DEBUG +config MAC80211_MPATH_DEBUG bool "Verbose mesh path debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -212,7 +234,7 @@ config MAC80211_VERBOSE_MPATH_DEBUG Do not select this option. -config MAC80211_VERBOSE_MHWMP_DEBUG +config MAC80211_MHWMP_DEBUG bool "Verbose mesh HWMP routing debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -225,7 +247,7 @@ config MAC80211_VERBOSE_MHWMP_DEBUG Do not select this option. -config MAC80211_VERBOSE_MESH_SYNC_DEBUG +config MAC80211_MESH_SYNC_DEBUG bool "Verbose mesh mesh synchronization debugging" depends on MAC80211_DEBUG_MENU depends on MAC80211_MESH @@ -236,7 +258,7 @@ config MAC80211_VERBOSE_MESH_SYNC_DEBUG Do not select this option. -config MAC80211_VERBOSE_TDLS_DEBUG +config MAC80211_TDLS_DEBUG bool "Verbose TDLS debugging" depends on MAC80211_DEBUG_MENU ---help--- diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 2b1470bac178..a7dd110faafa 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -24,7 +24,7 @@ mac80211-y := \ wme.o \ event.o \ chan.o \ - driver-trace.o mlme.o + trace.o mlme.o mac80211-$(CONFIG_MAC80211_LEDS) += led.o mac80211-$(CONFIG_MAC80211_DEBUGFS) += \ @@ -42,7 +42,7 @@ mac80211-$(CONFIG_MAC80211_MESH) += \ mac80211-$(CONFIG_PM) += pm.o -CFLAGS_driver-trace.o := -I$(src) +CFLAGS_trace.o := -I$(src) # objects for PID algorithm rc80211_pid-y := rc80211_pid_algo.o @@ -58,4 +58,4 @@ mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL_HT) += $(rc80211_minstrel_ht-y) -ccflags-y += -D__CHECK_ENDIAN__ +ccflags-y += -D__CHECK_ENDIAN__ -DDEBUG diff --git a/net/mac80211/agg-rx.c b/net/mac80211/agg-rx.c index 32ef11d69798..186d9919b043 100644 --- a/net/mac80211/agg-rx.c +++ b/net/mac80211/agg-rx.c @@ -74,15 +74,17 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); - ht_vdbg("Rx BA session stop requested for %pM tid %u %s reason: %d\n", - sta->sta.addr, tid, - initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", - (int)reason); + ht_dbg(sta->sdata, + "Rx BA session stop requested for %pM tid %u %s reason: %d\n", + sta->sta.addr, tid, + initiator == WLAN_BACK_RECIPIENT ? "recipient" : "inititator", + (int)reason); if (drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_STOP, &sta->sta, tid, NULL, 0)) - pr_debug("HW problem - can not stop rx aggregation for tid %d\n", - tid); + sdata_info(sta->sdata, + "HW problem - can not stop rx aggregation for tid %d\n", + tid); /* check if this is a self generated aggregation halt */ if (initiator == WLAN_BACK_RECIPIENT && tx) @@ -157,7 +159,7 @@ static void sta_rx_agg_session_timer_expired(unsigned long data) } rcu_read_unlock(); - ht_vdbg("rx session timer expired on tid %d\n", (u16)*ptid); + ht_dbg(sta->sdata, "rx session timer expired on tid %d\n", (u16)*ptid); set_bit(*ptid, sta->ampdu_mlme.tid_rx_timer_expired); ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work); @@ -245,7 +247,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, status = WLAN_STATUS_REQUEST_DECLINED; if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { - ht_vdbg("Suspend in progress - Denying ADDBA request\n"); + ht_dbg(sta->sdata, "Suspend in progress - Denying ADDBA request\n"); goto end_no_lock; } @@ -257,10 +259,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { status = WLAN_STATUS_INVALID_QOS_PARAM; -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", - mgmt->sa, tid, ba_policy, buf_size); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sta->sdata, + "AddBA Req with bad params from %pM on tid %u. policy %d, buffer size %d\n", + mgmt->sa, tid, ba_policy, buf_size); goto end_no_lock; } /* determine default buffer size */ @@ -275,10 +276,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, mutex_lock(&sta->ampdu_mlme.mtx); if (sta->ampdu_mlme.tid_rx[tid]) { -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("unexpected AddBA Req from %pM on tid %u\n", - mgmt->sa, tid); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sta->sdata, + "unexpected AddBA Req from %pM on tid %u\n", + mgmt->sa, tid); /* delete existing Rx BA session on the same tid */ ___ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_RECIPIENT, @@ -317,7 +317,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, ret = drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_RX_START, &sta->sta, tid, &start_seq_num, 0); - ht_vdbg("Rx A-MPDU request on tid %d result %d\n", tid, ret); + ht_dbg(sta->sdata, "Rx A-MPDU request on tid %d result %d\n", tid, ret); if (ret) { kfree(tid_agg_rx->reorder_buf); kfree(tid_agg_rx->reorder_time); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index da07f01cfe4d..d0deb3edae21 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -135,7 +135,8 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) bar->control = cpu_to_le16(bar_control); bar->start_seq_num = cpu_to_le16(ssn); - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_REQ_TX_STATUS; ieee80211_tx_skb_tid(sdata, skb, tid); } EXPORT_SYMBOL(ieee80211_send_bar); @@ -184,8 +185,8 @@ int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, spin_unlock_bh(&sta->lock); - ht_vdbg("Tx BA session stop requested for %pM tid %u\n", - sta->sta.addr, tid); + ht_dbg(sta->sdata, "Tx BA session stop requested for %pM tid %u\n", + sta->sta.addr, tid); del_timer_sync(&tid_tx->addba_resp_timer); del_timer_sync(&tid_tx->session_timer); @@ -251,12 +252,13 @@ static void sta_addba_resp_timer_expired(unsigned long data) if (!tid_tx || test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state)) { rcu_read_unlock(); - ht_vdbg("timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", - tid); + ht_dbg(sta->sdata, + "timer expired on tid %d but we are not (or no longer) expecting addBA response there\n", + tid); return; } - ht_vdbg("addBA response timer expired on tid %d\n", tid); + ht_dbg(sta->sdata, "addBA response timer expired on tid %d\n", tid); ieee80211_stop_tx_ba_session(&sta->sta, tid); rcu_read_unlock(); @@ -316,8 +318,9 @@ ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata, ieee80211_stop_queue_agg(sdata, tid); - if (WARN(!tid_tx, "TID %d gone but expected when splicing aggregates" - " from the pending queue\n", tid)) + if (WARN(!tid_tx, + "TID %d gone but expected when splicing aggregates from the pending queue\n", + tid)) return; if (!skb_queue_empty(&tid_tx->pending)) { @@ -365,7 +368,8 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) ret = drv_ampdu_action(local, sdata, IEEE80211_AMPDU_TX_START, &sta->sta, tid, &start_seq_num, 0); if (ret) { - ht_vdbg("BA request denied - HW unavailable for tid %d\n", tid); + ht_dbg(sdata, + "BA request denied - HW unavailable for tid %d\n", tid); spin_lock_bh(&sta->lock); ieee80211_agg_splice_packets(sdata, tid_tx, tid); ieee80211_assign_tid_tx(sta, tid, NULL); @@ -378,7 +382,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid) /* activate the timer for the recipient's addBA response */ mod_timer(&tid_tx->addba_resp_timer, jiffies + ADDBA_RESP_INTERVAL); - ht_vdbg("activated addBA response timer on tid %d\n", tid); + ht_dbg(sdata, "activated addBA response timer on tid %d\n", tid); spin_lock_bh(&sta->lock); sta->ampdu_mlme.last_addba_req_time[tid] = jiffies; @@ -425,7 +429,7 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) rcu_read_unlock(); - ht_vdbg("tx session timer expired on tid %d\n", (u16)*ptid); + ht_dbg(sta->sdata, "tx session timer expired on tid %d\n", (u16)*ptid); ieee80211_stop_tx_ba_session(&sta->sta, *ptid); } @@ -449,8 +453,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW)) return -EINVAL; - ht_vdbg("Open BA session requested for %pM tid %u\n", - pubsta->addr, tid); + ht_dbg(sdata, "Open BA session requested for %pM tid %u\n", + pubsta->addr, tid); if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_MESH_POINT && @@ -460,7 +464,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, return -EINVAL; if (test_sta_flag(sta, WLAN_STA_BLOCK_BA)) { - ht_vdbg("BA sessions blocked - Denying BA session request\n"); + ht_dbg(sdata, + "BA sessions blocked - Denying BA session request\n"); return -EINVAL; } @@ -478,8 +483,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, */ if (sta->sdata->vif.type == NL80211_IFTYPE_ADHOC && !sta->sta.ht_cap.ht_supported) { - ht_vdbg("BA request denied - IBSS STA %pM does not advertise HT support\n", - pubsta->addr); + ht_dbg(sdata, + "BA request denied - IBSS STA %pM does not advertise HT support\n", + pubsta->addr); return -EINVAL; } @@ -499,8 +505,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_BURST_RETRIES && time_before(jiffies, sta->ampdu_mlme.last_addba_req_time[tid] + HT_AGG_RETRIES_PERIOD)) { - ht_vdbg("BA request denied - waiting a grace period after %d failed requests on tid %u\n", - sta->ampdu_mlme.addba_req_num[tid], tid); + ht_dbg(sdata, + "BA request denied - waiting a grace period after %d failed requests on tid %u\n", + sta->ampdu_mlme.addba_req_num[tid], tid); ret = -EBUSY; goto err_unlock_sta; } @@ -508,8 +515,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid, tid_tx = rcu_dereference_protected_tid_tx(sta, tid); /* check if the TID is not in aggregation flow already */ if (tid_tx || sta->ampdu_mlme.tid_start_tx[tid]) { - ht_vdbg("BA request denied - session is not idle on tid %u\n", - tid); + ht_dbg(sdata, + "BA request denied - session is not idle on tid %u\n", + tid); ret = -EAGAIN; goto err_unlock_sta; } @@ -564,7 +572,7 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, tid_tx = rcu_dereference_protected_tid_tx(sta, tid); - ht_vdbg("Aggregation is on for tid %d\n", tid); + ht_dbg(sta->sdata, "Aggregation is on for tid %d\n", tid); drv_ampdu_action(local, sta->sdata, IEEE80211_AMPDU_TX_OPERATIONAL, @@ -598,7 +606,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) trace_api_start_tx_ba_cb(sdata, ra, tid); if (tid >= STA_TID_NUM) { - ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM); + ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); return; } @@ -606,7 +615,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) sta = sta_info_get_bss(sdata, ra); if (!sta) { mutex_unlock(&local->sta_mtx); - ht_vdbg("Could not find station: %pM\n", ra); + ht_dbg(sdata, "Could not find station: %pM\n", ra); return; } @@ -614,7 +623,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (WARN_ON(!tid_tx)) { - ht_vdbg("addBA was not requested!\n"); + ht_dbg(sdata, "addBA was not requested!\n"); goto unlock; } @@ -714,17 +723,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) trace_api_stop_tx_ba_cb(sdata, ra, tid); if (tid >= STA_TID_NUM) { - ht_vdbg("Bad TID value: tid = %d (>= %d)\n", tid, STA_TID_NUM); + ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", + tid, STA_TID_NUM); return; } - ht_vdbg("Stopping Tx BA session for %pM tid %d\n", ra, tid); + ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid); mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, ra); if (!sta) { - ht_vdbg("Could not find station: %pM\n", ra); + ht_dbg(sdata, "Could not find station: %pM\n", ra); goto unlock; } @@ -733,7 +743,7 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) tid_tx = rcu_dereference_protected_tid_tx(sta, tid); if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { - ht_vdbg("unexpected callback to A-MPDU stop\n"); + ht_dbg(sdata, "unexpected callback to A-MPDU stop\n"); goto unlock_sta; } @@ -809,13 +819,13 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, goto out; if (mgmt->u.action.u.addba_resp.dialog_token != tid_tx->dialog_token) { - ht_vdbg("wrong addBA response token, tid %d\n", tid); + ht_dbg(sta->sdata, "wrong addBA response token, tid %d\n", tid); goto out; } del_timer_sync(&tid_tx->addba_resp_timer); - ht_vdbg("switched off addBA timer for tid %d\n", tid); + ht_dbg(sta->sdata, "switched off addBA timer for tid %d\n", tid); /* * addba_resp_timer may have fired before we got here, and @@ -824,8 +834,9 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, */ if (test_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state) || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { - ht_vdbg("got addBA resp for tid %d but we already gave up\n", - tid); + ht_dbg(sta->sdata, + "got addBA resp for tid %d but we already gave up\n", + tid); goto out; } diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 498c94e34427..cfdc03f59e27 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,31 +20,31 @@ #include "rate.h" #include "mesh.h" -static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct net_device *dev; + struct wireless_dev *wdev; struct ieee80211_sub_if_data *sdata; int err; - err = ieee80211_if_add(local, name, &dev, type, params); + err = ieee80211_if_add(local, name, &wdev, type, params); if (err) return ERR_PTR(err); if (type == NL80211_IFTYPE_MONITOR && flags) { - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); sdata->u.mntr_flags = *flags; } - return dev; + return wdev; } -static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); + ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev)); return 0; } @@ -353,6 +353,7 @@ void sta_set_rate_info_tx(struct sta_info *sta, static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = sta->sdata; + struct ieee80211_local *local = sdata->local; struct timespec uptime; sinfo->generation = sdata->local->sta_generation; @@ -388,7 +389,9 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) if ((sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) || (sta->local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)) { sinfo->filled |= STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG; - sinfo->signal = (s8)sta->last_signal; + if (!local->ops->get_rssi || + drv_get_rssi(local, sdata, &sta->sta, &sinfo->signal)) + sinfo->signal = (s8)sta->last_signal; sinfo->signal_avg = (s8) -ewma_read(&sta->avg_signal); } @@ -517,7 +520,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, * network device. */ - rcu_read_lock(); + mutex_lock(&local->sta_mtx); if (sdata->vif.type == NL80211_IFTYPE_STATION) { sta = sta_info_get_bss(sdata, sdata->u.mgd.bssid); @@ -546,7 +549,7 @@ static void ieee80211_get_et_stats(struct wiphy *wiphy, data[i] = (u8)sinfo.signal_avg; i++; } else { - list_for_each_entry_rcu(sta, &local->sta_list, list) { + list_for_each_entry(sta, &local->sta_list, list) { /* Make sure this station belongs to the proper dev */ if (sta->sdata->dev != dev) continue; @@ -603,7 +606,7 @@ do_survey: else data[i++] = -1LL; - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); if (WARN_ON(i != STA_STATS_LEN)) return; @@ -629,10 +632,11 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *mac, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int ret = -ENOENT; - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get_by_idx(sdata, idx); if (sta) { @@ -641,7 +645,7 @@ static int ieee80211_dump_station(struct wiphy *wiphy, struct net_device *dev, sta_set_sinfo(sta, sinfo); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return ret; } @@ -658,10 +662,11 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, u8 *mac, struct station_info *sinfo) { struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_local *local = sdata->local; struct sta_info *sta; int ret = -ENOENT; - rcu_read_lock(); + mutex_lock(&local->sta_mtx); sta = sta_info_get_bss(sdata, mac); if (sta) { @@ -669,7 +674,7 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev, sta_set_sinfo(sta, sinfo); } - rcu_read_unlock(); + mutex_unlock(&local->sta_mtx); return ret; } @@ -689,7 +694,8 @@ static int ieee80211_set_channel(struct wiphy *wiphy, case CHAN_MODE_HOPPING: return -EBUSY; case CHAN_MODE_FIXED: - if (local->oper_channel != chan) + if (local->oper_channel != chan || + (!sdata && local->_oper_channel_type != channel_type)) return -EBUSY; if (!sdata && local->_oper_channel_type == channel_type) return 0; @@ -1529,7 +1535,7 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) conf->dot11MeshTTL = nconf->dot11MeshTTL; if (_chg_mesh_attr(NL80211_MESHCONF_ELEMENT_TTL, mask)) - conf->dot11MeshTTL = nconf->element_ttl; + conf->element_ttl = nconf->element_ttl; if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) conf->auto_open_plinks = nconf->auto_open_plinks; if (_chg_mesh_attr(NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, mask)) @@ -1564,17 +1570,16 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, * announcements, so require this ifmsh to also be a root node * */ if (nconf->dot11MeshGateAnnouncementProtocol && - !conf->dot11MeshHWMPRootMode) { - conf->dot11MeshHWMPRootMode = 1; + !(conf->dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT)) { + conf->dot11MeshHWMPRootMode = IEEE80211_PROACTIVE_RANN; ieee80211_mesh_root_setup(ifmsh); } conf->dot11MeshGateAnnouncementProtocol = nconf->dot11MeshGateAnnouncementProtocol; } - if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) { + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_RANN_INTERVAL, mask)) conf->dot11MeshHWMPRannInterval = nconf->dot11MeshHWMPRannInterval; - } if (_chg_mesh_attr(NL80211_MESHCONF_FORWARDING, mask)) conf->dot11MeshForwarding = nconf->dot11MeshForwarding; if (_chg_mesh_attr(NL80211_MESHCONF_RSSI_THRESHOLD, mask)) { @@ -1590,6 +1595,15 @@ static int ieee80211_update_mesh_config(struct wiphy *wiphy, sdata->vif.bss_conf.ht_operation_mode = nconf->ht_opmode; ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT); } + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, mask)) + conf->dot11MeshHWMPactivePathToRootTimeout = + nconf->dot11MeshHWMPactivePathToRootTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ROOT_INTERVAL, mask)) + conf->dot11MeshHWMProotInterval = + nconf->dot11MeshHWMProotInterval; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, mask)) + conf->dot11MeshHWMPconfirmationInterval = + nconf->dot11MeshHWMPconfirmationInterval; return 0; } @@ -1727,6 +1741,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + return 0; } @@ -1747,10 +1763,11 @@ static int ieee80211_resume(struct wiphy *wiphy) #endif static int ieee80211_scan(struct wiphy *wiphy, - struct net_device *dev, struct cfg80211_scan_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev); switch (ieee80211_vif_type_p2p(&sdata->vif)) { case NL80211_IFTYPE_STATION: @@ -2097,6 +2114,9 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy, struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); int i, ret; + if (!ieee80211_sdata_running(sdata)) + return -ENETDOWN; + if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) { ret = drv_set_bitrate_mask(local, sdata, mask); if (ret) @@ -2280,13 +2300,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, } static int ieee80211_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; int ret; @@ -2306,6 +2326,21 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, mutex_lock(&local->mtx); list_for_each_entry_safe(roc, tmp, &local->roc_list, list) { + struct ieee80211_roc_work *dep, *tmp2; + + list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) { + if (!mgmt_tx && (unsigned long)dep != cookie) + continue; + else if (mgmt_tx && dep->mgmt_tx_cookie != cookie) + continue; + /* found dependent item -- just remove it */ + list_del(&dep->list); + mutex_unlock(&local->mtx); + + ieee80211_roc_notify_destroy(dep); + return 0; + } + if (!mgmt_tx && (unsigned long)roc != cookie) continue; else if (mgmt_tx && roc->mgmt_tx_cookie != cookie) @@ -2320,6 +2355,13 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, return -ENOENT; } + /* + * We found the item to cancel, so do that. Note that it + * may have dependents, which we also cancel (and send + * the expired signal for.) Not doing so would be quite + * tricky here, but we may need to fix it later. + */ + if (local->ops->remain_on_channel) { if (found->started) { ret = drv_cancel_remain_on_channel(local); @@ -2331,8 +2373,8 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, list_del(&found->list); - ieee80211_run_deferred_scan(local); - ieee80211_start_next_roc(local); + if (found->started) + ieee80211_start_next_roc(local); mutex_unlock(&local->mtx); ieee80211_roc_notify_destroy(found); @@ -2351,23 +2393,23 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, } static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; return ieee80211_cancel_roc(local, cookie, false); } -static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct sta_info *sta; @@ -2472,30 +2514,43 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = wiphy_priv(wiphy); return ieee80211_cancel_roc(local, cookie, true); } static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg) { struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); - if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ)) - return; + switch (frame_type) { + case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: + if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { + struct ieee80211_if_ibss *ifibss = &sdata->u.ibss; - if (reg) - local->probe_req_reg++; - else - local->probe_req_reg--; + if (reg) + ifibss->auth_frame_registrations++; + else + ifibss->auth_frame_registrations--; + } + break; + case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ: + if (reg) + local->probe_req_reg++; + else + local->probe_req_reg--; - ieee80211_queue_work(&local->hw, &local->reconfig_filter); + ieee80211_queue_work(&local->hw, &local->reconfig_filter); + break; + default: + break; + } } static int ieee80211_set_antenna(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant) @@ -2615,8 +2670,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_req.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_RESPONSE: @@ -2629,8 +2684,8 @@ ieee80211_prep_tdls_encap_data(struct wiphy *wiphy, struct net_device *dev, tf->u.setup_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; case WLAN_TDLS_SETUP_CONFIRM: @@ -2690,8 +2745,8 @@ ieee80211_prep_tdls_direct(struct wiphy *wiphy, struct net_device *dev, mgmt->u.action.u.tdls_discover_resp.capability = cpu_to_le16(ieee80211_get_tdls_sta_capab(sdata)); - ieee80211_add_srates_ie(&sdata->vif, skb, false); - ieee80211_add_ext_srates_ie(&sdata->vif, skb, false); + ieee80211_add_srates_ie(sdata, skb, false); + ieee80211_add_ext_srates_ie(sdata, skb, false); ieee80211_tdls_add_ext_capab(skb); break; default: @@ -2721,9 +2776,8 @@ static int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev, !sdata->u.mgd.associated) return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG - pr_debug("TDLS mgmt action %d peer %pM\n", action_code, peer); -#endif + tdls_dbg(sdata, "TDLS mgmt action %d peer %pM\n", + action_code, peer); skb = dev_alloc_skb(local->hw.extra_tx_headroom + max(sizeof(struct ieee80211_mgmt), @@ -2832,9 +2886,7 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev, if (sdata->vif.type != NL80211_IFTYPE_STATION) return -EINVAL; -#ifdef CONFIG_MAC80211_VERBOSE_TDLS_DEBUG - pr_debug("TDLS oper %d peer %pM\n", oper, peer); -#endif + tdls_dbg(sdata, "TDLS oper %d peer %pM\n", oper, peer); switch (oper) { case NL80211_TDLS_ENABLE_LINK: @@ -2930,14 +2982,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, return 0; } -static struct ieee80211_channel * -ieee80211_wiphy_get_channel(struct wiphy *wiphy, - enum nl80211_channel_type *type) +static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled) { struct ieee80211_local *local = wiphy_priv(wiphy); - *type = local->_oper_channel_type; - return local->oper_channel; + if (enabled) + WARN_ON(ieee80211_add_virtual_monitor(local)); + else + ieee80211_del_virtual_monitor(local); } #ifdef CONFIG_PM @@ -3013,8 +3065,8 @@ struct cfg80211_ops mac80211_config_ops = { .tdls_oper = ieee80211_tdls_oper, .tdls_mgmt = ieee80211_tdls_mgmt, .probe_client = ieee80211_probe_client, - .get_channel = ieee80211_wiphy_get_channel, .set_noack_map = ieee80211_set_noack_map, + .set_monitor_enabled = ieee80211_set_monitor_enabled, #ifdef CONFIG_PM .set_wakeup = ieee80211_set_wakeup, #endif diff --git a/net/mac80211/debug.h b/net/mac80211/debug.h new file mode 100644 index 000000000000..8f383a576016 --- /dev/null +++ b/net/mac80211/debug.h @@ -0,0 +1,170 @@ +#ifndef __MAC80211_DEBUG_H +#define __MAC80211_DEBUG_H +#include <net/cfg80211.h> + +#ifdef CONFIG_MAC80211_IBSS_DEBUG +#define MAC80211_IBSS_DEBUG 1 +#else +#define MAC80211_IBSS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_PS_DEBUG +#define MAC80211_PS_DEBUG 1 +#else +#define MAC80211_PS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_HT_DEBUG +#define MAC80211_HT_DEBUG 1 +#else +#define MAC80211_HT_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPL_DEBUG +#define MAC80211_MPL_DEBUG 1 +#else +#define MAC80211_MPL_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MPATH_DEBUG +#define MAC80211_MPATH_DEBUG 1 +#else +#define MAC80211_MPATH_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MHWMP_DEBUG +#define MAC80211_MHWMP_DEBUG 1 +#else +#define MAC80211_MHWMP_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESH_SYNC_DEBUG +#define MAC80211_MESH_SYNC_DEBUG 1 +#else +#define MAC80211_MESH_SYNC_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_TDLS_DEBUG +#define MAC80211_TDLS_DEBUG 1 +#else +#define MAC80211_TDLS_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_STA_DEBUG +#define MAC80211_STA_DEBUG 1 +#else +#define MAC80211_STA_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MLME_DEBUG +#define MAC80211_MLME_DEBUG 1 +#else +#define MAC80211_MLME_DEBUG 0 +#endif + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) __printf(1, 2); +void __sdata_dbg(bool print, const char *fmt, ...) __printf(2, 3); +void __sdata_err(const char *fmt, ...) __printf(1, 2); +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) + __printf(3, 4); + +#define _sdata_info(sdata, fmt, ...) \ + __sdata_info("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_dbg(print, sdata, fmt, ...) \ + __sdata_dbg(print, "%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _sdata_err(sdata, fmt, ...) \ + __sdata_err("%s: " fmt, (sdata)->name, ##__VA_ARGS__) +#define _wiphy_dbg(print, wiphy, fmt, ...) \ + __wiphy_dbg(wiphy, print, fmt, ##__VA_ARGS__) +#else +#define _sdata_info(sdata, fmt, ...) \ +do { \ + pr_info("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _sdata_dbg(print, sdata, fmt, ...) \ +do { \ + if (print) \ + pr_debug("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _sdata_err(sdata, fmt, ...) \ +do { \ + pr_err("%s: " fmt, \ + (sdata)->name, ##__VA_ARGS__); \ +} while (0) + +#define _wiphy_dbg(print, wiphy, fmt, ...) \ +do { \ + if (print) \ + wiphy_dbg((wiphy), fmt, ##__VA_ARGS__); \ +} while (0) +#endif + +#define sdata_info(sdata, fmt, ...) \ + _sdata_info(sdata, fmt, ##__VA_ARGS__) +#define sdata_err(sdata, fmt, ...) \ + _sdata_err(sdata, fmt, ##__VA_ARGS__) +#define sdata_dbg(sdata, fmt, ...) \ + _sdata_dbg(1, sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_HT_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ht_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_HT_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#define ibss_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_IBSS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_PS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define ps_dbg_hw(hw, fmt, ...) \ + _wiphy_dbg(MAC80211_PS_DEBUG, \ + (hw)->wiphy, fmt, ##__VA_ARGS__) + +#define ps_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_PS_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#define mpl_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MPL_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mpath_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MPATH_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mhwmp_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MHWMP_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define msync_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MESH_SYNC_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define tdls_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_TDLS_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define sta_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_STA_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MLME_DEBUG, \ + sdata, fmt, ##__VA_ARGS__) + +#define mlme_dbg_ratelimited(sdata, fmt, ...) \ + _sdata_dbg(MAC80211_MLME_DEBUG && net_ratelimit(), \ + sdata, fmt, ##__VA_ARGS__) + +#endif /* __MAC80211_DEBUG_H */ diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 778e5916d7c3..b8dfb440c8ef 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->rx_handlers_drop_defrag); DEBUGFS_STATS_ADD(rx_handlers_drop_short, local->rx_handlers_drop_short); - DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, - local->rx_handlers_drop_passive_scan); DEBUGFS_STATS_ADD(tx_expand_skb_head, local->tx_expand_skb_head); DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767bb482..090d08ff22c4 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -283,6 +283,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&sdata->local->key_mtx); + if (sdata->debugfs.default_unicast_key) { + debugfs_remove(sdata->debugfs.default_unicast_key); + sdata->debugfs.default_unicast_key = NULL; + } + if (sdata->default_unicast_key) { key = key_mtx_dereference(sdata->local, sdata->default_unicast_key); @@ -290,9 +295,11 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) sdata->debugfs.default_unicast_key = debugfs_create_symlink("default_unicast_key", sdata->debugfs.dir, buf); - } else { - debugfs_remove(sdata->debugfs.default_unicast_key); - sdata->debugfs.default_unicast_key = NULL; + } + + if (sdata->debugfs.default_multicast_key) { + debugfs_remove(sdata->debugfs.default_multicast_key); + sdata->debugfs.default_multicast_key = NULL; } if (sdata->default_multicast_key) { @@ -302,9 +309,6 @@ void ieee80211_debugfs_key_update_default(struct ieee80211_sub_if_data *sdata) sdata->debugfs.default_multicast_key = debugfs_create_symlink("default_multicast_key", sdata->debugfs.dir, buf); - } else { - debugfs_remove(sdata->debugfs.default_multicast_key); - sdata->debugfs.default_multicast_key = NULL; } } diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index d4272ff43f71..6d5aec9418ee 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -468,48 +468,54 @@ IEEE80211_IF_FILE(fwded_unicast, u.mesh.mshstats.fwded_unicast, DEC); IEEE80211_IF_FILE(fwded_frames, u.mesh.mshstats.fwded_frames, DEC); IEEE80211_IF_FILE(dropped_frames_ttl, u.mesh.mshstats.dropped_frames_ttl, DEC); IEEE80211_IF_FILE(dropped_frames_congestion, - u.mesh.mshstats.dropped_frames_congestion, DEC); + u.mesh.mshstats.dropped_frames_congestion, DEC); IEEE80211_IF_FILE(dropped_frames_no_route, - u.mesh.mshstats.dropped_frames_no_route, DEC); + u.mesh.mshstats.dropped_frames_no_route, DEC); IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); /* Mesh parameters */ IEEE80211_IF_FILE(dot11MeshMaxRetries, - u.mesh.mshcfg.dot11MeshMaxRetries, DEC); + u.mesh.mshcfg.dot11MeshMaxRetries, DEC); IEEE80211_IF_FILE(dot11MeshRetryTimeout, - u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); + u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); IEEE80211_IF_FILE(dot11MeshConfirmTimeout, - u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); + u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); IEEE80211_IF_FILE(dot11MeshHoldingTimeout, - u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); + u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); IEEE80211_IF_FILE(element_ttl, u.mesh.mshcfg.element_ttl, DEC); IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, - u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); + u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, - u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); + u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, - u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); IEEE80211_IF_FILE(dot11MeshHWMPperrMinInterval, - u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPperrMinInterval, DEC); IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, - u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); + u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, - u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); + u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); IEEE80211_IF_FILE(path_refresh_time, - u.mesh.mshcfg.path_refresh_time, DEC); + u.mesh.mshcfg.path_refresh_time, DEC); IEEE80211_IF_FILE(min_discovery_timeout, - u.mesh.mshcfg.min_discovery_timeout, DEC); + u.mesh.mshcfg.min_discovery_timeout, DEC); IEEE80211_IF_FILE(dot11MeshHWMPRootMode, - u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); + u.mesh.mshcfg.dot11MeshHWMPRootMode, DEC); IEEE80211_IF_FILE(dot11MeshGateAnnouncementProtocol, - u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); + u.mesh.mshcfg.dot11MeshGateAnnouncementProtocol, DEC); IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, - u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); + u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPactivePathToRootTimeout, + u.mesh.mshcfg.dot11MeshHWMPactivePathToRootTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshHWMProotInterval, + u.mesh.mshcfg.dot11MeshHWMProotInterval, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPconfirmationInterval, + u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval, DEC); #endif #define DEBUGFS_ADD_MODE(name, mode) \ @@ -611,6 +617,9 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); MESHPARAMS_ADD(rssi_threshold); MESHPARAMS_ADD(ht_opmode); + MESHPARAMS_ADD(dot11MeshHWMPactivePathToRootTimeout); + MESHPARAMS_ADD(dot11MeshHWMProotInterval); + MESHPARAMS_ADD(dot11MeshHWMPconfirmationInterval); #undef MESHPARAMS_ADD } #endif @@ -686,6 +695,7 @@ void ieee80211_debugfs_rename_netdev(struct ieee80211_sub_if_data *sdata) sprintf(buf, "netdev:%s", sdata->name); if (!debugfs_rename(dir->d_parent, dir, dir->d_parent, buf)) - pr_err("mac80211: debugfs: failed to rename debugfs " - "dir to %s\n", buf); + sdata_err(sdata, + "debugfs: failed to rename debugfs dir to %s\n", + buf); } diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h index 6d33a0c743ab..df9203199102 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -3,7 +3,7 @@ #include <net/mac80211.h> #include "ieee80211_i.h" -#include "driver-trace.h" +#include "trace.h" static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata) { @@ -27,14 +27,6 @@ static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb) local->ops->tx(&local->hw, skb); } -static inline void drv_tx_frags(struct ieee80211_local *local, - struct ieee80211_vif *vif, - struct ieee80211_sta *sta, - struct sk_buff_head *skbs) -{ - local->ops->tx_frags(&local->hw, vif, sta, skbs); -} - static inline void drv_get_et_strings(struct ieee80211_sub_if_data *sdata, u32 sset, u8 *data) { @@ -845,4 +837,33 @@ drv_allow_buffered_frames(struct ieee80211_local *local, more_data); trace_drv_return_void(local); } + +static inline int drv_get_rssi(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, + s8 *rssi_dbm) +{ + int ret; + + might_sleep(); + + ret = local->ops->get_rssi(&local->hw, &sdata->vif, sta, rssi_dbm); + trace_drv_get_rssi(local, sta, *rssi_dbm, ret); + + return ret; +} + +static inline void drv_mgd_prepare_tx(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata) +{ + might_sleep(); + + check_sdata_in_driver(sdata); + WARN_ON_ONCE(sdata->vif.type != NL80211_IFTYPE_STATION); + + trace_drv_mgd_prepare_tx(local, sdata); + if (local->ops->mgd_prepare_tx) + local->ops->mgd_prepare_tx(&local->hw, &sdata->vif); + trace_drv_return_void(local); +} #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/driver-trace.c b/net/mac80211/driver-trace.c deleted file mode 100644 index 8ed8711b1a6d..000000000000 --- a/net/mac80211/driver-trace.c +++ /dev/null @@ -1,9 +0,0 @@ -/* bug in tracepoint.h, it should include this */ -#include <linux/module.h> - -/* sparse isn't too happy with all macros... */ -#ifndef __CHECKER__ -#include "driver-ops.h" -#define CREATE_TRACE_POINTS -#include "driver-trace.h" -#endif diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index 6f8615c54b22..4b4538d63925 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -305,12 +305,10 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; initiator = (params & IEEE80211_DELBA_PARAM_INITIATOR_MASK) >> 11; -#ifdef CONFIG_MAC80211_HT_DEBUG - net_dbg_ratelimited("delba from %pM (%s) tid %d reason code %d\n", - mgmt->sa, initiator ? "initiator" : "recipient", - tid, - le16_to_cpu(mgmt->u.action.u.delba.reason_code)); -#endif /* CONFIG_MAC80211_HT_DEBUG */ + ht_dbg_ratelimited(sdata, "delba from %pM (%s) tid %d reason code %d\n", + mgmt->sa, initiator ? "initiator" : "recipient", + tid, + le16_to_cpu(mgmt->u.action.u.delba.reason_code)); if (initiator == WLAN_BACK_INITIATOR) __ieee80211_stop_rx_ba_session(sta, tid, WLAN_BACK_INITIATOR, 0, diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 725cb4be229d..5746d62faba1 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -261,11 +261,7 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, memcpy(addr, sta->sta.addr, ETH_ALEN); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(sdata->local->hw.wiphy, - "Adding new IBSS station %pM (dev=%s)\n", - addr, sdata->name); -#endif + ibss_dbg(sdata, "Adding new IBSS station %pM\n", addr); sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); sta_info_pre_move_state(sta, IEEE80211_STA_ASSOC); @@ -279,9 +275,10 @@ static struct sta_info *ieee80211_ibss_finish_sta(struct sta_info *sta, /* If it fails, maybe we raced another insertion? */ if (sta_info_insert_rcu(sta)) return sta_info_get(sdata, addr); - if (auth) { - ibss_vdbg("TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", - sdata->vif.addr, sdata->u.ibss.bssid, addr); + if (auth && !sdata->u.ibss.auth_frame_registrations) { + ibss_dbg(sdata, + "TX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=1)\n", + sdata->vif.addr, sdata->u.ibss.bssid, addr); ieee80211_send_auth(sdata, 1, WLAN_AUTH_OPEN, NULL, 0, addr, sdata->u.ibss.bssid, NULL, 0, 0); } @@ -304,7 +301,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", + net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n", sdata->name, addr); rcu_read_lock(); return NULL; @@ -351,9 +348,9 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata, if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) return; - ibss_vdbg("%s: RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", - sdata->name, mgmt->sa, mgmt->da, mgmt->bssid, - auth_transaction); + ibss_dbg(sdata, + "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n", + mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction); sta_info_destroy_addr(sdata, mgmt->sa); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false); rcu_read_unlock(); @@ -416,10 +413,10 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, ieee80211_mandatory_rates(local, band); if (sta->sta.supp_rates[band] != prev_rates) { - ibss_vdbg("%s: updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", - sdata->name, sta->sta.addr, - prev_rates, - sta->sta.supp_rates[band]); + ibss_dbg(sdata, + "updated supp_rates set for %pM based on beacon/probe_resp (0x%x -> 0x%x)\n", + sta->sta.addr, prev_rates, + sta->sta.supp_rates[band]); rates_updated = true; } } else { @@ -534,16 +531,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, rx_timestamp = drv_get_tsf(local, sdata); } - ibss_vdbg("RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", - mgmt->sa, mgmt->bssid, - (unsigned long long)rx_timestamp, - (unsigned long long)beacon_timestamp, - (unsigned long long)(rx_timestamp - beacon_timestamp), - jiffies); + ibss_dbg(sdata, + "RX beacon SA=%pM BSSID=%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + mgmt->sa, mgmt->bssid, + (unsigned long long)rx_timestamp, + (unsigned long long)beacon_timestamp, + (unsigned long long)(rx_timestamp - beacon_timestamp), + jiffies); if (beacon_timestamp > rx_timestamp) { - ibss_vdbg("%s: beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", - sdata->name, mgmt->bssid); + ibss_dbg(sdata, + "beacon TSF higher than local TSF - IBSS merge with BSSID %pM\n", + mgmt->bssid); ieee80211_sta_join_ibss(sdata, bss); supp_rates = ieee80211_sta_get_rates(local, elems, band, NULL); ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, @@ -569,7 +568,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata, * allow new one to be added. */ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { - net_dbg_ratelimited("%s: No room for a new IBSS STA entry %pM\n", + net_info_ratelimited("%s: No room for a new IBSS STA entry %pM\n", sdata->name, addr); return; } @@ -645,8 +644,8 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata) if (ifibss->fixed_channel) return; - pr_debug("%s: No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n", - sdata->name); + sdata_info(sdata, + "No active IBSS STAs - trying to scan for other IBSS networks with same SSID (merge)\n"); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len, NULL); @@ -674,8 +673,7 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata) bssid[0] |= 0x02; } - pr_debug("%s: Creating new IBSS network, BSSID %pM\n", - sdata->name, bssid); + sdata_info(sdata, "Creating new IBSS network, BSSID %pM\n", bssid); capability = WLAN_CAPABILITY_IBSS; @@ -706,8 +704,7 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) lockdep_assert_held(&ifibss->mtx); active_ibss = ieee80211_sta_active_ibss(sdata); - ibss_vdbg("%s: sta_find_ibss (active_ibss=%d)\n", - sdata->name, active_ibss); + ibss_dbg(sdata, "sta_find_ibss (active_ibss=%d)\n", active_ibss); if (active_ibss) return; @@ -730,23 +727,24 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) struct ieee80211_bss *bss; bss = (void *)cbss->priv; - ibss_vdbg(" sta_find_ibss: selected %pM current %pM\n", - cbss->bssid, ifibss->bssid); - pr_debug("%s: Selected IBSS BSSID %pM based on configured SSID\n", - sdata->name, cbss->bssid); + ibss_dbg(sdata, + "sta_find_ibss: selected %pM current %pM\n", + cbss->bssid, ifibss->bssid); + sdata_info(sdata, + "Selected IBSS BSSID %pM based on configured SSID\n", + cbss->bssid); ieee80211_sta_join_ibss(sdata, bss); ieee80211_rx_bss_put(local, bss); return; } - ibss_vdbg(" did not try to join ibss\n"); + ibss_dbg(sdata, "sta_find_ibss: did not try to join ibss\n"); /* Selected IBSS not found in current scan results - try to scan */ if (time_after(jiffies, ifibss->last_scan_completed + IEEE80211_SCAN_INTERVAL)) { - pr_debug("%s: Trigger new scan to find an IBSS to join\n", - sdata->name); + sdata_info(sdata, "Trigger new scan to find an IBSS to join\n"); ieee80211_request_internal_scan(sdata, ifibss->ssid, ifibss->ssid_len, @@ -760,9 +758,8 @@ static void ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata) ieee80211_sta_create_ibss(sdata); return; } - pr_debug("%s: IBSS not allowed on %d MHz\n", - sdata->name, - local->hw.conf.channel->center_freq); + sdata_info(sdata, "IBSS not allowed on %d MHz\n", + local->hw.conf.channel->center_freq); /* No IBSS found - decrease scan interval and continue * scanning. */ @@ -797,9 +794,9 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, tx_last_beacon = drv_tx_last_beacon(local); - ibss_vdbg("%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", - sdata->name, mgmt->sa, mgmt->da, - mgmt->bssid, tx_last_beacon); + ibss_dbg(sdata, + "RX ProbeReq SA=%pM DA=%pM BSSID=%pM (tx_last_beacon=%d)\n", + mgmt->sa, mgmt->da, mgmt->bssid, tx_last_beacon); if (!tx_last_beacon && is_multicast_ether_addr(mgmt->da)) return; @@ -812,8 +809,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, pos = mgmt->u.probe_req.variable; if (pos[0] != WLAN_EID_SSID || pos + 2 + pos[1] > end) { - ibss_vdbg("%s: Invalid SSID IE in ProbeReq from %pM\n", - sdata->name, mgmt->sa); + ibss_dbg(sdata, "Invalid SSID IE in ProbeReq from %pM\n", + mgmt->sa); return; } if (pos[1] != 0 && @@ -830,7 +827,7 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); - ibss_vdbg("%s: Sending ProbeResp to %pM\n", sdata->name, resp->da); + ibss_dbg(sdata, "Sending ProbeResp to %pM\n", resp->da); IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e6cbf5b68c89..7998513ec831 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -30,6 +30,7 @@ #include <net/mac80211.h> #include "key.h" #include "sta_info.h" +#include "debug.h" struct ieee80211_local; @@ -55,11 +56,14 @@ struct ieee80211_local; #define TU_TO_JIFFIES(x) (usecs_to_jiffies((x) * 1024)) #define TU_TO_EXP_TIME(x) (jiffies + TU_TO_JIFFIES(x)) +/* + * Some APs experience problems when working with U-APSD. Decrease the + * probability of that happening by using legacy mode for all ACs but VO. + * The AP that caused us trouble was a Cisco 4410N. It ignores our + * setting, and always treats non-VO ACs as legacy. + */ #define IEEE80211_DEFAULT_UAPSD_QUEUES \ - (IEEE80211_WMM_IE_STA_QOSINFO_AC_BK | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_BE | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VI | \ - IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) + IEEE80211_WMM_IE_STA_QOSINFO_AC_VO #define IEEE80211_DEFAULT_MAX_SP_LEN \ IEEE80211_WMM_IE_STA_QOSINFO_SP_ALL @@ -81,6 +85,8 @@ struct ieee80211_bss { size_t ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; + u32 device_ts; + u8 dtim_period; bool wmm_used; @@ -203,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * enum ieee80211_packet_rx_flags - packet RX flags * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed * (incl. multicast frames) - * @IEEE80211_RX_IN_SCAN: received while scanning * @IEEE80211_RX_FRAGMENTED: fragmented frame * @IEEE80211_RX_AMSDU: a-MSDU packet * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed @@ -213,7 +218,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * @rx_flags field of &struct ieee80211_rx_status. */ enum ieee80211_packet_rx_flags { - IEEE80211_RX_IN_SCAN = BIT(0), IEEE80211_RX_RA_MATCH = BIT(1), IEEE80211_RX_FRAGMENTED = BIT(2), IEEE80211_RX_AMSDU = BIT(3), @@ -508,6 +512,7 @@ struct ieee80211_if_ibss { bool privacy; bool control_port; + unsigned int auth_frame_registrations; u8 bssid[ETH_ALEN] __aligned(2); u8 ssid[IEEE80211_MAX_SSID_LEN]; @@ -677,6 +682,9 @@ struct ieee80211_sub_if_data { /* TID bitmap for NoAck policy */ u16 noack_map; + /* bit field of ACM bits (BIT(802.1D tag)) */ + u8 wmm_acm; + struct ieee80211_key __rcu *keys[NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS]; struct ieee80211_key __rcu *default_unicast_key; struct ieee80211_key __rcu *default_multicast_key; @@ -881,6 +889,9 @@ struct ieee80211_local { /* device is started */ bool started; + /* device is during a HW reconfig */ + bool in_reconfig; + /* wowlan is enabled -- don't reconfig on resume */ bool wowlan; @@ -954,14 +965,14 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - bool sched_scanning; struct ieee80211_sched_scan_ies sched_scan_ies; struct work_struct sched_scan_stopped_work; + struct ieee80211_sub_if_data __rcu *sched_scan_sdata; unsigned long leave_oper_channel_time; enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; - struct ieee80211_sub_if_data *scan_sdata; + struct ieee80211_sub_if_data __rcu *scan_sdata; enum nl80211_channel_type _oper_channel_type; struct ieee80211_channel *oper_channel, *csa_channel; @@ -1003,7 +1014,6 @@ struct ieee80211_local { unsigned int rx_handlers_drop_nullfunc; unsigned int rx_handlers_drop_defrag; unsigned int rx_handlers_drop_short; - unsigned int rx_handlers_drop_passive_scan; unsigned int tx_expand_skb_head; unsigned int tx_expand_skb_head_cloned; unsigned int rx_expand_skb_head; @@ -1019,7 +1029,6 @@ struct ieee80211_local { int total_ps_buffered; /* total number of all buffered unicast and * multicast packets for power saving stations */ - unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ bool pspolling; bool offchannel_ps_enabled; @@ -1081,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } +static inline struct ieee80211_sub_if_data * +IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev) +{ + return container_of(wdev, struct ieee80211_sub_if_data, wdev); +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -1231,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); void ieee80211_scan_cancel(struct ieee80211_local *local); void ieee80211_run_deferred_scan(struct ieee80211_local *local); -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -1268,13 +1282,12 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); int ieee80211_iface_init(void); void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params); int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata); void ieee80211_remove_interfaces(struct ieee80211_local *local); -u32 __ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_recalc_idle(struct ieee80211_local *local); void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata, const int offset); @@ -1471,6 +1484,16 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, u16 prot_mode); +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap); +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool need_basic); +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, + struct sk_buff *skb, bool need_basic); + +/* virtual monitor */ +int ieee80211_add_virtual_monitor(struct ieee80211_local *local); +void ieee80211_del_virtual_monitor(struct ieee80211_local *local); /* channel management */ enum ieee80211_chan_mode { diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 87aeb4f21ffd..334ee0fb18ca 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -43,6 +43,128 @@ */ +static u32 ieee80211_idle_off(struct ieee80211_local *local, + const char *reason) +{ + if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) + return 0; + + local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 ieee80211_idle_on(struct ieee80211_local *local) +{ + if (local->hw.conf.flags & IEEE80211_CONF_IDLE) + return 0; + + drv_flush(local, false); + + local->hw.conf.flags |= IEEE80211_CONF_IDLE; + return IEEE80211_CONF_CHANGE_IDLE; +} + +static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) +{ + struct ieee80211_sub_if_data *sdata; + int count = 0; + bool working = false, scanning = false; + unsigned int led_trig_start = 0, led_trig_stop = 0; + struct ieee80211_roc_work *roc; + +#ifdef CONFIG_PROVE_LOCKING + WARN_ON(debug_locks && !lockdep_rtnl_is_held() && + !lockdep_is_held(&local->iflist_mtx)); +#endif + lockdep_assert_held(&local->mtx); + + list_for_each_entry(sdata, &local->interfaces, list) { + if (!ieee80211_sdata_running(sdata)) { + sdata->vif.bss_conf.idle = true; + continue; + } + + sdata->old_idle = sdata->vif.bss_conf.idle; + + /* do not count disabled managed interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_STATION && + !sdata->u.mgd.associated && + !sdata->u.mgd.auth_data && + !sdata->u.mgd.assoc_data) { + sdata->vif.bss_conf.idle = true; + continue; + } + /* do not count unused IBSS interfaces */ + if (sdata->vif.type == NL80211_IFTYPE_ADHOC && + !sdata->u.ibss.ssid_len) { + sdata->vif.bss_conf.idle = true; + continue; + } + /* count everything else */ + sdata->vif.bss_conf.idle = false; + count++; + } + + if (!local->ops->remain_on_channel) { + list_for_each_entry(roc, &local->roc_list, list) { + working = true; + roc->sdata->vif.bss_conf.idle = false; + } + } + + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); + if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { + scanning = true; + sdata->vif.bss_conf.idle = false; + } + + list_for_each_entry(sdata, &local->interfaces, list) { + if (sdata->vif.type == NL80211_IFTYPE_MONITOR || + sdata->vif.type == NL80211_IFTYPE_AP_VLAN) + continue; + if (sdata->old_idle == sdata->vif.bss_conf.idle) + continue; + if (!ieee80211_sdata_running(sdata)) + continue; + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); + } + + if (working || scanning) + led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; + else + led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; + + if (count) + led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; + else + led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; + + ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); + + if (working) + return ieee80211_idle_off(local, "working"); + if (scanning) + return ieee80211_idle_off(local, "scanning"); + if (!count) + return ieee80211_idle_on(local); + else + return ieee80211_idle_off(local, "in use"); + + return 0; +} + +void ieee80211_recalc_idle(struct ieee80211_local *local) +{ + u32 chg; + + mutex_lock(&local->iflist_mtx); + chg = __ieee80211_recalc_idle(local); + mutex_unlock(&local->iflist_mtx); + if (chg) + ieee80211_hw_config(local, chg); +} + static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) { int meshhdrlen; @@ -57,9 +179,6 @@ static int ieee80211_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - pr_debug("%s: setting MTU %d\n", dev->name, new_mtu); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ dev->mtu = new_mtu; return 0; } @@ -100,15 +219,12 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, { struct ieee80211_local *local = sdata->local; struct ieee80211_sub_if_data *nsdata; - struct net_device *dev = sdata->dev; ASSERT_RTNL(); /* we hold the RTNL here so can safely walk the list */ list_for_each_entry(nsdata, &local->interfaces, list) { - struct net_device *ndev = nsdata->dev; - - if (ndev != dev && ieee80211_sdata_running(nsdata)) { + if (nsdata != sdata && ieee80211_sdata_running(nsdata)) { /* * Allow only a single IBSS interface to be up at any * time. This is restricted because beacon distribution @@ -127,7 +243,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata, * The remaining checks are only performed for interfaces * with the same MAC address. */ - if (!ether_addr_equal(dev->dev_addr, ndev->dev_addr)) + if (!ether_addr_equal(sdata->vif.addr, + nsdata->vif.addr)) continue; /* @@ -214,20 +331,24 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } -static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) +int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - int ret; + int ret = 0; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return 0; + mutex_lock(&local->iflist_mtx); + if (local->monitor_sdata) - return 0; + goto out_unlock; sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); - if (!sdata) - return -ENOMEM; + if (!sdata) { + ret = -ENOMEM; + goto out_unlock; + } /* set up data */ sdata->local = local; @@ -241,31 +362,34 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) if (WARN_ON(ret)) { /* ok .. stupid driver, it asked for this! */ kfree(sdata); - return ret; + goto out_unlock; } ret = ieee80211_check_queues(sdata); if (ret) { kfree(sdata); - return ret; + goto out_unlock; } rcu_assign_pointer(local->monitor_sdata, sdata); - - return 0; + out_unlock: + mutex_unlock(&local->iflist_mtx); + return ret; } -static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) +void ieee80211_del_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return; - sdata = rtnl_dereference(local->monitor_sdata); + mutex_lock(&local->iflist_mtx); + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); if (!sdata) - return; + goto out_unlock; rcu_assign_pointer(local->monitor_sdata, NULL); synchronize_net(); @@ -273,6 +397,8 @@ static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) drv_remove_interface(local, sdata); kfree(sdata); + out_unlock: + mutex_unlock(&local->iflist_mtx); } /* @@ -371,12 +497,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) break; } - if (local->monitors == 0 && local->open_count == 0) { - res = ieee80211_add_virtual_monitor(local); - if (res) - goto err_stop; - } - /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) { @@ -391,8 +511,6 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) break; default: if (coming_up) { - ieee80211_del_virtual_monitor(local); - res = drv_add_interface(local, sdata); if (res) goto err_stop; @@ -520,7 +638,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, clear_bit(SDATA_STATE_RUNNING, &sdata->state); - if (local->scan_sdata == sdata) + if (rcu_access_pointer(local->scan_sdata) == sdata) ieee80211_scan_cancel(local); /* @@ -627,7 +745,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, if (local->monitors == 0) { local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; - ieee80211_del_virtual_monitor(local); } ieee80211_adjust_monitor_flags(sdata, -1); @@ -701,9 +818,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, } } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); - - if (local->monitors == local->open_count && local->monitors > 0) - ieee80211_add_virtual_monitor(local); } static int ieee80211_stop(struct net_device *dev) @@ -808,7 +922,7 @@ static u16 ieee80211_monitor_select_queue(struct net_device *dev, hdr = (void *)((u8 *)skb->data + le16_to_cpu(rtap->it_len)); - return ieee80211_select_queue_80211(local, skb, hdr); + return ieee80211_select_queue_80211(sdata, skb, hdr); } static const struct net_device_ops ieee80211_monitorif_ops = { @@ -1223,7 +1337,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, if (__ffs64(mask) + hweight64(mask) != fls64(mask)) { /* not a contiguous mask ... not handled now! */ - pr_debug("not contiguous\n"); + pr_info("not contiguous\n"); break; } @@ -1269,7 +1383,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params) { struct net_device *ndev; @@ -1359,8 +1473,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); - if (new_dev) - *new_dev = ndev; + if (new_wdev) + *new_wdev = &sdata->wdev; return 0; @@ -1408,135 +1522,6 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) list_del(&unreg_list); } -static u32 ieee80211_idle_off(struct ieee80211_local *local, - const char *reason) -{ - if (!(local->hw.conf.flags & IEEE80211_CONF_IDLE)) - return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "device no longer idle - %s\n", reason); -#endif - - local->hw.conf.flags &= ~IEEE80211_CONF_IDLE; - return IEEE80211_CONF_CHANGE_IDLE; -} - -static u32 ieee80211_idle_on(struct ieee80211_local *local) -{ - if (local->hw.conf.flags & IEEE80211_CONF_IDLE) - return 0; - -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "device now idle\n"); -#endif - - drv_flush(local, false); - - local->hw.conf.flags |= IEEE80211_CONF_IDLE; - return IEEE80211_CONF_CHANGE_IDLE; -} - -u32 __ieee80211_recalc_idle(struct ieee80211_local *local) -{ - struct ieee80211_sub_if_data *sdata; - int count = 0; - bool working = false, scanning = false; - unsigned int led_trig_start = 0, led_trig_stop = 0; - struct ieee80211_roc_work *roc; - -#ifdef CONFIG_PROVE_LOCKING - WARN_ON(debug_locks && !lockdep_rtnl_is_held() && - !lockdep_is_held(&local->iflist_mtx)); -#endif - lockdep_assert_held(&local->mtx); - - list_for_each_entry(sdata, &local->interfaces, list) { - if (!ieee80211_sdata_running(sdata)) { - sdata->vif.bss_conf.idle = true; - continue; - } - - sdata->old_idle = sdata->vif.bss_conf.idle; - - /* do not count disabled managed interfaces */ - if (sdata->vif.type == NL80211_IFTYPE_STATION && - !sdata->u.mgd.associated && - !sdata->u.mgd.auth_data && - !sdata->u.mgd.assoc_data) { - sdata->vif.bss_conf.idle = true; - continue; - } - /* do not count unused IBSS interfaces */ - if (sdata->vif.type == NL80211_IFTYPE_ADHOC && - !sdata->u.ibss.ssid_len) { - sdata->vif.bss_conf.idle = true; - continue; - } - /* count everything else */ - sdata->vif.bss_conf.idle = false; - count++; - } - - if (!local->ops->remain_on_channel) { - list_for_each_entry(roc, &local->roc_list, list) { - working = true; - roc->sdata->vif.bss_conf.idle = false; - } - } - - if (local->scan_sdata && - !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { - scanning = true; - local->scan_sdata->vif.bss_conf.idle = false; - } - - list_for_each_entry(sdata, &local->interfaces, list) { - if (sdata->vif.type == NL80211_IFTYPE_MONITOR || - sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - continue; - if (sdata->old_idle == sdata->vif.bss_conf.idle) - continue; - if (!ieee80211_sdata_running(sdata)) - continue; - ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IDLE); - } - - if (working || scanning) - led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_WORK; - else - led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_WORK; - - if (count) - led_trig_start |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; - else - led_trig_stop |= IEEE80211_TPT_LEDTRIG_FL_CONNECTED; - - ieee80211_mod_tpt_led_trig(local, led_trig_start, led_trig_stop); - - if (working) - return ieee80211_idle_off(local, "working"); - if (scanning) - return ieee80211_idle_off(local, "scanning"); - if (!count) - return ieee80211_idle_on(local); - else - return ieee80211_idle_off(local, "in use"); - - return 0; -} - -void ieee80211_recalc_idle(struct ieee80211_local *local) -{ - u32 chg; - - mutex_lock(&local->iflist_mtx); - chg = __ieee80211_recalc_idle(local); - mutex_unlock(&local->iflist_mtx); - if (chg) - ieee80211_hw_config(local, chg); -} - static int netdev_notify(struct notifier_block *nb, unsigned long state, void *ndev) diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5bb600d93d77..7ae678ba5d67 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -139,7 +139,7 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key) } if (ret != -ENOSPC && ret != -EOPNOTSUPP) - wiphy_err(key->local->hw.wiphy, + sdata_err(sdata, "failed to set key (%d, %pM) to hardware (%d)\n", key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); @@ -186,7 +186,7 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) sta ? &sta->sta : NULL, &key->conf); if (ret) - wiphy_err(key->local->hw.wiphy, + sdata_err(sdata, "failed to remove key (%d, %pM) from hardware (%d)\n", key->conf.keyidx, sta ? sta->sta.addr : bcast_addr, ret); @@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) -{ - struct ieee80211_key *key; - - key = container_of(key_conf, struct ieee80211_key, conf); - - might_sleep(); - assert_key_lock(key->local); - - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - - /* - * Flush TX path to avoid attempts to use this key - * after this function returns. Until then, drivers - * must be prepared to handle the key. - */ - synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(ieee80211_key_removed); - static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, bool uni, bool multi) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index d81c178c7712..c26e231c733a 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work) mutex_lock(&local->mtx); WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || - local->sched_scanning, + rcu_dereference_protected(local->sched_scan_sdata, + lockdep_is_held(&local->mtx)), "%s called with hardware scan in progress\n", __func__); mutex_unlock(&local->mtx); @@ -345,6 +346,13 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) ieee80211_stop_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_SUSPEND); + /* + * Stop all Rx during the reconfig. We don't want state changes + * or driver callbacks while this is in progress. + */ + local->in_reconfig = true; + barrier(); + schedule_work(&local->restart_work); } EXPORT_SYMBOL(ieee80211_restart_hw); @@ -455,7 +463,9 @@ static const struct ieee80211_txrx_stypes ieee80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = { [NL80211_IFTYPE_ADHOC] = { .tx = 0xffff, - .rx = BIT(IEEE80211_STYPE_ACTION >> 4), + .rx = BIT(IEEE80211_STYPE_ACTION >> 4) | + BIT(IEEE80211_STYPE_AUTH >> 4) | + BIT(IEEE80211_STYPE_DEAUTH >> 4), }, [NL80211_IFTYPE_STATION] = { .tx = 0xffff, @@ -578,7 +588,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.priv = (char *)local + ALIGN(sizeof(*local), NETDEV_ALIGN); - BUG_ON(!ops->tx && !ops->tx_frags); + BUG_ON(!ops->tx); BUG_ON(!ops->start); BUG_ON(!ops->stop); BUG_ON(!ops->config); @@ -679,7 +689,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) int result, i; enum ieee80211_band band; int channels, max_bitrates; - bool supp_ht; + bool supp_ht, supp_vht; netdev_features_t feature_whitelist; static const u32 cipher_suites[] = { /* keep WEP first, it may be removed below */ @@ -697,12 +707,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->hw.offchannel_tx_hw_queue >= local->hw.queues)) return -EINVAL; - if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) #ifdef CONFIG_PM - && (!local->ops->suspend || !local->ops->resume) -#endif - ) + if ((hw->wiphy->wowlan.flags || hw->wiphy->wowlan.n_patterns) && + (!local->ops->suspend || !local->ops->resume)) return -EINVAL; +#endif if ((hw->flags & IEEE80211_HW_SCAN_WHILE_IDLE) && !local->ops->hw_scan) return -EINVAL; @@ -724,6 +733,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) channels = 0; max_bitrates = 0; supp_ht = false; + supp_vht = false; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { struct ieee80211_supported_band *sband; @@ -741,6 +751,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (max_bitrates < sband->n_bitrates) max_bitrates = sband->n_bitrates; supp_ht = supp_ht || sband->ht_cap.ht_supported; + supp_vht = supp_vht || sband->vht_cap.vht_supported; } local->int_scan_req = kzalloc(sizeof(*local->int_scan_req) + @@ -816,6 +827,10 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) if (supp_ht) local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap); + if (supp_vht) + local->scan_ies_len += + 2 + sizeof(struct ieee80211_vht_capabilities); + if (!local->ops->hw_scan) { /* For hw_scan, driver needs to set these up. */ local->hw.wiphy->max_scan_ssids = 4; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 7cf19509fb68..764593d65fc3 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -443,7 +443,7 @@ static void ieee80211_mesh_path_root_timer(unsigned long data) void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh) { - if (ifmsh->mshcfg.dot11MeshHWMPRootMode) + if (ifmsh->mshcfg.dot11MeshHWMPRootMode > IEEE80211_ROOTMODE_ROOT) set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); else { clear_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags); @@ -523,10 +523,6 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, { bool free_plinks; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - pr_debug("%s: running mesh housekeeping\n", sdata->name); -#endif - ieee80211_sta_expire(sdata, IEEE80211_MESH_PEER_INACTIVITY_LIMIT); mesh_path_expire(sdata); @@ -541,11 +537,17 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata, static void ieee80211_mesh_rootpath(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + u32 interval; mesh_path_tx_root_frame(sdata); + + if (ifmsh->mshcfg.dot11MeshHWMPRootMode == IEEE80211_PROACTIVE_RANN) + interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; + else + interval = ifmsh->mshcfg.dot11MeshHWMProotInterval; + mod_timer(&ifmsh->mesh_path_root_timer, - round_jiffies(TU_TO_EXP_TIME( - ifmsh->mshcfg.dot11MeshHWMPRannInterval))); + round_jiffies(TU_TO_EXP_TIME(interval))); } #ifdef CONFIG_PM diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e3642756f8f4..faaa39bcfd10 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -104,6 +104,7 @@ enum mesh_deferred_task_flags { * an mpath to a hash bucket on a path table. * @rann_snd_addr: the RANN sender address * @rann_metric: the aggregated path metric towards the root node + * @last_preq_to_root: Timestamp of last PREQ sent to root * @is_root: the destination station of this path is a root node * @is_gate: the destination station of this path is a mesh gate * @@ -131,6 +132,7 @@ struct mesh_path { spinlock_t state_lock; u8 rann_snd_addr[ETH_ALEN]; u32 rann_metric; + unsigned long last_preq_to_root; bool is_root; bool is_gate; }; @@ -245,7 +247,7 @@ void mesh_rmc_free(struct ieee80211_sub_if_data *sdata); int mesh_rmc_init(struct ieee80211_sub_if_data *sdata); void ieee80211s_init(void); void ieee80211s_update_metric(struct ieee80211_local *local, - struct sta_info *stainfo, struct sk_buff *skb); + struct sta_info *sta, struct sk_buff *skb); void ieee80211s_stop(void); void ieee80211_mesh_init_sdata(struct ieee80211_sub_if_data *sdata); void ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata); diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index fa7c58035246..fb7b6a11d0ba 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -13,13 +13,6 @@ #include "wme.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MHWMP_DEBUG -#define mhwmp_dbg(fmt, args...) \ - pr_debug("Mesh HWMP (%s): " fmt "\n", sdata->name, ##args) -#else -#define mhwmp_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - #define TEST_FRAME_LEN 8192 #define MAX_METRIC 0xffffffff #define ARITH_SHIFT 8 @@ -98,6 +91,8 @@ static inline u32 u16_field_get(u8 *preq_elem, int offset, bool ae) #define max_preq_retries(s) (s->u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries) #define disc_timeout_jiff(s) \ msecs_to_jiffies(sdata->u.mesh.mshcfg.min_discovery_timeout) +#define root_path_confirmation_jiffies(s) \ + msecs_to_jiffies(sdata->u.mesh.mshcfg.dot11MeshHWMPconfirmationInterval) enum mpath_frame_type { MPATH_PREQ = 0, @@ -142,19 +137,19 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags, switch (action) { case MPATH_PREQ: - mhwmp_dbg("sending PREQ to %pM", target); + mhwmp_dbg(sdata, "sending PREQ to %pM\n", target); ie_len = 37; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREQ; break; case MPATH_PREP: - mhwmp_dbg("sending PREP to %pM", target); + mhwmp_dbg(sdata, "sending PREP to %pM\n", target); ie_len = 31; pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_PREP; break; case MPATH_RANN: - mhwmp_dbg("sending RANN from %pM", orig_addr); + mhwmp_dbg(sdata, "sending RANN from %pM\n", orig_addr); ie_len = sizeof(struct ieee80211_rann_ie); pos = skb_put(skb, 2 + ie_len); *pos++ = WLAN_EID_RANN; @@ -303,7 +298,7 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn, } void ieee80211s_update_metric(struct ieee80211_local *local, - struct sta_info *stainfo, struct sk_buff *skb) + struct sta_info *sta, struct sk_buff *skb) { struct ieee80211_tx_info *txinfo = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -315,15 +310,14 @@ void ieee80211s_update_metric(struct ieee80211_local *local, failed = !(txinfo->flags & IEEE80211_TX_STAT_ACK); /* moving average, scaled to 100 */ - stainfo->fail_avg = ((80 * stainfo->fail_avg + 5) / 100 + 20 * failed); - if (stainfo->fail_avg > 95) - mesh_plink_broken(stainfo); + sta->fail_avg = ((80 * sta->fail_avg + 5) / 100 + 20 * failed); + if (sta->fail_avg > 95) + mesh_plink_broken(sta); } static u32 airtime_link_metric_get(struct ieee80211_local *local, struct sta_info *sta) { - struct ieee80211_supported_band *sband; struct rate_info rinfo; /* This should be adjusted for each device */ int device_constant = 1 << ARITH_SHIFT; @@ -333,8 +327,6 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, u32 tx_time, estimated_retx; u64 result; - sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - if (sta->fail_avg >= 100) return MAX_METRIC; @@ -519,10 +511,11 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, struct mesh_path *mpath = NULL; u8 *target_addr, *orig_addr; const u8 *da; - u8 target_flags, ttl; - u32 orig_sn, target_sn, lifetime; + u8 target_flags, ttl, flags; + u32 orig_sn, target_sn, lifetime, orig_metric; bool reply = false; bool forward = true; + bool root_is_gate; /* Update target SN, if present */ target_addr = PREQ_IE_TARGET_ADDR(preq_elem); @@ -530,11 +523,15 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, target_sn = PREQ_IE_TARGET_SN(preq_elem); orig_sn = PREQ_IE_ORIG_SN(preq_elem); target_flags = PREQ_IE_TARGET_F(preq_elem); + orig_metric = metric; + /* Proactive PREQ gate announcements */ + flags = PREQ_IE_FLAGS(preq_elem); + root_is_gate = !!(flags & RANN_FLAG_IS_GATE); - mhwmp_dbg("received PREQ from %pM", orig_addr); + mhwmp_dbg(sdata, "received PREQ from %pM\n", orig_addr); if (ether_addr_equal(target_addr, sdata->vif.addr)) { - mhwmp_dbg("PREQ is for us"); + mhwmp_dbg(sdata, "PREQ is for us\n"); forward = false; reply = true; metric = 0; @@ -544,6 +541,22 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, target_sn = ++ifmsh->sn; ifmsh->last_sn_update = jiffies; } + } else if (is_broadcast_ether_addr(target_addr) && + (target_flags & IEEE80211_PREQ_TO_FLAG)) { + rcu_read_lock(); + mpath = mesh_path_lookup(orig_addr, sdata); + if (mpath) { + if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { + reply = true; + target_addr = sdata->vif.addr; + target_sn = ++ifmsh->sn; + metric = 0; + ifmsh->last_sn_update = jiffies; + } + if (root_is_gate) + mesh_path_add_gate(mpath); + } + rcu_read_unlock(); } else { rcu_read_lock(); mpath = mesh_path_lookup(target_addr, sdata); @@ -570,19 +583,20 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, lifetime = PREQ_IE_LIFETIME(preq_elem); ttl = ifmsh->mshcfg.element_ttl; if (ttl != 0) { - mhwmp_dbg("replying to the PREQ"); + mhwmp_dbg(sdata, "replying to the PREQ\n"); mesh_path_sel_frame_tx(MPATH_PREP, 0, orig_addr, cpu_to_le32(orig_sn), 0, target_addr, cpu_to_le32(target_sn), mgmt->sa, 0, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), 0, sdata); - } else + } else { ifmsh->mshstats.dropped_frames_ttl++; + } } if (forward && ifmsh->mshcfg.dot11MeshForwarding) { u32 preq_id; - u8 hopcount, flags; + u8 hopcount; ttl = PREQ_IE_TTL(preq_elem); lifetime = PREQ_IE_LIFETIME(preq_elem); @@ -590,13 +604,19 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, ifmsh->mshstats.dropped_frames_ttl++; return; } - mhwmp_dbg("forwarding the PREQ from %pM", orig_addr); + mhwmp_dbg(sdata, "forwarding the PREQ from %pM\n", orig_addr); --ttl; - flags = PREQ_IE_FLAGS(preq_elem); preq_id = PREQ_IE_PREQ_ID(preq_elem); hopcount = PREQ_IE_HOPCOUNT(preq_elem) + 1; da = (mpath && mpath->is_root) ? mpath->rann_snd_addr : broadcast_addr; + + if (flags & IEEE80211_PREQ_PROACTIVE_PREP_FLAG) { + target_addr = PREQ_IE_TARGET_ADDR(preq_elem); + target_sn = PREQ_IE_TARGET_SN(preq_elem); + metric = orig_metric; + } + mesh_path_sel_frame_tx(MPATH_PREQ, flags, orig_addr, cpu_to_le32(orig_sn), target_flags, target_addr, cpu_to_le32(target_sn), da, @@ -631,7 +651,8 @@ static void hwmp_prep_frame_process(struct ieee80211_sub_if_data *sdata, u8 next_hop[ETH_ALEN]; u32 target_sn, orig_sn, lifetime; - mhwmp_dbg("received PREP from %pM", PREP_IE_ORIG_ADDR(prep_elem)); + mhwmp_dbg(sdata, "received PREP from %pM\n", + PREP_IE_ORIG_ADDR(prep_elem)); orig_addr = PREP_IE_ORIG_ADDR(prep_elem); if (ether_addr_equal(orig_addr, sdata->vif.addr)) @@ -744,11 +765,6 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, bool root_is_gate; ttl = rann->rann_ttl; - if (ttl <= 1) { - ifmsh->mshstats.dropped_frames_ttl++; - return; - } - ttl--; flags = rann->rann_flags; root_is_gate = !!(flags & RANN_FLAG_IS_GATE); orig_addr = rann->rann_addr; @@ -762,8 +778,9 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, if (ether_addr_equal(orig_addr, sdata->vif.addr)) return; - mhwmp_dbg("received RANN from %pM via neighbour %pM (is_gate=%d)", - orig_addr, mgmt->sa, root_is_gate); + mhwmp_dbg(sdata, + "received RANN from %pM via neighbour %pM (is_gate=%d)\n", + orig_addr, mgmt->sa, root_is_gate); rcu_read_lock(); sta = sta_info_get(sdata, mgmt->sa); @@ -785,34 +802,50 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata, } } + if (!(SN_LT(mpath->sn, orig_sn)) && + !(mpath->sn == orig_sn && metric < mpath->rann_metric)) { + rcu_read_unlock(); + return; + } + if ((!(mpath->flags & (MESH_PATH_ACTIVE | MESH_PATH_RESOLVING)) || - time_after(jiffies, mpath->exp_time - 1*HZ)) && - !(mpath->flags & MESH_PATH_FIXED)) { - mhwmp_dbg("%s time to refresh root mpath %pM", sdata->name, - orig_addr); + (time_after(jiffies, mpath->last_preq_to_root + + root_path_confirmation_jiffies(sdata)) || + time_before(jiffies, mpath->last_preq_to_root))) && + !(mpath->flags & MESH_PATH_FIXED) && (ttl != 0)) { + mhwmp_dbg(sdata, + "time to refresh root mpath %pM\n", + orig_addr); mesh_queue_preq(mpath, PREQ_Q_F_START | PREQ_Q_F_REFRESH); + mpath->last_preq_to_root = jiffies; + } + + mpath->sn = orig_sn; + mpath->rann_metric = metric + metric_txsta; + mpath->is_root = true; + /* Recording RANNs sender address to send individually + * addressed PREQs destined for root mesh STA */ + memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); + + if (root_is_gate) + mesh_path_add_gate(mpath); + + if (ttl <= 1) { + ifmsh->mshstats.dropped_frames_ttl++; + rcu_read_unlock(); + return; } + ttl--; - if ((SN_LT(mpath->sn, orig_sn) || (mpath->sn == orig_sn && - metric < mpath->rann_metric)) && ifmsh->mshcfg.dot11MeshForwarding) { + if (ifmsh->mshcfg.dot11MeshForwarding) { mesh_path_sel_frame_tx(MPATH_RANN, flags, orig_addr, cpu_to_le32(orig_sn), 0, NULL, 0, broadcast_addr, hopcount, ttl, cpu_to_le32(interval), cpu_to_le32(metric + metric_txsta), 0, sdata); - mpath->sn = orig_sn; - mpath->rann_metric = metric + metric_txsta; - /* Recording RANNs sender address to send individually - * addressed PREQs destined for root mesh STA */ - memcpy(mpath->rann_snd_addr, mgmt->sa, ETH_ALEN); } - mpath->is_root = true; - - if (root_is_gate) - mesh_path_add_gate(mpath); - rcu_read_unlock(); } @@ -889,7 +922,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) preq_node = kmalloc(sizeof(struct mesh_preq_queue), GFP_ATOMIC); if (!preq_node) { - mhwmp_dbg("could not allocate PREQ node"); + mhwmp_dbg(sdata, "could not allocate PREQ node\n"); return; } @@ -898,7 +931,7 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags) spin_unlock_bh(&ifmsh->mesh_preq_queue_lock); kfree(preq_node); if (printk_ratelimit()) - mhwmp_dbg("PREQ node queue full"); + mhwmp_dbg(sdata, "PREQ node queue full\n"); return; } @@ -1146,7 +1179,7 @@ void mesh_path_timer(unsigned long data) if (!mpath->is_gate && mesh_gate_num(sdata) > 0) { ret = mesh_path_send_to_gates(mpath); if (ret) - mhwmp_dbg("no gate was reachable"); + mhwmp_dbg(sdata, "no gate was reachable\n"); } else mesh_path_flush_pending(mpath); } @@ -1157,13 +1190,34 @@ mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; u32 interval = ifmsh->mshcfg.dot11MeshHWMPRannInterval; - u8 flags; + u8 flags, target_flags = 0; flags = (ifmsh->mshcfg.dot11MeshGateAnnouncementProtocol) ? RANN_FLAG_IS_GATE : 0; - mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, + + switch (ifmsh->mshcfg.dot11MeshHWMPRootMode) { + case IEEE80211_PROACTIVE_RANN: + mesh_path_sel_frame_tx(MPATH_RANN, flags, sdata->vif.addr, cpu_to_le32(++ifmsh->sn), 0, NULL, 0, broadcast_addr, - 0, sdata->u.mesh.mshcfg.element_ttl, + 0, ifmsh->mshcfg.element_ttl, cpu_to_le32(interval), 0, 0, sdata); + break; + case IEEE80211_PROACTIVE_PREQ_WITH_PREP: + flags |= IEEE80211_PREQ_PROACTIVE_PREP_FLAG; + case IEEE80211_PROACTIVE_PREQ_NO_PREP: + interval = ifmsh->mshcfg.dot11MeshHWMPactivePathToRootTimeout; + target_flags |= IEEE80211_PREQ_TO_FLAG | + IEEE80211_PREQ_USN_FLAG; + mesh_path_sel_frame_tx(MPATH_PREQ, flags, sdata->vif.addr, + cpu_to_le32(++ifmsh->sn), target_flags, + (u8 *) broadcast_addr, 0, broadcast_addr, + 0, ifmsh->mshcfg.element_ttl, + cpu_to_le32(interval), + 0, cpu_to_le32(ifmsh->preq_id++), sdata); + break; + default: + mhwmp_dbg(sdata, "Proactive mechanism not supported\n"); + return; + } } diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 572f706fd65b..c9ae931dd693 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c @@ -18,12 +18,6 @@ #include "ieee80211_i.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPATH_DEBUG -#define mpath_dbg(fmt, args...) pr_debug(fmt, ##args) -#else -#define mpath_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - /* There will be initially 2^INIT_PATHS_SIZE_ORDER buckets */ #define INIT_PATHS_SIZE_ORDER 2 @@ -322,9 +316,8 @@ static void mesh_path_move_to_queue(struct mesh_path *gate_mpath, spin_lock_irqsave(&gate_mpath->frame_queue.lock, flags); skb_queue_splice(&gateq, &gate_mpath->frame_queue); - mpath_dbg("Mpath queue for gate %pM has %d frames\n", - gate_mpath->dst, - skb_queue_len(&gate_mpath->frame_queue)); + mpath_dbg(gate_mpath->sdata, "Mpath queue for gate %pM has %d frames\n", + gate_mpath->dst, skb_queue_len(&gate_mpath->frame_queue)); spin_unlock_irqrestore(&gate_mpath->frame_queue.lock, flags); if (!copy) @@ -446,9 +439,9 @@ int mesh_path_add_gate(struct mesh_path *mpath) hlist_add_head_rcu(&new_gate->list, tbl->known_gates); spin_unlock_bh(&tbl->gates_lock); rcu_read_unlock(); - mpath_dbg("Mesh path (%s): Recorded new gate: %pM. %d known gates\n", - mpath->sdata->name, mpath->dst, - mpath->sdata->u.mesh.num_gates); + mpath_dbg(mpath->sdata, + "Mesh path: Recorded new gate: %pM. %d known gates\n", + mpath->dst, mpath->sdata->u.mesh.num_gates); return 0; err_rcu: rcu_read_unlock(); @@ -477,8 +470,8 @@ static int mesh_gate_del(struct mesh_table *tbl, struct mesh_path *mpath) spin_unlock_bh(&tbl->gates_lock); mpath->sdata->u.mesh.num_gates--; mpath->is_gate = false; - mpath_dbg("Mesh path (%s): Deleted gate: %pM. " - "%d known gates\n", mpath->sdata->name, + mpath_dbg(mpath->sdata, + "Mesh path: Deleted gate: %pM. %d known gates\n", mpath->dst, mpath->sdata->u.mesh.num_gates); break; } @@ -946,19 +939,20 @@ int mesh_path_send_to_gates(struct mesh_path *mpath) continue; if (gate->mpath->flags & MESH_PATH_ACTIVE) { - mpath_dbg("Forwarding to %pM\n", gate->mpath->dst); + mpath_dbg(sdata, "Forwarding to %pM\n", gate->mpath->dst); mesh_path_move_to_queue(gate->mpath, from_mpath, copy); from_mpath = gate->mpath; copy = true; } else { - mpath_dbg("Not forwarding %p\n", gate->mpath); - mpath_dbg("flags %x\n", gate->mpath->flags); + mpath_dbg(sdata, + "Not forwarding %p (flags %#x)\n", + gate->mpath, gate->mpath->flags); } } hlist_for_each_entry_rcu(gate, n, known_gates, list) if (gate->mpath->sdata == sdata) { - mpath_dbg("Sending to %pM\n", gate->mpath->dst); + mpath_dbg(sdata, "Sending to %pM\n", gate->mpath->dst); mesh_path_tx_pending(gate->mpath); } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index be4fad128c34..425685914d7d 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -13,12 +13,6 @@ #include "rate.h" #include "mesh.h" -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG -#define mpl_dbg(fmt, args...) pr_debug(fmt, ##args) -#else -#define mpl_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - #define PLINK_GET_LLID(p) (p + 2) #define PLINK_GET_PLID(p) (p + 4) @@ -134,12 +128,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) switch (sta->ch_type) { case NL80211_CHAN_NO_HT: - mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", + mpl_dbg(sdata, + "mesh_plink %pM: nonHT sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); non_ht_sta = true; goto out; case NL80211_CHAN_HT20: - mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", + mpl_dbg(sdata, + "mesh_plink %pM: HT20 sta (%pM) is present\n", sdata->vif.addr, sta->sta.addr); ht20_sta = true; default: @@ -160,7 +156,8 @@ out: sdata->vif.bss_conf.ht_operation_mode = ht_opmode; sdata->u.mesh.mshcfg.ht_opmode = ht_opmode; changed = BSS_CHANGED_HT; - mpl_dbg("mesh_plink %pM: protection mode changed to %d", + mpl_dbg(sdata, + "mesh_plink %pM: protection mode changed to %d\n", sdata->vif.addr, ht_opmode); } @@ -261,8 +258,8 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, pos = skb_put(skb, 2); memcpy(pos + 2, &plid, 2); } - if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || - ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true) || + ieee80211_add_ext_srates_ie(sdata, skb, true) || mesh_add_rsn_ie(skb, sdata) || mesh_add_meshid_ie(skb, sdata) || mesh_add_meshconf_ie(skb, sdata)) @@ -437,7 +434,8 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->lock); return; } - mpl_dbg("Mesh plink timer for %pM fired on state %d\n", + mpl_dbg(sta->sdata, + "Mesh plink timer for %pM fired on state %d\n", sta->sta.addr, sta->plink_state); reason = 0; llid = sta->llid; @@ -450,7 +448,8 @@ static void mesh_plink_timer(unsigned long data) /* retry timer */ if (sta->plink_retries < dot11MeshMaxRetries(sdata)) { u32 rand; - mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", + mpl_dbg(sta->sdata, + "Mesh plink for %pM (retry, timeout): %d %d\n", sta->sta.addr, sta->plink_retries, sta->plink_timeout); get_random_bytes(&rand, sizeof(u32)); @@ -530,7 +529,8 @@ int mesh_plink_open(struct sta_info *sta) sta->plink_state = NL80211_PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->lock); - mpl_dbg("Mesh plink: starting establishment with %pM\n", + mpl_dbg(sdata, + "Mesh plink: starting establishment with %pM\n", sta->sta.addr); return mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_OPEN, @@ -565,7 +565,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m u8 *baseaddr; u32 changed = 0; __le16 plid, llid, reason; -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG static const char *mplstates[] = { [NL80211_PLINK_LISTEN] = "LISTEN", [NL80211_PLINK_OPN_SNT] = "OPN-SNT", @@ -575,14 +574,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m [NL80211_PLINK_HOLDING] = "HOLDING", [NL80211_PLINK_BLOCKED] = "BLOCKED" }; -#endif /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) return; if (is_multicast_ether_addr(mgmt->da)) { - mpl_dbg("Mesh plink: ignore frame from multicast address"); + mpl_dbg(sdata, + "Mesh plink: ignore frame from multicast address\n"); return; } @@ -595,12 +594,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } ieee802_11_parse_elems(baseaddr, len - baselen, &elems); if (!elems.peering) { - mpl_dbg("Mesh plink: missing necessary peer link ie\n"); + mpl_dbg(sdata, + "Mesh plink: missing necessary peer link ie\n"); return; } if (elems.rsn_len && sdata->u.mesh.security == IEEE80211_MESH_SEC_NONE) { - mpl_dbg("Mesh plink: can't establish link with secure peer\n"); + mpl_dbg(sdata, + "Mesh plink: can't establish link with secure peer\n"); return; } @@ -610,14 +611,15 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m (ftype == WLAN_SP_MESH_PEERING_CONFIRM && ie_len != 6) || (ftype == WLAN_SP_MESH_PEERING_CLOSE && ie_len != 6 && ie_len != 8)) { - mpl_dbg("Mesh plink: incorrect plink ie length %d %d\n", - ftype, ie_len); + mpl_dbg(sdata, + "Mesh plink: incorrect plink ie length %d %d\n", + ftype, ie_len); return; } if (ftype != WLAN_SP_MESH_PEERING_CLOSE && (!elems.mesh_id || !elems.mesh_config)) { - mpl_dbg("Mesh plink: missing necessary ie\n"); + mpl_dbg(sdata, "Mesh plink: missing necessary ie\n"); return; } /* Note the lines below are correct, the llid in the frame is the plid @@ -632,21 +634,21 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta = sta_info_get(sdata, mgmt->sa); if (!sta && ftype != WLAN_SP_MESH_PEERING_OPEN) { - mpl_dbg("Mesh plink: cls or cnf from unknown peer\n"); + mpl_dbg(sdata, "Mesh plink: cls or cnf from unknown peer\n"); rcu_read_unlock(); return; } if (ftype == WLAN_SP_MESH_PEERING_OPEN && !rssi_threshold_check(sta, sdata)) { - mpl_dbg("Mesh plink: %pM does not meet rssi threshold\n", + mpl_dbg(sdata, "Mesh plink: %pM does not meet rssi threshold\n", mgmt->sa); rcu_read_unlock(); return; } if (sta && !test_sta_flag(sta, WLAN_STA_AUTH)) { - mpl_dbg("Mesh plink: Action frame from non-authed peer\n"); + mpl_dbg(sdata, "Mesh plink: Action frame from non-authed peer\n"); rcu_read_unlock(); return; } @@ -683,7 +685,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } else if (!sta) { /* ftype == WLAN_SP_MESH_PEERING_OPEN */ if (!mesh_plink_free_count(sdata)) { - mpl_dbg("Mesh plink error: no more free plinks\n"); + mpl_dbg(sdata, "Mesh plink error: no more free plinks\n"); rcu_read_unlock(); return; } @@ -724,7 +726,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m event = CLS_ACPT; break; default: - mpl_dbg("Mesh plink: unknown frame subtype\n"); + mpl_dbg(sdata, "Mesh plink: unknown frame subtype\n"); rcu_read_unlock(); return; } @@ -734,13 +736,14 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m /* allocate sta entry if necessary and update info */ sta = mesh_peer_init(sdata, mgmt->sa, &elems); if (!sta) { - mpl_dbg("Mesh plink: failed to init peer!\n"); + mpl_dbg(sdata, "Mesh plink: failed to init peer!\n"); rcu_read_unlock(); return; } } - mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", + mpl_dbg(sdata, + "Mesh plink (peer, state, llid, plid, event): %pM %s %d %d %d\n", mgmt->sa, mplstates[sta->plink_state], le16_to_cpu(sta->llid), le16_to_cpu(sta->plid), event); @@ -851,7 +854,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= BSS_CHANGED_BEACON; - mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); break; default: @@ -887,7 +890,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m mesh_plink_inc_estab_count(sdata); changed |= mesh_set_ht_prot_mode(sdata); changed |= BSS_CHANGED_BEACON; - mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + mpl_dbg(sdata, "Mesh plink with %pM ESTABLISHED\n", sta->sta.addr); mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CONFIRM, diff --git a/net/mac80211/mesh_sync.c b/net/mac80211/mesh_sync.c index 0ccdad49f987..accfa00ffcdf 100644 --- a/net/mac80211/mesh_sync.c +++ b/net/mac80211/mesh_sync.c @@ -12,13 +12,6 @@ #include "mesh.h" #include "driver-ops.h" -#ifdef CONFIG_MAC80211_VERBOSE_MESH_SYNC_DEBUG -#define msync_dbg(fmt, args...) \ - pr_debug("Mesh sync (%s): " fmt "\n", sdata->name, ##args) -#else -#define msync_dbg(fmt, args...) do { (void)(0); } while (0) -#endif - /* This is not in the standard. It represents a tolerable tbtt drift below * which we do no TSF adjustment. */ @@ -65,14 +58,14 @@ void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata) spin_lock_bh(&ifmsh->sync_offset_lock); if (ifmsh->sync_offset_clockdrift_max < beacon_int_fraction) { - msync_dbg("TBTT : max clockdrift=%lld; adjusting", - (long long) ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting\n", + (long long) ifmsh->sync_offset_clockdrift_max); tsfdelta = -ifmsh->sync_offset_clockdrift_max; ifmsh->sync_offset_clockdrift_max = 0; } else { - msync_dbg("TBTT : max clockdrift=%lld; adjusting by %llu", - (long long) ifmsh->sync_offset_clockdrift_max, - (unsigned long long) beacon_int_fraction); + msync_dbg(sdata, "TBTT : max clockdrift=%lld; adjusting by %llu\n", + (long long) ifmsh->sync_offset_clockdrift_max, + (unsigned long long) beacon_int_fraction); tsfdelta = -beacon_int_fraction; ifmsh->sync_offset_clockdrift_max -= beacon_int_fraction; } @@ -120,7 +113,7 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (elems->mesh_config && mesh_peer_tbtt_adjusting(elems)) { clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); - msync_dbg("STA %pM : is adjusting TBTT", sta->sta.addr); + msync_dbg(sdata, "STA %pM : is adjusting TBTT\n", sta->sta.addr); goto no_sync; } @@ -169,7 +162,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (test_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN)) { s64 t_clockdrift = sta->t_offset_setpoint - sta->t_offset; - msync_dbg("STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld", + msync_dbg(sdata, + "STA %pM : sta->t_offset=%lld, sta->t_offset_setpoint=%lld, t_clockdrift=%lld\n", sta->sta.addr, (long long) sta->t_offset, (long long) @@ -178,7 +172,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, if (t_clockdrift > TOFFSET_MAXIMUM_ADJUSTMENT || t_clockdrift < -TOFFSET_MAXIMUM_ADJUSTMENT) { - msync_dbg("STA %pM : t_clockdrift=%lld too large, setpoint reset", + msync_dbg(sdata, + "STA %pM : t_clockdrift=%lld too large, setpoint reset\n", sta->sta.addr, (long long) t_clockdrift); clear_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); @@ -197,8 +192,8 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, } else { sta->t_offset_setpoint = sta->t_offset - TOFFSET_SET_MARGIN; set_sta_flag(sta, WLAN_STA_TOFFSET_KNOWN); - msync_dbg("STA %pM : offset was invalid, " - " sta->t_offset=%lld", + msync_dbg(sdata, + "STA %pM : offset was invalid, sta->t_offset=%lld\n", sta->sta.addr, (long long) sta->t_offset); rcu_read_unlock(); @@ -226,17 +221,15 @@ static void mesh_sync_offset_adjust_tbtt(struct ieee80211_sub_if_data *sdata) * to the driver tsf setter, we punt * the tsf adjustment to the mesh tasklet */ - msync_dbg("TBTT : kicking off TBTT " - "adjustment with " - "clockdrift_max=%lld", - ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, + "TBTT : kicking off TBTT adjustment with clockdrift_max=%lld\n", + ifmsh->sync_offset_clockdrift_max); set_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags); } else { - msync_dbg("TBTT : max clockdrift=%lld; " - "too small to adjust", - (long long) - ifmsh->sync_offset_clockdrift_max); + msync_dbg(sdata, + "TBTT : max clockdrift=%lld; too small to adjust\n", + (long long)ifmsh->sync_offset_clockdrift_max); ifmsh->sync_offset_clockdrift_max = 0; } spin_unlock_bh(&ifmsh->sync_offset_lock); @@ -268,7 +261,7 @@ static void mesh_sync_vendor_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, const u8 *oui; WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg("called mesh_sync_vendor_rx_bcn_presp"); + msync_dbg(sdata, "called mesh_sync_vendor_rx_bcn_presp\n"); oui = mesh_get_vendor_oui(sdata); /* here you would implement the vendor offset tracking for this oui */ } @@ -278,7 +271,7 @@ static void mesh_sync_vendor_adjust_tbtt(struct ieee80211_sub_if_data *sdata) const u8 *oui; WARN_ON(sdata->u.mesh.mesh_sp_id != IEEE80211_SYNC_METHOD_VENDOR); - msync_dbg("called mesh_sync_vendor_adjust_tbtt"); + msync_dbg(sdata, "called mesh_sync_vendor_adjust_tbtt\n"); oui = mesh_get_vendor_oui(sdata); /* here you would implement the vendor tsf adjustment for this oui */ } diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index d7134c170336..de4350fce11e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -541,6 +541,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata) memcpy(pos, assoc_data->ie + offset, noffset - offset); } + drv_mgd_prepare_tx(local, sdata); + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; ieee80211_tx_skb(sdata, skb); } @@ -580,6 +582,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata, if (!(ifmgd->flags & IEEE80211_STA_MFP_ENABLED)) IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + + drv_mgd_prepare_tx(local, sdata); + ieee80211_tx_skb(sdata, skb); } } @@ -902,9 +907,6 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata) if (!mgd->associated) return false; - if (!mgd->associated->beacon_ies) - return false; - if (mgd->flags & (IEEE80211_STA_BEACON_POLL | IEEE80211_STA_CONNECTION_POLL)) return false; @@ -1106,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) } /* MLME */ -static void ieee80211_sta_wmm_params(struct ieee80211_local *local, +static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, u8 *wmm_param, size_t wmm_param_len) { @@ -1117,23 +1119,23 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, u8 *pos, uapsd_queues = 0; if (!local->ops->conf_tx) - return; + return false; if (local->hw.queues < IEEE80211_NUM_ACS) - return; + return false; if (!wmm_param) - return; + return false; if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) - return; + return false; if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) uapsd_queues = ifmgd->uapsd_queues; count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) - return; + return false; ifmgd->wmm_last_param_set = count; pos = wmm_param + 8; @@ -1141,7 +1143,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, memset(¶ms, 0, sizeof(params)); - local->wmm_acm = 0; + sdata->wmm_acm = 0; for (; left >= 4; left -= 4, pos += 4) { int aci = (pos[0] >> 5) & 0x03; int acm = (pos[0] >> 4) & 0x01; @@ -1152,21 +1154,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, case 1: /* AC_BK */ queue = 3; if (acm) - local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ + sdata->wmm_acm |= BIT(1) | BIT(2); /* BK/- */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BK) uapsd = true; break; case 2: /* AC_VI */ queue = 1; if (acm) - local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ + sdata->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VI) uapsd = true; break; case 3: /* AC_VO */ queue = 0; if (acm) - local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ + sdata->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_VO) uapsd = true; break; @@ -1174,7 +1176,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, default: queue = 2; if (acm) - local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ + sdata->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */ if (uapsd_queues & IEEE80211_WMM_IE_STA_QOSINFO_AC_BE) uapsd = true; break; @@ -1186,23 +1188,21 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, params.txop = get_unaligned_le16(pos + 2); params.uapsd = uapsd; -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "WMM queue=%d aci=%d acm=%d aifs=%d " - "cWmin=%d cWmax=%d txop=%d uapsd=%d\n", - queue, aci, acm, - params.aifs, params.cw_min, params.cw_max, - params.txop, params.uapsd); -#endif + mlme_dbg(sdata, + "WMM queue=%d aci=%d acm=%d aifs=%d cWmin=%d cWmax=%d txop=%d uapsd=%d\n", + queue, aci, acm, + params.aifs, params.cw_min, params.cw_max, + params.txop, params.uapsd); sdata->tx_conf[queue] = params; if (drv_conf_tx(local, sdata, queue, ¶ms)) - wiphy_debug(local->hw.wiphy, - "failed to set TX queue parameters for queue %d\n", - queue); + sdata_err(sdata, + "failed to set TX queue parameters for queue %d\n", + queue); } /* enable WMM or activate new settings */ sdata->vif.bss_conf.qos = true; + return true; } static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) @@ -1269,13 +1269,8 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; bss_info_changed |= BSS_CHANGED_ASSOC; - /* set timing information */ - bss_conf->beacon_int = cbss->beacon_interval; - bss_conf->last_tsf = cbss->tsf; - - bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, - cbss->capability, bss->has_erp_value, bss->erp_value); + bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value); sdata->u.mgd.beacon_timeout = usecs_to_jiffies(ieee80211_tu_to_usec( IEEE80211_BEACON_LOSS_COUNT * bss_conf->beacon_int)); @@ -1327,7 +1322,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; u32 changed = 0; - u8 bssid[ETH_ALEN]; ASSERT_MGD_MTX(ifmgd); @@ -1337,10 +1331,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, if (WARN_ON(!ifmgd->associated)) return; - memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); + ieee80211_stop_poll(sdata); ifmgd->associated = NULL; - memset(ifmgd->bssid, 0, ETH_ALEN); /* * we need to commit the associated = NULL change because the @@ -1360,22 +1353,29 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, netif_carrier_off(sdata->dev); mutex_lock(&local->sta_mtx); - sta = sta_info_get(sdata, bssid); + sta = sta_info_get(sdata, ifmgd->bssid); if (sta) { set_sta_flag(sta, WLAN_STA_BLOCK_BA); ieee80211_sta_tear_down_BA_sessions(sta, tx); } mutex_unlock(&local->sta_mtx); + /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ + if (tx) + drv_flush(local, false); + /* deauthenticate/disassociate now */ if (tx || frame_buf) - ieee80211_send_deauth_disassoc(sdata, bssid, stype, reason, - tx, frame_buf); + ieee80211_send_deauth_disassoc(sdata, ifmgd->bssid, stype, + reason, tx, frame_buf); /* flush out frame */ if (tx) drv_flush(local, false); + /* clear bssid only after building the needed mgmt frames */ + memset(ifmgd->bssid, 0, ETH_ALEN); + /* remove AP and TDLS peers */ sta_info_flush(local, sdata); @@ -1565,11 +1565,10 @@ static void ieee80211_mgd_probe_ap(struct ieee80211_sub_if_data *sdata, goto out; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (beacon) - net_dbg_ratelimited("%s: detected beacon loss from AP - sending probe request\n", - sdata->name); -#endif + mlme_dbg_ratelimited(sdata, + "detected beacon loss from AP - sending probe request\n"); + ieee80211_cqm_rssi_notify(&sdata->vif, NL80211_CQM_RSSI_BEACON_LOSS_EVENT, GFP_KERNEL); @@ -1613,6 +1612,7 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, { struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; + struct cfg80211_bss *cbss; struct sk_buff *skb; const u8 *ssid; int ssid_len; @@ -1622,16 +1622,22 @@ struct sk_buff *ieee80211_ap_probereq_get(struct ieee80211_hw *hw, ASSERT_MGD_MTX(ifmgd); - if (!ifmgd->associated) + if (ifmgd->associated) + cbss = ifmgd->associated; + else if (ifmgd->auth_data) + cbss = ifmgd->auth_data->bss; + else if (ifmgd->assoc_data) + cbss = ifmgd->assoc_data->bss; + else return NULL; - ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID); + ssid = ieee80211_bss_get_ie(cbss, WLAN_EID_SSID); if (WARN_ON_ONCE(ssid == NULL)) ssid_len = 0; else ssid_len = ssid[1]; - skb = ieee80211_build_probe_req(sdata, ifmgd->associated->bssid, + skb = ieee80211_build_probe_req(sdata, cbss->bssid, (u32) -1, ssid + 2, ssid_len, NULL, 0, true); @@ -1654,7 +1660,7 @@ static void __ieee80211_connection_loss(struct ieee80211_sub_if_data *sdata) memcpy(bssid, ifmgd->associated->bssid, ETH_ALEN); - pr_debug("%s: Connection to AP %pM lost\n", sdata->name, bssid); + sdata_info(sdata, "Connection to AP %pM lost\n", bssid); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, @@ -1750,6 +1756,7 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata, if (!elems.challenge) return; auth_data->expected_transaction = 4; + drv_mgd_prepare_tx(sdata->local, sdata); ieee80211_send_auth(sdata, 3, auth_data->algorithm, elems.challenge - 2, elems.challenge_len + 2, auth_data->bss->bssid, auth_data->bss->bssid, @@ -1788,8 +1795,8 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; if (status_code != WLAN_STATUS_SUCCESS) { - pr_debug("%s: %pM denied authentication (status %d)\n", - sdata->name, mgmt->sa, status_code); + sdata_info(sdata, "%pM denied authentication (status %d)\n", + mgmt->sa, status_code); ieee80211_destroy_auth_data(sdata, false); return RX_MGMT_CFG80211_RX_AUTH; } @@ -1812,7 +1819,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, return RX_MGMT_NONE; } - pr_debug("%s: authenticated\n", sdata->name); + sdata_info(sdata, "authenticated\n"); ifmgd->auth_data->done = true; ifmgd->auth_data->timeout = jiffies + IEEE80211_AUTH_WAIT_ASSOC; run_again(ifmgd, ifmgd->auth_data->timeout); @@ -1825,7 +1832,7 @@ ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, goto out_err; } if (sta_info_move_state(sta, IEEE80211_STA_AUTH)) { - pr_debug("%s: failed moving %pM to auth\n", sdata->name, bssid); + sdata_info(sdata, "failed moving %pM to auth\n", bssid); goto out_err; } mutex_unlock(&sdata->local->sta_mtx); @@ -1859,8 +1866,8 @@ ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); - pr_debug("%s: deauthenticated from %pM (Reason: %u)\n", - sdata->name, bssid, reason_code); + sdata_info(sdata, "deauthenticated from %pM (Reason: %u)\n", + bssid, reason_code); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1890,8 +1897,8 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); - pr_debug("%s: disassociated from %pM (Reason: %u)\n", - sdata->name, mgmt->sa, reason_code); + sdata_info(sdata, "disassociated from %pM (Reason: %u)\n", + mgmt->sa, reason_code); ieee80211_set_disassoc(sdata, 0, 0, false, NULL); @@ -1983,15 +1990,15 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info); if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14))) - pr_debug("%s: invalid AID value 0x%x; bits 15:14 not set\n", - sdata->name, aid); + sdata_info(sdata, "invalid AID value 0x%x; bits 15:14 not set\n", + aid); aid &= ~(BIT(15) | BIT(14)); ifmgd->broken_ap = false; if (aid == 0 || aid > IEEE80211_MAX_AID) { - pr_debug("%s: invalid AID value %d (out of range), turn off PS\n", - sdata->name, aid); + sdata_info(sdata, "invalid AID value %d (out of range), turn off PS\n", + aid); aid = 0; ifmgd->broken_ap = true; } @@ -2000,8 +2007,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); if (!elems.supp_rates) { - pr_debug("%s: no SuppRates element in AssocResp\n", - sdata->name); + sdata_info(sdata, "no SuppRates element in AssocResp\n"); return false; } @@ -2041,8 +2047,9 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata, if (!err && !(ifmgd->flags & IEEE80211_STA_CONTROL_PORT)) err = sta_info_move_state(sta, IEEE80211_STA_AUTHORIZED); if (err) { - pr_debug("%s: failed to move station %pM to desired state\n", - sdata->name, sta->sta.addr); + sdata_info(sdata, + "failed to move station %pM to desired state\n", + sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); mutex_unlock(&sdata->local->sta_mtx); return false; @@ -2125,9 +2132,10 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - pr_debug("%s: RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", - sdata->name, reassoc ? "Rea" : "A", mgmt->sa, - capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); + sdata_info(sdata, + "RX %sssocResp from %pM (capab=0x%x status=%d aid=%d)\n", + reassoc ? "Rea" : "A", mgmt->sa, + capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); pos = mgmt->u.assoc_resp.variable; ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems); @@ -2138,8 +2146,9 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, u32 tu, ms; tu = get_unaligned_le32(elems.timeout_int + 1); ms = tu * 1024 / 1000; - pr_debug("%s: %pM rejected association temporarily; comeback duration %u TU (%u ms)\n", - sdata->name, mgmt->sa, tu, ms); + sdata_info(sdata, + "%pM rejected association temporarily; comeback duration %u TU (%u ms)\n", + mgmt->sa, tu, ms); assoc_data->timeout = jiffies + msecs_to_jiffies(ms); if (ms > IEEE80211_ASSOC_TIMEOUT) run_again(ifmgd, assoc_data->timeout); @@ -2149,19 +2158,17 @@ ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, *bss = assoc_data->bss; if (status_code != WLAN_STATUS_SUCCESS) { - pr_debug("%s: %pM denied association (code=%d)\n", - sdata->name, mgmt->sa, status_code); + sdata_info(sdata, "%pM denied association (code=%d)\n", + mgmt->sa, status_code); ieee80211_destroy_assoc_data(sdata, false); } else { - pr_debug("%s: associated\n", sdata->name); - if (!ieee80211_assoc_success(sdata, *bss, mgmt, len)) { /* oops -- internal error -- send timeout for now */ - ieee80211_destroy_assoc_data(sdata, true); - sta_info_destroy_addr(sdata, mgmt->bssid); + ieee80211_destroy_assoc_data(sdata, false); cfg80211_put_bss(*bss); return RX_MGMT_CFG80211_ASSOC_TIMEOUT; } + sdata_info(sdata, "associated\n"); /* * destroy assoc_data afterwards, as otherwise an idle @@ -2261,7 +2268,7 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata, if (ifmgd->auth_data && !ifmgd->auth_data->bss->proberesp_ies && ether_addr_equal(mgmt->bssid, ifmgd->auth_data->bss->bssid)) { /* got probe response, continue with auth */ - pr_debug("%s: direct probe responded\n", sdata->name); + sdata_info(sdata, "direct probe responded\n"); ifmgd->auth_data->tries = 0; ifmgd->auth_data->timeout = jiffies; run_again(ifmgd, ifmgd->auth_data->timeout); @@ -2397,10 +2404,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, } if (ifmgd->flags & IEEE80211_STA_BEACON_POLL) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - net_dbg_ratelimited("%s: cancelling probereq poll due to a received beacon\n", - sdata->name); -#endif + mlme_dbg_ratelimited(sdata, + "cancelling probereq poll due to a received beacon\n"); mutex_lock(&local->mtx); ifmgd->flags &= ~IEEE80211_STA_BEACON_POLL; ieee80211_run_deferred_scan(local); @@ -2426,14 +2431,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid); - if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, - true); - - ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, - elems.wmm_param_len); - } - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { if (directed_tim) { if (local->hw.conf.dynamic_ps_timeout > 0) { @@ -2464,6 +2461,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc_valid = true; + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + true); + + if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, + elems.wmm_param_len)) + changed |= BSS_CHANGED_QOS; + if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; erp_value = elems.erp_info[0]; @@ -2592,8 +2596,6 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; u8 frame_buf[DEAUTH_DISASSOC_LEN]; - ieee80211_stop_poll(sdata); - ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, reason, false, frame_buf); mutex_unlock(&ifmgd->mtx); @@ -2625,8 +2627,8 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) auth_data->tries++; if (auth_data->tries > IEEE80211_AUTH_MAX_TRIES) { - pr_debug("%s: authentication with %pM timed out\n", - sdata->name, auth_data->bss->bssid); + sdata_info(sdata, "authentication with %pM timed out\n", + auth_data->bss->bssid); /* * Most likely AP is not in the range so remove the @@ -2637,10 +2639,12 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) return -ETIMEDOUT; } + drv_mgd_prepare_tx(local, sdata); + if (auth_data->bss->proberesp_ies) { - pr_debug("%s: send auth to %pM (try %d/%d)\n", - sdata->name, auth_data->bss->bssid, auth_data->tries, - IEEE80211_AUTH_MAX_TRIES); + sdata_info(sdata, "send auth to %pM (try %d/%d)\n", + auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); auth_data->expected_transaction = 2; ieee80211_send_auth(sdata, 1, auth_data->algorithm, @@ -2650,9 +2654,9 @@ static int ieee80211_probe_auth(struct ieee80211_sub_if_data *sdata) } else { const u8 *ssidie; - pr_debug("%s: direct probe to %pM (try %d/%i)\n", - sdata->name, auth_data->bss->bssid, auth_data->tries, - IEEE80211_AUTH_MAX_TRIES); + sdata_info(sdata, "direct probe to %pM (try %d/%i)\n", + auth_data->bss->bssid, auth_data->tries, + IEEE80211_AUTH_MAX_TRIES); ssidie = ieee80211_bss_get_ie(auth_data->bss, WLAN_EID_SSID); if (!ssidie) @@ -2680,8 +2684,8 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) assoc_data->tries++; if (assoc_data->tries > IEEE80211_ASSOC_MAX_TRIES) { - pr_debug("%s: association with %pM timed out\n", - sdata->name, assoc_data->bss->bssid); + sdata_info(sdata, "association with %pM timed out\n", + assoc_data->bss->bssid); /* * Most likely AP is not in the range so remove the @@ -2692,9 +2696,9 @@ static int ieee80211_do_assoc(struct ieee80211_sub_if_data *sdata) return -ETIMEDOUT; } - pr_debug("%s: associate with %pM (try %d/%d)\n", - sdata->name, assoc_data->bss->bssid, assoc_data->tries, - IEEE80211_ASSOC_MAX_TRIES); + sdata_info(sdata, "associate with %pM (try %d/%d)\n", + assoc_data->bss->bssid, assoc_data->tries, + IEEE80211_ASSOC_MAX_TRIES); ieee80211_send_assoc(sdata); assoc_data->timeout = jiffies + IEEE80211_ASSOC_TIMEOUT; @@ -2767,45 +2771,31 @@ void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata) ieee80211_reset_ap_probe(sdata); else if (ifmgd->nullfunc_failed) { if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No ack for nullfunc frame to" - " AP %pM, try %d/%i\n", - sdata->name, bssid, - ifmgd->probe_send_count, max_tries); -#endif + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, try %d/%i\n", + bssid, ifmgd->probe_send_count, + max_tries); ieee80211_mgd_probe_ap_send(sdata); } else { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No ack for nullfunc frame to" - " AP %pM, disconnecting.\n", - sdata->name, bssid); -#endif + mlme_dbg(sdata, + "No ack for nullfunc frame to AP %pM, disconnecting.\n", + bssid); ieee80211_sta_connection_lost(sdata, bssid, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } } else if (time_is_after_jiffies(ifmgd->probe_timeout)) run_again(ifmgd, ifmgd->probe_timeout); else if (local->hw.flags & IEEE80211_HW_REPORTS_TX_ACK_STATUS) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: Failed to send nullfunc to AP %pM" - " after %dms, disconnecting.\n", - sdata->name, - bssid, probe_wait_ms); -#endif + mlme_dbg(sdata, + "Failed to send nullfunc to AP %pM after %dms, disconnecting\n", + bssid, probe_wait_ms); ieee80211_sta_connection_lost(sdata, bssid, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); } else if (ifmgd->probe_send_count < max_tries) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, - "%s: No probe response from AP %pM" - " after %dms, try %d/%i\n", - sdata->name, - bssid, probe_wait_ms, - ifmgd->probe_send_count, max_tries); -#endif + mlme_dbg(sdata, + "No probe response from AP %pM after %dms, try %d/%i\n", + bssid, probe_wait_ms, + ifmgd->probe_send_count, max_tries); ieee80211_mgd_probe_ap_send(sdata); } else { /* @@ -2920,11 +2910,8 @@ void ieee80211_sta_restart(struct ieee80211_sub_if_data *sdata) sdata->flags &= ~IEEE80211_SDATA_DISCONNECT_RESUME; mutex_lock(&ifmgd->mtx); if (ifmgd->associated) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(sdata->local->hw.wiphy, - "%s: driver requested disconnect after resume.\n", - sdata->name); -#endif + mlme_dbg(sdata, + "driver requested disconnect after resume\n"); ieee80211_sta_connection_lost(sdata, ifmgd->associated->bssid, WLAN_REASON_UNSPECIFIED); @@ -2982,7 +2969,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) /* scan finished notification */ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; /* Restart STA timers */ rcu_read_lock(); @@ -3012,7 +2999,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; struct ieee80211_bss *bss = (void *)cbss->priv; - struct sta_info *sta; + struct sta_info *sta = NULL; bool have_sta = false; int err; int ht_cfreq; @@ -3065,10 +3052,11 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, * since we look at probe response/beacon data here * it should be OK. */ - pr_debug("%s: Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", - sdata->name, cbss->channel->center_freq, - ht_cfreq, ht_oper->primary_chan, - cbss->channel->band); + sdata_info(sdata, + "Wrong control channel: center-freq: %d ht-cfreq: %d ht->primary_chan: %d band: %d - Disabling HT\n", + cbss->channel->center_freq, + ht_cfreq, ht_oper->primary_chan, + cbss->channel->band); ht_oper = NULL; } } @@ -3092,8 +3080,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, if (!ieee80211_set_channel_type(local, sdata, channel_type)) { /* can only fail due to HT40+/- mismatch */ channel_type = NL80211_CHAN_HT20; - pr_debug("%s: disabling 40 MHz due to multi-vif mismatch\n", - sdata->name); + sdata_info(sdata, + "disabling 40 MHz due to multi-vif mismatch\n"); ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ; WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type)); @@ -3102,7 +3090,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, local->oper_channel = cbss->channel; ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); - if (!have_sta) { + if (sta) { u32 rates = 0, basic_rates = 0; bool have_higher_than_11mbit; int min_rate = INT_MAX, min_rate_index = -1; @@ -3122,8 +3110,8 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, * we can connect -- with a warning. */ if (!basic_rates && min_rate_index >= 0) { - pr_debug("%s: No basic rates, using min rate instead\n", - sdata->name); + sdata_info(sdata, + "No basic rates, using min rate instead\n"); basic_rates = BIT(min_rate_index); } @@ -3139,9 +3127,15 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); - /* tell driver about BSSID and basic rates */ + /* set timing information */ + sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; + sdata->vif.bss_conf.sync_tsf = cbss->tsf; + sdata->vif.bss_conf.sync_device_ts = bss->device_ts; + + /* tell driver about BSSID, basic rates and timing */ ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); + BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | + BSS_CHANGED_BEACON_INT); if (assoc) sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); @@ -3149,8 +3143,9 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, err = sta_info_insert(sta); sta = NULL; if (err) { - pr_debug("%s: failed to insert STA entry for the AP (error %d)\n", - sdata->name, err); + sdata_info(sdata, + "failed to insert STA entry for the AP (error %d)\n", + err); return err; } } else @@ -3228,7 +3223,7 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, if (ifmgd->associated) ieee80211_set_disassoc(sdata, 0, 0, false, NULL); - pr_debug("%s: authenticate with %pM\n", sdata->name, req->bss->bssid); + sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); err = ieee80211_prep_connection(sdata, req->bss, false); if (err) @@ -3410,8 +3405,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, * Wait up to one beacon interval ... * should this be more if we miss one? */ - pr_debug("%s: waiting for beacon from %pM\n", - sdata->name, ifmgd->bssid); + sdata_info(sdata, "waiting for beacon from %pM\n", + ifmgd->bssid); assoc_data->timeout = TU_TO_EXP_TIME(req->bss->beacon_interval); } else { assoc_data->have_beacon = true; @@ -3430,8 +3425,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, corrupt_type = "beacon"; } else if (bss->corrupt_data & IEEE80211_BSS_CORRUPT_PROBE_RESP) corrupt_type = "probe response"; - pr_debug("%s: associating with AP with corrupt %s\n", - sdata->name, corrupt_type); + sdata_info(sdata, "associating with AP with corrupt %s\n", + corrupt_type); } err = 0; @@ -3460,8 +3455,9 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, return 0; } - pr_debug("%s: deauthenticating from %pM by local choice (reason=%d)\n", - sdata->name, req->bssid, req->reason_code); + sdata_info(sdata, + "deauthenticating from %pM by local choice (reason=%d)\n", + req->bssid, req->reason_code); if (ifmgd->associated && ether_addr_equal(ifmgd->associated->bssid, req->bssid)) @@ -3503,8 +3499,9 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, return -ENOLINK; } - pr_debug("%s: disassociating from %pM by local choice (reason=%d)\n", - sdata->name, req->bss->bssid, req->reason_code); + sdata_info(sdata, + "disassociating from %pM by local choice (reason=%d)\n", + req->bss->bssid, req->reason_code); memcpy(bssid, req->bss->bssid, ETH_ALEN); ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DISASSOC, diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index abb226dc4753..8c047fc8b325 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -15,7 +15,6 @@ #include <linux/export.h> #include <net/mac80211.h> #include "ieee80211_i.h" -#include "driver-trace.h" #include "driver-ops.h" /* @@ -25,8 +24,7 @@ * because we *may* be doing work on-operating channel, and want our * hardware unconditionally awake, but still let the AP send us normal frames. */ -static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, - bool tell_ap) +static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata) { struct ieee80211_local *local = sdata->local; struct ieee80211_if_managed *ifmgd = &sdata->u.mgd; @@ -47,8 +45,8 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata, ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - if (tell_ap && (!local->offchannel_ps_enabled || - !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK))) + if (!local->offchannel_ps_enabled || + !(local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)) /* * If power save was enabled, no need to send a nullfunc * frame because AP knows that we are sleeping. But if the @@ -133,7 +131,7 @@ void ieee80211_offchannel_stop_vifs(struct ieee80211_local *local, if (offchannel_ps_enable && (sdata->vif.type == NL80211_IFTYPE_STATION) && sdata->u.mgd.associated) - ieee80211_offchannel_ps_enable(sdata, true); + ieee80211_offchannel_ps_enable(sdata); } } mutex_unlock(&local->iflist_mtx); @@ -193,7 +191,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) roc->frame = NULL; } } else { - cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc, + cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, roc->chan, roc->chan_type, roc->req_duration, GFP_KERNEL); } @@ -263,6 +261,9 @@ void ieee80211_start_next_roc(struct ieee80211_local *local) roc = list_first_entry(&local->roc_list, struct ieee80211_roc_work, list); + if (WARN_ON_ONCE(roc->started)) + return; + if (local->ops->remain_on_channel) { int ret, duration = roc->duration; @@ -298,7 +299,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) /* was never transmitted */ if (roc->frame) { - cfg80211_mgmt_tx_status(roc->sdata->dev, + cfg80211_mgmt_tx_status(&roc->sdata->wdev, (unsigned long)roc->frame, roc->frame->data, roc->frame->len, false, GFP_KERNEL); @@ -306,7 +307,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) } if (!roc->mgmt_tx_cookie) - cfg80211_remain_on_channel_expired(roc->sdata->dev, + cfg80211_remain_on_channel_expired(&roc->sdata->wdev, (unsigned long)roc, roc->chan, roc->chan_type, GFP_KERNEL); @@ -378,8 +379,8 @@ void ieee80211_sw_roc_work(struct work_struct *work) ieee80211_recalc_idle(local); - ieee80211_start_next_roc(local); - ieee80211_run_deferred_scan(local); + if (roc->started) + ieee80211_start_next_roc(local); } out_unlock: @@ -410,9 +411,6 @@ static void ieee80211_hw_roc_done(struct work_struct *work) /* if there's another roc, start it now */ ieee80211_start_next_roc(local); - /* or scan maybe */ - ieee80211_run_deferred_scan(local); - out_unlock: mutex_unlock(&local->mtx); } @@ -455,7 +453,6 @@ void ieee80211_roc_purge(struct ieee80211_sub_if_data *sdata) } ieee80211_start_next_roc(local); - ieee80211_run_deferred_scan(local); mutex_unlock(&local->mtx); list_for_each_entry_safe(roc, tmp, &tmp_list, list) { diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c index 98c128be3827..5c572e7a1a71 100644 --- a/net/mac80211/pm.c +++ b/net/mac80211/pm.c @@ -78,6 +78,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) if (err < 0) { local->quiescing = false; local->wowlan = false; + if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) { + mutex_lock(&local->sta_mtx); + list_for_each_entry(sta, + &local->sta_list, list) { + clear_sta_flag(sta, WLAN_STA_BLOCK_BA); + } + mutex_unlock(&local->sta_mtx); + } + ieee80211_wake_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_SUSPEND); return err; } else if (err > 0) { WARN_ON(err != 1); diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index 2d1acc6c5445..fb1d4aa65e8c 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, #ifdef CONFIG_MAC80211_DEBUGFS /* use fixed index if set */ - if (mp->fixed_rate_idx != -1) - sample_idx = mp->fixed_rate_idx; + if (mp->fixed_rate_idx != -1) { + mi->max_tp_rate = mp->fixed_rate_idx; + mi->max_tp_rate2 = mp->fixed_rate_idx; + mi->max_prob_rate = mp->fixed_rate_idx; + sample_idx = -1; + } #endif if (sample_idx >= 0) { @@ -809,7 +813,7 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) max_rates = sband->n_bitrates; } - msp = kzalloc(sizeof(struct minstrel_ht_sta), gfp); + msp = kzalloc(sizeof(*msp), gfp); if (!msp) return NULL; diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 6fd2cb0838c4..090d417919af 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) /* rx handlers */ -static ieee80211_rx_result debug_noinline -ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - struct sk_buff *skb = rx->skb; - - if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !local->sched_scanning)) - return RX_CONTINUE; - - if (test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - local->sched_scanning) - return ieee80211_scan_rx(rx->sdata, skb); - - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return RX_DROP_UNUSABLE; -} - - static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -554,11 +531,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) } -static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, int index) { - struct ieee80211_local *local = hw_to_local(hw); + struct ieee80211_local *local = sdata->local; struct sk_buff *skb = tid_agg_rx->reorder_buf[index]; struct ieee80211_rx_status *status; @@ -578,7 +555,7 @@ no_frame: tid_agg_rx->head_seq_num = seq_inc(tid_agg_rx->head_seq_num); } -static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, +static void ieee80211_release_reorder_frames(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, u16 head_seq_num) { @@ -589,7 +566,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) { index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); } } @@ -604,7 +581,7 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw, */ #define HT_RX_REORDER_BUF_TIMEOUT (HZ / 10) -static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, +static void ieee80211_sta_reorder_release(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx) { int index, j; @@ -632,12 +609,9 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, HT_RX_REORDER_BUF_TIMEOUT)) goto set_release_timer; -#ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) - wiphy_debug(hw->wiphy, - "release an RX reorder frame due to timeout on earlier frames\n"); -#endif - ieee80211_release_reorder_frame(hw, tid_agg_rx, j); + ht_dbg_ratelimited(sdata, + "release an RX reorder frame due to timeout on earlier frames\n"); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, j); /* * Increment the head seq# also for the skipped slots. @@ -647,7 +621,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, skipped = 0; } } else while (tid_agg_rx->reorder_buf[index]) { - ieee80211_release_reorder_frame(hw, tid_agg_rx, index); + ieee80211_release_reorder_frame(sdata, tid_agg_rx, index); index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) % tid_agg_rx->buf_size; } @@ -677,7 +651,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw, * rcu_read_lock protection. It returns false if the frame * can be processed immediately, true if it was consumed. */ -static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, +static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_sub_if_data *sdata, struct tid_ampdu_rx *tid_agg_rx, struct sk_buff *skb) { @@ -706,7 +680,8 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, if (!seq_less(mpdu_seq_num, head_seq_num + buf_size)) { head_seq_num = seq_inc(seq_sub(mpdu_seq_num, buf_size)); /* release stored frames up to new head to stack */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, head_seq_num); + ieee80211_release_reorder_frames(sdata, tid_agg_rx, + head_seq_num); } /* Now the new frame is always in the range of the reordering buffer */ @@ -736,7 +711,7 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, tid_agg_rx->reorder_buf[index] = skb; tid_agg_rx->reorder_time[index] = jiffies; tid_agg_rx->stored_mpdu_num++; - ieee80211_sta_reorder_release(hw, tid_agg_rx); + ieee80211_sta_reorder_release(sdata, tid_agg_rx); out: spin_unlock(&tid_agg_rx->reorder_lock); @@ -751,7 +726,6 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) { struct sk_buff *skb = rx->skb; struct ieee80211_local *local = rx->local; - struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct sta_info *sta = rx->sta; @@ -813,7 +787,7 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx) * sure that we cannot get to it any more before doing * anything with it. */ - if (ieee80211_sta_manage_reorder_buf(hw, tid_agg_rx, skb)) + if (ieee80211_sta_manage_reorder_buf(rx->sdata, tid_agg_rx, skb)) return; dont_reorder: @@ -1136,24 +1110,18 @@ static void ap_sta_ps_start(struct sta_info *sta) set_sta_flag(sta, WLAN_STA_PS_STA); if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS)) drv_sta_notify(local, sdata, STA_NOTIFY_SLEEP, &sta->sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("%s: STA %pM aid %d enters power save mode\n", - sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", + sta->sta.addr, sta->sta.aid); } static void ap_sta_ps_end(struct sta_info *sta) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("%s: STA %pM aid %d exits power save mode\n", - sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sta->sdata, "STA %pM aid %d exits power save mode\n", + sta->sta.addr, sta->sta.aid); if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("%s: STA %pM aid %d driver-ps-blocked\n", - sta->sdata->name, sta->sta.addr, sta->sta.aid); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", + sta->sta.addr, sta->sta.aid); return; } @@ -1383,17 +1351,8 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, if (sdata->fragment_next >= IEEE80211_FRAGMENT_MAX) sdata->fragment_next = 0; - if (!skb_queue_empty(&entry->skb_list)) { -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - struct ieee80211_hdr *hdr = - (struct ieee80211_hdr *) entry->skb_list.next->data; - pr_debug("%s: RX reassembly removed oldest fragment entry (idx=%d age=%lu seq=%d last_frag=%d addr1=%pM addr2=%pM\n", - sdata->name, idx, - jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, hdr->addr1, hdr->addr2); -#endif + if (!skb_queue_empty(&entry->skb_list)) __skb_queue_purge(&entry->skb_list); - } __skb_queue_tail(&entry->skb_list, *skb); /* no need for locking */ *skb = NULL; @@ -1751,7 +1710,7 @@ ieee80211_deliver_skb(struct ieee80211_rx_data *rx) */ xmit_skb = skb_copy(skb, GFP_ATOMIC); if (!xmit_skb) - net_dbg_ratelimited("%s: failed to clone multicast frame\n", + net_info_ratelimited("%s: failed to clone multicast frame\n", dev->name); } else { dsta = sta_info_get(sdata, skb->data); @@ -1935,7 +1894,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) ether_addr_equal(sdata->vif.addr, hdr->addr3)) return RX_CONTINUE; - q = ieee80211_select_queue_80211(local, skb, hdr); + q = ieee80211_select_queue_80211(sdata, skb, hdr); if (ieee80211_queue_stopped(&local->hw, q)) { IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_congestion); return RX_DROP_MONITOR; @@ -1955,7 +1914,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx) fwd_skb = skb_copy(skb, GFP_ATOMIC); if (!fwd_skb) { - net_dbg_ratelimited("%s: failed to clone mesh frame\n", + net_info_ratelimited("%s: failed to clone mesh frame\n", sdata->name); goto out; } @@ -2058,8 +2017,6 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx) static ieee80211_rx_result debug_noinline ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) { - struct ieee80211_local *local = rx->local; - struct ieee80211_hw *hw = &local->hw; struct sk_buff *skb = rx->skb; struct ieee80211_bar *bar = (struct ieee80211_bar *)skb->data; struct tid_ampdu_rx *tid_agg_rx; @@ -2096,7 +2053,8 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx) spin_lock(&tid_agg_rx->reorder_lock); /* release stored frames up to start of BAR */ - ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num); + ieee80211_release_reorder_frames(rx->sdata, tid_agg_rx, + start_seq_num); spin_unlock(&tid_agg_rx->reorder_lock); kfree_skb(skb); @@ -2423,7 +2381,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) sig = status->signal; - if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, + if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, rx->skb->data, rx->skb->len, GFP_ATOMIC)) { if (rx->sta) @@ -2453,7 +2411,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) * frames that we didn't handle, including returning unknown * ones. For all other modes we will return them to the sender, * setting the 0x80 bit in the action category, as required by - * 802.11-2007 7.3.1.11. + * 802.11-2012 9.24.4. * Newer versions of hostapd shall also use the management frame * registration mechanisms, but older ones still use cooked * monitor interfaces so push all frames there. @@ -2463,6 +2421,9 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx) sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) return RX_DROP_MONITOR; + if (is_multicast_ether_addr(mgmt->da)) + return RX_DROP_MONITOR; + /* do not return rejected action frames */ if (mgmt->u.action.category & 0x80) return RX_DROP_UNUSABLE; @@ -2711,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) goto rxh_next; \ } while (0); - CALL_RXH(ieee80211_rx_h_passive_scan) CALL_RXH(ieee80211_rx_h_check) ieee80211_rx_reorder_ampdu(rx); @@ -2747,7 +2707,7 @@ void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid) return; spin_lock(&tid_agg_rx->reorder_lock); - ieee80211_sta_reorder_release(&sta->local->hw, tid_agg_rx); + ieee80211_sta_reorder_release(sta->sdata, tid_agg_rx); spin_unlock(&tid_agg_rx->reorder_lock); ieee80211_rx_handlers(&rx); @@ -2781,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 0; if (ieee80211_is_beacon(hdr->frame_control)) { return 1; - } - else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) - return 0; - status->rx_flags &= ~IEEE80211_RX_RA_MATCH; + } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { + return 0; } else if (!multicast && !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { if (!(sdata->dev->flags & IFF_PROMISC)) @@ -2823,11 +2780,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, * and location updates. Note that mac80211 * itself never looks at these frames. */ - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - ieee80211_is_public_action(hdr, skb->len)) + if (ieee80211_is_public_action(hdr, skb->len)) return 1; - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !ieee80211_is_beacon(hdr->frame_control)) + if (!ieee80211_is_beacon(hdr->frame_control)) return 0; status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } @@ -2893,7 +2848,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2911,11 +2865,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) local->dot11ReceivedFragmentCount++; - if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning))) - status->rx_flags |= IEEE80211_RX_IN_SCAN; - if (ieee80211_is_mgmt(fc)) err = skb_linearize(skb); else @@ -2930,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control))) + ieee80211_scan_rx(local, skb); + if (ieee80211_is_data(fc)) { prev_sta = NULL; @@ -3027,6 +2980,10 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb) if (unlikely(local->quiescing || local->suspended)) goto drop; + /* We might be during a HW reconfig, prevent Rx for the same reason */ + if (unlikely(local->in_reconfig)) + goto drop; + /* * The same happens when we're not even started, * but that's worth a warning. diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 379f178eab5f..e80a8b644aa0 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, mgmt, len, signal, GFP_ATOMIC); - if (!cbss) return NULL; cbss->free_priv = ieee80211_rx_bss_free; bss = (void *)cbss->priv; + bss->device_ts = rx_status->device_timestamp; + if (elems->parse_error) { if (beacon) bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; @@ -165,52 +166,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local, return bss; } -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_mgmt *mgmt; + struct ieee80211_sub_if_data *sdata1, *sdata2; + struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_bss *bss; u8 *elements; struct ieee80211_channel *channel; size_t baselen; int freq; - __le16 fc; - bool presp, beacon = false; + bool beacon; struct ieee802_11_elems elems; - if (skb->len < 2) - return RX_DROP_UNUSABLE; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = mgmt->frame_control; + if (skb->len < 24 || + (!ieee80211_is_probe_resp(mgmt->frame_control) && + !ieee80211_is_beacon(mgmt->frame_control))) + return; - if (ieee80211_is_ctl(fc)) - return RX_CONTINUE; + sdata1 = rcu_dereference(local->scan_sdata); + sdata2 = rcu_dereference(local->sched_scan_sdata); - if (skb->len < 24) - return RX_CONTINUE; + if (likely(!sdata1 && !sdata2)) + return; - presp = ieee80211_is_probe_resp(fc); - if (presp) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { /* ignore ProbeResp to foreign address */ - if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) - return RX_DROP_MONITOR; + if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && + (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) + return; - presp = true; elements = mgmt->u.probe_resp.variable; baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + beacon = false; } else { - beacon = ieee80211_is_beacon(fc); baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); elements = mgmt->u.beacon.variable; + beacon = true; } - if (!presp && !beacon) - return RX_CONTINUE; - if (baselen > skb->len) - return RX_DROP_MONITOR; + return; ieee802_11_parse_elems(elements, skb->len - baselen, &elems); @@ -220,22 +216,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) else freq = rx_status->freq; - channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) - return RX_DROP_MONITOR; + return; - bss = ieee80211_bss_info_update(sdata->local, rx_status, + bss = ieee80211_bss_info_update(local, rx_status, mgmt, skb->len, &elems, channel, beacon); if (bss) - ieee80211_rx_bss_put(sdata->local, bss); - - if (channel == sdata->local->oper_channel) - return RX_CONTINUE; - - dev_kfree_skb(skb); - return RX_QUEUED; + ieee80211_rx_bss_put(local, bss); } /* return false if no more work */ @@ -293,7 +283,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, return; if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { - int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); + int rc; + + rc = drv_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)), + local->hw_scan_req); + if (rc == 0) return; } @@ -394,7 +390,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) if (!local->scan_req || local->scanning) return; - if (!ieee80211_can_scan(local, local->scan_sdata)) + if (!ieee80211_can_scan(local, + rcu_dereference_protected( + local->scan_sdata, + lockdep_is_held(&local->mtx)))) return; ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -405,9 +404,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay) { int i; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; enum ieee80211_band band = local->hw.conf.channel->band; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx));; + for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( sdata, NULL, @@ -439,7 +441,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (!ieee80211_can_scan(local, sdata)) { /* wait for the work to finish/time out */ local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); return 0; } @@ -473,7 +475,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); @@ -533,7 +535,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); } return rc; @@ -720,7 +722,8 @@ void ieee80211_scan_work(struct work_struct *work) mutex_lock(&local->mtx); - sdata = local->scan_sdata; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); /* When scanning on-channel, the first-callback means completed. */ if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { @@ -741,7 +744,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); rc = __ieee80211_start_scan(sdata, req); if (rc) { @@ -893,7 +896,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { if (local->ops->cancel_hw_scan) - drv_cancel_hw_scan(local, local->scan_sdata); + drv_cancel_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx))); goto out; } @@ -915,9 +920,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; int ret, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { ret = -EBUSY; goto out; } @@ -928,6 +933,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, } for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + if (!local->hw.wiphy->bands[i]) + continue; + local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + @@ -948,7 +956,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, ret = drv_sched_scan_start(local, sdata, req, &local->sched_scan_ies); if (ret == 0) { - local->sched_scanning = true; + rcu_assign_pointer(local->sched_scan_sdata, sdata); goto out; } @@ -956,7 +964,7 @@ out_free: while (i > 0) kfree(local->sched_scan_ies.ie[--i]); out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -965,22 +973,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; int ret = 0, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); if (!local->ops->sched_scan_stop) { ret = -ENOTSUPP; goto out; } - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); drv_sched_scan_stop(local, sdata); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); } out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -1004,7 +1012,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) mutex_lock(&local->mtx); - if (!local->sched_scanning) { + if (!rcu_access_pointer(local->sched_scan_sdata)) { mutex_unlock(&local->mtx); return; } @@ -1012,7 +1020,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); mutex_unlock(&local->mtx); diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index 77dcf2f89d42..06fa75ceb025 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -169,9 +169,7 @@ void sta_info_free(struct ieee80211_local *local, struct sta_info *sta) if (sta->rate_ctrl) rate_control_free_sta(sta); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Destroyed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sta->sdata, "Destroyed STA %pM\n", sta->sta.addr); kfree(sta); } @@ -278,9 +276,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, for (i = 0; i < NUM_RX_DATA_QUEUES; i++) sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Allocated STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr); #ifdef CONFIG_MAC80211_MESH sta->plink_state = NL80211_PLINK_LISTEN; @@ -333,8 +329,9 @@ static int sta_info_insert_drv_state(struct ieee80211_local *local, } if (sdata->vif.type == NL80211_IFTYPE_ADHOC) { - pr_debug("%s: failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n", - sdata->name, sta->sta.addr, state + 1, err); + sdata_info(sdata, + "failed to move IBSS STA %pM to state %d (%d) - keeping it anyway\n", + sta->sta.addr, state + 1, err); err = 0; } @@ -389,9 +386,7 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) sinfo.generation = local->sta_generation; cfg80211_new_sta(sdata->dev, sta->sta.addr, &sinfo, GFP_KERNEL); -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Inserted STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Inserted STA %pM\n", sta->sta.addr); /* move reference to rcu-protected */ rcu_read_lock(); @@ -617,9 +612,8 @@ static bool sta_info_cleanup_expire_buffered_ac(struct ieee80211_local *local, break; local->total_ps_buffered--; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("Buffered frame expired (STA %pM)\n", sta->sta.addr); -#endif + ps_dbg(sta->sdata, "Buffered frame expired (STA %pM)\n", + sta->sta.addr); dev_kfree_skb(skb); } @@ -745,9 +739,8 @@ int __must_check __sta_info_destroy(struct sta_info *sta) mesh_accept_plinks_update(sdata); #endif -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - wiphy_debug(local->hw.wiphy, "Removed STA %pM\n", sta->sta.addr); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sta_dbg(sdata, "Removed STA %pM\n", sta->sta.addr); + cancel_work_sync(&sta->drv_unblock_wk); cfg80211_del_sta(sdata->dev, sta->sta.addr, GFP_KERNEL); @@ -887,8 +880,8 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, continue; if (time_after(jiffies, sta->last_rx + exp_time)) { - ibss_vdbg("%s: expiring inactive STA %pM\n", - sdata->name, sta->sta.addr); + ibss_dbg(sdata, "expiring inactive STA %pM\n", + sta->sta.addr); WARN_ON(__sta_info_destroy(sta)); } } @@ -986,10 +979,9 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) sta_info_recalc_tim(sta); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("%s: STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n", - sdata->name, sta->sta.addr, sta->sta.aid, filtered, buffered); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sdata, + "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n", + sta->sta.addr, sta->sta.aid, filtered, buffered); } static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, @@ -1379,10 +1371,8 @@ int sta_info_move_state(struct sta_info *sta, return -EINVAL; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - pr_debug("%s: moving STA %pM to state %d\n", - sta->sdata->name, sta->sta.addr, new_state); -#endif + sta_dbg(sta->sdata, "moving STA %pM to state %d\n", + sta->sta.addr, new_state); /* * notify the driver before the actual changes so it can diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 3bb24a121c95..a470e1123a55 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -271,6 +271,9 @@ struct sta_ampdu_mlme { * @plink_timer: peer link watch timer * @plink_timer_was_running: used by suspend/resume to restore timers * @t_offset: timing offset relative to this host + * @t_offset_setpoint: reference timing offset of this sta to be used when + * calculating clockdrift + * @ch_type: peer's channel type * @debugfs: debug filesystem info * @dead: set to true when sta is unlinked * @uploaded: set to true when sta is uploaded to the driver @@ -278,6 +281,8 @@ struct sta_ampdu_mlme { * @sta: station information we share with the driver * @sta_state: duplicates information about station state (for debug) * @beacon_loss_count: number of times beacon loss has triggered + * @supports_40mhz: tracks whether the station advertised 40 MHz support + * as we overwrite its HT parameters with the currently used value */ struct sta_info { /* General information, mostly static */ diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 6b4f42527887..8cd72914cdaf 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -155,13 +155,10 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } -#ifdef CONFIG_MAC80211_VERBOSE_DEBUG - if (net_ratelimit()) - wiphy_debug(local->hw.wiphy, - "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", - skb_queue_len(&sta->tx_filtered[ac]), - !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); -#endif + ps_dbg_ratelimited(sta->sdata, + "dropped TX filtered frame, queue_len=%d PS=%d @%lu\n", + skb_queue_len(&sta->tx_filtered[ac]), + !!test_sta_flag(sta, WLAN_STA_PS_STA), jiffies); dev_kfree_skb(skb); } @@ -522,14 +519,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) u64 cookie = (unsigned long)skb; acked = info->flags & IEEE80211_TX_STAT_ACK; + /* + * TODO: When we have non-netdev frame TX, + * we cannot use skb->dev->ieee80211_ptr + */ + if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) cfg80211_probe_status(skb->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); else cfg80211_mgmt_tx_status( - skb->dev, cookie, skb->data, skb->len, - acked, GFP_ATOMIC); + skb->dev->ieee80211_ptr, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); } if (unlikely(info->ack_frame_id)) { diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 68be47ca208f..57e14d59e12f 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -260,16 +260,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, keyid = pos[3]; iv32 = get_unaligned_le32(pos + 4); pos += 8; -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - pr_debug("TKIP decrypt: data(len=%zd)", payload_len); - for (i = 0; i < payload_len; i++) - printk(" %02x", payload[i]); - printk("\n"); - pr_debug("TKIP decrypt: iv16=%04x iv32=%08x\n", iv16, iv32); - } -#endif if (!(keyid & (1 << 5))) return TKIP_DECRYPT_NO_EXT_IV; @@ -280,15 +270,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, if (key->u.tkip.rx[queue].state != TKIP_STATE_NOT_INIT && (iv32 < key->u.tkip.rx[queue].iv32 || (iv32 == key->u.tkip.rx[queue].iv32 && - iv16 <= key->u.tkip.rx[queue].iv16))) { -#ifdef CONFIG_MAC80211_TKIP_DEBUG - pr_debug("TKIP replay detected for RX frame from %pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - ta, iv32, iv16, - key->u.tkip.rx[queue].iv32, - key->u.tkip.rx[queue].iv16); -#endif + iv16 <= key->u.tkip.rx[queue].iv16))) return TKIP_DECRYPT_REPLAY; - } if (only_iv) { res = TKIP_DECRYPT_OK; @@ -300,21 +283,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, key->u.tkip.rx[queue].iv32 != iv32) { /* IV16 wrapped around - perform TKIP phase 1 */ tkip_mixing_phase1(tk, &key->u.tkip.rx[queue], ta, iv32); -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; - pr_debug("TKIP decrypt: Phase1 TA=%pM TK=", ta); - for (i = 0; i < 16; i++) - printk("%02x ", - key->conf.key[key_offset + i]); - printk("\n"); - pr_debug("TKIP decrypt: P1K="); - for (i = 0; i < 5; i++) - printk("%04x ", key->u.tkip.rx[queue].p1k[i]); - printk("\n"); - } -#endif } if (key->local->ops->update_tkip_key && key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE && @@ -330,15 +298,6 @@ int ieee80211_tkip_decrypt_data(struct crypto_cipher *tfm, } tkip_mixing_phase2(tk, &key->u.tkip.rx[queue], iv16, rc4key); -#ifdef CONFIG_MAC80211_TKIP_DEBUG - { - int i; - pr_debug("TKIP decrypt: Phase2 rc4key="); - for (i = 0; i < 16; i++) - printk("%02x ", rc4key[i]); - printk("\n"); - } -#endif res = ieee80211_wep_decrypt_data(tfm, rc4key, 16, pos, payload_len - 12); done: diff --git a/net/mac80211/trace.c b/net/mac80211/trace.c new file mode 100644 index 000000000000..386e45d8a958 --- /dev/null +++ b/net/mac80211/trace.c @@ -0,0 +1,75 @@ +/* bug in tracepoint.h, it should include this */ +#include <linux/module.h> + +/* sparse isn't too happy with all macros... */ +#ifndef __CHECKER__ +#include <net/cfg80211.h> +#include "driver-ops.h" +#include "debug.h" +#define CREATE_TRACE_POINTS +#include "trace.h" + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +void __sdata_info(const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + pr_info("%pV", &vaf); + trace_mac80211_info(&vaf); + va_end(args); +} + +void __sdata_dbg(bool print, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + if (print) + pr_debug("%pV", &vaf); + trace_mac80211_dbg(&vaf); + va_end(args); +} + +void __sdata_err(const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + pr_err("%pV", &vaf); + trace_mac80211_err(&vaf); + va_end(args); +} + +void __wiphy_dbg(struct wiphy *wiphy, bool print, const char *fmt, ...) +{ + struct va_format vaf = { + .fmt = fmt, + }; + va_list args; + + va_start(args, fmt); + vaf.va = &args; + + if (print) + wiphy_dbg(wiphy, "%pV", &vaf); + trace_mac80211_dbg(&vaf); + va_end(args); +} +#endif +#endif diff --git a/net/mac80211/driver-trace.h b/net/mac80211/trace.h index 6de00b2c268c..c6d33b55b2df 100644 --- a/net/mac80211/driver-trace.h +++ b/net/mac80211/trace.h @@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u8, dtimper) __field(u16, bcnint) __field(u16, assoc_cap) - __field(u64, timestamp) + __field(u64, sync_tsf) + __field(u32, sync_device_ts) __field(u32, basic_rates) __field(u32, changed) __field(bool, enable_beacon) @@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed, __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; __entry->assoc_cap = info->assoc_capability; - __entry->timestamp = info->last_tsf; + __entry->sync_tsf = info->sync_tsf; + __entry->sync_device_ts = info->sync_device_ts; __entry->basic_rates = info->basic_rates; __entry->enable_beacon = info->enable_beacon; __entry->ht_operation_mode = info->ht_operation_mode; @@ -1218,6 +1220,39 @@ DEFINE_EVENT(release_evt, drv_allow_buffered_frames, TP_ARGS(local, sta, tids, num_frames, reason, more_data) ); +TRACE_EVENT(drv_get_rssi, + TP_PROTO(struct ieee80211_local *local, struct ieee80211_sta *sta, + s8 rssi, int ret), + + TP_ARGS(local, sta, rssi, ret), + + TP_STRUCT__entry( + LOCAL_ENTRY + STA_ENTRY + __field(s8, rssi) + __field(int, ret) + ), + + TP_fast_assign( + LOCAL_ASSIGN; + STA_ASSIGN; + __entry->rssi = rssi; + __entry->ret = ret; + ), + + TP_printk( + LOCAL_PR_FMT STA_PR_FMT " rssi:%d ret:%d", + LOCAL_PR_ARG, STA_PR_ARG, __entry->rssi, __entry->ret + ) +); + +DEFINE_EVENT(local_sdata_evt, drv_mgd_prepare_tx, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata), + + TP_ARGS(local, sdata) +); + /* * Tracing for API calls that drivers call. */ @@ -1606,10 +1641,49 @@ TRACE_EVENT(stop_queue, LOCAL_PR_ARG, __entry->queue, __entry->reason ) ); + +#ifdef CONFIG_MAC80211_MESSAGE_TRACING +#undef TRACE_SYSTEM +#define TRACE_SYSTEM mac80211_msg + +#define MAX_MSG_LEN 100 + +DECLARE_EVENT_CLASS(mac80211_msg_event, + TP_PROTO(struct va_format *vaf), + + TP_ARGS(vaf), + + TP_STRUCT__entry( + __dynamic_array(char, msg, MAX_MSG_LEN) + ), + + TP_fast_assign( + WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg), + MAX_MSG_LEN, vaf->fmt, + *vaf->va) >= MAX_MSG_LEN); + ), + + TP_printk("%s", __get_str(msg)) +); + +DEFINE_EVENT(mac80211_msg_event, mac80211_info, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_dbg, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +DEFINE_EVENT(mac80211_msg_event, mac80211_err, + TP_PROTO(struct va_format *vaf), + TP_ARGS(vaf) +); +#endif + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ #undef TRACE_INCLUDE_PATH #define TRACE_INCLUDE_PATH . #undef TRACE_INCLUDE_FILE -#define TRACE_INCLUDE_FILE driver-trace +#define TRACE_INCLUDE_FILE trace #include <trace/define_trace.h> diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index af25c4e7ec5c..b755e778b0c4 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -140,6 +140,8 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, if (r->flags & IEEE80211_RATE_MANDATORY_A) mrate = r->bitrate; break; + case IEEE80211_BAND_60GHZ: + /* TODO, for now fall through */ case IEEE80211_NUM_BANDS: WARN_ON(1); break; @@ -175,12 +177,6 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, return cpu_to_le16(dur); } -static inline int is_ieee80211_device(struct ieee80211_local *local, - struct net_device *dev) -{ - return local == wdev_priv(dev->ieee80211_ptr); -} - /* tx handlers */ static ieee80211_tx_result debug_noinline ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx) @@ -297,9 +293,10 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) if (unlikely(!assoc && ieee80211_is_data(hdr->frame_control))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - pr_debug("%s: dropped data frame to not associated station %pM\n", - tx->sdata->name, hdr->addr1); -#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ + sdata_info(tx->sdata, + "dropped data frame to not associated station %pM\n", + hdr->addr1); +#endif I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TX_DROP; } @@ -366,10 +363,7 @@ static void purge_old_ps_buffers(struct ieee80211_local *local) rcu_read_unlock(); local->total_ps_buffered = total; -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - wiphy_debug(local->hw.wiphy, "PS buffers full - purged %d frames\n", - purged); -#endif + ps_dbg_hw(&local->hw, "PS buffers full - purged %d frames\n", purged); } static ieee80211_tx_result @@ -411,10 +405,8 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx) purge_old_ps_buffers(tx->local); if (skb_queue_len(&tx->sdata->bss->ps_bc_buf) >= AP_MAX_BC_BUFFER) { -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - net_dbg_ratelimited("%s: BC TX buffer full - dropping the oldest frame\n", - tx->sdata->name); -#endif + ps_dbg(tx->sdata, + "BC TX buffer full - dropping the oldest frame\n"); dev_kfree_skb(skb_dequeue(&tx->sdata->bss->ps_bc_buf)); } else tx->local->total_ps_buffered++; @@ -465,18 +457,15 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) return TX_CONTINUE; } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - pr_debug("STA %pM aid %d: PS buffer for AC %d\n", - sta->sta.addr, sta->sta.aid, ac); -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ + ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n", + sta->sta.addr, sta->sta.aid, ac); if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) purge_old_ps_buffers(tx->local); if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - net_dbg_ratelimited("%s: STA %pM TX buffer for AC %d full - dropping oldest frame\n", - tx->sdata->name, sta->sta.addr, ac); -#endif + ps_dbg(tx->sdata, + "STA %pM TX buffer for AC %d full - dropping oldest frame\n", + sta->sta.addr, ac); dev_kfree_skb(old); } else tx->local->total_ps_buffered++; @@ -498,13 +487,11 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) sta_info_recalc_tim(sta); return TX_QUEUED; + } else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { + ps_dbg(tx->sdata, + "STA %pM in PS mode, but polling/in SP -> send frame\n", + sta->sta.addr); } -#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - else if (unlikely(test_sta_flag(sta, WLAN_STA_PS_STA))) { - pr_debug("%s: STA %pM in PS mode, but polling/in SP -> send frame\n", - tx->sdata->name, sta->sta.addr); - } -#endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ return TX_CONTINUE; } @@ -536,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key = NULL; + struct ieee80211_key *key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -555,16 +542,23 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) else if (!is_multicast_ether_addr(hdr->addr1) && (key = rcu_dereference(tx->sdata->default_unicast_key))) tx->key = key; - else if (tx->sdata->drop_unencrypted && - (tx->skb->protocol != tx->sdata->control_port_protocol) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && - (!ieee80211_is_robust_mgmt_frame(hdr) || - (ieee80211_is_action(hdr->frame_control) && - tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { + else if (info->flags & IEEE80211_TX_CTL_INJECTED) + tx->key = NULL; + else if (!tx->sdata->drop_unencrypted) + tx->key = NULL; + else if (tx->skb->protocol == tx->sdata->control_port_protocol) + tx->key = NULL; + else if (ieee80211_is_robust_mgmt_frame(hdr) && + !(ieee80211_is_action(hdr->frame_control) && + tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) + tx->key = NULL; + else if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_robust_mgmt_frame(hdr)) + tx->key = NULL; + else { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; - } else - tx->key = NULL; + } if (tx->key) { bool skip_hw = false; @@ -972,8 +966,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) info->control.rates[1].idx = -1; info->control.rates[2].idx = -1; info->control.rates[3].idx = -1; - info->control.rates[4].idx = -1; - BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 4); info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; } else { hdr->frame_control &= ~morefrags; @@ -1308,11 +1301,8 @@ static bool __ieee80211_tx(struct ieee80211_local *local, break; } - if (local->ops->tx_frags) - drv_tx_frags(local, vif, pubsta, skbs); - else - result = ieee80211_tx_frags(local, vif, pubsta, skbs, - txpending); + result = ieee80211_tx_frags(local, vif, pubsta, skbs, + txpending); ieee80211_tpt_led_trig_tx(local, fc, led_len); ieee80211_led_tx(local, 1); @@ -1963,7 +1953,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, (cpu_to_be16(ethertype) != sdata->control_port_protocol || !ether_addr_equal(sdata->vif.addr, skb->data + ETH_ALEN)))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - net_dbg_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", + net_info_ratelimited("%s: dropped frame to %pM (unauthorized port)\n", dev->name, hdr.addr1); #endif @@ -2435,9 +2425,9 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw, *pos++ = WLAN_EID_SSID; *pos++ = 0x0; - if (ieee80211_add_srates_ie(&sdata->vif, skb, true) || + if (ieee80211_add_srates_ie(sdata, skb, true) || mesh_add_ds_params_ie(skb, sdata) || - ieee80211_add_ext_srates_ie(&sdata->vif, skb, true) || + ieee80211_add_ext_srates_ie(sdata, skb, true) || mesh_add_rsn_ie(skb, sdata) || mesh_add_ht_cap_ie(skb, sdata) || mesh_add_ht_oper_ie(skb, sdata) || diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 1df4019f294b..39b82fee4904 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -268,6 +268,10 @@ EXPORT_SYMBOL(ieee80211_ctstoself_duration); void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) { struct ieee80211_sub_if_data *sdata; + int n_acs = IEEE80211_NUM_ACS; + + if (local->hw.queues < IEEE80211_NUM_ACS) + n_acs = 1; list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; @@ -279,7 +283,7 @@ void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue) local->queue_stop_reasons[sdata->vif.cab_queue] != 0) continue; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + for (ac = 0; ac < n_acs; ac++) { int ac_queue = sdata->vif.hw_queue[ac]; if (ac_queue == queue || @@ -341,6 +345,7 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; + int n_acs = IEEE80211_NUM_ACS; trace_stop_queue(local, queue, reason); @@ -352,11 +357,14 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, __set_bit(reason, &local->queue_stop_reasons[queue]); + if (local->hw.queues < IEEE80211_NUM_ACS) + n_acs = 1; + rcu_read_lock(); list_for_each_entry_rcu(sdata, &local->interfaces, list) { int ac; - for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { + for (ac = 0; ac < n_acs; ac++) { if (sdata->vif.hw_queue[ac] == queue || sdata->vif.cab_queue == queue) netif_stop_subqueue(sdata->dev, ac); @@ -521,6 +529,11 @@ void ieee80211_iterate_active_interfaces( &sdata->vif); } + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + mutex_unlock(&local->iflist_mtx); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); @@ -549,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic( &sdata->vif); } + sdata = rcu_dereference(local->monitor_sdata); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); @@ -991,6 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, int ext_rates_len; sband = local->hw.wiphy->bands[band]; + if (WARN_ON_ONCE(!sband)) + return 0; pos = buffer; @@ -1072,6 +1091,10 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, pos += noffset - offset; } + if (sband->vht_cap.vht_supported) + pos = ieee80211_ie_build_vht_cap(pos, &sband->vht_cap, + sband->vht_cap.cap); + return pos - buffer; } @@ -1412,6 +1435,9 @@ int ieee80211_reconfig(struct ieee80211_local *local) ieee80211_enable_keys(sdata); wake_up: + local->in_reconfig = false; + barrier(); + /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. @@ -1696,6 +1722,27 @@ u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, return pos; } +u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap, + u32 cap) +{ + __le32 tmp; + + *pos++ = WLAN_EID_VHT_CAPABILITY; + *pos++ = sizeof(struct ieee80211_vht_capabilities); + memset(pos, 0, sizeof(struct ieee80211_vht_capabilities)); + + /* capability flags */ + tmp = cpu_to_le32(cap); + memcpy(pos, &tmp, sizeof(u32)); + pos += sizeof(u32); + + /* VHT MCS set */ + memcpy(pos, &vht_cap->vht_mcs, sizeof(vht_cap->vht_mcs)); + pos += sizeof(vht_cap->vht_mcs); + + return pos; +} + u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap, struct ieee80211_channel *channel, enum nl80211_channel_type channel_type, @@ -1761,15 +1808,14 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper) return channel_type; } -int ieee80211_add_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; int rate; u8 i, rates, *pos; - u32 basic_rates = vif->bss_conf.basic_rates; + u32 basic_rates = sdata->vif.bss_conf.basic_rates; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; rates = sband->n_bitrates; @@ -1793,15 +1839,14 @@ int ieee80211_add_srates_ie(struct ieee80211_vif *vif, return 0; } -int ieee80211_add_ext_srates_ie(struct ieee80211_vif *vif, +int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic) { - struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_local *local = sdata->local; struct ieee80211_supported_band *sband; int rate; u8 i, exrates, *pos; - u32 basic_rates = vif->bss_conf.basic_rates; + u32 basic_rates = sdata->vif.bss_conf.basic_rates; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; exrates = sband->n_bitrates; diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index c3d643a6536c..cea06e9f26f4 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -52,11 +52,11 @@ static int wme_downgrade_ac(struct sk_buff *skb) } } -static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, +static u16 ieee80211_downgrade_queue(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) { /* in case we are a client verify acm is not set for this ac */ - while (unlikely(local->wmm_acm & BIT(skb->priority))) { + while (unlikely(sdata->wmm_acm & BIT(skb->priority))) { if (wme_downgrade_ac(skb)) { /* * This should not really happen. The AP has marked all @@ -73,10 +73,11 @@ static u16 ieee80211_downgrade_queue(struct ieee80211_local *local, } /* Indicate which queue to use for this fully formed 802.11 frame */ -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_hdr *hdr) { + struct ieee80211_local *local = sdata->local; u8 *p; if (local->hw.queues < IEEE80211_NUM_ACS) @@ -94,7 +95,7 @@ u16 ieee80211_select_queue_80211(struct ieee80211_local *local, p = ieee80211_get_qos_ctl(hdr); skb->priority = *p & IEEE80211_QOS_CTL_TAG1D_MASK; - return ieee80211_downgrade_queue(local, skb); + return ieee80211_downgrade_queue(sdata, skb); } /* Indicate which queue to use. */ @@ -156,7 +157,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, * data frame has */ skb->priority = cfg80211_classify8021d(skb); - return ieee80211_downgrade_queue(local, skb); + return ieee80211_downgrade_queue(sdata, skb); } void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/wme.h b/net/mac80211/wme.h index ca80818b7b66..7fea4bb8acbc 100644 --- a/net/mac80211/wme.h +++ b/net/mac80211/wme.h @@ -15,7 +15,7 @@ extern const int ieee802_1d_to_ac[8]; -u16 ieee80211_select_queue_80211(struct ieee80211_local *local, +u16 ieee80211_select_queue_80211(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, struct ieee80211_hdr *hdr); u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, diff --git a/net/nfc/core.c b/net/nfc/core.c index 4177bb5104b9..ff749794bc5b 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -29,6 +29,8 @@ #include <linux/slab.h> #include <linux/nfc.h> +#include <net/genetlink.h> + #include "nfc.h" #define VERSION "0.1" @@ -560,6 +562,8 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * The device driver must call this function when one or many nfc targets * are found. After calling this function, the device driver must stop * polling for targets. + * NOTE: This function can be called with targets=NULL and n_targets=0 to + * notify a driver error, meaning that the polling operation cannot complete. * IMPORTANT: this function must not be called from an atomic context. * In addition, it must also not be called from a context that would prevent * the NFC Core to call other nfc ops entry point concurrently. @@ -571,23 +575,33 @@ int nfc_targets_found(struct nfc_dev *dev, pr_debug("dev_name=%s n_targets=%d\n", dev_name(&dev->dev), n_targets); - dev->polling = false; - for (i = 0; i < n_targets; i++) targets[i].idx = dev->target_next_idx++; device_lock(&dev->dev); + if (dev->polling == false) { + device_unlock(&dev->dev); + return 0; + } + + dev->polling = false; + dev->targets_generation++; kfree(dev->targets); - dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target), - GFP_ATOMIC); + dev->targets = NULL; - if (!dev->targets) { - dev->n_targets = 0; - device_unlock(&dev->dev); - return -ENOMEM; + if (targets) { + dev->targets = kmemdup(targets, + n_targets * sizeof(struct nfc_target), + GFP_ATOMIC); + + if (!dev->targets) { + dev->n_targets = 0; + device_unlock(&dev->dev); + return -ENOMEM; + } } dev->n_targets = n_targets; @@ -651,6 +665,12 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } EXPORT_SYMBOL(nfc_target_lost); +inline void nfc_driver_failure(struct nfc_dev *dev, int err) +{ + nfc_targets_found(dev, NULL, 0); +} +EXPORT_SYMBOL(nfc_driver_failure); + static void nfc_release(struct device *d) { struct nfc_dev *dev = to_nfc_dev(d); @@ -906,3 +926,5 @@ MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>"); MODULE_DESCRIPTION("NFC Core ver " VERSION); MODULE_VERSION(VERSION); MODULE_LICENSE("GPL"); +MODULE_ALIAS_NETPROTO(PF_NFC); +MODULE_ALIAS_GENL_FAMILY(NFC_GENL_NAME); diff --git a/net/nfc/hci/command.c b/net/nfc/hci/command.c index 8729abf5f18b..46362ef979db 100644 --- a/net/nfc/hci/command.c +++ b/net/nfc/hci/command.c @@ -28,26 +28,14 @@ #include "hci.h" -static int nfc_hci_result_to_errno(u8 result) -{ - switch (result) { - case NFC_HCI_ANY_OK: - return 0; - case NFC_HCI_ANY_E_TIMEOUT: - return -ETIMEDOUT; - default: - return -1; - } -} - -static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, u8 result, +static void nfc_hci_execute_cb(struct nfc_hci_dev *hdev, int err, struct sk_buff *skb, void *cb_data) { struct hcp_exec_waiter *hcp_ew = (struct hcp_exec_waiter *)cb_data; - pr_debug("HCI Cmd completed with HCI result=%d\n", result); + pr_debug("HCI Cmd completed with result=%d\n", err); - hcp_ew->exec_result = nfc_hci_result_to_errno(result); + hcp_ew->exec_result = err; if (hcp_ew->exec_result == 0) hcp_ew->result_skb = skb; else @@ -311,9 +299,9 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_disconnect_all_gates); -int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) +int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, + u8 pipe) { - u8 pipe = NFC_HCI_INVALID_PIPE; bool pipe_created = false; int r; @@ -322,6 +310,9 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) return -EADDRINUSE; + if (pipe != NFC_HCI_INVALID_PIPE) + goto pipe_is_open; + switch (dest_gate) { case NFC_HCI_LINK_MGMT_GATE: pipe = NFC_HCI_LINK_MGMT_PIPE; @@ -347,6 +338,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate) return r; } +pipe_is_open: hdev->gate2pipe[dest_gate] = pipe; return 0; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index a8b0b71e8f86..36717cebfbb6 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -32,6 +32,18 @@ /* Largest headroom needed for outgoing HCI commands */ #define HCI_CMDS_HEADROOM 1 +static int nfc_hci_result_to_errno(u8 result) +{ + switch (result) { + case NFC_HCI_ANY_OK: + return 0; + case NFC_HCI_ANY_E_TIMEOUT: + return -ETIME; + default: + return -1; + } +} + static void nfc_hci_msg_tx_work(struct work_struct *work) { struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, @@ -46,7 +58,7 @@ static void nfc_hci_msg_tx_work(struct work_struct *work) if (timer_pending(&hdev->cmd_timer) == 0) { if (hdev->cmd_pending_msg->cb) hdev->cmd_pending_msg->cb(hdev, - NFC_HCI_ANY_E_TIMEOUT, + -ETIME, NULL, hdev-> cmd_pending_msg-> @@ -71,8 +83,7 @@ next_msg: kfree_skb(skb); skb_queue_purge(&msg->msg_frags); if (msg->cb) - msg->cb(hdev, NFC_HCI_ANY_E_NOK, NULL, - msg->cb_context); + msg->cb(hdev, r, NULL, msg->cb_context); kfree(msg); break; } @@ -116,20 +127,13 @@ static void nfc_hci_msg_rx_work(struct work_struct *work) } } -void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, - struct sk_buff *skb) +static void __nfc_hci_cmd_completion(struct nfc_hci_dev *hdev, int err, + struct sk_buff *skb) { - mutex_lock(&hdev->msg_tx_mutex); - - if (hdev->cmd_pending_msg == NULL) { - kfree_skb(skb); - goto exit; - } - del_timer_sync(&hdev->cmd_timer); if (hdev->cmd_pending_msg->cb) - hdev->cmd_pending_msg->cb(hdev, result, skb, + hdev->cmd_pending_msg->cb(hdev, err, skb, hdev->cmd_pending_msg->cb_context); else kfree_skb(skb); @@ -138,6 +142,19 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, hdev->cmd_pending_msg = NULL; queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); +} + +void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, + struct sk_buff *skb) +{ + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg == NULL) { + kfree_skb(skb); + goto exit; + } + + __nfc_hci_cmd_completion(hdev, nfc_hci_result_to_errno(result), skb); exit: mutex_unlock(&hdev->msg_tx_mutex); @@ -213,7 +230,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) } break; case NFC_HCI_RF_READER_B_GATE: - targets->supported_protocols = NFC_PROTO_ISO14443_MASK; + targets->supported_protocols = NFC_PROTO_ISO14443_B_MASK; break; default: if (hdev->ops->target_from_gate) @@ -298,15 +315,15 @@ static void nfc_hci_cmd_timeout(unsigned long data) } static int hci_dev_connect_gates(struct nfc_hci_dev *hdev, u8 gate_count, - u8 gates[]) + struct nfc_hci_gate *gates) { int r; - u8 *p = gates; while (gate_count--) { - r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, *p); + r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, + gates->gate, gates->pipe); if (r < 0) return r; - p++; + gates++; } return 0; @@ -316,14 +333,13 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) { struct sk_buff *skb = NULL; int r; - u8 hci_gates[] = { /* NFC_HCI_ADMIN_GATE MUST be first */ - NFC_HCI_ADMIN_GATE, NFC_HCI_LOOPBACK_GATE, - NFC_HCI_ID_MGMT_GATE, NFC_HCI_LINK_MGMT_GATE, - NFC_HCI_RF_READER_B_GATE, NFC_HCI_RF_READER_A_GATE - }; + + if (hdev->init_data.gates[0].gate != NFC_HCI_ADMIN_GATE) + return -EPROTO; r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, - NFC_HCI_ADMIN_GATE); + hdev->init_data.gates[0].gate, + hdev->init_data.gates[0].pipe); if (r < 0) goto exit; @@ -351,10 +367,6 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev) if (r < 0) goto exit; - r = hci_dev_connect_gates(hdev, sizeof(hci_gates), hci_gates); - if (r < 0) - goto disconnect_all; - r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count, hdev->init_data.gates); if (r < 0) @@ -717,6 +729,27 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev) } EXPORT_SYMBOL(nfc_hci_get_clientdata); +static void nfc_hci_failure(struct nfc_hci_dev *hdev, int err) +{ + mutex_lock(&hdev->msg_tx_mutex); + + if (hdev->cmd_pending_msg == NULL) { + nfc_driver_failure(hdev->ndev, err); + goto exit; + } + + __nfc_hci_cmd_completion(hdev, err, NULL); + +exit: + mutex_unlock(&hdev->msg_tx_mutex); +} + +void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err) +{ + nfc_hci_failure(hdev, err); +} +EXPORT_SYMBOL(nfc_hci_driver_failure); + void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) { struct hcp_packet *packet; @@ -727,16 +760,6 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) struct sk_buff *frag_skb; int msg_len; - if (skb == NULL) { - /* TODO ELa: lower layer had permanent failure, need to - * propagate that up - */ - - skb_queue_purge(&hdev->rx_hcp_frags); - - return; - } - packet = (struct hcp_packet *)skb->data; if ((packet->header & ~NFC_HCI_FRAGMENT) == 0) { skb_queue_tail(&hdev->rx_hcp_frags, skb); @@ -757,9 +780,8 @@ void nfc_hci_recv_frame(struct nfc_hci_dev *hdev, struct sk_buff *skb) hcp_skb = nfc_alloc_recv_skb(NFC_HCI_HCP_PACKET_HEADER_LEN + msg_len, GFP_KERNEL); if (hcp_skb == NULL) { - /* TODO ELa: cannot deliver HCP message. How to - * propagate error up? - */ + nfc_hci_failure(hdev, -ENOMEM); + return; } *skb_put(hcp_skb, NFC_HCI_HCP_PACKET_HEADER_LEN) = pipe; diff --git a/net/nfc/hci/hci.h b/net/nfc/hci/hci.h index 45f2fe4fd486..fa9a21e92239 100644 --- a/net/nfc/hci/hci.h +++ b/net/nfc/hci/hci.h @@ -37,10 +37,11 @@ struct hcp_packet { /* * HCI command execution completion callback. - * result will be one of the HCI response codes. - * skb contains the response data and must be disposed. + * result will be a standard linux error (may be converted from HCI response) + * skb contains the response data and must be disposed, or may be NULL if + * an error occured */ -typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, u8 result, +typedef void (*hci_cmd_cb_t) (struct nfc_hci_dev *hdev, int result, struct sk_buff *skb, void *cb_data); struct hcp_exec_waiter { @@ -131,9 +132,4 @@ void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, #define NFC_HCI_ANY_E_REG_ACCESS_DENIED 0x0a #define NFC_HCI_ANY_E_PIPE_ACCESS_DENIED 0x0b -/* Pipes */ -#define NFC_HCI_INVALID_PIPE 0x80 -#define NFC_HCI_LINK_MGMT_PIPE 0x00 -#define NFC_HCI_ADMIN_PIPE 0x01 - #endif /* __LOCAL_HCI_H */ diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 6b836e6242b7..6f840c18c892 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -340,15 +340,6 @@ static void nfc_shdlc_connect_complete(struct nfc_shdlc *shdlc, int r) shdlc->state = SHDLC_CONNECTED; } else { shdlc->state = SHDLC_DISCONNECTED; - - /* - * TODO: Could it be possible that there are pending - * executing commands that are waiting for connect to complete - * before they can be carried? As connect is a blocking - * operation, it would require that the userspace process can - * send commands on the same device from a second thread before - * the device is up. I don't think that is possible, is it? - */ } shdlc->connect_result = r; @@ -413,12 +404,12 @@ static void nfc_shdlc_rcv_u_frame(struct nfc_shdlc *shdlc, r = nfc_shdlc_connect_send_ua(shdlc); nfc_shdlc_connect_complete(shdlc, r); } - } else if (shdlc->state > SHDLC_NEGOCIATING) { + } else if (shdlc->state == SHDLC_CONNECTED) { /* - * TODO: Chip wants to reset link - * send ua, empty skb lists, reset counters - * propagate info to HCI layer + * Chip wants to reset link. This is unexpected and + * unsupported. */ + shdlc->hard_fault = -ECONNRESET; } break; case U_FRAME_UA: @@ -523,10 +514,6 @@ static void nfc_shdlc_handle_send_queue(struct nfc_shdlc *shdlc) r = shdlc->ops->xmit(shdlc, skb); if (r < 0) { - /* - * TODO: Cannot send, shdlc machine is dead, we - * must propagate the information up to HCI. - */ shdlc->hard_fault = r; break; } @@ -590,6 +577,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) skb_queue_purge(&shdlc->ack_pending_q); break; case SHDLC_CONNECTING: + if (shdlc->hard_fault) { + nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); + break; + } + if (shdlc->connect_tries++ < 5) r = nfc_shdlc_connect_initiate(shdlc); else @@ -610,6 +602,11 @@ static void nfc_shdlc_sm_work(struct work_struct *work) } nfc_shdlc_handle_rcv_queue(shdlc); + + if (shdlc->hard_fault) { + nfc_shdlc_connect_complete(shdlc, shdlc->hard_fault); + break; + } break; case SHDLC_CONNECTED: nfc_shdlc_handle_rcv_queue(shdlc); @@ -637,10 +634,7 @@ static void nfc_shdlc_sm_work(struct work_struct *work) } if (shdlc->hard_fault) { - /* - * TODO: Handle hard_fault that occured during - * this invocation of the shdlc worker - */ + nfc_hci_driver_failure(shdlc->hdev, shdlc->hard_fault); } break; default: @@ -923,8 +917,6 @@ void nfc_shdlc_free(struct nfc_shdlc *shdlc) { pr_debug("\n"); - /* TODO: Check that this cannot be called while still in use */ - nfc_hci_unregister_device(shdlc->hdev); nfc_hci_free_device(shdlc->hdev); diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 5d503eeb15a1..82f0f7588b46 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -45,7 +45,7 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk) write_unlock(&l->lock); } -static void nfc_llcp_socket_release(struct nfc_llcp_local *local) +static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen) { struct sock *sk; struct hlist_node *node, *tmp; @@ -78,6 +78,11 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local) sock_orphan(accept_sk); } + + if (listen == true) { + release_sock(sk); + continue; + } } sk->sk_state = LLCP_CLOSED; @@ -106,7 +111,7 @@ static void local_release(struct kref *ref) local = container_of(ref, struct nfc_llcp_local, ref); list_del(&local->list); - nfc_llcp_socket_release(local); + nfc_llcp_socket_release(local, false); del_timer_sync(&local->link_timer); skb_queue_purge(&local->tx_queue); destroy_workqueue(local->tx_wq); @@ -118,23 +123,48 @@ static void local_release(struct kref *ref) int nfc_llcp_local_put(struct nfc_llcp_local *local) { - WARN_ON(local == NULL); - if (local == NULL) return 0; return kref_put(&local->ref, local_release); } -static void nfc_llcp_clear_sdp(struct nfc_llcp_local *local) +static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, + u8 ssap, u8 dsap) { - mutex_lock(&local->sdp_lock); + struct sock *sk; + struct hlist_node *node; + struct nfc_llcp_sock *llcp_sock; - local->local_wks = 0; - local->local_sdp = 0; - local->local_sap = 0; + pr_debug("ssap dsap %d %d\n", ssap, dsap); - mutex_unlock(&local->sdp_lock); + if (ssap == 0 && dsap == 0) + return NULL; + + read_lock(&local->sockets.lock); + + llcp_sock = NULL; + + sk_for_each(sk, node, &local->sockets.head) { + llcp_sock = nfc_llcp_sock(sk); + + if (llcp_sock->ssap == ssap && llcp_sock->dsap == dsap) + break; + } + + read_unlock(&local->sockets.lock); + + if (llcp_sock == NULL) + return NULL; + + sock_hold(&llcp_sock->sk); + + return llcp_sock; +} + +static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) +{ + sock_put(&sock->sk); } static void nfc_llcp_timeout_work(struct work_struct *work) @@ -197,6 +227,51 @@ static int nfc_llcp_wks_sap(char *service_name, size_t service_name_len) return -EINVAL; } +static +struct nfc_llcp_sock *nfc_llcp_sock_from_sn(struct nfc_llcp_local *local, + u8 *sn, size_t sn_len) +{ + struct sock *sk; + struct hlist_node *node; + struct nfc_llcp_sock *llcp_sock, *tmp_sock; + + pr_debug("sn %zd %p\n", sn_len, sn); + + if (sn == NULL || sn_len == 0) + return NULL; + + read_lock(&local->sockets.lock); + + llcp_sock = NULL; + + sk_for_each(sk, node, &local->sockets.head) { + tmp_sock = nfc_llcp_sock(sk); + + pr_debug("llcp sock %p\n", tmp_sock); + + if (tmp_sock->sk.sk_state != LLCP_LISTEN) + continue; + + if (tmp_sock->service_name == NULL || + tmp_sock->service_name_len == 0) + continue; + + if (tmp_sock->service_name_len != sn_len) + continue; + + if (memcmp(sn, tmp_sock->service_name, sn_len) == 0) { + llcp_sock = tmp_sock; + break; + } + } + + read_unlock(&local->sockets.lock); + + pr_debug("Found llcp sock %p\n", llcp_sock); + + return llcp_sock; +} + u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, struct nfc_llcp_sock *sock) { @@ -223,41 +298,26 @@ u8 nfc_llcp_get_sdp_ssap(struct nfc_llcp_local *local, } /* - * This is not a well known service, - * we should try to find a local SDP free spot + * Check if there already is a non WKS socket bound + * to this service name. */ - ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); - if (ssap == LLCP_SDP_NUM_SAP) { + if (nfc_llcp_sock_from_sn(local, sock->service_name, + sock->service_name_len) != NULL) { mutex_unlock(&local->sdp_lock); return LLCP_SAP_MAX; } - pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); - - set_bit(ssap, &local->local_sdp); mutex_unlock(&local->sdp_lock); - return LLCP_WKS_NUM_SAP + ssap; - - } else if (sock->ssap != 0) { - if (sock->ssap < LLCP_WKS_NUM_SAP) { - if (!test_bit(sock->ssap, &local->local_wks)) { - set_bit(sock->ssap, &local->local_wks); - mutex_unlock(&local->sdp_lock); - - return sock->ssap; - } + return LLCP_SDP_UNBOUND; - } else if (sock->ssap < LLCP_SDP_NUM_SAP) { - if (!test_bit(sock->ssap - LLCP_WKS_NUM_SAP, - &local->local_sdp)) { - set_bit(sock->ssap - LLCP_WKS_NUM_SAP, - &local->local_sdp); - mutex_unlock(&local->sdp_lock); + } else if (sock->ssap != 0 && sock->ssap < LLCP_WKS_NUM_SAP) { + if (!test_bit(sock->ssap, &local->local_wks)) { + set_bit(sock->ssap, &local->local_wks); + mutex_unlock(&local->sdp_lock); - return sock->ssap; - } + return sock->ssap; } } @@ -294,8 +354,34 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) local_ssap = ssap; sdp = &local->local_wks; } else if (ssap < LLCP_LOCAL_NUM_SAP) { + atomic_t *client_cnt; + local_ssap = ssap - LLCP_WKS_NUM_SAP; sdp = &local->local_sdp; + client_cnt = &local->local_sdp_cnt[local_ssap]; + + pr_debug("%d clients\n", atomic_read(client_cnt)); + + mutex_lock(&local->sdp_lock); + + if (atomic_dec_and_test(client_cnt)) { + struct nfc_llcp_sock *l_sock; + + pr_debug("No more clients for SAP %d\n", ssap); + + clear_bit(local_ssap, sdp); + + /* Find the listening sock and set it back to UNBOUND */ + l_sock = nfc_llcp_sock_get(local, ssap, LLCP_SAP_SDP); + if (l_sock) { + l_sock->ssap = LLCP_SDP_UNBOUND; + nfc_llcp_sock_put(l_sock); + } + } + + mutex_unlock(&local->sdp_lock); + + return; } else if (ssap < LLCP_MAX_SAP) { local_ssap = ssap - LLCP_LOCAL_NUM_SAP; sdp = &local->local_sap; @@ -310,19 +396,26 @@ void nfc_llcp_put_ssap(struct nfc_llcp_local *local, u8 ssap) mutex_unlock(&local->sdp_lock); } -u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) +static u8 nfc_llcp_reserve_sdp_ssap(struct nfc_llcp_local *local) { - struct nfc_llcp_local *local; + u8 ssap; - local = nfc_llcp_find_local(dev); - if (local == NULL) { - *general_bytes_len = 0; - return NULL; + mutex_lock(&local->sdp_lock); + + ssap = find_first_zero_bit(&local->local_sdp, LLCP_SDP_NUM_SAP); + if (ssap == LLCP_SDP_NUM_SAP) { + mutex_unlock(&local->sdp_lock); + + return LLCP_SAP_MAX; } - *general_bytes_len = local->gb_len; + pr_debug("SDP ssap %d\n", LLCP_WKS_NUM_SAP + ssap); - return local->gb; + set_bit(ssap, &local->local_sdp); + + mutex_unlock(&local->sdp_lock); + + return LLCP_WKS_NUM_SAP + ssap; } static int nfc_llcp_build_gb(struct nfc_llcp_local *local) @@ -386,6 +479,23 @@ static int nfc_llcp_build_gb(struct nfc_llcp_local *local) return 0; } +u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *general_bytes_len) +{ + struct nfc_llcp_local *local; + + local = nfc_llcp_find_local(dev); + if (local == NULL) { + *general_bytes_len = 0; + return NULL; + } + + nfc_llcp_build_gb(local); + + *general_bytes_len = local->gb_len; + + return local->gb; +} + int nfc_llcp_set_remote_gb(struct nfc_dev *dev, u8 *gb, u8 gb_len) { struct nfc_llcp_local *local = nfc_llcp_find_local(dev); @@ -509,74 +619,12 @@ out: return llcp_sock; } -static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, - u8 ssap, u8 dsap) -{ - struct sock *sk; - struct hlist_node *node; - struct nfc_llcp_sock *llcp_sock; - - pr_debug("ssap dsap %d %d\n", ssap, dsap); - - if (ssap == 0 && dsap == 0) - return NULL; - - read_lock(&local->sockets.lock); - - llcp_sock = NULL; - - sk_for_each(sk, node, &local->sockets.head) { - llcp_sock = nfc_llcp_sock(sk); - - if (llcp_sock->ssap == ssap && - llcp_sock->dsap == dsap) - break; - } - - read_unlock(&local->sockets.lock); - - if (llcp_sock == NULL) - return NULL; - - sock_hold(&llcp_sock->sk); - - return llcp_sock; -} - static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, u8 *sn, size_t sn_len) { - struct sock *sk; - struct hlist_node *node; struct nfc_llcp_sock *llcp_sock; - pr_debug("sn %zd\n", sn_len); - - if (sn == NULL || sn_len == 0) - return NULL; - - read_lock(&local->sockets.lock); - - llcp_sock = NULL; - - sk_for_each(sk, node, &local->sockets.head) { - llcp_sock = nfc_llcp_sock(sk); - - if (llcp_sock->sk.sk_state != LLCP_LISTEN) - continue; - - if (llcp_sock->service_name == NULL || - llcp_sock->service_name_len == 0) - continue; - - if (llcp_sock->service_name_len != sn_len) - continue; - - if (memcmp(sn, llcp_sock->service_name, sn_len) == 0) - break; - } - - read_unlock(&local->sockets.lock); + llcp_sock = nfc_llcp_sock_from_sn(local, sn, sn_len); if (llcp_sock == NULL) return NULL; @@ -586,11 +634,6 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get_sn(struct nfc_llcp_local *local, return llcp_sock; } -static void nfc_llcp_sock_put(struct nfc_llcp_sock *sock) -{ - sock_put(&sock->sk); -} - static u8 *nfc_llcp_connect_sn(struct sk_buff *skb, size_t *sn_len) { u8 *tlv = &skb->data[2], type, length; @@ -662,6 +705,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, goto fail; } + if (sock->ssap == LLCP_SDP_UNBOUND) { + u8 ssap = nfc_llcp_reserve_sdp_ssap(local); + + pr_debug("First client, reserving %d\n", ssap); + + if (ssap == LLCP_SAP_MAX) { + reason = LLCP_DM_REJ; + release_sock(&sock->sk); + sock_put(&sock->sk); + goto fail; + } + + sock->ssap = ssap; + } + new_sk = nfc_llcp_sock_alloc(NULL, parent->sk_type, GFP_ATOMIC); if (new_sk == NULL) { reason = LLCP_DM_REJ; @@ -675,9 +733,21 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local, new_sock->local = nfc_llcp_local_get(local); new_sock->miu = local->remote_miu; new_sock->nfc_protocol = sock->nfc_protocol; - new_sock->ssap = sock->ssap; new_sock->dsap = ssap; + new_sock->target_idx = local->target_idx; new_sock->parent = parent; + new_sock->ssap = sock->ssap; + if (sock->ssap < LLCP_LOCAL_NUM_SAP && sock->ssap >= LLCP_WKS_NUM_SAP) { + atomic_t *client_count; + + pr_debug("reserved_ssap %d for %p\n", sock->ssap, new_sock); + + client_count = + &local->local_sdp_cnt[sock->ssap - LLCP_WKS_NUM_SAP]; + + atomic_inc(client_count); + new_sock->reserved_ssap = sock->ssap; + } nfc_llcp_parse_connection_tlv(new_sock, &skb->data[LLCP_HEADER_SIZE], skb->len - LLCP_HEADER_SIZE); @@ -886,6 +956,45 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) nfc_llcp_sock_put(llcp_sock); } +static void nfc_llcp_recv_dm(struct nfc_llcp_local *local, struct sk_buff *skb) +{ + struct nfc_llcp_sock *llcp_sock; + struct sock *sk; + u8 dsap, ssap, reason; + + dsap = nfc_llcp_dsap(skb); + ssap = nfc_llcp_ssap(skb); + reason = skb->data[2]; + + pr_debug("%d %d reason %d\n", ssap, dsap, reason); + + switch (reason) { + case LLCP_DM_NOBOUND: + case LLCP_DM_REJ: + llcp_sock = nfc_llcp_connecting_sock_get(local, dsap); + break; + + default: + llcp_sock = nfc_llcp_sock_get(local, dsap, ssap); + break; + } + + if (llcp_sock == NULL) { + pr_err("Invalid DM\n"); + return; + } + + sk = &llcp_sock->sk; + + sk->sk_err = ENXIO; + sk->sk_state = LLCP_CLOSED; + sk->sk_state_change(sk); + + nfc_llcp_sock_put(llcp_sock); + + return; +} + static void nfc_llcp_rx_work(struct work_struct *work) { struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local, @@ -929,6 +1038,11 @@ static void nfc_llcp_rx_work(struct work_struct *work) nfc_llcp_recv_cc(local, skb); break; + case LLCP_PDU_DM: + pr_debug("DM\n"); + nfc_llcp_recv_dm(local, skb); + break; + case LLCP_PDU_I: case LLCP_PDU_RR: case LLCP_PDU_RNR: @@ -985,10 +1099,8 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev) if (local == NULL) return; - nfc_llcp_clear_sdp(local); - /* Close and purge all existing sockets */ - nfc_llcp_socket_release(local); + nfc_llcp_socket_release(local, true); } void nfc_llcp_mac_is_up(struct nfc_dev *dev, u32 target_idx, diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 7286c86982ff..83b8bba5a280 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -37,6 +37,7 @@ enum llcp_state { #define LLCP_LOCAL_NUM_SAP 32 #define LLCP_LOCAL_SAP_OFFSET (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP) #define LLCP_MAX_SAP (LLCP_WKS_NUM_SAP + LLCP_SDP_NUM_SAP + LLCP_LOCAL_NUM_SAP) +#define LLCP_SDP_UNBOUND (LLCP_MAX_SAP + 1) struct nfc_llcp_sock; @@ -69,6 +70,7 @@ struct nfc_llcp_local { unsigned long local_wks; /* Well known services */ unsigned long local_sdp; /* Local services */ unsigned long local_sap; /* Local SAPs, not available for discovery */ + atomic_t local_sdp_cnt[LLCP_SDP_NUM_SAP]; /* local */ u8 gb[NFC_MAX_GT_LEN]; @@ -113,6 +115,9 @@ struct nfc_llcp_sock { /* Is the remote peer ready to receive */ u8 remote_ready; + /* Reserved source SAP */ + u8 reserved_ssap; + struct sk_buff_head tx_queue; struct sk_buff_head tx_pending_queue; struct sk_buff_head tx_backlog_queue; diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index 2c0b317344b7..ddeb9aa398f0 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -78,11 +78,11 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) struct sockaddr_nfc_llcp llcp_addr; int len, ret = 0; - pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); - if (!addr || addr->sa_family != AF_NFC) return -EINVAL; + pr_debug("sk %p addr %p family %d\n", sk, addr, addr->sa_family); + memset(&llcp_addr, 0, sizeof(llcp_addr)); len = min_t(unsigned int, sizeof(llcp_addr), alen); memcpy(&llcp_addr, addr, len); @@ -121,8 +121,12 @@ static int llcp_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) GFP_KERNEL); llcp_sock->ssap = nfc_llcp_get_sdp_ssap(local, llcp_sock); - if (llcp_sock->ssap == LLCP_MAX_SAP) + if (llcp_sock->ssap == LLCP_SAP_MAX) { + ret = -EADDRINUSE; goto put_dev; + } + + llcp_sock->reserved_ssap = llcp_sock->ssap; nfc_llcp_sock_link(&local->sockets, sk); @@ -283,22 +287,28 @@ error: return ret; } -static int llcp_sock_getname(struct socket *sock, struct sockaddr *addr, +static int llcp_sock_getname(struct socket *sock, struct sockaddr *uaddr, int *len, int peer) { - struct sockaddr_nfc_llcp *llcp_addr = (struct sockaddr_nfc_llcp *)addr; struct sock *sk = sock->sk; struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); + DECLARE_SOCKADDR(struct sockaddr_nfc_llcp *, llcp_addr, uaddr); - pr_debug("%p\n", sk); + if (llcp_sock == NULL || llcp_sock->dev == NULL) + return -EBADFD; + + pr_debug("%p %d %d %d\n", sk, llcp_sock->target_idx, + llcp_sock->dsap, llcp_sock->ssap); - if (llcp_sock == NULL) + if (llcp_sock == NULL || llcp_sock->dev == NULL) return -EBADFD; - addr->sa_family = AF_NFC; + uaddr->sa_family = AF_NFC; + *len = sizeof(struct sockaddr_nfc_llcp); llcp_addr->dev_idx = llcp_sock->dev->idx; + llcp_addr->target_idx = llcp_sock->target_idx; llcp_addr->dsap = llcp_sock->dsap; llcp_addr->ssap = llcp_sock->ssap; llcp_addr->service_name_len = llcp_sock->service_name_len; @@ -406,7 +416,8 @@ static int llcp_sock_release(struct socket *sock) } } - nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); + if (llcp_sock->reserved_ssap < LLCP_SAP_MAX) + nfc_llcp_put_ssap(llcp_sock->local, llcp_sock->ssap); release_sock(sk); @@ -486,6 +497,9 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, ret = -ENOMEM; goto put_dev; } + + llcp_sock->reserved_ssap = llcp_sock->ssap; + if (addr->service_name_len == 0) llcp_sock->dsap = addr->dsap; else @@ -687,6 +701,7 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp) llcp_sock->send_n = llcp_sock->send_ack_n = 0; llcp_sock->recv_n = llcp_sock->recv_ack_n = 0; llcp_sock->remote_ready = 1; + llcp_sock->reserved_ssap = LLCP_SAP_MAX; skb_queue_head_init(&llcp_sock->tx_queue); skb_queue_head_init(&llcp_sock->tx_pending_queue); skb_queue_head_init(&llcp_sock->tx_backlog_queue); diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 766a02b1dfa1..5bb4da680427 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -194,7 +194,7 @@ static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt) } if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) && - (protocols & NFC_PROTO_ISO14443_MASK)) { + (protocols & NFC_PROTO_ISO14443_B_MASK)) { cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode = NCI_NFC_B_PASSIVE_POLL_MODE; cmd.disc_configs[cmd.num_disc_configs].frequency = 1; @@ -486,7 +486,8 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, param.rf_protocol = NCI_RF_PROTOCOL_T2T; else if (protocol == NFC_PROTO_FELICA) param.rf_protocol = NCI_RF_PROTOCOL_T3T; - else if (protocol == NFC_PROTO_ISO14443) + else if (protocol == NFC_PROTO_ISO14443 || + protocol == NFC_PROTO_ISO14443_B) param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP; else param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP; diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index cb2646179e5f..af7a93b04393 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -106,7 +106,7 @@ static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev, nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data)); data += 2; - nfca_poll->nfcid1_len = *data++; + nfca_poll->nfcid1_len = min_t(__u8, *data++, NFC_NFCID1_MAXSIZE); pr_debug("sens_res 0x%x, nfcid1_len %d\n", nfca_poll->sens_res, nfca_poll->nfcid1_len); @@ -130,7 +130,7 @@ static __u8 *nci_extract_rf_params_nfcb_passive_poll(struct nci_dev *ndev, struct rf_tech_specific_params_nfcb_poll *nfcb_poll, __u8 *data) { - nfcb_poll->sensb_res_len = *data++; + nfcb_poll->sensb_res_len = min_t(__u8, *data++, NFC_SENSB_RES_MAXSIZE); pr_debug("sensb_res_len %d\n", nfcb_poll->sensb_res_len); @@ -145,7 +145,7 @@ static __u8 *nci_extract_rf_params_nfcf_passive_poll(struct nci_dev *ndev, __u8 *data) { nfcf_poll->bit_rate = *data++; - nfcf_poll->sensf_res_len = *data++; + nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE); pr_debug("bit_rate %d, sensf_res_len %d\n", nfcf_poll->bit_rate, nfcf_poll->sensf_res_len); @@ -170,7 +170,10 @@ static int nci_add_new_protocol(struct nci_dev *ndev, if (rf_protocol == NCI_RF_PROTOCOL_T2T) protocol = NFC_PROTO_MIFARE_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP) - protocol = NFC_PROTO_ISO14443_MASK; + if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE) + protocol = NFC_PROTO_ISO14443_MASK; + else + protocol = NFC_PROTO_ISO14443_B_MASK; else if (rf_protocol == NCI_RF_PROTOCOL_T3T) protocol = NFC_PROTO_FELICA_MASK; else @@ -331,7 +334,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, switch (ntf->activation_rf_tech_and_mode) { case NCI_NFC_A_PASSIVE_POLL_MODE: nfca_poll = &ntf->activation_params.nfca_poll_iso_dep; - nfca_poll->rats_res_len = *data++; + nfca_poll->rats_res_len = min_t(__u8, *data++, 20); pr_debug("rats_res_len %d\n", nfca_poll->rats_res_len); if (nfca_poll->rats_res_len > 0) { memcpy(nfca_poll->rats_res, @@ -341,7 +344,7 @@ static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev, case NCI_NFC_B_PASSIVE_POLL_MODE: nfcb_poll = &ntf->activation_params.nfcb_poll_iso_dep; - nfcb_poll->attrib_res_len = *data++; + nfcb_poll->attrib_res_len = min_t(__u8, *data++, 50); pr_debug("attrib_res_len %d\n", nfcb_poll->attrib_res_len); if (nfcb_poll->attrib_res_len > 0) { memcpy(nfcb_poll->attrib_res, diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index 03c31db38f12..99bc6f7faa7b 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -634,6 +634,15 @@ static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info) if (!dev) return -ENODEV; + device_lock(&dev->dev); + + if (!dev->polling) { + device_unlock(&dev->dev); + return -EINVAL; + } + + device_unlock(&dev->dev); + mutex_lock(&dev->genl_data.genl_data_mutex); if (dev->genl_data.poll_req_pid != info->snd_pid) { diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c index ec1134c9e07f..8b8a6a2b2bad 100644 --- a/net/nfc/rawsock.c +++ b/net/nfc/rawsock.c @@ -54,7 +54,10 @@ static int rawsock_release(struct socket *sock) { struct sock *sk = sock->sk; - pr_debug("sock=%p\n", sock); + pr_debug("sock=%p sk=%p\n", sock, sk); + + if (!sk) + return 0; sock_orphan(sk); sock_put(sk); diff --git a/net/wireless/Makefile b/net/wireless/Makefile index 55a28ab21db9..0f7e0d621ab0 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -10,7 +10,7 @@ obj-$(CONFIG_WEXT_SPY) += wext-spy.o obj-$(CONFIG_WEXT_PRIV) += wext-priv.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o scan.o nl80211.o -cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o +cfg80211-y += mlme.o ibss.o sme.o chan.o ethtool.o mesh.o ap.o cfg80211-$(CONFIG_CFG80211_DEBUGFS) += debugfs.o cfg80211-$(CONFIG_CFG80211_WEXT) += wext-compat.o wext-sme.o cfg80211-$(CONFIG_CFG80211_INTERNAL_REGDB) += regdb.o diff --git a/net/wireless/ap.c b/net/wireless/ap.c new file mode 100644 index 000000000000..fcc60d8dbefa --- /dev/null +++ b/net/wireless/ap.c @@ -0,0 +1,46 @@ +#include <linux/ieee80211.h> +#include <linux/export.h> +#include <net/cfg80211.h> +#include "nl80211.h" +#include "core.h" + + +static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + ASSERT_WDEV_LOCK(wdev); + + if (!rdev->ops->stop_ap) + return -EOPNOTSUPP; + + if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && + dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + return -EOPNOTSUPP; + + if (!wdev->beacon_interval) + return -ENOENT; + + err = rdev->ops->stop_ap(&rdev->wiphy, dev); + if (!err) { + wdev->beacon_interval = 0; + wdev->channel = NULL; + } + + return err; +} + +int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + int err; + + wdev_lock(wdev); + err = __cfg80211_stop_ap(rdev, dev); + wdev_unlock(wdev); + + return err; +} diff --git a/net/wireless/chan.c b/net/wireless/chan.c index c1999e45a07c..1cc4b7cc7372 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -82,13 +82,71 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, int freq, enum nl80211_channel_type chantype) { struct ieee80211_channel *chan; + int err; if (!rdev->ops->set_monitor_channel) return -EOPNOTSUPP; + if (!cfg80211_has_monitors_only(rdev)) + return -EBUSY; chan = rdev_freq_to_chan(rdev, freq, chantype); if (!chan) return -EINVAL; - return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); + err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); + if (!err) { + rdev->monitor_channel = chan; + rdev->monitor_channel_type = chantype; + } + + return err; +} + +void +cfg80211_get_chan_state(struct wireless_dev *wdev, + struct ieee80211_channel **chan, + enum cfg80211_chan_mode *chanmode) +{ + *chan = NULL; + *chanmode = CHAN_MODE_UNDEFINED; + + ASSERT_WDEV_LOCK(wdev); + + if (!netif_running(wdev->netdev)) + return; + + switch (wdev->iftype) { + case NL80211_IFTYPE_ADHOC: + if (wdev->current_bss) { + *chan = wdev->current_bss->pub.channel; + *chanmode = wdev->ibss_fixed + ? CHAN_MODE_SHARED + : CHAN_MODE_EXCLUSIVE; + return; + } + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_P2P_CLIENT: + if (wdev->current_bss) { + *chan = wdev->current_bss->pub.channel; + *chanmode = CHAN_MODE_SHARED; + return; + } + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_P2P_GO: + case NL80211_IFTYPE_MESH_POINT: + *chan = wdev->channel; + *chanmode = CHAN_MODE_SHARED; + return; + case NL80211_IFTYPE_MONITOR: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_WDS: + /* these interface types don't really have a channel */ + return; + case NL80211_IFTYPE_UNSPECIFIED: + case NUM_NL80211_IFTYPES: + WARN_ON(1); + } + + return; } diff --git a/net/wireless/core.c b/net/wireless/core.c index a87d43552974..0557bb159025 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -96,69 +96,6 @@ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx) return &rdev->wiphy; } -/* requires cfg80211_mutex to be held! */ -struct cfg80211_registered_device * -__cfg80211_rdev_from_info(struct genl_info *info) -{ - int ifindex; - struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL; - struct net_device *dev; - int err = -EINVAL; - - assert_cfg80211_lock(); - - if (info->attrs[NL80211_ATTR_WIPHY]) { - bywiphyidx = cfg80211_rdev_by_wiphy_idx( - nla_get_u32(info->attrs[NL80211_ATTR_WIPHY])); - err = -ENODEV; - } - - if (info->attrs[NL80211_ATTR_IFINDEX]) { - ifindex = nla_get_u32(info->attrs[NL80211_ATTR_IFINDEX]); - dev = dev_get_by_index(genl_info_net(info), ifindex); - if (dev) { - if (dev->ieee80211_ptr) - byifidx = - wiphy_to_dev(dev->ieee80211_ptr->wiphy); - dev_put(dev); - } - err = -ENODEV; - } - - if (bywiphyidx && byifidx) { - if (bywiphyidx != byifidx) - return ERR_PTR(-EINVAL); - else - return bywiphyidx; /* == byifidx */ - } - if (bywiphyidx) - return bywiphyidx; - - if (byifidx) - return byifidx; - - return ERR_PTR(err); -} - -struct cfg80211_registered_device * -cfg80211_get_dev_from_info(struct genl_info *info) -{ - struct cfg80211_registered_device *rdev; - - mutex_lock(&cfg80211_mutex); - rdev = __cfg80211_rdev_from_info(info); - - /* if it is not an error we grab the lock on - * it to assure it won't be going away while - * we operate on it */ - if (!IS_ERR(rdev)) - mutex_lock(&rdev->mtx); - - mutex_unlock(&cfg80211_mutex); - - return rdev; -} - struct cfg80211_registered_device * cfg80211_get_dev_from_ifindex(struct net *net, int ifindex) { @@ -239,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { + if (!wdev->netdev) + continue; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); if (err) @@ -251,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, /* failed -- clean up to old netns */ net = wiphy_net(&rdev->wiphy); - list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, + list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, list) { + if (!wdev->netdev) + continue; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); @@ -289,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) rtnl_lock(); mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) - dev_close(wdev->netdev); + list_for_each_entry(wdev, &rdev->wdev_list, list) + if (wdev->netdev) + dev_close(wdev->netdev); mutex_unlock(&rdev->devlist_mtx); rtnl_unlock(); @@ -367,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); mutex_init(&rdev->sched_scan_mtx); - INIT_LIST_HEAD(&rdev->netdev_list); + INIT_LIST_HEAD(&rdev->wdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); @@ -436,6 +378,14 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) if (WARN_ON(!c->num_different_channels)) return -EINVAL; + /* + * Put a sane limit on maximum number of different + * channels to simplify channel accounting code. + */ + if (WARN_ON(c->num_different_channels > + CFG80211_MAX_NUM_DIFFERENT_CHANNELS)) + return -EINVAL; + if (WARN_ON(!c->n_limits)) return -EINVAL; @@ -484,9 +434,11 @@ int wiphy_register(struct wiphy *wiphy) int i; u16 ifmodes = wiphy->interface_modes; +#ifdef CONFIG_PM if (WARN_ON((wiphy->wowlan.flags & WIPHY_WOWLAN_GTK_REKEY_FAILURE) && !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY))) return -EINVAL; +#endif if (WARN_ON(wiphy->ap_sme_capa && !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME))) @@ -521,8 +473,14 @@ int wiphy_register(struct wiphy *wiphy) continue; sband->band = band; - - if (WARN_ON(!sband->n_channels || !sband->n_bitrates)) + if (WARN_ON(!sband->n_channels)) + return -EINVAL; + /* + * on 60gHz band, there are no legacy rates, so + * n_bitrates is 0 + */ + if (WARN_ON(band != IEEE80211_BAND_60GHZ && + !sband->n_bitrates)) return -EINVAL; /* @@ -563,12 +521,14 @@ int wiphy_register(struct wiphy *wiphy) return -EINVAL; } +#ifdef CONFIG_PM if (rdev->wiphy.wowlan.n_patterns) { if (WARN_ON(!rdev->wiphy.wowlan.pattern_min_len || rdev->wiphy.wowlan.pattern_min_len > rdev->wiphy.wowlan.pattern_max_len)) return -EINVAL; } +#endif /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); @@ -667,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy) __count == 0; })); mutex_lock(&rdev->devlist_mtx); - BUG_ON(!list_empty(&rdev->netdev_list)); + BUG_ON(!list_empty(&rdev->wdev_list)); mutex_unlock(&rdev->devlist_mtx); /* @@ -748,7 +708,7 @@ static void wdev_cleanup_work(struct work_struct *work) cfg80211_lock_rdev(rdev); - if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { rdev->scan_req->aborted = true; ___cfg80211_scan_done(rdev, true); } @@ -776,6 +736,62 @@ static struct device_type wiphy_type = { .name = "wlan", }; +static struct ieee80211_channel * +cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) +{ + struct ieee80211_supported_band *sband; + int i; + + for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + sband = rdev->wiphy.bands[i]; + if (sband && sband->n_channels > 0) + return &sband->channels[0]; + } + + return NULL; +} + +static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) +{ + struct ieee80211_channel *chan; + + chan = cfg80211_get_any_chan(rdev); + if (WARN_ON(!chan)) + return; + + mutex_lock(&rdev->devlist_mtx); + WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, + NL80211_CHAN_NO_HT)); + mutex_unlock(&rdev->devlist_mtx); +} + +void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype, int num) +{ + bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); + bool has_monitors_only_new; + + ASSERT_RTNL(); + + rdev->num_running_ifaces += num; + if (iftype == NL80211_IFTYPE_MONITOR) + rdev->num_running_monitor_ifaces += num; + + has_monitors_only_new = cfg80211_has_monitors_only(rdev); + if (has_monitors_only_new != has_monitors_only_old) { + if (rdev->ops->set_monitor_enabled) + rdev->ops->set_monitor_enabled(&rdev->wiphy, + has_monitors_only_new); + + if (!has_monitors_only_new) { + rdev->monitor_channel = NULL; + rdev->monitor_channel_type = NL80211_CHAN_NO_HT; + } else { + cfg80211_init_mon_chan(rdev); + } + } +} + static int cfg80211_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *ndev) @@ -810,7 +826,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, spin_lock_init(&wdev->mgmt_registrations_lock); mutex_lock(&rdev->devlist_mtx); - list_add_rcu(&wdev->list, &rdev->netdev_list); + wdev->identifier = ++rdev->wdev_id; + list_add_rcu(&wdev->list, &rdev->wdev_list); rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -869,12 +886,16 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, case NL80211_IFTYPE_MESH_POINT: cfg80211_leave_mesh(rdev, dev); break; + case NL80211_IFTYPE_AP: + cfg80211_stop_ap(rdev, dev); + break; default: break; } wdev->beacon_interval = 0; break; case NETDEV_DOWN: + cfg80211_update_iface_num(rdev, wdev->iftype, -1); dev_hold(dev); queue_work(cfg80211_wq, &wdev->cleanup_work); break; @@ -980,9 +1001,12 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, return notifier_from_errno(-EOPNOTSUPP); if (rfkill_blocked(rdev->rfkill)) return notifier_from_errno(-ERFKILL); + mutex_lock(&rdev->devlist_mtx); ret = cfg80211_can_add_interface(rdev, wdev->iftype); + mutex_unlock(&rdev->devlist_mtx); if (ret) return notifier_from_errno(ret); + cfg80211_update_iface_num(rdev, wdev->iftype, 1); break; } diff --git a/net/wireless/core.h b/net/wireless/core.h index 9348a47562a4..bac97da751df 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -13,6 +13,7 @@ #include <linux/debugfs.h> #include <linux/rfkill.h> #include <linux/workqueue.h> +#include <linux/rtnetlink.h> #include <net/genetlink.h> #include <net/cfg80211.h> #include "reg.h" @@ -46,16 +47,23 @@ struct cfg80211_registered_device { /* wiphy index, internal only */ int wiphy_idx; - /* associate netdev list */ + /* associated wireless interfaces */ struct mutex devlist_mtx; /* protected by devlist_mtx or RCU */ - struct list_head netdev_list; - int devlist_generation; + struct list_head wdev_list; + int devlist_generation, wdev_id; int opencount; /* also protected by devlist_mtx */ wait_queue_head_t dev_wait; u32 ap_beacons_nlpid; + /* protected by RTNL only */ + int num_running_ifaces; + int num_running_monitor_ifaces; + + struct ieee80211_channel *monitor_channel; + enum nl80211_channel_type monitor_channel_type; + /* BSSes/scanning */ spinlock_t bss_lock; struct list_head bss_list; @@ -159,32 +167,6 @@ static inline void cfg80211_unhold_bss(struct cfg80211_internal_bss *bss) struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx); int get_wiphy_idx(struct wiphy *wiphy); -struct cfg80211_registered_device * -__cfg80211_rdev_from_info(struct genl_info *info); - -/* - * This function returns a pointer to the driver - * that the genl_info item that is passed refers to. - * If successful, it returns non-NULL and also locks - * the driver's mutex! - * - * This means that you need to call cfg80211_unlock_rdev() - * before being allowed to acquire &cfg80211_mutex! - * - * This is necessary because we need to lock the global - * mutex to get an item off the list safely, and then - * we lock the rdev mutex so it doesn't go away under us. - * - * We don't want to keep cfg80211_mutex locked - * for all the time in order to allow requests on - * other interfaces to go through at the same time. - * - * The result of this can be a PTR_ERR and hence must - * be checked with IS_ERR() for errors. - */ -extern struct cfg80211_registered_device * -cfg80211_get_dev_from_info(struct genl_info *info); - /* requires cfg80211_rdev_mutex to be held! */ struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx); @@ -223,6 +205,14 @@ static inline void wdev_unlock(struct wireless_dev *wdev) #define ASSERT_RDEV_LOCK(rdev) lockdep_assert_held(&(rdev)->mtx) #define ASSERT_WDEV_LOCK(wdev) lockdep_assert_held(&(wdev)->mtx) +static inline bool cfg80211_has_monitors_only(struct cfg80211_registered_device *rdev) +{ + ASSERT_RTNL(); + + return rdev->num_running_ifaces == rdev->num_running_monitor_ifaces && + rdev->num_running_ifaces > 0; +} + enum cfg80211_event_type { EVENT_CONNECT_RESULT, EVENT_ROAMED, @@ -267,6 +257,12 @@ struct cfg80211_cached_keys { int def, defmgmt; }; +enum cfg80211_chan_mode { + CHAN_MODE_UNDEFINED, + CHAN_MODE_SHARED, + CHAN_MODE_EXCLUSIVE, +}; + /* free object */ extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev); @@ -315,6 +311,10 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type); +/* AP */ +int cfg80211_stop_ap(struct cfg80211_registered_device *rdev, + struct net_device *dev); + /* MLME */ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, struct net_device *dev, @@ -372,7 +372,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, @@ -430,9 +430,20 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, u32 *flags, struct vif_params *params); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); -int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - enum nl80211_iftype iftype); +int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype, + struct ieee80211_channel *chan, + enum cfg80211_chan_mode chanmode); + +static inline int +cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype) +{ + return cfg80211_can_use_iftype_chan(rdev, wdev, iftype, NULL, + CHAN_MODE_UNDEFINED); +} static inline int cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, @@ -441,6 +452,21 @@ cfg80211_can_add_interface(struct cfg80211_registered_device *rdev, return cfg80211_can_change_interface(rdev, NULL, iftype); } +static inline int +cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct ieee80211_channel *chan, + enum cfg80211_chan_mode chanmode) +{ + return cfg80211_can_use_iftype_chan(rdev, wdev, wdev->iftype, + chan, chanmode); +} + +void +cfg80211_get_chan_state(struct wireless_dev *wdev, + struct ieee80211_channel **chan, + enum cfg80211_chan_mode *chanmode); + struct ieee80211_channel * rdev_freq_to_chan(struct cfg80211_registered_device *rdev, int freq, enum nl80211_channel_type channel_type); @@ -454,6 +480,11 @@ int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, u32 beacon_int); +void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, + enum nl80211_iftype iftype, int num); + +#define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10 + #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS #define CFG80211_DEV_WARN_ON(cond) WARN_ON(cond) #else diff --git a/net/wireless/ibss.c b/net/wireless/ibss.c index 89baa3328411..ca5672f6ee2f 100644 --- a/net/wireless/ibss.c +++ b/net/wireless/ibss.c @@ -113,10 +113,21 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev, kfree(wdev->connect_keys); wdev->connect_keys = connkeys; + wdev->ibss_fixed = params->channel_fixed; #ifdef CONFIG_CFG80211_WEXT wdev->wext.ibss.channel = params->channel; #endif wdev->sme_state = CFG80211_SME_CONNECTING; + + err = cfg80211_can_use_chan(rdev, wdev, params->channel, + params->channel_fixed + ? CHAN_MODE_SHARED + : CHAN_MODE_EXCLUSIVE); + if (err) { + wdev->connect_keys = NULL; + return err; + } + err = rdev->ops->join_ibss(&rdev->wiphy, dev, params); if (err) { wdev->connect_keys = NULL; diff --git a/net/wireless/mesh.c b/net/wireless/mesh.c index b44c736bf9cf..c384e77ff77a 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -14,6 +14,9 @@ #define MESH_PATH_TIMEOUT 5000 #define MESH_RANN_INTERVAL 5000 +#define MESH_PATH_TO_ROOT_TIMEOUT 6000 +#define MESH_ROOT_INTERVAL 5000 +#define MESH_ROOT_CONFIRMATION_INTERVAL 2000 /* * Minimum interval between two consecutive PREQs originated by the same @@ -62,6 +65,9 @@ const struct mesh_config default_mesh_config = { .dot11MeshForwarding = true, .rssi_threshold = MESH_RSSI_THRESHOLD, .ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED, + .dot11MeshHWMPactivePathToRootTimeout = MESH_PATH_TO_ROOT_TIMEOUT, + .dot11MeshHWMProotInterval = MESH_ROOT_INTERVAL, + .dot11MeshHWMPconfirmationInterval = MESH_ROOT_CONFIRMATION_INTERVAL, }; const struct mesh_setup default_mesh_setup = { @@ -149,10 +155,16 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev, setup->channel_type)) return -EINVAL; + err = cfg80211_can_use_chan(rdev, wdev, setup->channel, + CHAN_MODE_SHARED); + if (err) + return err; + err = rdev->ops->join_mesh(&rdev->wiphy, dev, conf, setup); if (!err) { memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len); wdev->mesh_id_len = setup->mesh_id_len; + wdev->channel = setup->channel; } return err; @@ -166,9 +178,11 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); err = __cfg80211_join_mesh(rdev, dev, setup, conf); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -178,6 +192,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, enum nl80211_channel_type channel_type) { struct ieee80211_channel *channel; + int err; channel = rdev_freq_to_chan(rdev, freq, channel_type); if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy, @@ -199,9 +214,19 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev, if (!netif_running(wdev->netdev)) return -ENETDOWN; - return rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, - wdev->netdev, - channel); + + err = cfg80211_can_use_chan(rdev, wdev, channel, + CHAN_MODE_SHARED); + if (err) + return err; + + err = rdev->ops->libertas_set_mesh_channel(&rdev->wiphy, + wdev->netdev, + channel); + if (!err) + wdev->channel = channel; + + return err; } if (wdev->mesh_id_len) @@ -243,8 +268,11 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev, return -ENOTCONN; err = rdev->ops->leave_mesh(&rdev->wiphy, dev); - if (!err) + if (!err) { wdev->mesh_id_len = 0; + wdev->channel = NULL; + } + return err; } diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index da4406f11929..abe9f82d5a82 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -302,8 +302,14 @@ int __cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, if (!req.bss) return -ENOENT; + err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, + CHAN_MODE_SHARED); + if (err) + goto out; + err = rdev->ops->auth(&rdev->wiphy, dev, &req); +out: cfg80211_put_bss(req.bss); return err; } @@ -317,11 +323,13 @@ int cfg80211_mlme_auth(struct cfg80211_registered_device *rdev, { int err; + mutex_lock(&rdev->devlist_mtx); wdev_lock(dev->ieee80211_ptr); err = __cfg80211_mlme_auth(rdev, dev, chan, auth_type, bssid, ssid, ssid_len, ie, ie_len, key, key_len, key_idx); wdev_unlock(dev->ieee80211_ptr); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -397,8 +405,14 @@ int __cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, return -ENOENT; } + err = cfg80211_can_use_chan(rdev, wdev, req.bss->channel, + CHAN_MODE_SHARED); + if (err) + goto out; + err = rdev->ops->assoc(&rdev->wiphy, dev, &req); +out: if (err) { if (was_connected) wdev->sme_state = CFG80211_SME_CONNECTED; @@ -421,11 +435,13 @@ int cfg80211_mlme_assoc(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev = dev->ieee80211_ptr; int err; + mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); err = __cfg80211_mlme_assoc(rdev, dev, chan, bssid, prev_bssid, ssid, ssid_len, ie, ie_len, use_mfp, crypt, assoc_flags, ht_capa, ht_capa_mask); wdev_unlock(wdev); + mutex_unlock(&rdev->devlist_mtx); return err; } @@ -551,29 +567,28 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, } } -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, +void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, + nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, duration, gfp); } EXPORT_SYMBOL(cfg80211_ready_on_channel); -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, +void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, + nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, channel_type, gfp); } EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); @@ -662,8 +677,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, list_add(&nreg->list, &wdev->mgmt_registrations); if (rdev->ops->mgmt_frame_register) - rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, - frame_type, true); + rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true); out: spin_unlock_bh(&wdev->mgmt_registrations_lock); @@ -686,7 +700,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) if (rdev->ops->mgmt_frame_register) { u16 frame_type = le16_to_cpu(reg->frame_type); - rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, false); } @@ -715,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) } int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct wireless_dev *wdev = dev->ieee80211_ptr; + struct net_device *dev = wdev->netdev; const struct ieee80211_mgmt *mgmt; u16 stype; @@ -809,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return -EINVAL; /* Transmit the Action frame as requested by user space */ - return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, + return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, channel_type_valid, wait, buf, len, no_cck, dont_wait_for_ack, cookie); } -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, +bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, const u8 *buf, size_t len, gfp_t gfp) { - struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg; @@ -855,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, dev, reg->nlpid, + if (nl80211_send_mgmt(rdev, wdev, reg->nlpid, freq, sig_mbm, buf, len, gfp)) continue; @@ -870,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, } EXPORT_SYMBOL(cfg80211_rx_mgmt); -void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, +void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { - struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); /* Indicate TX status of the Action frame to user space */ - nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); + nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); @@ -947,6 +959,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq, if (WARN_ON(!chan)) goto out; + wdev->channel = chan; nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL); out: wdev_unlock(wdev); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 7ae54b82291f..6472c7f928dc 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -46,28 +46,175 @@ static struct genl_family nl80211_fam = { .post_doit = nl80211_post_doit, }; -/* internal helper: get rdev and dev */ -static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, - struct cfg80211_registered_device **rdev, - struct net_device **dev) +/* returns ERR_PTR values */ +static struct wireless_dev * +__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) { - int ifindex; + struct cfg80211_registered_device *rdev; + struct wireless_dev *result = NULL; + bool have_ifidx = attrs[NL80211_ATTR_IFINDEX]; + bool have_wdev_id = attrs[NL80211_ATTR_WDEV]; + u64 wdev_id; + int wiphy_idx = -1; + int ifidx = -1; - if (!attrs[NL80211_ATTR_IFINDEX]) - return -EINVAL; + assert_cfg80211_lock(); - ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); - *dev = dev_get_by_index(netns, ifindex); - if (!*dev) - return -ENODEV; + if (!have_ifidx && !have_wdev_id) + return ERR_PTR(-EINVAL); - *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); - if (IS_ERR(*rdev)) { - dev_put(*dev); - return PTR_ERR(*rdev); + if (have_ifidx) + ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); + if (have_wdev_id) { + wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); + wiphy_idx = wdev_id >> 32; } - return 0; + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + struct wireless_dev *wdev; + + if (wiphy_net(&rdev->wiphy) != netns) + continue; + + if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) + continue; + + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev, &rdev->wdev_list, list) { + if (have_ifidx && wdev->netdev && + wdev->netdev->ifindex == ifidx) { + result = wdev; + break; + } + if (have_wdev_id && wdev->identifier == (u32)wdev_id) { + result = wdev; + break; + } + } + mutex_unlock(&rdev->devlist_mtx); + + if (result) + break; + } + + if (result) + return result; + return ERR_PTR(-ENODEV); +} + +static struct cfg80211_registered_device * +__cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) +{ + struct cfg80211_registered_device *rdev = NULL, *tmp; + struct net_device *netdev; + + assert_cfg80211_lock(); + + if (!attrs[NL80211_ATTR_WIPHY] && + !attrs[NL80211_ATTR_IFINDEX] && + !attrs[NL80211_ATTR_WDEV]) + return ERR_PTR(-EINVAL); + + if (attrs[NL80211_ATTR_WIPHY]) + rdev = cfg80211_rdev_by_wiphy_idx( + nla_get_u32(attrs[NL80211_ATTR_WIPHY])); + + if (attrs[NL80211_ATTR_WDEV]) { + u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); + struct wireless_dev *wdev; + bool found = false; + + tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); + if (tmp) { + /* make sure wdev exists */ + mutex_lock(&tmp->devlist_mtx); + list_for_each_entry(wdev, &tmp->wdev_list, list) { + if (wdev->identifier != (u32)wdev_id) + continue; + found = true; + break; + } + mutex_unlock(&tmp->devlist_mtx); + + if (!found) + tmp = NULL; + + if (rdev && tmp != rdev) + return ERR_PTR(-EINVAL); + rdev = tmp; + } + } + + if (attrs[NL80211_ATTR_IFINDEX]) { + int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); + netdev = dev_get_by_index(netns, ifindex); + if (netdev) { + if (netdev->ieee80211_ptr) + tmp = wiphy_to_dev( + netdev->ieee80211_ptr->wiphy); + else + tmp = NULL; + + dev_put(netdev); + + /* not wireless device -- return error */ + if (!tmp) + return ERR_PTR(-EINVAL); + + /* mismatch -- return error */ + if (rdev && tmp != rdev) + return ERR_PTR(-EINVAL); + + rdev = tmp; + } + } + + if (!rdev) + return ERR_PTR(-ENODEV); + + if (netns != wiphy_net(&rdev->wiphy)) + return ERR_PTR(-ENODEV); + + return rdev; +} + +/* + * This function returns a pointer to the driver + * that the genl_info item that is passed refers to. + * If successful, it returns non-NULL and also locks + * the driver's mutex! + * + * This means that you need to call cfg80211_unlock_rdev() + * before being allowed to acquire &cfg80211_mutex! + * + * This is necessary because we need to lock the global + * mutex to get an item off the list safely, and then + * we lock the rdev mutex so it doesn't go away under us. + * + * We don't want to keep cfg80211_mutex locked + * for all the time in order to allow requests on + * other interfaces to go through at the same time. + * + * The result of this can be a PTR_ERR and hence must + * be checked with IS_ERR() for errors. + */ +static struct cfg80211_registered_device * +cfg80211_get_dev_from_info(struct net *netns, struct genl_info *info) +{ + struct cfg80211_registered_device *rdev; + + mutex_lock(&cfg80211_mutex); + rdev = __cfg80211_rdev_from_attrs(netns, info->attrs); + + /* if it is not an error we grab the lock on + * it to assure it won't be going away while + * we operate on it */ + if (!IS_ERR(rdev)) + mutex_lock(&rdev->mtx); + + mutex_unlock(&cfg80211_mutex); + + return rdev; } /* policy for the attributes */ @@ -115,7 +262,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_STA_VLAN] = { .type = NLA_U32 }, [NL80211_ATTR_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_MESH_ID_LEN }, + .len = IEEE80211_MAX_MESH_ID_LEN }, [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, [NL80211_ATTR_REG_ALPHA2] = { .type = NLA_STRING, .len = 2 }, @@ -206,6 +353,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, + [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, }; /* policy for the key attributes */ @@ -250,8 +398,9 @@ nl80211_rekey_policy[NUM_NL80211_REKEY_DATA] = { static const struct nla_policy nl80211_match_policy[NL80211_SCHED_SCAN_MATCH_ATTR_MAX + 1] = { - [NL80211_ATTR_SCHED_SCAN_MATCH_SSID] = { .type = NLA_BINARY, + [NL80211_SCHED_SCAN_MATCH_ATTR_SSID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_SSID_LEN }, + [NL80211_SCHED_SCAN_MATCH_ATTR_RSSI] = { .type = NLA_U32 }, }; /* ifidx get helper */ @@ -832,6 +981,15 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, dev->wiphy.bands[band]->ht_cap.ampdu_density))) goto nla_put_failure; + /* add VHT info */ + if (dev->wiphy.bands[band]->vht_cap.vht_supported && + (nla_put(msg, NL80211_BAND_ATTR_VHT_MCS_SET, + sizeof(dev->wiphy.bands[band]->vht_cap.vht_mcs), + &dev->wiphy.bands[band]->vht_cap.vht_mcs) || + nla_put_u32(msg, NL80211_BAND_ATTR_VHT_CAPA, + dev->wiphy.bands[band]->vht_cap.cap))) + goto nla_put_failure; + /* add frequencies */ nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); if (!nl_freqs) @@ -1023,6 +1181,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_ifs); } +#ifdef CONFIG_PM if (dev->wiphy.wowlan.flags || dev->wiphy.wowlan.n_patterns) { struct nlattr *nl_wowlan; @@ -1063,6 +1222,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, nla_nest_end(msg, nl_wowlan); } +#endif if (nl80211_put_iftypes(msg, NL80211_ATTR_SOFTWARE_IFTYPES, dev->wiphy.software_iftypes)) @@ -1334,7 +1494,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) } if (!netdev) { - rdev = __cfg80211_rdev_from_info(info); + rdev = __cfg80211_rdev_from_attrs(genl_info_net(info), + info->attrs); if (IS_ERR(rdev)) { mutex_unlock(&cfg80211_mutex); return PTR_ERR(rdev); @@ -1567,37 +1728,42 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) return result; } +static inline u64 wdev_id(struct wireless_dev *wdev) +{ + return (u64)wdev->identifier | + ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); +} static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *rdev, - struct net_device *dev) + struct wireless_dev *wdev) { + struct net_device *dev = wdev->netdev; void *hdr; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); if (!hdr) return -1; - if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || - nla_put_u32(msg, NL80211_ATTR_IFTYPE, - dev->ieee80211_ptr->iftype) || + if (dev && + (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->devlist_generation ^ (cfg80211_rdev_list_generation << 2))) goto nla_put_failure; - if (rdev->ops->get_channel) { - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; - - chan = rdev->ops->get_channel(&rdev->wiphy, &channel_type); - if (chan && - (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, - chan->center_freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - channel_type))) + if (rdev->monitor_channel) { + if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + rdev->monitor_channel->center_freq) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + rdev->monitor_channel_type)) goto nla_put_failure; } @@ -1628,14 +1794,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * if_idx = 0; mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { if (if_idx < if_start) { if_idx++; continue; } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - rdev, wdev->netdev) < 0) { + rdev, wdev) < 0) { mutex_unlock(&rdev->devlist_mtx); goto out; } @@ -1658,14 +1824,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct cfg80211_registered_device *dev = info->user_ptr[0]; - struct net_device *netdev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, - dev, netdev) < 0) { + dev, wdev) < 0) { nlmsg_free(msg); return -ENOBUFS; } @@ -1805,7 +1971,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; - struct net_device *dev; + struct wireless_dev *wdev; + struct sk_buff *msg; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; u32 flags; @@ -1832,19 +1999,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return err; } + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); - dev = rdev->ops->add_virtual_intf(&rdev->wiphy, + wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); - if (IS_ERR(dev)) - return PTR_ERR(dev); + if (IS_ERR(wdev)) { + nlmsg_free(msg); + return PTR_ERR(wdev); + } if (type == NL80211_IFTYPE_MESH_POINT && info->attrs[NL80211_ATTR_MESH_ID]) { - struct wireless_dev *wdev = dev->ieee80211_ptr; - wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); @@ -1855,18 +2026,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) wdev_unlock(wdev); } - return 0; + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, + rdev, wdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); } static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; if (!rdev->ops->del_virtual_intf) return -EOPNOTSUPP; - return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); + /* + * If we remove a wireless device without a netdev then clear + * user_ptr[1] so that nl80211_post_doit won't dereference it + * to check if it needs to do dev_put(). Otherwise it crashes + * since the wdev has been freed, unlike with a netdev where + * we need the dev_put() for the netdev to really be freed. + */ + if (!wdev->netdev) + info->user_ptr[1] = NULL; + + return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); } static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) @@ -2246,6 +2433,33 @@ static int nl80211_parse_beacon(struct genl_info *info, return 0; } +static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, + struct cfg80211_ap_settings *params) +{ + struct wireless_dev *wdev; + bool ret = false; + + mutex_lock(&rdev->devlist_mtx); + + list_for_each_entry(wdev, &rdev->wdev_list, list) { + if (wdev->iftype != NL80211_IFTYPE_AP && + wdev->iftype != NL80211_IFTYPE_P2P_GO) + continue; + + if (!wdev->preset_chan) + continue; + + params->channel = wdev->preset_chan; + params->channel_type = wdev->preset_chantype; + ret = true; + break; + } + + mutex_unlock(&rdev->devlist_mtx); + + return ret; +} + static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -2348,16 +2562,28 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) } else if (wdev->preset_chan) { params.channel = wdev->preset_chan; params.channel_type = wdev->preset_chantype; - } else + } else if (!nl80211_get_ap_channel(rdev, ¶ms)) return -EINVAL; if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel, params.channel_type)) return -EINVAL; + mutex_lock(&rdev->devlist_mtx); + err = cfg80211_can_use_chan(rdev, wdev, params.channel, + CHAN_MODE_SHARED); + mutex_unlock(&rdev->devlist_mtx); + + if (err) + return err; + err = rdev->ops->start_ap(&rdev->wiphy, dev, ¶ms); - if (!err) + if (!err) { + wdev->preset_chan = params.channel; + wdev->preset_chantype = params.channel_type; wdev->beacon_interval = params.beacon_interval; + wdev->channel = params.channel; + } return err; } @@ -2390,23 +2616,8 @@ static int nl80211_stop_ap(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct net_device *dev = info->user_ptr[1]; - struct wireless_dev *wdev = dev->ieee80211_ptr; - int err; - - if (!rdev->ops->stop_ap) - return -EOPNOTSUPP; - - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) - return -EOPNOTSUPP; - if (!wdev->beacon_interval) - return -ENOENT; - - err = rdev->ops->stop_ap(&rdev->wiphy, dev); - if (!err) - wdev->beacon_interval = 0; - return err; + return cfg80211_stop_ap(rdev, dev); } static const struct nla_policy sta_flags_policy[NL80211_STA_FLAG_MAX + 1] = { @@ -2498,7 +2709,8 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, int attr) { struct nlattr *rate; - u16 bitrate; + u32 bitrate; + u16 bitrate_compat; rate = nla_nest_start(msg, attr); if (!rate) @@ -2506,8 +2718,12 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info, /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */ bitrate = cfg80211_calculate_bitrate(info); + /* report 16-bit bitrate only if we can */ + bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0; if ((bitrate > 0 && - nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate)) || + nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) || + (bitrate_compat > 0 && + nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) || ((info->flags & RATE_INFO_FLAGS_MCS) && nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) || ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) && @@ -3469,7 +3685,13 @@ static int nl80211_get_mesh_config(struct sk_buff *skb, nla_put_u32(msg, NL80211_MESHCONF_RSSI_THRESHOLD, cur_params.rssi_threshold) || nla_put_u32(msg, NL80211_MESHCONF_HT_OPMODE, - cur_params.ht_opmode)) + cur_params.ht_opmode) || + nla_put_u32(msg, NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, + cur_params.dot11MeshHWMPactivePathToRootTimeout) || + nla_put_u16(msg, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, + cur_params.dot11MeshHWMProotInterval) || + nla_put_u16(msg, NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, + cur_params.dot11MeshHWMPconfirmationInterval)) goto nla_put_failure; nla_nest_end(msg, pinfoattr); genlmsg_end(msg, hdr); @@ -3492,7 +3714,6 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_ELEMENT_TTL] = { .type = NLA_U8 }, [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, [NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR] = { .type = NLA_U32 }, - [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, @@ -3504,8 +3725,11 @@ static const struct nla_policy nl80211_meshconf_params_policy[NL80211_MESHCONF_A [NL80211_MESHCONF_HWMP_RANN_INTERVAL] = { .type = NLA_U16 }, [NL80211_MESHCONF_GATE_ANNOUNCEMENTS] = { .type = NLA_U8 }, [NL80211_MESHCONF_FORWARDING] = { .type = NLA_U8 }, - [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32}, - [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16}, + [NL80211_MESHCONF_RSSI_THRESHOLD] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HT_OPMODE] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HWMP_ROOT_INTERVAL] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL] = { .type = NLA_U16 }, }; static const struct nla_policy @@ -3515,7 +3739,7 @@ static const struct nla_policy [NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC] = { .type = NLA_U8 }, [NL80211_MESH_SETUP_USERSPACE_AUTH] = { .type = NLA_FLAG }, [NL80211_MESH_SETUP_IE] = { .type = NLA_BINARY, - .len = IEEE80211_MAX_DATA_LEN }, + .len = IEEE80211_MAX_DATA_LEN }, [NL80211_MESH_SETUP_USERSPACE_AMPE] = { .type = NLA_FLAG }, }; @@ -3548,63 +3772,82 @@ do {\ /* Fill in the params struct */ FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, - mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); + mask, NL80211_MESHCONF_RETRY_TIMEOUT, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, - mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); + mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, - mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); + mask, NL80211_MESHCONF_HOLDING_TIMEOUT, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, - mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); + mask, NL80211_MESHCONF_MAX_PEER_LINKS, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, - mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); + mask, NL80211_MESHCONF_MAX_RETRIES, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, - mask, NL80211_MESHCONF_TTL, nla_get_u8); + mask, NL80211_MESHCONF_TTL, nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, element_ttl, - mask, NL80211_MESHCONF_ELEMENT_TTL, nla_get_u8); + mask, NL80211_MESHCONF_ELEMENT_TTL, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, - mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, - mask, NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, - nla_get_u32); + mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshNbrOffsetMaxNeighbor, mask, + NL80211_MESHCONF_SYNC_OFFSET_MAX_NEIGHBOR, + nla_get_u32); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, - mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, - nla_get_u8); + mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, - mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); + mask, NL80211_MESHCONF_PATH_REFRESH_TIME, + nla_get_u32); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, - mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, - nla_get_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, - mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, - nla_get_u32); + mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, mask, + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + nla_get_u32); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, - mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, - nla_get_u16); + mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPperrMinInterval, - mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, - nla_get_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshHWMPnetDiameterTraversalTime, - mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, - nla_get_u16); - FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshHWMPRootMode, mask, - NL80211_MESHCONF_HWMP_ROOTMODE, - nla_get_u8); + mask, NL80211_MESHCONF_HWMP_PERR_MIN_INTERVAL, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshHWMPRannInterval, mask, - NL80211_MESHCONF_HWMP_RANN_INTERVAL, - nla_get_u16); + dot11MeshHWMPnetDiameterTraversalTime, mask, + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRootMode, mask, + NL80211_MESHCONF_HWMP_ROOTMODE, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPRannInterval, mask, + NL80211_MESHCONF_HWMP_RANN_INTERVAL, + nla_get_u16); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, - dot11MeshGateAnnouncementProtocol, mask, - NL80211_MESHCONF_GATE_ANNOUNCEMENTS, - nla_get_u8); + dot11MeshGateAnnouncementProtocol, mask, + NL80211_MESHCONF_GATE_ANNOUNCEMENTS, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshForwarding, - mask, NL80211_MESHCONF_FORWARDING, nla_get_u8); + mask, NL80211_MESHCONF_FORWARDING, + nla_get_u8); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, rssi_threshold, - mask, NL80211_MESHCONF_RSSI_THRESHOLD, nla_get_u32); + mask, NL80211_MESHCONF_RSSI_THRESHOLD, + nla_get_u32); FILL_IN_MESH_PARAM_IF_SET(tb, cfg, ht_opmode, - mask, NL80211_MESHCONF_HT_OPMODE, nla_get_u16); + mask, NL80211_MESHCONF_HT_OPMODE, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathToRootTimeout, + mask, + NL80211_MESHCONF_HWMP_PATH_TO_ROOT_TIMEOUT, + nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMProotInterval, + mask, NL80211_MESHCONF_HWMP_ROOT_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPconfirmationInterval, mask, + NL80211_MESHCONF_HWMP_CONFIRMATION_INTERVAL, + nla_get_u16); if (mask_out) *mask_out = mask; @@ -3887,7 +4130,7 @@ static int validate_scan_freqs(struct nlattr *freqs) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct cfg80211_scan_request *request; struct nlattr *attr; struct wiphy *wiphy; @@ -4047,15 +4290,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); - request->dev = dev; + request->wdev = wdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; - err = rdev->ops->scan(&rdev->wiphy, dev, request); + err = rdev->ops->scan(&rdev->wiphy, request); if (!err) { - nl80211_send_scan_start(rdev, dev); - dev_hold(dev); + nl80211_send_scan_start(rdev, wdev); + if (wdev->netdev) + dev_hold(wdev->netdev); } else { out_free: rdev->scan_req = NULL; @@ -4241,12 +4485,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCHED_SCAN_MATCH], tmp) { - struct nlattr *ssid; + struct nlattr *ssid, *rssi; nla_parse(tb, NL80211_SCHED_SCAN_MATCH_ATTR_MAX, nla_data(attr), nla_len(attr), nl80211_match_policy); - ssid = tb[NL80211_ATTR_SCHED_SCAN_MATCH_SSID]; + ssid = tb[NL80211_SCHED_SCAN_MATCH_ATTR_SSID]; if (ssid) { if (nla_len(ssid) > IEEE80211_MAX_SSID_LEN) { err = -EINVAL; @@ -4257,6 +4501,12 @@ static int nl80211_start_sched_scan(struct sk_buff *skb, request->match_sets[i].ssid.ssid_len = nla_len(ssid); } + rssi = tb[NL80211_SCHED_SCAN_MATCH_ATTR_RSSI]; + if (rssi) + request->rssi_thold = nla_get_u32(rssi); + else + request->rssi_thold = + NL80211_SCAN_RSSI_THOLD_OFF; i++; } } @@ -5114,21 +5364,18 @@ static int nl80211_testmode_dump(struct sk_buff *skb, nl80211_policy); if (err) return err; - if (nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]) { - phy_idx = nla_get_u32( - nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]); - } else { - struct net_device *netdev; - err = get_rdev_dev_by_ifindex(sock_net(skb->sk), - nl80211_fam.attrbuf, - &rdev, &netdev); - if (err) - return err; - dev_put(netdev); - phy_idx = rdev->wiphy_idx; - cfg80211_unlock_rdev(rdev); + mutex_lock(&cfg80211_mutex); + rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), + nl80211_fam.attrbuf); + if (IS_ERR(rdev)) { + mutex_unlock(&cfg80211_mutex); + return PTR_ERR(rdev); } + phy_idx = rdev->wiphy_idx; + rdev = NULL; + mutex_unlock(&cfg80211_mutex); + if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]) cb->args[1] = (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA]; @@ -5530,7 +5777,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct ieee80211_channel *chan; struct sk_buff *msg; void *hdr; @@ -5578,7 +5825,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, goto free_msg; } - err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, + err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, duration, &cookie); if (err) @@ -5602,7 +5849,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u64 cookie; if (!info->attrs[NL80211_ATTR_COOKIE]) @@ -5613,7 +5860,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); } static u32 rateset_to_mask(struct ieee80211_supported_band *sband, @@ -5762,7 +6009,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) @@ -5771,21 +6018,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_FRAME_TYPE]) frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } /* not much point in registering if we can't reply */ if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; - return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, - frame_type, + return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); } @@ -5793,7 +6043,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct ieee80211_channel *chan; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; bool channel_type_valid = false; @@ -5814,14 +6064,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } if (info->attrs[NL80211_ATTR_DURATION]) { if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) @@ -5870,7 +6124,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, + err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, channel_type_valid, wait, nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]), @@ -5898,7 +6152,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u64 cookie; if (!info->attrs[NL80211_ATTR_COOKIE]) @@ -5907,17 +6161,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in if (!rdev->ops->mgmt_tx_cancel_wait) return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); + return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); } static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) @@ -6126,6 +6384,7 @@ static int nl80211_leave_mesh(struct sk_buff *skb, struct genl_info *info) return cfg80211_leave_mesh(rdev, dev); } +#ifdef CONFIG_PM static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; @@ -6354,6 +6613,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) kfree(new_triggers.patterns); return err; } +#endif static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info) { @@ -6498,44 +6758,75 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) +#define NL80211_FLAG_NEED_WDEV 0x10 +/* If a netdev is associated, it must be UP */ +#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ + NL80211_FLAG_CHECK_NETDEV_UP) static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; struct net_device *dev; - int err; bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; if (rtnl) rtnl_lock(); if (ops->internal_flags & NL80211_FLAG_NEED_WIPHY) { - rdev = cfg80211_get_dev_from_info(info); + rdev = cfg80211_get_dev_from_info(genl_info_net(info), info); if (IS_ERR(rdev)) { if (rtnl) rtnl_unlock(); return PTR_ERR(rdev); } info->user_ptr[0] = rdev; - } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { - err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, - &rdev, &dev); - if (err) { + } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || + ops->internal_flags & NL80211_FLAG_NEED_WDEV) { + mutex_lock(&cfg80211_mutex); + wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), + info->attrs); + if (IS_ERR(wdev)) { + mutex_unlock(&cfg80211_mutex); if (rtnl) rtnl_unlock(); - return err; + return PTR_ERR(wdev); } - if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && - !netif_running(dev)) { - cfg80211_unlock_rdev(rdev); - dev_put(dev); - if (rtnl) - rtnl_unlock(); - return -ENETDOWN; + + dev = wdev->netdev; + rdev = wiphy_to_dev(wdev->wiphy); + + if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { + if (!dev) { + mutex_unlock(&cfg80211_mutex); + if (rtnl) + rtnl_unlock(); + return -EINVAL; + } + + info->user_ptr[1] = dev; + } else { + info->user_ptr[1] = wdev; } + + if (dev) { + if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + mutex_unlock(&cfg80211_mutex); + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } + + dev_hold(dev); + } + + cfg80211_lock_rdev(rdev); + + mutex_unlock(&cfg80211_mutex); + info->user_ptr[0] = rdev; - info->user_ptr[1] = dev; } return 0; @@ -6546,8 +6837,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, { if (info->user_ptr[0]) cfg80211_unlock_rdev(info->user_ptr[0]); - if (info->user_ptr[1]) - dev_put(info->user_ptr[1]); + if (info->user_ptr[1]) { + if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { + struct wireless_dev *wdev = info->user_ptr[1]; + + if (wdev->netdev) + dev_put(wdev->netdev); + } else { + dev_put(info->user_ptr[1]); + } + } if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) rtnl_unlock(); } @@ -6574,7 +6873,7 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_interface, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ - .internal_flags = NL80211_FLAG_NEED_NETDEV, + .internal_flags = NL80211_FLAG_NEED_WDEV, }, { .cmd = NL80211_CMD_SET_INTERFACE, @@ -6597,7 +6896,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_WDEV | NL80211_FLAG_NEED_RTNL, }, { @@ -6768,7 +7067,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6909,7 +7208,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6917,7 +7216,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6933,7 +7232,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_register_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_WDEV | NL80211_FLAG_NEED_RTNL, }, { @@ -6941,7 +7240,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -6949,7 +7248,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt_cancel_wait, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7008,6 +7307,7 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | NL80211_FLAG_NEED_RTNL, }, +#ifdef CONFIG_PM { .cmd = NL80211_CMD_GET_WOWLAN, .doit = nl80211_get_wowlan, @@ -7024,6 +7324,7 @@ static struct genl_ops nl80211_ops[] = { .internal_flags = NL80211_FLAG_NEED_WIPHY | NL80211_FLAG_NEED_RTNL, }, +#endif { .cmd = NL80211_CMD_SET_REKEY_OFFLOAD, .doit = nl80211_set_rekey_data, @@ -7158,7 +7459,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, static int nl80211_send_scan_msg(struct sk_buff *msg, struct cfg80211_registered_device *rdev, - struct net_device *netdev, + struct wireless_dev *wdev, u32 pid, u32 seq, int flags, u32 cmd) { @@ -7169,7 +7470,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, return -1; if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) + (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + wdev->netdev->ifindex)) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) goto nla_put_failure; /* ignore errors and send incomplete event anyway */ @@ -7206,7 +7509,7 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, } void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7214,7 +7517,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_TRIGGER_SCAN) < 0) { nlmsg_free(msg); return; @@ -7225,7 +7528,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7233,7 +7536,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_NEW_SCAN_RESULTS) < 0) { nlmsg_free(msg); return; @@ -7244,7 +7547,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7252,7 +7555,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_SCAN_ABORTED) < 0) { nlmsg_free(msg); return; @@ -7775,7 +8078,7 @@ nla_put_failure: static void nl80211_send_remain_on_chan_event( int cmd, struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) @@ -7794,7 +8097,9 @@ static void nl80211_send_remain_on_chan_event( } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + wdev->netdev->ifindex)) || + nla_put_u32(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) @@ -7816,23 +8121,24 @@ static void nl80211_send_remain_on_chan_event( } void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, + rdev, wdev, cookie, chan, channel_type, duration, gfp); } void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, + struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, + rdev, wdev, cookie, chan, channel_type, 0, gfp); } @@ -7946,10 +8252,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, } int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, + struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp) { + struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; @@ -7964,7 +8271,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + netdev->ifindex)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || (sig_dbm && nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || @@ -7982,10 +8290,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, } void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { + struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; @@ -8000,7 +8309,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + netdev->ifindex)) || nla_put(msg, NL80211_ATTR_FRAME, len, buf) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) @@ -8324,7 +8634,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, rcu_read_lock(); list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { - list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) + list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) cfg80211_mlme_unregister_socket(wdev, notify->pid); if (rdev->ap_beacons_nlpid == notify->pid) rdev->ap_beacons_nlpid = 0; diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 01a1122c3b33..89ce99675e61 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -7,11 +7,11 @@ int nl80211_init(void); void nl80211_exit(void); void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 cmd); void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, @@ -74,13 +74,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, gfp_t gfp); void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, + struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp); @@ -92,11 +92,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, + struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 15f347477a99..b2b32229b607 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -129,7 +129,7 @@ static DECLARE_DELAYED_WORK(reg_timeout, reg_timeout_work); /* We keep a static world regulatory domain in case of the absence of CRDA */ static const struct ieee80211_regdomain world_regdom = { - .n_reg_rules = 5, + .n_reg_rules = 6, .alpha2 = "00", .reg_rules = { /* IEEE 802.11b/g, channels 1..11 */ @@ -156,6 +156,9 @@ static const struct ieee80211_regdomain world_regdom = { REG_RULE(5745-10, 5825+10, 40, 6, 20, NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS), + + /* IEEE 802.11ad (60gHz), channels 1..3 */ + REG_RULE(56160+2160*1-1080, 56160+2160*3+1080, 2160, 0, 0, 0), } }; @@ -1389,7 +1392,7 @@ static void reg_set_request_processed(void) spin_unlock(®_requests_lock); if (last_request->initiator == NL80211_REGDOM_SET_BY_USER) - cancel_delayed_work_sync(®_timeout); + cancel_delayed_work(®_timeout); if (need_more_processing) schedule_work(®_work); diff --git a/net/wireless/scan.c b/net/wireless/scan.c index af2b1caa37fa..848523a2b22f 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -23,7 +23,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; - struct net_device *dev; + struct wireless_dev *wdev; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) if (!request) return; - dev = request->dev; + wdev = request->wdev; /* * This must be before sending the other events! * Otherwise, wpa_supplicant gets completely confused with * wext events. */ - cfg80211_sme_scan_done(dev); + if (wdev->netdev) + cfg80211_sme_scan_done(wdev->netdev); if (request->aborted) - nl80211_send_scan_aborted(rdev, dev); + nl80211_send_scan_aborted(rdev, wdev); else - nl80211_send_scan_done(rdev, dev); + nl80211_send_scan_done(rdev, wdev); #ifdef CONFIG_CFG80211_WEXT - if (!request->aborted) { + if (wdev->netdev && !request->aborted) { memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL); } #endif - dev_put(dev); + if (wdev->netdev) + dev_put(wdev->netdev); rdev->scan_req = NULL; @@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, } creq->wiphy = wiphy; - creq->dev = dev; + creq->wdev = dev->ieee80211_ptr; /* SSIDs come after channels */ creq->ssids = (void *)&creq->channels[n_channels]; creq->n_channels = n_channels; @@ -1024,12 +1026,12 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; rdev->scan_req = creq; - err = rdev->ops->scan(wiphy, dev, creq); + err = rdev->ops->scan(wiphy, creq); if (err) { rdev->scan_req = NULL; /* creq will be freed below */ } else { - nl80211_send_scan_start(rdev, dev); + nl80211_send_scan_start(rdev, dev->ieee80211_ptr); /* creq now owned by driver */ creq = NULL; dev_hold(dev); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f7e937ff8978..6f39cb808302 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void) */ list_for_each_entry(rdev, &cfg80211_rdev_list, list) { cfg80211_lock_rdev(rdev); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) is_all_idle = false; @@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) wdev->conn->params.ssid_len); request->ssids[0].ssid_len = wdev->conn->params.ssid_len; - request->dev = wdev->netdev; + request->wdev = wdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; - err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); + err = rdev->ops->scan(wdev->wiphy, request); if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; - nl80211_send_scan_start(rdev, wdev->netdev); + nl80211_send_scan_start(rdev, wdev); dev_hold(wdev->netdev); } else { rdev->scan_req = NULL; @@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work) cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { wdev_lock(wdev); if (!netif_running(wdev->netdev)) { wdev_unlock(wdev); diff --git a/net/wireless/util.c b/net/wireless/util.c index 8f2d68fc3a44..26f8cd30f712 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -35,19 +35,29 @@ int ieee80211_channel_to_frequency(int chan, enum ieee80211_band band) { /* see 802.11 17.3.8.3.2 and Annex J * there are overlapping channel numbers in 5GHz and 2GHz bands */ - if (band == IEEE80211_BAND_5GHZ) { - if (chan >= 182 && chan <= 196) - return 4000 + chan * 5; - else - return 5000 + chan * 5; - } else { /* IEEE80211_BAND_2GHZ */ + if (chan <= 0) + return 0; /* not supported */ + switch (band) { + case IEEE80211_BAND_2GHZ: if (chan == 14) return 2484; else if (chan < 14) return 2407 + chan * 5; + break; + case IEEE80211_BAND_5GHZ: + if (chan >= 182 && chan <= 196) + return 4000 + chan * 5; else - return 0; /* not supported */ + return 5000 + chan * 5; + break; + case IEEE80211_BAND_60GHZ: + if (chan < 5) + return 56160 + chan * 2160; + break; + default: + ; } + return 0; /* not supported */ } EXPORT_SYMBOL(ieee80211_channel_to_frequency); @@ -60,8 +70,12 @@ int ieee80211_frequency_to_channel(int freq) return (freq - 2407) / 5; else if (freq >= 4910 && freq <= 4980) return (freq - 4000) / 5; - else + else if (freq <= 45000) /* DMG band lower limit */ return (freq - 5000) / 5; + else if (freq >= 58320 && freq <= 64800) + return (freq - 56160) / 2160; + else + return 0; } EXPORT_SYMBOL(ieee80211_frequency_to_channel); @@ -137,6 +151,11 @@ static void set_mandatory_flags_band(struct ieee80211_supported_band *sband, } WARN_ON(want != 0 && want != 3 && want != 6); break; + case IEEE80211_BAND_60GHZ: + /* check for mandatory HT MCS 1..4 */ + WARN_ON(!sband->ht_cap.ht_supported); + WARN_ON((sband->ht_cap.mcs.rx_mask[0] & 0x1e) != 0x1e); + break; case IEEE80211_NUM_BANDS: WARN_ON(1); break; @@ -774,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) + list_for_each_entry(wdev, &rdev->wdev_list, list) cfg80211_process_wdev_events(wdev); mutex_unlock(&rdev->devlist_mtx); @@ -804,9 +823,11 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ntype == NL80211_IFTYPE_P2P_CLIENT)) return -EBUSY; - if (ntype != otype) { + if (ntype != otype && netif_running(dev)) { + mutex_lock(&rdev->devlist_mtx); err = cfg80211_can_change_interface(rdev, dev->ieee80211_ptr, ntype); + mutex_unlock(&rdev->devlist_mtx); if (err) return err; @@ -814,6 +835,9 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, dev->ieee80211_ptr->mesh_id_up_len = 0; switch (otype) { + case NL80211_IFTYPE_AP: + cfg80211_stop_ap(rdev, dev); + break; case NL80211_IFTYPE_ADHOC: cfg80211_leave_ibss(rdev, dev, false); break; @@ -868,15 +892,69 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, } } + if (!err && ntype != otype && netif_running(dev)) { + cfg80211_update_iface_num(rdev, ntype, 1); + cfg80211_update_iface_num(rdev, otype, -1); + } + return err; } -u16 cfg80211_calculate_bitrate(struct rate_info *rate) +static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate) +{ + static const u32 __mcs2bitrate[] = { + /* control PHY */ + [0] = 275, + /* SC PHY */ + [1] = 3850, + [2] = 7700, + [3] = 9625, + [4] = 11550, + [5] = 12512, /* 1251.25 mbps */ + [6] = 15400, + [7] = 19250, + [8] = 23100, + [9] = 25025, + [10] = 30800, + [11] = 38500, + [12] = 46200, + /* OFDM PHY */ + [13] = 6930, + [14] = 8662, /* 866.25 mbps */ + [15] = 13860, + [16] = 17325, + [17] = 20790, + [18] = 27720, + [19] = 34650, + [20] = 41580, + [21] = 45045, + [22] = 51975, + [23] = 62370, + [24] = 67568, /* 6756.75 mbps */ + /* LP-SC PHY */ + [25] = 6260, + [26] = 8340, + [27] = 11120, + [28] = 12510, + [29] = 16680, + [30] = 22240, + [31] = 25030, + }; + + if (WARN_ON_ONCE(rate->mcs >= ARRAY_SIZE(__mcs2bitrate))) + return 0; + + return __mcs2bitrate[rate->mcs]; +} + +u32 cfg80211_calculate_bitrate(struct rate_info *rate) { int modulation, streams, bitrate; if (!(rate->flags & RATE_INFO_FLAGS_MCS)) return rate->legacy; + if (rate->flags & RATE_INFO_FLAGS_60G) + return cfg80211_calculate_bitrate_60g(rate); /* the formula below does only work for MCS values smaller than 32 */ if (WARN_ON_ONCE(rate->mcs >= 32)) @@ -916,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { if (!wdev->beacon_interval) continue; if (wdev->beacon_interval != beacon_int) { @@ -930,28 +1008,49 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, return res; } -int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, - enum nl80211_iftype iftype) +int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + enum nl80211_iftype iftype, + struct ieee80211_channel *chan, + enum cfg80211_chan_mode chanmode) { struct wireless_dev *wdev_iter; u32 used_iftypes = BIT(iftype); int num[NUM_NL80211_IFTYPES]; + struct ieee80211_channel + *used_channels[CFG80211_MAX_NUM_DIFFERENT_CHANNELS]; + struct ieee80211_channel *ch; + enum cfg80211_chan_mode chmode; + int num_different_channels = 0; int total = 1; int i, j; ASSERT_RTNL(); + lockdep_assert_held(&rdev->devlist_mtx); /* Always allow software iftypes */ if (rdev->wiphy.software_iftypes & BIT(iftype)) return 0; memset(num, 0, sizeof(num)); + memset(used_channels, 0, sizeof(used_channels)); num[iftype] = 1; - mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { + switch (chanmode) { + case CHAN_MODE_UNDEFINED: + break; + case CHAN_MODE_SHARED: + WARN_ON(!chan); + used_channels[0] = chan; + num_different_channels++; + break; + case CHAN_MODE_EXCLUSIVE: + num_different_channels++; + break; + } + + list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { if (wdev_iter == wdev) continue; if (!netif_running(wdev_iter->netdev)) @@ -960,11 +1059,42 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) continue; + /* + * We may be holding the "wdev" mutex, but now need to lock + * wdev_iter. This is OK because once we get here wdev_iter + * is not wdev (tested above), but we need to use the nested + * locking for lockdep. + */ + mutex_lock_nested(&wdev_iter->mtx, 1); + __acquire(wdev_iter->mtx); + cfg80211_get_chan_state(wdev_iter, &ch, &chmode); + wdev_unlock(wdev_iter); + + switch (chmode) { + case CHAN_MODE_UNDEFINED: + break; + case CHAN_MODE_SHARED: + for (i = 0; i < CFG80211_MAX_NUM_DIFFERENT_CHANNELS; i++) + if (!used_channels[i] || used_channels[i] == ch) + break; + + if (i == CFG80211_MAX_NUM_DIFFERENT_CHANNELS) + return -EBUSY; + + if (used_channels[i] == NULL) { + used_channels[i] = ch; + num_different_channels++; + } + break; + case CHAN_MODE_EXCLUSIVE: + num_different_channels++; + break; + } + num[wdev_iter->iftype]++; total++; used_iftypes |= BIT(wdev_iter->iftype); } - mutex_unlock(&rdev->devlist_mtx); if (total == 1) return 0; @@ -976,12 +1106,15 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, c = &rdev->wiphy.iface_combinations[i]; + if (total > c->max_interfaces) + continue; + if (num_different_channels > c->num_different_channels) + continue; + limits = kmemdup(c->limits, sizeof(limits[0]) * c->n_limits, GFP_KERNEL); if (!limits) return -ENOMEM; - if (total > c->max_interfaces) - goto cont; for (iftype = 0; iftype < NUM_NL80211_IFTYPES; iftype++) { if (rdev->wiphy.software_iftypes & BIT(iftype)) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index bc879833b21f..7df42f541873 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -827,8 +827,6 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); - struct ieee80211_channel *chan; - enum nl80211_channel_type channel_type; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -836,13 +834,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, case NL80211_IFTYPE_ADHOC: return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); case NL80211_IFTYPE_MONITOR: - if (!rdev->ops->get_channel) + if (!rdev->monitor_channel) return -EINVAL; - chan = rdev->ops->get_channel(wdev->wiphy, &channel_type); - if (!chan) - return -EINVAL; - freq->m = chan->center_freq; + freq->m = rdev->monitor_channel->center_freq; freq->e = 6; return 0; default: |