diff options
198 files changed, 4692 insertions, 15819 deletions
diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt index 320f933..89a339c 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 ce7398e..b4321fb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3661,14 +3661,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 b81755b..f6589eb 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 bc6e892..63c8b47 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 e9f1b3f..a4c3ebc 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 61ce405..4432617 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 c3e9dff..ef34ed2 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 b9a86ed..cbae2c2 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 6c05cf4..11b32d2 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 7e138ec..7ff4bac 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 a342058..a0272bb 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -340,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; } } @@ -427,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; } @@ -482,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); } @@ -538,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 f16f42d3..26823d9 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/misc/Kconfig b/drivers/misc/Kconfig index 2661f6e..154f3ef 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 456972f..b88df7a 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 9e4b88f..0000000 --- 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 fbf53fb..0000000 --- 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 62fbaec..0000000 --- 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 71d4575..0000000 --- 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 e27afde..0000000 --- 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 9e26b75..0000000 --- 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 620973e..0000000 --- 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 a36a55a..0000000 --- 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 4434bb1..0000000 --- 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 701eb60..0000000 --- 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 672de18..71453db 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 5d9e018..f6d19c3 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 47cae71..850b8bc 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 d09e449..283237f 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 1d63ffd..0000000 --- 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 c806d45..79c6505 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 c519987..0000000 --- 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 8e02541..0000000 --- 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 fb6396d..0000000 --- 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 b53cd1c..0000000 --- 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 21a9edd..0000000 --- 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 5f58fa5..6deaae1 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 0ce218b..062dfdf 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/ath/ath5k/Kconfig b/drivers/net/wireless/ath/ath5k/Kconfig index e18a9aa..338c5c4 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 44ad6fe..8c4c040 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++; diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index fd7dbd4..aca1d26 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -3627,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 | @@ -3636,6 +3637,7 @@ 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_SSIDS; diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c index 4a4e8a2..3a69804 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/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index d7deb8c..84b558d 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 b1e5923..ab2bfcb 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 a0e3394..41e88c6 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_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 6155837..9a34fca 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -1015,12 +1015,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) return; if (mci->is_2g) { - if (!force) { - ar9003_mci_send_2g5g_status(ah, true); - - ar9003_mci_send_lna_transfer(ah, true); - udelay(5); - } + ar9003_mci_send_2g5g_status(ah, true); + ar9003_mci_send_lna_transfer(ah, true); + udelay(5); REG_CLR_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); @@ -1030,10 +1027,8 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA)) ar9003_mci_osla_setup(ah, true); } else { - if (!force) { - ar9003_mci_send_lna_take(ah, true); - udelay(5); - } + ar9003_mci_send_lna_take(ah, true); + udelay(5); REG_SET_BIT(ah, AR_MCI_TX_CTRL, AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE); @@ -1041,8 +1036,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force) AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL); ar9003_mci_osla_setup(ah, false); - if (!force) - ar9003_mci_send_2g5g_status(ah, true); + ar9003_mci_send_2g5g_status(ah, true); } } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_paprd.c b/drivers/net/wireless/ath/ath9k/ar9003_paprd.c index 3d400e8..2c9f7d7 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 6b91ebb..d2346db 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; @@ -180,7 +181,8 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah, * is out-of-band and can be ignored. */ - 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)) { if (spur_fbin_ptr[0] == 0) /* No spur */ return; max_spur_cnts = 5; @@ -205,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 @@ -618,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) { @@ -659,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 diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index ed662c3..751c83b 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/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h new file mode 100644 index 0000000..df97f21 --- /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/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index fe39eb4..79840d6 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -481,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) { @@ -504,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 */ /********************/ diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c index 9ae6a4d..bacdb8f 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)) @@ -232,6 +240,7 @@ static void ath_btcoex_period_timer(unsigned long data) } ath9k_ps_restore(sc); +skip_hw_wakeup: timer_period = btcoex->btcoex_period; mod_timer(&btcoex->period_timer, jiffies + msecs_to_jiffies(timer_period)); } @@ -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); } diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index ebfb2a3..c1659d0 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; @@ -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; @@ -865,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); @@ -879,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); @@ -894,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); @@ -906,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 */ @@ -919,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); @@ -943,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)) { @@ -1949,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; @@ -1987,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); @@ -2000,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); @@ -3137,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 9409660..26da173 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; diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c index 04ef775..7990cd5 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 21c9556..0eba36d 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 e4e73f0..248e5b2 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -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; } @@ -169,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)); @@ -666,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); @@ -774,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 */ @@ -1139,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; + } } /* diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 64cc782..87acff7 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -174,8 +174,8 @@ 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; diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 6a7dd26..11f3703 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; } diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 5046b28..6592c07 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 diff --git a/drivers/net/wireless/ath/carl9170/carl9170.h b/drivers/net/wireless/ath/carl9170/carl9170.h index 0cea20e..376be11 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 5c73c03..c5ca6f1 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 6d9c089..66848d4 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 8d2523b..858e58d 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 7a8e90e..6f6a341 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 aed3051..6a86814 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 e651db8..2ec3e91 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/b43/phy_n.c b/drivers/net/wireless/b43/phy_n.c index 1081188..b92bb9c 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/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index 3c6f9b1..8c9345d 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 d6fa982..89562c1 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/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 2d365d3..9a4c63f 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -763,20 +763,17 @@ void brcms_c_regd_init(struct brcms_c_info *wlc) int band_idx, i; /* Disable any channels not supported by the phy */ - for (band_idx = 0; band_idx < IEEE80211_NUM_BANDS; band_idx++) { - if (band_idx == IEEE80211_BAND_2GHZ) - band = wlc->bandstate[BAND_2G_INDEX]; - else - band = wlc->bandstate[BAND_5G_INDEX]; - - /* skip if band not initialized */ - if (band->pi == NULL) - continue; + 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); - sband = wiphy->bands[band_idx]; + 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)) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/dma.c b/drivers/net/wireless/brcm80211/brcmsmac/dma.c index 7516639..5e53305 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 2d5a404..2b57f57 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, diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index bb00b65..cb73f22 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -269,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; @@ -333,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 */ @@ -343,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 @@ -1942,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 @@ -2023,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 @@ -2126,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); @@ -2791,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 | @@ -4218,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); @@ -4241,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) @@ -4284,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) @@ -4454,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; } @@ -4528,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() @@ -4595,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 = @@ -5036,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))) @@ -5130,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, @@ -5767,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; @@ -5787,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) { diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c index 264f8c4..91937c5 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 3667181..65db9b7 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 4931d29..7e9df56 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 3e39c5e..f7cff87 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 aa5d67f..5855f4f 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/soc.h b/drivers/net/wireless/brcm80211/include/soc.h index 4e9b7e4..123cfa8 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 4b10157..d4fd29a 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/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 64811cd..97bea16 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -190,6 +190,44 @@ enum { REPLY_MAX = 0xff }; +/* + * Minimum number of queues. MAX_NUM is defined in hw specific files. + * Set the minimum to accommodate + * - 4 standard TX queues + * - the command queue + * - 4 PAN TX queues + * - the PAN multicast queue, and + * - the AUX (TX during scan dwell) queue. + */ +#define IWL_MIN_NUM_QUEUES 11 + +/* + * Command queue depends on iPAN support. + */ +#define IWL_DEFAULT_CMD_QUEUE_NUM 4 +#define IWL_IPAN_CMD_QUEUE_NUM 9 + +#define IWL_TX_FIFO_BK 0 /* shared */ +#define IWL_TX_FIFO_BE 1 +#define IWL_TX_FIFO_VI 2 /* shared */ +#define IWL_TX_FIFO_VO 3 +#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK +#define IWL_TX_FIFO_BE_IPAN 4 +#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI +#define IWL_TX_FIFO_VO_IPAN 5 +/* re-uses the VO FIFO, uCode will properly flush/schedule */ +#define IWL_TX_FIFO_AUX 5 +#define IWL_TX_FIFO_UNUSED 255 + +#define IWLAGN_CMD_FIFO_NUM 7 + +/* + * This queue number is required for proper operation + * because the ucode will stop/start the scheduler as + * required. + */ +#define IWL_IPAN_MCAST_QUEUE 8 + /****************************************************************************** * (0) * Commonly used structures and definitions: @@ -755,8 +793,6 @@ struct iwl_qosparam_cmd { #define IWLAGN_BROADCAST_ID 15 #define IWLAGN_STATION_COUNT 16 -#define IWL_INVALID_STATION 255 -#define IWL_MAX_TID_COUNT 8 #define IWL_TID_NON_QOS IWL_MAX_TID_COUNT #define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2) diff --git a/drivers/net/wireless/iwlwifi/dvm/debugfs.c b/drivers/net/wireless/iwlwifi/dvm/debugfs.c index b0eff1c..46782f1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/debugfs.c +++ b/drivers/net/wireless/iwlwifi/dvm/debugfs.c @@ -83,7 +83,7 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file, \ #define DEBUGFS_READ_FILE_OPS(name) \ DEBUGFS_READ_FUNC(name); \ static const struct file_operations iwl_dbgfs_##name##_ops = { \ - .read = iwl_dbgfs_##name##_read, \ + .read = iwl_dbgfs_##name##_read, \ .open = simple_open, \ .llseek = generic_file_llseek, \ }; @@ -2255,6 +2255,10 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, char buf[8]; int buf_size; + /* check that the interface is up */ + if (!iwl_is_ready(priv)) + return -EAGAIN; + memset(buf, 0, sizeof(buf)); buf_size = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, buf_size)) diff --git a/drivers/net/wireless/iwlwifi/dvm/dev.h b/drivers/net/wireless/iwlwifi/dvm/dev.h index 54cf085..054f728 100644 --- a/drivers/net/wireless/iwlwifi/dvm/dev.h +++ b/drivers/net/wireless/iwlwifi/dvm/dev.h @@ -90,22 +90,6 @@ #define IWL_NUM_SCAN_RATES (2) -/* - * Minimum number of queues. MAX_NUM is defined in hw specific files. - * Set the minimum to accommodate - * - 4 standard TX queues - * - the command queue - * - 4 PAN TX queues - * - the PAN multicast queue, and - * - the AUX (TX during scan dwell) queue. - */ -#define IWL_MIN_NUM_QUEUES 11 - -/* - * Command queue depends on iPAN support. - */ -#define IWL_DEFAULT_CMD_QUEUE_NUM 4 -#define IWL_IPAN_CMD_QUEUE_NUM 9 #define IEEE80211_DATA_LEN 2304 #define IEEE80211_4ADDR_LEN 30 diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index abfd791..612f05d 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -518,49 +518,6 @@ static void iwl_bg_tx_flush(struct work_struct *work) * queue/FIFO/AC mapping definitions */ -#define IWL_TX_FIFO_BK 0 /* shared */ -#define IWL_TX_FIFO_BE 1 -#define IWL_TX_FIFO_VI 2 /* shared */ -#define IWL_TX_FIFO_VO 3 -#define IWL_TX_FIFO_BK_IPAN IWL_TX_FIFO_BK -#define IWL_TX_FIFO_BE_IPAN 4 -#define IWL_TX_FIFO_VI_IPAN IWL_TX_FIFO_VI -#define IWL_TX_FIFO_VO_IPAN 5 -/* re-uses the VO FIFO, uCode will properly flush/schedule */ -#define IWL_TX_FIFO_AUX 5 -#define IWL_TX_FIFO_UNUSED -1 - -#define IWLAGN_CMD_FIFO_NUM 7 - -/* - * This queue number is required for proper operation - * because the ucode will stop/start the scheduler as - * required. - */ -#define IWL_IPAN_MCAST_QUEUE 8 - -static const u8 iwlagn_default_queue_to_tx_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, - IWLAGN_CMD_FIFO_NUM, -}; - -static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { - IWL_TX_FIFO_VO, - IWL_TX_FIFO_VI, - IWL_TX_FIFO_BE, - IWL_TX_FIFO_BK, - IWL_TX_FIFO_BK_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWL_TX_FIFO_VI_IPAN, - IWL_TX_FIFO_VO_IPAN, - IWL_TX_FIFO_BE_IPAN, - IWLAGN_CMD_FIFO_NUM, - IWL_TX_FIFO_AUX, -}; - static const u8 iwlagn_bss_ac_to_fifo[] = { IWL_TX_FIFO_VO, IWL_TX_FIFO_VI, @@ -1350,6 +1307,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, else trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED; trans_cfg.command_names = iwl_dvm_cmd_strings; + trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM; WARN_ON(sizeof(priv->transport_queue_stop) * BITS_PER_BYTE < priv->cfg->base_params->num_of_queues); @@ -1363,15 +1321,9 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, if (ucode_flags & IWL_UCODE_TLV_FLAGS_PAN) { priv->sta_key_max_num = STA_KEY_MAX_NUM_PAN; trans_cfg.cmd_queue = IWL_IPAN_CMD_QUEUE_NUM; - trans_cfg.queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo; - trans_cfg.n_queue_to_fifo = - ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); } else { priv->sta_key_max_num = STA_KEY_MAX_NUM; trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; - trans_cfg.n_queue_to_fifo = - ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); } /* Configure transport layer */ @@ -1460,9 +1412,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, ucode_flags &= ~IWL_UCODE_TLV_FLAGS_P2P; priv->sta_key_max_num = STA_KEY_MAX_NUM; trans_cfg.cmd_queue = IWL_DEFAULT_CMD_QUEUE_NUM; - trans_cfg.queue_to_fifo = iwlagn_default_queue_to_tx_fifo; - trans_cfg.n_queue_to_fifo = - ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); /* Configure transport layer again*/ iwl_trans_configure(priv->trans, &trans_cfg); @@ -1480,9 +1429,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, atomic_set(&priv->queue_stop_count[i], 0); } - WARN_ON(trans_cfg.queue_to_fifo[trans_cfg.cmd_queue] != - IWLAGN_CMD_FIFO_NUM); - if (iwl_init_drv(priv)) goto out_free_eeprom; diff --git a/drivers/net/wireless/iwlwifi/dvm/scan.c b/drivers/net/wireless/iwlwifi/dvm/scan.c index 6633074..e3467fa 100644 --- a/drivers/net/wireless/iwlwifi/dvm/scan.c +++ b/drivers/net/wireless/iwlwifi/dvm/scan.c @@ -396,15 +396,21 @@ static u16 iwl_get_active_dwell_time(struct iwl_priv *priv, static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) { struct iwl_rxon_context *ctx; + int limits[NUM_IWL_RXON_CTX] = {}; + int n_active = 0; + u16 limit; + + BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2); /* * If we're associated, we clamp the dwell time 98% - * of the smallest beacon interval (minus 2 * channel - * tune time) + * of the beacon interval (minus 2 * channel tune time) + * If both contexts are active, we have to restrict to + * 1/2 of the minimum of them, because they might be in + * lock-step with the time inbetween only half of what + * time we'd have in each of them. */ for_each_context(priv, ctx) { - u16 value; - switch (ctx->staging.dev_type) { case RXON_DEV_TYPE_P2P: /* no timing constraints */ @@ -424,14 +430,25 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time) break; } - value = ctx->beacon_int; - if (!value) - value = IWL_PASSIVE_DWELL_BASE; - value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; - dwell_time = min(value, dwell_time); + limits[n_active++] = ctx->beacon_int ?: IWL_PASSIVE_DWELL_BASE; } - return dwell_time; + switch (n_active) { + case 0: + return dwell_time; + case 2: + limit = (limits[1] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + limit /= 2; + dwell_time = min(limit, dwell_time); + /* fall through to limit further */ + case 1: + limit = (limits[0] * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2; + limit /= n_active; + return min(limit, dwell_time); + default: + WARN_ON_ONCE(1); + return dwell_time; + } } static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv, diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c index b3a314b..6d8d6dd 100644 --- a/drivers/net/wireless/iwlwifi/dvm/ucode.c +++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c @@ -226,13 +226,50 @@ int iwl_send_bt_env(struct iwl_priv *priv, u8 action, u8 type) return ret; } +static const u8 iwlagn_default_queue_to_tx_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, +}; + +static const u8 iwlagn_ipan_queue_to_tx_fifo[] = { + IWL_TX_FIFO_VO, + IWL_TX_FIFO_VI, + IWL_TX_FIFO_BE, + IWL_TX_FIFO_BK, + IWL_TX_FIFO_BK_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWL_TX_FIFO_VI_IPAN, + IWL_TX_FIFO_VO_IPAN, + IWL_TX_FIFO_BE_IPAN, + IWL_TX_FIFO_UNUSED, + IWL_TX_FIFO_AUX, +}; static int iwl_alive_notify(struct iwl_priv *priv) { + const u8 *queue_to_txf; + u8 n_queues; int ret; + int i; iwl_trans_fw_alive(priv->trans); + if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN && + priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE) { + n_queues = ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo); + queue_to_txf = iwlagn_ipan_queue_to_tx_fifo; + } else { + n_queues = ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo); + queue_to_txf = iwlagn_default_queue_to_tx_fifo; + } + + for (i = 0; i < n_queues; i++) + if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED) + iwl_trans_ac_txq_enable(priv->trans, i, + queue_to_txf[i]); + priv->passive_no_rx = false; priv->transport_queue_stop = 0; diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.c b/drivers/net/wireless/iwlwifi/iwl-debug.c index 0f8fcd1..87535a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.c +++ b/drivers/net/wireless/iwlwifi/iwl-debug.c @@ -61,6 +61,9 @@ * *****************************************************************************/ +#define DEBUG + +#include <linux/device.h> #include <linux/interrupt.h> #include <linux/export.h> #include "iwl-debug.h" @@ -124,7 +127,7 @@ void __iwl_dbg(struct device *dev, #ifdef CONFIG_IWLWIFI_DEBUG if (iwl_have_debug_level(level) && (!limit || net_ratelimit())) - dev_err(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', + dev_dbg(dev, "%c %s %pV", in_interrupt() ? 'I' : 'U', function, &vaf); #endif trace_iwlwifi_dbg(level, in_interrupt(), function, &vaf); diff --git a/drivers/net/wireless/iwlwifi/iwl-devtrace.h b/drivers/net/wireless/iwlwifi/iwl-devtrace.h index 6536479..06ca505 100644 --- a/drivers/net/wireless/iwlwifi/iwl-devtrace.h +++ b/drivers/net/wireless/iwlwifi/iwl-devtrace.h @@ -176,7 +176,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event, #undef TRACE_SYSTEM #define TRACE_SYSTEM iwlwifi_msg -#define MAX_MSG_LEN 100 +#define MAX_MSG_LEN 110 DECLARE_EVENT_CLASS(iwlwifi_msg_event, TP_PROTO(struct va_format *vaf), @@ -189,7 +189,7 @@ DECLARE_EVENT_CLASS(iwlwifi_msg_event, MAX_MSG_LEN, vaf->fmt, *vaf->va) >= MAX_MSG_LEN); ), - TP_printk("%s", (char *)__get_dynamic_array(msg)) + TP_printk("%s", __get_str(msg)) ); DEFINE_EVENT(iwlwifi_msg_event, iwlwifi_err, diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c index a175997..cc41cfa 100644 --- a/drivers/net/wireless/iwlwifi/iwl-drv.c +++ b/drivers/net/wireless/iwlwifi/iwl-drv.c @@ -1013,6 +1013,7 @@ struct iwl_mod_params iwlwifi_mod_params = { .power_level = IWL_POWER_INDEX_1, .bt_ch_announce = true, .auto_agg = true, + .wd_disable = true, /* the rest are 0 by default */ }; EXPORT_SYMBOL_GPL(iwlwifi_mod_params); diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 00efde8..867d8e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -290,16 +290,17 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) * currently supports */ #define IWL_MAX_HW_QUEUES 32 +#define IWL_INVALID_STATION 255 +#define IWL_MAX_TID_COUNT 8 +#define IWL_FRAME_LIMIT 64 /** * struct iwl_trans_config - transport configuration * * @op_mode: pointer to the upper layer. - * @queue_to_fifo: queue to FIFO mapping to set up by - * default - * @n_queue_to_fifo: number of queues to set up * @cmd_queue: the index of the command queue. * Must be set before start_fw. + * @cmd_fifo: the fifo for host commands * @no_reclaim_cmds: Some devices erroneously don't set the * SEQ_RX_FRAME bit on some notifications, this is the * list of such notifications to filter. Max length is @@ -314,10 +315,9 @@ static inline struct page *rxb_steal_page(struct iwl_rx_cmd_buffer *r) */ struct iwl_trans_config { struct iwl_op_mode *op_mode; - const u8 *queue_to_fifo; - u8 n_queue_to_fifo; u8 cmd_queue; + u8 cmd_fifo; const u8 *no_reclaim_cmds; int n_no_reclaim_cmds; @@ -355,9 +355,9 @@ struct iwl_trans; * Must be atomic * @reclaim: free packet until ssn. Returns a list of freed packets. * Must be atomic - * @txq_enable: setup a tx queue for AMPDU - will be called once the HW is - * ready and a successful ADDBA response has been received. - * May sleep + * @txq_enable: setup a queue. To setup an AC queue, use the + * iwl_trans_ac_txq_enable wrapper. fw_alive must have been called before + * this one. The op_mode must not configure the HCMD queue. May sleep. * @txq_disable: de-configure a Tx queue to send AMPDUs * Must be atomic * @wait_tx_queue_empty: wait until all tx queues are empty @@ -497,9 +497,9 @@ static inline void iwl_trans_fw_alive(struct iwl_trans *trans) { might_sleep(); - trans->ops->fw_alive(trans); - trans->state = IWL_TRANS_FW_ALIVE; + + trans->ops->fw_alive(trans); } static inline int iwl_trans_start_fw(struct iwl_trans *trans, @@ -593,6 +593,13 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue, frame_limit, ssn); } +static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, + int fifo) +{ + iwl_trans_txq_enable(trans, queue, fifo, IWL_INVALID_STATION, + IWL_MAX_TID_COUNT, IWL_FRAME_LIMIT, 0); +} + static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans) { WARN_ONCE(trans->state != IWL_TRANS_FW_ALIVE, diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h index 5024fb6..d9694c5 100644 --- a/drivers/net/wireless/iwlwifi/pcie/internal.h +++ b/drivers/net/wireless/iwlwifi/pcie/internal.h @@ -269,10 +269,9 @@ struct iwl_trans_pcie { wait_queue_head_t ucode_write_waitq; unsigned long status; u8 cmd_queue; + u8 cmd_fifo; u8 n_no_reclaim_cmds; u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS]; - u8 setup_q_to_fifo[IWL_MAX_HW_QUEUES]; - u8 n_q_to_fifo; bool rx_buf_size_8k; u32 rx_page_order; diff --git a/drivers/net/wireless/iwlwifi/pcie/rx.c b/drivers/net/wireless/iwlwifi/pcie/rx.c index be143eb..39a6ca1 100644 --- a/drivers/net/wireless/iwlwifi/pcie/rx.c +++ b/drivers/net/wireless/iwlwifi/pcie/rx.c @@ -879,9 +879,6 @@ static irqreturn_t iwl_isr(int irq, void *data) lockdep_assert_held(&trans_pcie->irq_lock); - if (!trans) - return IRQ_NONE; - trace_iwlwifi_dev_irq(trans->dev); /* Disable (but don't clear!) interrupts here to avoid diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index d195083..09795af 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -1059,7 +1059,7 @@ static void iwl_tx_start(struct iwl_trans *trans) { struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); u32 a; - int i, chan; + int chan; u32 reg_val; /* make sure all queue are not stopped/used */ @@ -1091,12 +1091,8 @@ static void iwl_tx_start(struct iwl_trans *trans) */ iwl_write_prph(trans, SCD_CHAINEXT_EN, 0); - for (i = 0; i < trans_pcie->n_q_to_fifo; i++) { - int fifo = trans_pcie->setup_q_to_fifo[i]; - - iwl_trans_pcie_txq_enable(trans, i, fifo, IWL_INVALID_STATION, - IWL_TID_NON_QOS, SCD_FRAME_LIMIT, 0); - } + iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue, + trans_pcie->cmd_fifo); /* Activate all Tx DMA/FIFO channels */ iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7)); @@ -1145,7 +1141,7 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000); if (ret < 0) IWL_ERR(trans, - "Failing on timeout while stopping DMA channel %d [0x%08x]", + "Failing on timeout while stopping DMA channel %d [0x%08x]\n", ch, iwl_read_direct32(trans, FH_TSSR_TX_STATUS_REG)); @@ -1153,7 +1149,8 @@ static int iwl_trans_tx_stop(struct iwl_trans *trans) spin_unlock_irqrestore(&trans_pcie->irq_lock, flags); if (!trans_pcie->txq) { - IWL_WARN(trans, "Stopping tx queues that aren't allocated..."); + IWL_WARN(trans, + "Stopping tx queues that aren't allocated...\n"); return 0; } @@ -1430,7 +1427,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans) err = iwl_prepare_card_hw(trans); if (err) { - IWL_ERR(trans, "Error while preparing HW: %d", err); + IWL_ERR(trans, "Error while preparing HW: %d\n", err); goto err_free_irq; } @@ -1528,6 +1525,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); trans_pcie->cmd_queue = trans_cfg->cmd_queue; + trans_pcie->cmd_fifo = trans_cfg->cmd_fifo; if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS)) trans_pcie->n_no_reclaim_cmds = 0; else @@ -1536,17 +1534,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans, memcpy(trans_pcie->no_reclaim_cmds, trans_cfg->no_reclaim_cmds, trans_pcie->n_no_reclaim_cmds * sizeof(u8)); - trans_pcie->n_q_to_fifo = trans_cfg->n_queue_to_fifo; - - if (WARN_ON(trans_pcie->n_q_to_fifo > IWL_MAX_HW_QUEUES)) - trans_pcie->n_q_to_fifo = IWL_MAX_HW_QUEUES; - - /* at least the command queue must be mapped */ - WARN_ON(!trans_pcie->n_q_to_fifo); - - memcpy(trans_pcie->setup_q_to_fifo, trans_cfg->queue_to_fifo, - trans_pcie->n_q_to_fifo * sizeof(u8)); - trans_pcie->rx_buf_size_8k = trans_cfg->rx_buf_size_8k; if (trans_pcie->rx_buf_size_8k) trans_pcie->rx_page_order = get_order(8 * 1024); @@ -2141,13 +2128,14 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, err = pci_request_regions(pdev, DRV_NAME); if (err) { - dev_printk(KERN_ERR, &pdev->dev, "pci_request_regions failed"); + dev_printk(KERN_ERR, &pdev->dev, + "pci_request_regions failed\n"); goto out_pci_disable_device; } trans_pcie->hw_base = pci_ioremap_bar(pdev, 0); if (!trans_pcie->hw_base) { - dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed"); + dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed\n"); err = -ENODEV; goto out_pci_release_regions; } @@ -2168,7 +2156,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, err = pci_enable_msi(pdev); if (err) dev_printk(KERN_ERR, &pdev->dev, - "pci_enable_msi failed(0X%x)", err); + "pci_enable_msi failed(0X%x)\n", err); trans->dev = &pdev->dev; trans_pcie->irq = pdev->irq; diff --git a/drivers/net/wireless/iwmc3200wifi/Kconfig b/drivers/net/wireless/iwmc3200wifi/Kconfig deleted file mode 100644 index 7107ce5..0000000 --- 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 cdc7e07..0000000 --- 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 62edd58..0000000 --- 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 48e8218..0000000 --- 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 56a3414..0000000 --- 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 bd75078..0000000 --- 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 6421689..0000000 --- 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 a0c13a4..0000000 --- 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 b6199d1..0000000 --- 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 e80e776..0000000 --- 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 4e3a3fd..0000000 --- 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 6f1afe6..0000000 --- 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 c70a3b4..0000000 --- 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 1cabcb3..0000000 --- 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 c20936d..0000000 --- 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 51d7efa..0000000 --- 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 5ddcdf8..0000000 --- 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 1f868b1..0000000 --- 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 5091d77..0000000 --- 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 7d708f4..0000000 --- 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 da0db91..0000000 --- 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 0042f20..0000000 --- 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 aab6b68..0000000 --- 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 904d36f..0000000 --- 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 f5f7070..0000000 --- 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 be98074..0000000 --- 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 4a137d3..0000000 --- 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/host.h b/drivers/net/wireless/libertas/host.h index 2e2dbfa..96726f7 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 f578d0b..200bcc0 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)]; @@ -1082,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] = { @@ -1121,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; } @@ -1855,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/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index 3af88b8..c7a177c 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -914,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. */ @@ -947,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); @@ -1697,7 +1760,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, }; /* @@ -1744,7 +1809,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->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/fw.h b/drivers/net/wireless/mwifiex/fw.h index ffb6cdf..14e985d 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -227,6 +227,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #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 @@ -322,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)) | \ @@ -884,6 +891,18 @@ struct host_cmd_ds_rf_tx_pwr { 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; @@ -1370,6 +1389,8 @@ struct host_cmd_ds_command { 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 8374e33..1d8dd00 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); @@ -217,34 +214,107 @@ mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, return ret; } -/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs, +/* 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. + */ +static int mwifiex_update_wps_ie(const u8 *ies, int ies_len, + struct mwifiex_ie **ie_ptr, u16 mask) +{ + 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; + + 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); + } + + *ie_ptr = ie; + return 0; +} + +/* 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; + + 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 (data->proberesp_ies && data->proberesp_ies_len) + mwifiex_update_wps_ie(data->proberesp_ies, + data->proberesp_ies_len, &pr_ie, + MGMT_MASK_PROBE_RESP); + + 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, + &beacon_idx, pr_ie, + &pr_idx, ar_ie, &ar_idx); + if (ret) + goto done; + } + + priv->beacon_idx = beacon_idx; + priv->proberesp_idx = pr_idx; + priv->assocresp_idx = ar_idx; + +done: + kfree(beacon_ie); + kfree(pr_ie); + kfree(ar_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_ap_settings *params) + struct cfg80211_beacon_data *info) { - struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; - struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL; - struct ieee_types_header *rsn_ie = NULL, *wpa_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, ie_len = 0; + 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; - int ret = 0; - if (params->beacon.tail && params->beacon.tail_len) { + 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); - mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | - MGMT_MASK_ASSOC_RESP; - gen_ie->mgmt_subtype_mask = cpu_to_le16(mask); + 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, - params->beacon.tail, - params->beacon.tail_len); + 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; @@ -253,8 +323,8 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, vendor_ie = cfg80211_find_vendor_ie(WLAN_OUI_MICROSOFT, WLAN_OUI_TYPE_MICROSOFT_WPA, - params->beacon.tail, - params->beacon.tail_len); + info->tail, + info->tail_len); if (vendor_ie) { wpa_ie = (struct ieee_types_header *)vendor_ie; memcpy(gen_ie->ie_buffer + ie_len, @@ -267,79 +337,16 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv, if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx, NULL, NULL, NULL, NULL)) { - ret = -1; - goto done; + kfree(gen_ie); + return -1; } - priv->rsn_idx = rsn_idx; } - } - - 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); - } - - 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; - } - - 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 (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; - } - 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 (beacon_ie || pr_ie || ar_ie) { - ret = mwifiex_update_uap_custom_ie(priv, beacon_ie, - &beacon_idx, pr_ie, - &pr_idx, ar_ie, &ar_idx); - if (ret) - goto done; + kfree(gen_ie); } - priv->beacon_idx = beacon_idx; - priv->proberesp_idx = pr_idx; - priv->assocresp_idx = ar_idx; - -done: - kfree(beacon_ie); - kfree(pr_ie); - kfree(ar_ie); - kfree(gen_ie); - - return ret; + return mwifiex_set_mgmt_beacon_data_ies(priv, info); } /* This function removes management IE set */ diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index 9f088fb..e121294 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -277,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.h b/drivers/net/wireless/mwifiex/main.h index 7cd95cc..9e63653 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -1013,7 +1013,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); 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/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index b9cd9ed..225d4c7 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -277,6 +277,39 @@ static int mwifiex_cmd_rf_tx_power(struct mwifiex_private *priv, } /* + * 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 - @@ -1070,6 +1103,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, 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); diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 78fc352..97715df 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -475,6 +475,33 @@ static int mwifiex_ret_rf_tx_power(struct mwifiex_private *priv, } /* + * 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. @@ -868,6 +895,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, 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/p54/txrx.c b/drivers/net/wireless/p54/txrx.c index 82a1cac..f38786e 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/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c index 068276e..e76f03c 100644 --- a/drivers/net/wireless/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/rt2x00/rt2800lib.c @@ -1940,10 +1940,8 @@ static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 7, rfcsr); } -#define RT3290_POWER_BOUND 0x27 -#define RT3290_FREQ_OFFSET_BOUND 0x5f -#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, @@ -1959,16 +1957,15 @@ static void rt2800_config_channel_rf3290(struct rt2x00_dev *rt2x00dev, rt2800_rfcsr_write(rt2x00dev, 11, rfcsr); rt2800_rfcsr_read(rt2x00dev, 49, &rfcsr); - if (info->default_power1 > RT3290_POWER_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR49_TX, RT3290_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); rt2800_rfcsr_read(rt2x00dev, 17, &rfcsr); - if (rt2x00dev->freq_offset > RT3290_FREQ_OFFSET_BOUND) - rt2x00_set_field8(&rfcsr, RFCSR17_CODE, - RT3290_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); @@ -2002,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); @@ -2031,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); diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index dd43612..235376e 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -986,7 +986,7 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) int i, count; rt2800_register_read(rt2x00dev, WLAN_FUN_CTRL, ®); - if ((rt2x00_get_field32(reg, WLAN_EN) == 1)) + if (rt2x00_get_field32(reg, WLAN_EN)) return 0; rt2x00_set_field32(®, WLAN_GPIO_OUT_OE_BIT_ALL, 0xff); @@ -1004,9 +1004,9 @@ static int rt2800_enable_wlan_rt3290(struct rt2x00_dev *rt2x00dev) */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { rt2800_register_read(rt2x00dev, CMB_CTRL, ®); - if ((rt2x00_get_field32(reg, PLL_LD) == 1) && - (rt2x00_get_field32(reg, XTAL_RDY) == 1)) - break; + if (rt2x00_get_field32(reg, PLL_LD) && + rt2x00_get_field32(reg, XTAL_RDY)) + break; udelay(REGISTER_BUSY_DELAY); } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 2fd8301..f7e74a0 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 5f1392c..9b8c10a 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 74ecc33..40ea807 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, - Q_INDEX_DONE, - 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/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 47ba2e0..3d6c71b 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -242,7 +242,7 @@ 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, @@ -590,13 +590,13 @@ 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 int wl127x_prepare_read(struct wl1271 *wl, u32 rx_desc, u32 len) { @@ -637,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; @@ -646,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: @@ -653,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; @@ -663,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: @@ -674,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: diff --git a/drivers/net/wireless/ti/wl12xx/wl12xx.h b/drivers/net/wireless/ti/wl12xx/wl12xx.h index de11324..26990fb 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/main.c b/drivers/net/wireless/ti/wl18xx/main.c index 5e583be8..b378b34 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -369,7 +369,7 @@ 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, @@ -609,7 +609,12 @@ static int wl18xx_identify_chip(struct wl1271 *wl) 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_warning("chip id 0x%x (185x PG10) is deprecated", @@ -1020,14 +1025,24 @@ 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"); - + /* + * we don't care about HT channel here - if a peer doesn't + * support MIMO, we won't enable it in its rates + */ return CONF_TX_MIMO_RATES; } else { return 0; diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h index bc67a47..6452396 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/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 8965960..375ea57 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c @@ -81,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; @@ -101,6 +148,10 @@ static int wlcore_boot_static_data(struct wl1271 *wl) 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; @@ -141,7 +192,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, partition.mem.start = dest; ret = wlcore_set_partition(wl, &partition); if (ret < 0) - return ret; + goto out; /* 10.1 set partition limit and chunk num */ chunk_num = 0; @@ -157,7 +208,7 @@ static int wl1271_boot_upload_firmware_chunk(struct wl1271 *wl, void *buf, partition.mem.start = addr; ret = wlcore_set_partition(wl, &partition); if (ret < 0) - return ret; + goto out; } /* 10.3 upload the chunk */ diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 56c7a23..a23949c 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 @@ -138,6 +139,7 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 *events_vector; u32 event; unsigned long timeout_time; + u16 poll_count = 0; int ret = 0; *timeout = false; @@ -156,7 +158,11 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, 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 */ ret = wlcore_read(wl, wl->mbox_ptr[0], events_vector, @@ -1007,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); @@ -1023,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: diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index c8a6510..d7d9f80 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 diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c index 8a8a897..a3c8677 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), diff --git a/drivers/net/wireless/ti/wlcore/io.c b/drivers/net/wireless/ti/wlcore/io.c index 9976219..68e74ee 100644 --- a/drivers/net/wireless/ti/wlcore/io.c +++ b/drivers/net/wireless/ti/wlcore/io.c @@ -60,6 +60,12 @@ void wlcore_enable_interrupts(struct wl1271 *wl) } 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; diff --git a/drivers/net/wireless/ti/wlcore/io.h b/drivers/net/wireless/ti/wlcore/io.h index fef80ad..259149f 100644 --- a/drivers/net/wireless/ti/wlcore/io.h +++ b/drivers/net/wireless/ti/wlcore/io.h @@ -47,6 +47,7 @@ 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); @@ -59,12 +60,12 @@ static inline int __must_check wlcore_raw_write(struct wl1271 *wl, int addr, { int ret; - if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags)) + if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) return -EIO; ret = wl->if_ops->write(wl->dev, addr, buf, len, fixed); - if (ret) - set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags); + if (ret && wl->state != WL1271_STATE_OFF) + set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); return ret; } @@ -75,12 +76,12 @@ static inline int __must_check wlcore_raw_read(struct wl1271 *wl, int addr, { int ret; - if (test_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags)) + if (test_bit(WL1271_FLAG_IO_FAILED, &wl->flags)) return -EIO; ret = wl->if_ops->read(wl->dev, addr, buf, len, fixed); - if (ret) - set_bit(WL1271_FLAG_SDIO_FAILED, &wl->flags); + if (ret && wl->state != WL1271_STATE_OFF) + set_bit(WL1271_FLAG_IO_FAILED, &wl->flags); return ret; } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2240cca..9f04b64 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, @@ -916,16 +916,16 @@ static void wl1271_recovery_work(struct work_struct *work) if (wl->state != WL1271_STATE_ON || wl->plt) goto out_unlock; - wl12xx_read_fwlog_panic(wl); - - wlcore_print_recovery(wl); + 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; } @@ -956,9 +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); + + wlcore_op_stop_locked(wl); ieee80211_restart_hw(wl->hw); @@ -967,9 +966,10 @@ 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); } @@ -1211,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); @@ -1797,33 +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) { if (test_and_clear_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags)) wlcore_enable_interrupts(wl); - mutex_unlock(&wl->mutex); - - /* - * 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; } @@ -1832,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); @@ -1900,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); } @@ -4566,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, @@ -4634,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; @@ -4796,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, @@ -4824,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) }; @@ -5504,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; @@ -5517,6 +5529,7 @@ 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); diff --git a/drivers/net/wireless/ti/wlcore/scan.c b/drivers/net/wireless/ti/wlcore/scan.c index d9daed5..dbeca1b 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 204e69f..73ace4b 100644 --- a/drivers/net/wireless/ti/wlcore/sdio.c +++ b/drivers/net/wireless/ti/wlcore/sdio.c @@ -411,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 6420aba..8da4ed24 100644 --- a/drivers/net/wireless/ti/wlcore/spi.c +++ b/drivers/net/wireless/ti/wlcore/spi.c @@ -435,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 eeb339d..d6f57e2 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 @@ -272,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; @@ -350,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/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index e796974..27ccc27 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -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; @@ -390,6 +390,9 @@ struct wl1271 { /* 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); @@ -408,6 +411,18 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, 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 @@ -437,6 +452,12 @@ wlcore_set_ht_cap(struct wl1271 *wl, enum ieee80211_band band, /* 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 4273a21..0187eef 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. */ @@ -247,7 +241,7 @@ enum wl12xx_flags { WL1271_FLAG_RECOVERY_IN_PROGRESS, WL1271_FLAG_VIF_CHANGE_IN_PROGRESS, WL1271_FLAG_INTENDED_FW_RECOVERY, - WL1271_FLAG_SDIO_FAILED, + WL1271_FLAG_IO_FAILED, }; enum wl12xx_vif_flags { @@ -369,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 1f74a77..e7fd493 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 9ac829e..d606f52 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 457eac3..aa71807 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 12334f9..03b2f30 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -137,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 8bbfe31..fbd0d49 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 318fc1f..e02fc68 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 @@ -1092,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 @@ -1124,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) @@ -1133,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) @@ -1145,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, @@ -1196,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, }; @@ -1352,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 */ @@ -1368,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, }; @@ -1616,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 diff --git a/include/linux/nfc.h b/include/linux/nfc.h index f4e6dd9..6189f27 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 c0fc5d2..db961a5 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1638,12 +1638,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 */ @@ -1653,6 +1661,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, @@ -1813,6 +1822,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 */ @@ -1826,6 +1838,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 @@ -2539,10 +2554,12 @@ 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, }; /** diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 061c019..51f67a9 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, }; /** @@ -1482,9 +1503,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(). @@ -1791,15 +1811,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); }; /* @@ -2153,7 +2172,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; @@ -2389,6 +2410,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; @@ -3463,7 +3489,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 670a58b..e3fa90c 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -475,7 +475,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 +563,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 +634,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)); @@ -1896,19 +1896,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 @@ -2257,11 +2244,21 @@ enum ieee80211_rate_control_changed { * @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 @@ -2398,6 +2395,9 @@ struct ieee80211_ops { 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); }; /** @@ -3832,12 +3832,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 * diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index e30e6a8..f5169b0 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 180964b..6431f5e 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/mac80211/cfg.c b/net/mac80211/cfg.c index c2a2dcb..ccbe241 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -2668,8 +2668,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: @@ -2682,8 +2682,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: @@ -2743,8 +2743,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: @@ -2980,14 +2980,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 @@ -3063,8 +3063,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/debugfs_key.c b/net/mac80211/debugfs_key.c index 7932767..090d08f 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/driver-ops.h b/net/mac80211/driver-ops.h index 44e8c12..df92031 100644 --- a/net/mac80211/driver-ops.h +++ b/net/mac80211/driver-ops.h @@ -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) { @@ -860,4 +852,18 @@ static inline int drv_get_rssi(struct ieee80211_local *local, 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/ieee80211_i.h b/net/mac80211/ieee80211_i.h index f834a00..e0423f8 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -1284,7 +1284,6 @@ 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); @@ -1481,6 +1480,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 58c2ab3..fbef7a1 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -43,6 +43,127 @@ */ +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; + } + } + + 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 ieee80211_change_mtu(struct net_device *dev, int new_mtu) { int meshhdrlen; @@ -209,7 +330,7 @@ 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; @@ -250,7 +371,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) return 0; } -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; @@ -366,12 +487,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) { @@ -386,8 +501,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; @@ -622,7 +735,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); @@ -696,9 +808,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) @@ -1403,127 +1512,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; - - 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; -} - -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/main.c b/net/mac80211/main.c index 0b040fb..c794101 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -587,7 +587,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); @@ -688,7 +688,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 */ @@ -706,12 +706,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; @@ -733,6 +732,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; @@ -750,6 +750,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) + @@ -825,6 +826,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_plink.c b/net/mac80211/mesh_plink.c index 9ad74dd..af671b9 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -258,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)) diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index aa69a33..f49f14f 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; @@ -1362,6 +1364,10 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } 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, ifmgd->bssid, stype, @@ -1610,6 +1616,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; @@ -1619,16 +1626,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); @@ -1747,6 +1760,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, @@ -2630,6 +2644,8 @@ 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) { sdata_info(sdata, "send auth to %pM (try %d/%d)\n", auth_data->bss->bssid, auth_data->tries, diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index 2e60f4a..e1e9d10 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -1244,6 +1244,13 @@ TRACE_EVENT(drv_get_rssi, ) ); +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. */ diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index ec8f5346..c9d2175 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; @@ -957,8 +959,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; @@ -1293,11 +1294,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); @@ -2420,9 +2418,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 242ecde..64493a7 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); @@ -1072,6 +1080,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; } @@ -1411,10 +1423,10 @@ int ieee80211_reconfig(struct ieee80211_local *local) if (ieee80211_sdata_running(sdata)) ieee80211_enable_keys(sdata); + wake_up: local->in_reconfig = false; barrier(); - wake_up: /* * Clear the WLAN_STA_BLOCK_BA flag so new aggregation * sessions can be established after a resume. @@ -1699,6 +1711,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, @@ -1764,15 +1797,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; @@ -1796,15 +1828,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/nfc/core.c b/net/nfc/core.c index 4177bb5..ff74979 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 8729abf..46362ef 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 a8b0b71..36717ce 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 45f2fe4..fa9a21e 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 6b836e6..6f840c1 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 5d503ee..82f0f75 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 7286c86..83b8bba 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 05ca5a6..ddeb9aa 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 || 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 766a02b..5bb4da6 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 2ab196a..af7a93b 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -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 diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f4f07f9..4c51714 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/wireless/Makefile b/net/wireless/Makefile index 55a28ab..0f7e0d6 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 0000000..fcc60d8 --- /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 c1999e4..434c56b 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -82,13 +82,73 @@ 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 cfg80211_registered_device *rdev, + struct wireless_dev *wdev, + struct ieee80211_channel **chan, + enum cfg80211_chan_mode *chanmode) +{ + *chan = NULL; + *chanmode = CHAN_MODE_UNDEFINED; + + ASSERT_RDEV_LOCK(rdev); + 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 907f62c..eb60410 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -373,6 +373,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; @@ -421,9 +429,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))) @@ -458,8 +468,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; /* @@ -500,12 +516,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); @@ -713,6 +731,61 @@ 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) { + 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) @@ -806,12 +879,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; @@ -917,9 +994,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 609a579..377dc39 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" @@ -56,6 +57,13 @@ struct cfg80211_registered_device { 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; @@ -197,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, @@ -241,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); @@ -289,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, @@ -404,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, @@ -415,6 +452,22 @@ 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 cfg80211_registered_device *rdev, + 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); @@ -428,6 +481,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 89baa33..ca5672f 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 3b73b07..c384e77 100644 --- a/net/wireless/mesh.c +++ b/net/wireless/mesh.c @@ -155,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; @@ -172,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; } @@ -184,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, @@ -205,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) @@ -249,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 da4406f..d4fece3 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; } @@ -947,6 +963,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 3b508ea..0249cea 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -921,6 +921,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) @@ -1112,6 +1121,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; @@ -1152,6 +1162,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)) @@ -1678,16 +1689,11 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, (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; } @@ -2472,11 +2478,20 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info) 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) { wdev->preset_chan = params.channel; wdev->preset_chantype = params.channel_type; wdev->beacon_interval = params.beacon_interval; + wdev->channel = params.channel; } return err; } @@ -2510,23 +2525,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] = { @@ -2618,7 +2618,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) @@ -2626,8 +2627,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) && @@ -6276,6 +6281,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]; @@ -6504,6 +6510,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) { @@ -7158,6 +7165,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, @@ -7174,6 +7182,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, diff --git a/net/wireless/reg.c b/net/wireless/reg.c index baf5704..b2b3222 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), } }; diff --git a/net/wireless/util.c b/net/wireless/util.c index 316cfd0..e31f1db 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; @@ -805,8 +824,10 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, return -EBUSY; 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)) @@ -930,27 +1008,48 @@ 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); + 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->netdev_list, list) { if (wdev_iter == wdev) continue; @@ -960,11 +1059,33 @@ int cfg80211_can_change_interface(struct cfg80211_registered_device *rdev, if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) continue; + cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); + + 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 +1097,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 bc87983..7df42f5 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: |