diff options
Diffstat (limited to 'drivers')
112 files changed, 4938 insertions, 4577 deletions
diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 893f6e0c759..bc6e89212ad 100644 --- a/drivers/bcma/core.c +++ b/drivers/bcma/core.c @@ -30,6 +30,7 @@ void bcma_core_disable(struct bcma_device *core, u32 flags) udelay(10); bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET); + bcma_aread32(core, BCMA_RESET_CTL); udelay(1); } EXPORT_SYMBOL_GPL(bcma_core_disable); @@ -77,7 +78,7 @@ void bcma_core_set_clockmode(struct bcma_device *core, pr_err("HT force timeout\n"); break; case BCMA_CLKMODE_DYNAMIC: - pr_warn("Dynamic clockmode not supported yet!\n"); + bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT); break; } } diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c index 4d38ae179b4..9a96f14c8f4 100644 --- a/drivers/bcma/driver_pci.c +++ b/drivers/bcma/driver_pci.c @@ -24,14 +24,12 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address) return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA); } -#if 0 static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data) { pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address); pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR); pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data); } -#endif static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy) { @@ -170,13 +168,50 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc) tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN); } +static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc) +{ + struct bcma_device *core = pc->core; + u16 val16, core_index; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET); + core_index = (u16)core->core_index; + + val16 = pcicore_read16(pc, regoff); + if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT) + != core_index) { + val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) | + (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK); + pcicore_write16(pc, regoff, val16); + } +} + +/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ +/* Needs to happen when coming out of 'standby'/'hibernate' */ +static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc) +{ + u16 val16; + uint regoff; + + regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG); + + val16 = pcicore_read16(pc, regoff); + + if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) { + val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST; + pcicore_write16(pc, regoff, val16); + } +} + /************************************************** * Init. **************************************************/ static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc) { + bcma_core_pci_fixcfg(pc); bcma_pcicore_serdes_workaround(pc); + bcma_core_pci_config_fixup(pc); } void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc) @@ -224,3 +259,17 @@ out: return err; } EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl); + +void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend) +{ + u32 w; + + w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); + if (extend) + w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND; + else + w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND; + bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w); + bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG); +} +EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer); diff --git a/drivers/bcma/driver_pci_host.c b/drivers/bcma/driver_pci_host.c index d2097a11c3c..b9a86edfec3 100644 --- a/drivers/bcma/driver_pci_host.c +++ b/drivers/bcma/driver_pci_host.c @@ -119,7 +119,7 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev, if (unlikely(!addr)) goto out; err = -ENOMEM; - mmio = ioremap_nocache(addr, len); + mmio = ioremap_nocache(addr, sizeof(val)); if (!mmio) goto out; @@ -171,7 +171,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0; addr |= (func << 8); addr |= (off & 0xfc); - mmio = ioremap_nocache(addr, len); + mmio = ioremap_nocache(addr, sizeof(val)); if (!mmio) goto out; } @@ -180,7 +180,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev, if (unlikely(!addr)) goto out; err = -ENOMEM; - mmio = ioremap_nocache(addr, len); + mmio = ioremap_nocache(addr, sizeof(val)); if (!mmio) goto out; @@ -491,8 +491,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc) /* Ok, ready to run, register it to the system. * The following needs change, if we want to port hostmode * to non-MIPS platform. */ - io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM, - 0x04000000); + io_map_base = (unsigned long)ioremap_nocache(pc_host->mem_resource.start, + resource_size(&pc_host->mem_resource)); pc_host->pci_controller.io_map_base = io_map_base; set_io_port_base(pc_host->pci_controller.io_map_base); /* Give some time to the PCI controller to configure itself with the new diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c index e3928d68802..6c05cf470f9 100644 --- a/drivers/bcma/host_pci.c +++ b/drivers/bcma/host_pci.c @@ -201,6 +201,9 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev, bus->hosttype = BCMA_HOSTTYPE_PCI; bus->ops = &bcma_host_pci_ops; + bus->boardinfo.vendor = bus->host_pci->subsystem_vendor; + bus->boardinfo.type = bus->host_pci->subsystem_device; + /* Register */ err = bcma_bus_register(bus); if (err) @@ -222,7 +225,7 @@ err_kfree_bus: return err; } -static void bcma_host_pci_remove(struct pci_dev *dev) +static void __devexit bcma_host_pci_remove(struct pci_dev *dev) { struct bcma_bus *bus = pci_get_drvdata(dev); @@ -277,7 +280,7 @@ static struct pci_driver bcma_pci_bridge_driver = { .name = "bcma-pci-bridge", .id_table = bcma_pci_bridge_tbl, .probe = bcma_host_pci_probe, - .remove = bcma_host_pci_remove, + .remove = __devexit_p(bcma_host_pci_remove), .driver.pm = BCMA_PM_OPS, }; diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index 3bea7fe25b2..5ed0718fc66 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -19,7 +19,14 @@ struct bcma_device_id_name { u16 id; const char *name; }; -struct bcma_device_id_name bcma_device_names[] = { + +static const struct bcma_device_id_name bcma_arm_device_names[] = { + { BCMA_CORE_ARM_1176, "ARM 1176" }, + { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, + { BCMA_CORE_ARM_CM3, "ARM CM3" }, +}; + +static const struct bcma_device_id_name bcma_bcm_device_names[] = { { BCMA_CORE_OOB_ROUTER, "OOB Router" }, { BCMA_CORE_INVALID, "Invalid" }, { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, @@ -27,7 +34,6 @@ struct bcma_device_id_name bcma_device_names[] = { { BCMA_CORE_SRAM, "SRAM" }, { BCMA_CORE_SDRAM, "SDRAM" }, { BCMA_CORE_PCI, "PCI" }, - { BCMA_CORE_MIPS, "MIPS" }, { BCMA_CORE_ETHERNET, "Fast Ethernet" }, { BCMA_CORE_V90, "V90" }, { BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" }, @@ -44,7 +50,6 @@ struct bcma_device_id_name bcma_device_names[] = { { BCMA_CORE_PHY_A, "PHY A" }, { BCMA_CORE_PHY_B, "PHY B" }, { BCMA_CORE_PHY_G, "PHY G" }, - { BCMA_CORE_MIPS_3302, "MIPS 3302" }, { BCMA_CORE_USB11_HOST, "USB 1.1 Host" }, { BCMA_CORE_USB11_DEV, "USB 1.1 Device" }, { BCMA_CORE_USB20_HOST, "USB 2.0 Host" }, @@ -58,15 +63,11 @@ struct bcma_device_id_name bcma_device_names[] = { { BCMA_CORE_PHY_N, "PHY N" }, { BCMA_CORE_SRAM_CTL, "SRAM Controller" }, { BCMA_CORE_MINI_MACPHY, "Mini MACPHY" }, - { BCMA_CORE_ARM_1176, "ARM 1176" }, - { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, { BCMA_CORE_PHY_LP, "PHY LP" }, { BCMA_CORE_PMU, "PMU" }, { BCMA_CORE_PHY_SSN, "PHY SSN" }, { BCMA_CORE_SDIO_DEV, "SDIO Device" }, - { BCMA_CORE_ARM_CM3, "ARM CM3" }, { BCMA_CORE_PHY_HT, "PHY HT" }, - { BCMA_CORE_MIPS_74K, "MIPS 74K" }, { BCMA_CORE_MAC_GBIT, "GBit MAC" }, { BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" }, { BCMA_CORE_PCIE_RC, "PCIe Root Complex" }, @@ -79,16 +80,41 @@ struct bcma_device_id_name bcma_device_names[] = { { BCMA_CORE_SHIM, "SHIM" }, { BCMA_CORE_DEFAULT, "Default" }, }; -const char *bcma_device_name(struct bcma_device_id *id) + +static const struct bcma_device_id_name bcma_mips_device_names[] = { + { BCMA_CORE_MIPS, "MIPS" }, + { BCMA_CORE_MIPS_3302, "MIPS 3302" }, + { BCMA_CORE_MIPS_74K, "MIPS 74K" }, +}; + +static const char *bcma_device_name(const struct bcma_device_id *id) { - int i; + const struct bcma_device_id_name *names; + int size, i; + + /* search manufacturer specific names */ + switch (id->manuf) { + case BCMA_MANUF_ARM: + names = bcma_arm_device_names; + size = ARRAY_SIZE(bcma_arm_device_names); + break; + case BCMA_MANUF_BCM: + names = bcma_bcm_device_names; + size = ARRAY_SIZE(bcma_bcm_device_names); + break; + case BCMA_MANUF_MIPS: + names = bcma_mips_device_names; + size = ARRAY_SIZE(bcma_mips_device_names); + break; + default: + return "UNKNOWN"; + } - if (id->manuf == BCMA_MANUF_BCM) { - for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) { - if (bcma_device_names[i].id == id->id) - return bcma_device_names[i].name; - } + for (i = 0; i < size; i++) { + if (names[i].id == id->id) + return names[i].name; } + return "UNKNOWN"; } diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c index 3e2a6002aae..c7f93359acb 100644 --- a/drivers/bcma/sprom.c +++ b/drivers/bcma/sprom.c @@ -181,6 +181,22 @@ static int bcma_sprom_valid(const u16 *sprom) #define SPEX(_field, _offset, _mask, _shift) \ bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift)) +#define SPEX32(_field, _offset, _mask, _shift) \ + bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \ + sprom[SPOFF(_offset)]) & (_mask)) >> (_shift)) + +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) { u16 v, o; @@ -243,7 +259,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0); SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0); - SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); /* Extract cores power info info */ for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) { @@ -298,6 +315,136 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom) SSB_SROM8_FEM_TR_ISO_SHIFT); SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + + SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A, + SSB_SPROM8_ANTAVAIL_A_SHIFT); + SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG, + SSB_SPROM8_ANTAVAIL_BG_SHIFT); + SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0); + SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG, + SSB_SPROM8_ITSSI_BG_SHIFT); + SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0); + SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A, + SSB_SPROM8_ITSSI_A_SHIFT); + SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0); + SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK, + SSB_SPROM8_MAXP_AL_SHIFT); + SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0); + SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1, + SSB_SPROM8_GPIOA_P1_SHIFT); + SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0); + SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3, + SSB_SPROM8_GPIOB_P3_SHIFT); + SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0); + SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G, + SSB_SPROM8_TRI5G_SHIFT); + SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0); + SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH, + SSB_SPROM8_TRI5GH_SHIFT); + SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G, + SSB_SPROM8_RXPO2G_SHIFT); + SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G, + SSB_SPROM8_RXPO5G_SHIFT); + SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0); + SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G, + SSB_SPROM8_RSSISMC2G_SHIFT); + SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G, + SSB_SPROM8_RSSISAV2G_SHIFT); + SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G, + SSB_SPROM8_BXA2G_SHIFT); + SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0); + SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G, + SSB_SPROM8_RSSISMC5G_SHIFT); + SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G, + SSB_SPROM8_RSSISAV5G_SHIFT); + SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G, + SSB_SPROM8_BXA5G_SHIFT); + + SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0); + SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0); + SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0); + SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0); + SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0); + SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0); + SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0); + SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0); + SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0); + SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0); + SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0); + SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0); + SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0); + SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0); + SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0); + SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0); + SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0); + + /* Extract the antenna gain values. */ + SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT); + SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01, + SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT); + SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT); + SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23, + SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT); + + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); } /* diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index 2812b152d6e..ad591bd240e 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -81,6 +81,9 @@ static struct usb_device_id ath3k_table[] = { /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xE02C) }, + /* Atheros AR5BBU22 with sflash firmware */ + { USB_DEVICE(0x0489, 0xE03C) }, + { } /* Terminating entry */ }; @@ -99,6 +102,9 @@ static struct usb_device_id ath3k_blist_tbl[] = { { USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 }, + /* Atheros AR5BBU22 with sflash firmware */ + { USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 }, + { } /* Terminating entry */ }; diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index 90bda50dc44..94f2d65131c 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -67,6 +67,7 @@ struct btmrvl_adapter { u8 wakeup_tries; wait_queue_head_t cmd_wait_q; u8 cmd_complete; + bool is_suspended; }; struct btmrvl_private { @@ -139,8 +140,10 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb); int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd); +int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv); int btmrvl_enable_ps(struct btmrvl_private *priv); int btmrvl_prepare_command(struct btmrvl_private *priv); +int btmrvl_enable_hs(struct btmrvl_private *priv); #ifdef CONFIG_DEBUG_FS void btmrvl_debugfs_init(struct hci_dev *hdev); diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index d1209adc882..681ca9d18e1 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -200,6 +200,36 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd) } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); +int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv) +{ + struct sk_buff *skb; + struct btmrvl_cmd *cmd; + + skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); + if (!skb) { + BT_ERR("No free skb"); + return -ENOMEM; + } + + cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); + cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, + BT_CMD_HOST_SLEEP_CONFIG)); + cmd->length = 2; + cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; + cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); + + bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; + + skb->dev = (void *) priv->btmrvl_dev.hcidev; + skb_queue_head(&priv->adapter->tx_queue, skb); + + BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0], + cmd->data[1]); + + return 0; +} +EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd); + int btmrvl_enable_ps(struct btmrvl_private *priv) { struct sk_buff *skb; @@ -232,7 +262,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv) } EXPORT_SYMBOL_GPL(btmrvl_enable_ps); -static int btmrvl_enable_hs(struct btmrvl_private *priv) +int btmrvl_enable_hs(struct btmrvl_private *priv) { struct sk_buff *skb; struct btmrvl_cmd *cmd; @@ -268,35 +298,15 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv) return ret; } +EXPORT_SYMBOL_GPL(btmrvl_enable_hs); int btmrvl_prepare_command(struct btmrvl_private *priv) { - struct sk_buff *skb = NULL; - struct btmrvl_cmd *cmd; int ret = 0; if (priv->btmrvl_dev.hscfgcmd) { priv->btmrvl_dev.hscfgcmd = 0; - - skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC); - if (skb == NULL) { - BT_ERR("No free skb"); - return -ENOMEM; - } - - cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd)); - cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG)); - cmd->length = 2; - cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8; - cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff); - - bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT; - - skb->dev = (void *) priv->btmrvl_dev.hcidev; - skb_queue_head(&priv->adapter->tx_queue, skb); - - BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", - cmd->data[0], cmd->data[1]); + btmrvl_send_hscfg_cmd(priv); } if (priv->btmrvl_dev.pscmd) { diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 27b74b0d547..a853244e7fd 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -339,9 +339,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card) done: kfree(tmphlprbuf); - if (fw_helper) - release_firmware(fw_helper); - + release_firmware(fw_helper); return ret; } @@ -484,10 +482,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) done: kfree(tmpfwbuf); - - if (fw_firmware) - release_firmware(fw_firmware); - + release_firmware(fw_firmware); return ret; } @@ -1013,6 +1008,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func, priv->btmrvl_dev.psmode = 1; btmrvl_enable_ps(priv); + priv->btmrvl_dev.gpio_gap = 0xffff; + btmrvl_send_hscfg_cmd(priv); + return 0; disable_host_int: @@ -1048,11 +1046,111 @@ static void btmrvl_sdio_remove(struct sdio_func *func) } } +static int btmrvl_sdio_suspend(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct btmrvl_sdio_card *card; + struct btmrvl_private *priv; + mmc_pm_flag_t pm_flags; + struct hci_dev *hcidev; + + if (func) { + pm_flags = sdio_get_host_pm_caps(func); + BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func), + pm_flags); + if (!(pm_flags & MMC_PM_KEEP_POWER)) { + BT_ERR("%s: cannot remain alive while suspended", + sdio_func_id(func)); + return -ENOSYS; + } + card = sdio_get_drvdata(func); + if (!card || !card->priv) { + BT_ERR("card or priv structure is not valid"); + return 0; + } + } else { + BT_ERR("sdio_func is not specified"); + return 0; + } + + priv = card->priv; + + if (priv->adapter->hs_state != HS_ACTIVATED) { + if (btmrvl_enable_hs(priv)) { + BT_ERR("HS not actived, suspend failed!"); + return -EBUSY; + } + } + hcidev = priv->btmrvl_dev.hcidev; + BT_DBG("%s: SDIO suspend", hcidev->name); + hci_suspend_dev(hcidev); + skb_queue_purge(&priv->adapter->tx_queue); + + priv->adapter->is_suspended = true; + + /* We will keep the power when hs enabled successfully */ + if (priv->adapter->hs_state == HS_ACTIVATED) { + BT_DBG("suspend with MMC_PM_KEEP_POWER"); + return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER); + } else { + BT_DBG("suspend without MMC_PM_KEEP_POWER"); + return 0; + } +} + +static int btmrvl_sdio_resume(struct device *dev) +{ + struct sdio_func *func = dev_to_sdio_func(dev); + struct btmrvl_sdio_card *card; + struct btmrvl_private *priv; + mmc_pm_flag_t pm_flags; + struct hci_dev *hcidev; + + if (func) { + pm_flags = sdio_get_host_pm_caps(func); + BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func), + pm_flags); + card = sdio_get_drvdata(func); + if (!card || !card->priv) { + BT_ERR("card or priv structure is not valid"); + return 0; + } + } else { + BT_ERR("sdio_func is not specified"); + return 0; + } + priv = card->priv; + + if (!priv->adapter->is_suspended) { + BT_DBG("device already resumed"); + return 0; + } + + priv->adapter->is_suspended = false; + hcidev = priv->btmrvl_dev.hcidev; + BT_DBG("%s: SDIO resume", hcidev->name); + hci_resume_dev(hcidev); + priv->hw_wakeup_firmware(priv); + priv->adapter->hs_state = HS_DEACTIVATED; + BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name); + + return 0; +} + +static const struct dev_pm_ops btmrvl_sdio_pm_ops = { + .suspend = btmrvl_sdio_suspend, + .resume = btmrvl_sdio_resume, +}; + static struct sdio_driver bt_mrvl_sdio = { .name = "btmrvl_sdio", .id_table = btmrvl_sdio_ids, .probe = btmrvl_sdio_probe, .remove = btmrvl_sdio_remove, + .drv = { + .owner = THIS_MODULE, + .pm = &btmrvl_sdio_pm_ops, + } }; static int __init btmrvl_sdio_init_module(void) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 461c68bc4dd..c9463af8e56 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -143,6 +143,9 @@ static struct usb_device_id blacklist_table[] = { /* Atheros AR5BBU12 with sflash firmware */ { USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE }, + /* Atheros AR5BBU12 with sflash firmware */ + { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, @@ -855,6 +858,7 @@ static void btusb_work(struct work_struct *work) { struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; + int new_alts; int err; if (hdev->conn_hash.sco_num > 0) { @@ -868,11 +872,19 @@ static void btusb_work(struct work_struct *work) set_bit(BTUSB_DID_ISO_RESUME, &data->flags); } - if (data->isoc_altsetting != 2) { + + if (hdev->voice_setting & 0x0020) { + static const int alts[3] = { 2, 4, 5 }; + new_alts = alts[hdev->conn_hash.sco_num - 1]; + } else { + new_alts = hdev->conn_hash.sco_num; + } + + if (data->isoc_altsetting != new_alts) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); usb_kill_anchored_urbs(&data->isoc_anchor); - if (__set_isoc_interface(hdev, 2) < 0) + if (__set_isoc_interface(hdev, new_alts) < 0) return; } diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 98a8c05d4f2..e564579a611 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -388,7 +388,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->close = hci_uart_close; hdev->flush = hci_uart_flush; hdev->send = hci_uart_send_frame; - hdev->parent = hu->tty->dev; + SET_HCIDEV_DEV(hdev, hu->tty->dev); if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 158bfe507da..3f72595a601 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -252,8 +252,9 @@ static int vhci_open(struct inode *inode, struct file *file) } file->private_data = data; + nonseekable_open(inode, file); - return nonseekable_open(inode, file); + return 0; } static int vhci_release(struct inode *inode, struct file *file) diff --git a/drivers/isdn/hardware/mISDN/hfcsusb.h b/drivers/isdn/hardware/mISDN/hfcsusb.h index cb1231b08f7..4157311d569 100644 --- a/drivers/isdn/hardware/mISDN/hfcsusb.h +++ b/drivers/isdn/hardware/mISDN/hfcsusb.h @@ -410,6 +410,12 @@ static struct usb_device_id hfcsusb_idtab[] = { {LED_SCHEME1, {0x88, -64, -32, -16}, "ZyXEL OMNI.NET USB II"}), }, + { + USB_DEVICE(0x1ae7, 0x0525), + .driver_info = (unsigned long) &((struct hfcsusb_vdata) + {LED_SCHEME1, {0x88, -64, -32, -16}, + "X-Tensions USB ISDN TA XC-525"}), + }, { } }; diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c index 1adb0245b9d..0741aded9eb 100644 --- a/drivers/net/ethernet/freescale/gianfar.c +++ b/drivers/net/ethernet/freescale/gianfar.c @@ -1082,7 +1082,7 @@ static int gfar_probe(struct platform_device *ofdev) if (dev->features & NETIF_F_IP_CSUM || priv->device_flags & FSL_GIANFAR_DEV_HAS_TIMER) - dev->hard_header_len += GMAC_FCB_LEN; + dev->needed_headroom = GMAC_FCB_LEN; /* Program the isrg regs only if number of grps > 1 */ if (priv->num_grps > 1) { diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 28a65d3a03d..b869a358ce4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -693,8 +693,8 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif, ie, 2 + vif->ssid_len + beacon_ie_len, 0, GFP_KERNEL); if (bss) - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to " - "cfg80211\n", bssid); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "added bss %pM to cfg80211\n", bssid); kfree(ie); } else ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n"); @@ -882,6 +882,32 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason, vif->sme_state = SME_DISCONNECTED; } +static int ath6kl_set_probed_ssids(struct ath6kl *ar, + struct ath6kl_vif *vif, + struct cfg80211_ssid *ssids, int n_ssids) +{ + u8 i; + + if (n_ssids > MAX_PROBED_SSID_INDEX) + return -EINVAL; + + for (i = 0; i < n_ssids; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + ssids[i].ssid_len ? + SPECIFIC_SSID_FLAG : ANY_SSID_FLAG, + ssids[i].ssid_len, + ssids[i].ssid); + } + + /* Make sure no old entries are left behind */ + for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) { + ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i, + DISABLE_SSID_FLAG, 0, NULL); + } + + return 0; +} + static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, struct cfg80211_scan_request *request) { @@ -899,36 +925,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, if (!ar->usr_bss_filter) { clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags); - ret = ath6kl_wmi_bssfilter_cmd( - ar->wmi, vif->fw_vif_idx, - (test_bit(CONNECTED, &vif->flags) ? - ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0); + ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, + ALL_BSS_FILTER, 0); if (ret) { ath6kl_err("couldn't set bss filtering\n"); return ret; } } - if (request->n_ssids && request->ssids[0].ssid_len) { - u8 i; - - if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1)) - request->n_ssids = MAX_PROBED_SSID_INDEX - 1; - - for (i = 0; i < request->n_ssids; i++) - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i + 1, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids); + if (ret < 0) + return ret; /* this also clears IE in fw if it's not set */ ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx, WMI_FRAME_PROBE_REQ, request->ie, request->ie_len); if (ret) { - ath6kl_err("failed to set Probe Request appie for " - "scan"); + ath6kl_err("failed to set Probe Request appie for scan"); return ret; } @@ -945,8 +960,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL); if (channels == NULL) { - ath6kl_warn("failed to set scan channels, " - "scan all channels"); + ath6kl_warn("failed to set scan channels, scan all channels"); n_channels = 0; } @@ -1018,6 +1032,20 @@ out: vif->scan_req = NULL; } +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode) +{ + enum nl80211_channel_type type; + + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "channel switch notify nw_type %d freq %d mode %d\n", + vif->nw_type, freq, mode); + + type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT; + + cfg80211_ch_switch_notify(vif->ndev, freq, type); +} + static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, u8 key_index, bool pairwise, const u8 *mac_addr, @@ -1111,9 +1139,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, ar->ap_mode_bkey.key_len = key->key_len; memcpy(ar->ap_mode_bkey.key, key->key, key->key_len); if (!test_bit(CONNECTED, &vif->flags)) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group " - "key configuration until AP mode has been " - "started\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delay initial group key configuration until AP mode has been started\n"); /* * The key will be set in ath6kl_connect_ap_mode() once * the connected event is received from the target. @@ -1129,8 +1156,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev, * the AP mode has properly started * (ath6kl_install_statioc_wep_keys). */ - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration " - "until AP mode has been started\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delay WEP key configuration until AP mode has been started\n"); vif->wep_key_list[key_index].key_len = key->key_len; memcpy(vif->wep_key_list[key_index].key, key->key, key->key_len); @@ -1962,8 +1989,7 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif) sizeof(discvr_pattern), discvr_offset, discvr_pattern, discvr_mask); if (ret) { - ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR " - "pattern\n"); + ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n"); return ret; } } @@ -2031,6 +2057,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) u8 index = 0; __be32 ips[MAX_IP_ADDRS]; + /* The FW currently can't support multi-vif WoW properly. */ + if (ar->num_vif > 1) + return -EIO; + vif = ath6kl_vif_first(ar); if (!vif) return -EIO; @@ -2044,6 +2074,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST)) return -EINVAL; + if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, false); + if (ret) + return ret; + } + /* Clear existing WOW patterns */ for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++) ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx, @@ -2147,8 +2184,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_HOST_MODE_AWAKE); if (ret) { - ath6kl_warn("Failed to configure host sleep mode for " - "wow resume: %d\n", ret); + ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n", + ret); ar->state = ATH6KL_STATE_WOW; return ret; } @@ -2172,6 +2209,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar) ar->state = ATH6KL_STATE_ON; + if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) { + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, + vif->fw_vif_idx, true); + if (ret) + return ret; + } + netif_wake_queue(vif->ndev); return 0; @@ -2186,8 +2230,10 @@ static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar) if (!vif) return -EIO; - if (!ath6kl_cfg80211_ready(vif)) + if (!test_bit(WMI_READY, &ar->flag)) { + ath6kl_err("deepsleep failed as wmi is not ready\n"); return -EIO; + } ath6kl_cfg80211_stop_all(ar); @@ -2447,6 +2493,24 @@ static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band, band, htcap); } +static int ath6kl_restore_htcap(struct ath6kl_vif *vif) +{ + struct wiphy *wiphy = vif->ar->wiphy; + int band, ret = 0; + + for (band = 0; band < IEEE80211_NUM_BANDS; band++) { + if (!wiphy->bands[band]) + continue; + + ret = ath6kl_set_htcap(vif, band, + wiphy->bands[band]->ht_cap.ht_supported); + if (ret) + return ret; + } + + return ret; +} + static bool ath6kl_is_p2p_ie(const u8 *pos) { return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 && @@ -2568,28 +2632,34 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon, /* skip element id and length */ rsn_ie += 2; - /* skip version, group cipher */ - if (rsn_ie_len < 6) + /* skip version */ + if (rsn_ie_len < 2) return -EINVAL; - rsn_ie += 6; - rsn_ie_len -= 6; + rsn_ie += 2; + rsn_ie_len -= 2; + + /* skip group cipher suite */ + if (rsn_ie_len < 4) + return 0; + rsn_ie += 4; + rsn_ie_len -= 4; /* skip pairwise cipher suite */ if (rsn_ie_len < 2) - return -EINVAL; - cnt = *((u16 *) rsn_ie); + return 0; + cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); /* skip akm suite */ if (rsn_ie_len < 2) - return -EINVAL; - cnt = *((u16 *) rsn_ie); + return 0; + cnt = get_unaligned_le16(rsn_ie); rsn_ie += (2 + cnt * 4); rsn_ie_len -= (2 + cnt * 4); if (rsn_ie_len < 2) - return -EINVAL; + return 0; memcpy(rsn_capab, rsn_ie, 2); @@ -2766,6 +2836,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, return res; } + memcpy(&vif->profile, &p, sizeof(p)); res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p); if (res < 0) return res; @@ -2801,13 +2872,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev) clear_bit(CONNECTED, &vif->flags); /* Restore ht setting in firmware */ - if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true)) - return -EIO; - - if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true)) - return -EIO; - - return 0; + return ath6kl_restore_htcap(vif); } static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -3081,7 +3146,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, struct ath6kl_vif *vif = netdev_priv(dev); u16 interval; int ret; - u8 i; if (ar->state != ATH6KL_STATE_ON) return -EIO; @@ -3089,29 +3153,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy, if (vif->sme_state != SME_DISCONNECTED) return -EBUSY; + /* The FW currently can't support multi-vif WoW properly. */ + if (ar->num_vif > 1) + return -EIO; + ath6kl_cfg80211_scan_complete_event(vif, true); - for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, DISABLE_SSID_FLAG, - 0, NULL); - } + ret = ath6kl_set_probed_ssids(ar, vif, request->ssids, + request->n_ssids); + if (ret < 0) + return ret; /* fw uses seconds, also make sure that it's >0 */ interval = max_t(u16, 1, request->interval / 1000); ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx, interval, interval, - 10, 0, 0, 0, 3, 0, 0, 0); - - if (request->n_ssids && request->ssids[0].ssid_len) { - for (i = 0; i < request->n_ssids; i++) { - ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, - i, SPECIFIC_SSID_FLAG, - request->ssids[i].ssid_len, - request->ssids[i].ssid); - } - } + vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0); ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx, ATH6KL_WOW_MODE_ENABLE, @@ -3271,8 +3329,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar) ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode; if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0) - ath6kl_warn("ath6kl_deep_sleep_enable: " - "wmi_powermode_cmd failed\n"); + ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n"); return; } @@ -3352,6 +3409,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, vif->next_mode = nw_type; vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL; vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME; + vif->bg_scan_period = 0; vif->htcap.ht_enable = true; memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN); @@ -3393,6 +3451,7 @@ err: int ath6kl_cfg80211_init(struct ath6kl *ar) { struct wiphy *wiphy = ar->wiphy; + bool band_2gig = false, band_5gig = false, ht = false; int ret; wiphy->mgmt_stypes = ath6kl_mgmt_stypes; @@ -3413,8 +3472,46 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) /* max num of ssids that can be probed during scanning */ wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX; wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */ - wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; - wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + switch (ar->hw.cap) { + case WMI_11AN_CAP: + ht = true; + case WMI_11A_CAP: + band_5gig = true; + break; + case WMI_11GN_CAP: + ht = true; + case WMI_11G_CAP: + band_2gig = true; + break; + case WMI_11AGN_CAP: + ht = true; + case WMI_11AG_CAP: + band_2gig = true; + band_5gig = true; + break; + default: + ath6kl_err("invalid phy capability!\n"); + return -EINVAL; + } + + /* + * Even if the fw has HT support, advertise HT cap only when + * the firmware has support to override RSN capability, otherwise + * 4-way handshake would fail. + */ + if (!(ht && + test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities))) { + ath6kl_band_2ghz.ht_cap.cap = 0; + ath6kl_band_2ghz.ht_cap.ht_supported = false; + ath6kl_band_5ghz.ht_cap.cap = 0; + ath6kl_band_5ghz.ht_cap.ht_supported = false; + } + if (band_2gig) + wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz; + if (band_5gig) + wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz; + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; wiphy->cipher_suites = cipher_suites; @@ -3430,7 +3527,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) wiphy->wowlan.pattern_min_len = 1; wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE; - wiphy->max_sched_scan_ssids = 10; + wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX; ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM | WIPHY_FLAG_HAVE_AP_SME | @@ -3447,8 +3544,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar) ar->wiphy->probe_resp_offload = NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS | NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P | - NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U; + NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P; ret = wiphy_register(wiphy); if (ret < 0) { diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index c5def436417..5ea8cbb79f4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode { struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, enum nl80211_iftype type, u8 fw_vif_idx, u8 nw_type); +void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, + enum wmi_phy_mode mode); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel, diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 9d67964a51d..4d9c6f14269 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -126,9 +126,9 @@ struct ath6kl_fw_ie { #define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77" #define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin" #define AR6003_HW_2_0_PATCH_FILE "data.patch.bin" -#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin" +#define AR6003_HW_2_0_BOARD_DATA_FILE AR6003_HW_2_0_FW_DIR "/bdata.bin" #define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6003/hw2.0/bdata.SD31.bin" + AR6003_HW_2_0_FW_DIR "/bdata.SD31.bin" /* AR6003 3.0 definitions */ #define AR6003_HW_2_1_1_VERSION 0x30000582 @@ -139,25 +139,33 @@ struct ath6kl_fw_ie { #define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin" #define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin" #define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin" -#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin" +#define AR6003_HW_2_1_1_BOARD_DATA_FILE AR6003_HW_2_1_1_FW_DIR "/bdata.bin" #define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6003/hw2.1.1/bdata.SD31.bin" + AR6003_HW_2_1_1_FW_DIR "/bdata.SD31.bin" /* AR6004 1.0 definitions */ #define AR6004_HW_1_0_VERSION 0x30000623 #define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0" #define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin" +#define AR6004_HW_1_0_BOARD_DATA_FILE AR6004_HW_1_0_FW_DIR "/bdata.bin" #define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6004/hw1.0/bdata.DB132.bin" + AR6004_HW_1_0_FW_DIR "/bdata.DB132.bin" /* AR6004 1.1 definitions */ #define AR6004_HW_1_1_VERSION 0x30000001 #define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1" #define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin" -#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin" +#define AR6004_HW_1_1_BOARD_DATA_FILE AR6004_HW_1_1_FW_DIR "/bdata.bin" #define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \ - "ath6k/AR6004/hw1.1/bdata.DB132.bin" + AR6004_HW_1_1_FW_DIR "/bdata.DB132.bin" + +/* AR6004 1.2 definitions */ +#define AR6004_HW_1_2_VERSION 0x300007e8 +#define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2" +#define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin" +#define AR6004_HW_1_2_BOARD_DATA_FILE AR6004_HW_1_2_FW_DIR "/bdata.bin" +#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \ + AR6004_HW_1_2_FW_DIR "/bdata.bin" /* Per STA data, used in AP mode */ #define STA_PS_AWAKE BIT(0) @@ -502,6 +510,8 @@ enum ath6kl_vif_state { WLAN_ENABLED, STATS_UPDATE_PEND, HOST_SLEEP_MODE_CMD_PROCESSED, + NETDEV_MCAST_ALL_ON, + NETDEV_MCAST_ALL_OFF, }; struct ath6kl_vif { @@ -549,9 +559,11 @@ struct ath6kl_vif { u16 assoc_bss_beacon_int; u16 listen_intvl_t; u16 bmiss_time_t; + u16 bg_scan_period; u8 assoc_bss_dtim_period; struct net_device_stats net_stats; struct target_stats target_stats; + struct wmi_connect_cmd profile; struct list_head mc_filter; }; @@ -640,6 +652,7 @@ struct ath6kl { u8 sta_list_index; struct ath6kl_req_key ap_mode_bkey; struct sk_buff_head mcastpsq; + u32 want_ch_switch; /* * FIXME: protects access to mcastpsq but is actually useless as @@ -672,6 +685,7 @@ struct ath6kl { u32 refclk_hz; u32 uarttx_pin; u32 testscript_addr; + enum wmi_phy_cap cap; struct ath6kl_hw_fw { const char *dir; @@ -805,7 +819,8 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn); struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr); struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid); -void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver); +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, + enum wmi_phy_cap cap); int ath6kl_control_tx(void *devt, struct sk_buff *skb, enum htc_endpoint_id eid); void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, diff --git a/drivers/net/wireless/ath/ath6kl/debug.c b/drivers/net/wireless/ath/ath6kl/debug.c index 1b76aff7850..15cfe30e54f 100644 --- a/drivers/net/wireless/ath/ath6kl/debug.c +++ b/drivers/net/wireless/ath/ath6kl/debug.c @@ -401,8 +401,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file, ret = wait_for_completion_interruptible( &ar->debug.fwlog_completion); - if (ret == -ERESTARTSYS) + if (ret == -ERESTARTSYS) { + vfree(buf); return ret; + } spin_lock(&ar->debug.fwlog_queue.lock); } @@ -1570,10 +1572,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, size_t count, loff_t *ppos) { struct ath6kl *ar = file->private_data; + struct ath6kl_vif *vif; u16 bgscan_int; char buf[32]; ssize_t len; + vif = ath6kl_vif_first(ar); + if (!vif) + return -EIO; + len = min(count, sizeof(buf) - 1); if (copy_from_user(buf, user_buf, len)) return -EFAULT; @@ -1585,6 +1592,8 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file, if (bgscan_int == 0) bgscan_int = 0xffff; + vif->bg_scan_period = bgscan_int; + ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3, 0, 0, 0); @@ -1809,6 +1818,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar) void ath6kl_debug_cleanup(struct ath6kl *ar) { skb_queue_purge(&ar->debug.fwlog_queue); + complete(&ar->debug.fwlog_completion); kfree(ar->debug.roam_tbl); } diff --git a/drivers/net/wireless/ath/ath6kl/htc_mbox.c b/drivers/net/wireless/ath/ath6kl/htc_mbox.c index 065e61516d7..2798624d3a9 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_mbox.c +++ b/drivers/net/wireless/ath/ath6kl/htc_mbox.c @@ -83,10 +83,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, * never goes inactive EVER. */ cur_ep_dist->dist_flags |= HTC_EP_ACTIVE; - } else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC) - /* this is the lowest priority data endpoint */ - /* FIXME: this looks fishy, check */ - cred_info->lowestpri_ep_dist = cur_ep_dist->list; + } /* * Streams have to be created (explicit | implicit) for all @@ -100,6 +97,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info, */ } + /* + * For ath6kl_credit_seek function, + * it use list_for_each_entry_reverse to walk around the whole ep list. + * Therefore assign this lowestpri_ep_dist after walk around the ep_list + */ + cred_info->lowestpri_ep_dist = cur_ep_dist->list; + WARN_ON(cred_info->cur_free_credits <= 0); list_for_each_entry(cur_ep_dist, ep_list, list) { @@ -758,7 +762,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, u32 txb_mask; u8 ac = WMM_NUM_AC; - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; @@ -793,16 +797,17 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint, * itself */ txb_mask = ((1 << ac) - 1); - /* - * when the scatter request resources drop below a - * certain threshold, disable Tx bundling for all - * AC's with priority lower than the current requesting - * AC. Otherwise re-enable Tx bundling for them - */ - if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) - target->tx_bndl_mask &= ~txb_mask; - else - target->tx_bndl_mask |= txb_mask; + + /* + * when the scatter request resources drop below a + * certain threshold, disable Tx bundling for all + * AC's with priority lower than the current requesting + * AC. Otherwise re-enable Tx bundling for them + */ + if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS) + target->tx_bndl_mask &= ~txb_mask; + else + target->tx_bndl_mask |= txb_mask; } ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n", @@ -849,6 +854,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, int bundle_sent; int n_pkts_bundle; u8 ac = WMM_NUM_AC; + int status; spin_lock_bh(&target->tx_lock); @@ -866,7 +872,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, */ INIT_LIST_HEAD(&txq); - if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) || + if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) && (WMI_CONTROL_SVC != endpoint->svc_id)) ac = target->dev->ar->ep2ac_map[endpoint->eid]; @@ -910,7 +916,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target, ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags, 0, packet->info.tx.seqno); - ath6kl_htc_tx_issue(target, packet); + status = ath6kl_htc_tx_issue(target, packet); + + if (status) { + packet->status = status; + packet->completion(packet->context, packet); + } } spin_lock_bh(&target->tx_lock); diff --git a/drivers/net/wireless/ath/ath6kl/htc_pipe.c b/drivers/net/wireless/ath/ath6kl/htc_pipe.c index b277b344688..f9626c72369 100644 --- a/drivers/net/wireless/ath/ath6kl/htc_pipe.c +++ b/drivers/net/wireless/ath/ath6kl/htc_pipe.c @@ -108,8 +108,6 @@ static void get_htc_packet_credit_based(struct htc_target *target, /* get packet at head, but don't remove it */ packet = list_first_entry(&ep->txq, struct htc_packet, list); - if (packet == NULL) - break; ath6kl_dbg(ATH6KL_DBG_HTC, "%s: got head packet:0x%p , queue depth: %d\n", @@ -803,8 +801,6 @@ static int htc_send_packets_multiple(struct htc_target *target, /* get first packet to find out which ep the packets will go into */ packet = list_first_entry(pkt_queue, struct htc_packet, list); - if (packet == NULL) - return -EINVAL; if (packet->endpoint >= ENDPOINT_MAX) { WARN_ON_ONCE(1); @@ -1382,6 +1378,9 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target, /* copy all the callbacks */ ep->ep_cb = conn_req->ep_cb; + /* initialize tx_drop_packet_threshold */ + ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM; + status = ath6kl_hif_pipe_map_service(ar, ep->svc_id, &ep->pipe.pipeid_ul, &ep->pipe.pipeid_dl); @@ -1636,10 +1635,6 @@ static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target, return -EINVAL; first = list_first_entry(pkt_queue, struct htc_packet, list); - if (first == NULL) { - WARN_ON_ONCE(1); - return -EINVAL; - } if (first->endpoint >= ENDPOINT_MAX) { WARN_ON_ONCE(1); diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 29ef50ea07d..7eb0515f458 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -119,6 +119,24 @@ static const struct ath6kl_hw hw_list[] = { .fw_board = AR6004_HW_1_1_BOARD_DATA_FILE, .fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE, }, + { + .id = AR6004_HW_1_2_VERSION, + .name = "ar6004 hw 1.2", + .dataset_patch_addr = 0x436ecc, + .app_load_addr = 0x1234, + .board_ext_data_addr = 0x437000, + .reserved_ram_size = 9216, + .board_addr = 0x435c00, + .refclk_hz = 40000000, + .uarttx_pin = 11, + + .fw = { + .dir = AR6004_HW_1_2_FW_DIR, + .fw = AR6004_HW_1_2_FIRMWARE_FILE, + }, + .fw_board = AR6004_HW_1_2_BOARD_DATA_FILE, + .fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE, + }, }; /* @@ -445,9 +463,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) P2P_FLAG_MACADDR_REQ | P2P_FLAG_HMODEL_REQ); if (ret) { - ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P " - "capabilities (%d) - assuming P2P not " - "supported\n", ret); + ath6kl_dbg(ATH6KL_DBG_TRC, + "failed to request P2P capabilities (%d) - assuming P2P not supported\n", + ret); ar->p2p = false; } } @@ -456,8 +474,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx) /* Enable Probe Request reporting for P2P */ ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true); if (ret) { - ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe " - "Request reporting (%d)\n", ret); + ath6kl_dbg(ATH6KL_DBG_TRC, + "failed to enable Probe Request reporting (%d)\n", + ret); } } diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c index 4d818f96c41..e5524470529 100644 --- a/drivers/net/wireless/ath/ath6kl/main.c +++ b/drivers/net/wireless/ath/ath6kl/main.c @@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) if (!ik->valid) break; - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for " - "the initial group key for AP mode\n"); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delayed addkey for the initial group key for AP mode\n"); memset(key_rsc, 0, sizeof(key_rsc)); res = ath6kl_wmi_addkey_cmd( ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type, @@ -430,12 +430,19 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel) ik->key, KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG); if (res) { - ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed " - "addkey failed: %d\n", res); + ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, + "Delayed addkey failed: %d\n", res); } break; } + if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) { + ar->want_ch_switch &= ~(1 << vif->fw_vif_idx); + /* we actually don't know the phymode, default to HT20 */ + ath6kl_cfg80211_ch_switch_notify(vif, channel, + WMI_11G_HT20); + } + ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0); set_bit(CONNECTED, &vif->flags); netif_carrier_on(vif->ndev); @@ -541,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif) /* WMI Event handlers */ -void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) +void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver, + enum wmi_phy_cap cap) { struct ath6kl *ar = devt; @@ -551,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver) ar->version.wlan_ver = sw_ver; ar->version.abi_ver = abi_ver; + ar->hw.cap = cap; snprintf(ar->wiphy->fw_version, sizeof(ar->wiphy->fw_version), @@ -584,6 +593,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status) ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status); } +static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel) +{ + + struct ath6kl *ar = vif->ar; + + vif->next_chan = channel; + vif->profile.ch = cpu_to_le16(channel); + + switch (vif->nw_type) { + case AP_NETWORK: + return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, + &vif->profile); + default: + ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type); + return -ENOTSUPP; + } +} + +static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel) +{ + + struct ath6kl_vif *vif; + int res = 0; + + if (!ar->want_ch_switch) + return; + + spin_lock_bh(&ar->list_lock); + list_for_each_entry(vif, &ar->vif_list, list) { + if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) + res = ath6kl_commit_ch_switch(vif, channel); + + if (res) + ath6kl_err("channel switch failed nw_type %d res %d\n", + vif->nw_type, res); + } + spin_unlock_bh(&ar->list_lock); +} + void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, u16 listen_int, u16 beacon_int, enum network_type net_type, u8 beacon_ie_len, @@ -601,9 +649,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid, memcpy(vif->bssid, bssid, sizeof(vif->bssid)); vif->bss_ch = channel; - if ((vif->nw_type == INFRA_NETWORK)) + if ((vif->nw_type == INFRA_NETWORK)) { ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx, vif->listen_intvl_t, 0); + ath6kl_check_ch_switch(ar, channel); + } netif_wake_queue(vif->ndev); @@ -926,6 +976,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid, struct ath6kl *ar = vif->ar; if (vif->nw_type == AP_NETWORK) { + /* disconnect due to other STA vif switching channels */ + if (reason == BSS_DISCONNECTED && + prot_reason_status == WMI_AP_REASON_STA_ROAM) + ar->want_ch_switch |= 1 << vif->fw_vif_idx; + if (!ath6kl_remove_sta(ar, bssid, prot_reason_status)) return; @@ -1090,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev, static void ath6kl_set_multicast_list(struct net_device *ndev) { struct ath6kl_vif *vif = netdev_priv(ndev); - bool mc_all_on = false, mc_all_off = false; + bool mc_all_on = false; int mc_count = netdev_mc_count(ndev); struct netdev_hw_addr *ha; bool found; @@ -1102,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev) !test_bit(WLAN_ENABLED, &vif->flags)) return; + /* Enable multicast-all filter. */ mc_all_on = !!(ndev->flags & IFF_PROMISC) || !!(ndev->flags & IFF_ALLMULTI) || !!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST); - mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0; + if (mc_all_on) + set_bit(NETDEV_MCAST_ALL_ON, &vif->flags); + else + clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags); + + mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON); - if (mc_all_on || mc_all_off) { - /* Enable/disable all multicast */ - ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n", - mc_all_on ? "enabling" : "disabling"); - ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, + if (!(ndev->flags & IFF_MULTICAST)) { + mc_all_on = false; + set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } else { + clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags); + } + + /* Enable/disable "multicast-all" filter*/ + ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n", + mc_all_on ? "enabling" : "disabling"); + + ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx, mc_all_on); - if (ret) - ath6kl_warn("Failed to %s multicast receive\n", - mc_all_on ? "enable" : "disable"); + if (ret) { + ath6kl_warn("Failed to %s multicast-all receive\n", + mc_all_on ? "enable" : "disable"); return; } + if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) + return; + + /* Keep the driver and firmware mcast list in sync. */ list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) { found = false; netdev_for_each_mc_addr(ha, ndev) { diff --git a/drivers/net/wireless/ath/ath6kl/sdio.c b/drivers/net/wireless/ath/ath6kl/sdio.c index 44ea7a74210..05b95405f7b 100644 --- a/drivers/net/wireless/ath/ath6kl/sdio.c +++ b/drivers/net/wireless/ath/ath6kl/sdio.c @@ -552,7 +552,7 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer, bus_req = ath6kl_sdio_alloc_busreq(ar_sdio); - if (!bus_req) + if (WARN_ON_ONCE(!bus_req)) return -ENOMEM; bus_req->address = address; @@ -915,6 +915,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow) } cut_pwr: + if (func->card && func->card->host) + func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER; + return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL); } @@ -985,9 +988,8 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr) } if (status) { - ath6kl_err("%s: failed to write initial bytes of 0x%x " - "to window reg: 0x%X\n", __func__, - addr, reg_addr); + ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n", + __func__, addr, reg_addr); return status; } @@ -1076,8 +1078,8 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar) (u8 *)&ar->bmi.cmd_credits, 4, HIF_RD_SYNC_BYTE_INC); if (ret) { - ath6kl_err("Unable to decrement the command credit " - "count register: %d\n", ret); + ath6kl_err("Unable to decrement the command credit count register: %d\n", + ret); return ret; } @@ -1457,3 +1459,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/txrx.c b/drivers/net/wireless/ath/ath6kl/txrx.c index 82f2f5cb475..67206aedea6 100644 --- a/drivers/net/wireless/ath/ath6kl/txrx.c +++ b/drivers/net/wireless/ath/ath6kl/txrx.c @@ -362,15 +362,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev) skb, skb->data, skb->len); /* If target is not associated */ - if (!test_bit(CONNECTED, &vif->flags)) { - dev_kfree_skb(skb); - return 0; - } + if (!test_bit(CONNECTED, &vif->flags)) + goto fail_tx; - if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) { - dev_kfree_skb(skb); - return 0; - } + if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) + goto fail_tx; if (!test_bit(WMI_READY, &ar->flag)) goto fail_tx; diff --git a/drivers/net/wireless/ath/ath6kl/usb.c b/drivers/net/wireless/ath/ath6kl/usb.c index 44a795f14da..3740c3d6ab8 100644 --- a/drivers/net/wireless/ath/ath6kl/usb.c +++ b/drivers/net/wireless/ath/ath6kl/usb.c @@ -1037,6 +1037,14 @@ static void ath6kl_usb_stop(struct ath6kl *ar) hif_stop(ar); } +static void ath6kl_usb_cleanup_scatter(struct ath6kl *ar) +{ + /* + * USB doesn't support it. Just return. + */ + return; +} + static const struct ath6kl_hif_ops ath6kl_usb_ops = { .diag_read32 = ath6kl_usb_diag_read32, .diag_write32 = ath6kl_usb_diag_write32, @@ -1049,6 +1057,7 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = { .pipe_get_default = ath6kl_usb_get_default_pipe, .pipe_map_service = ath6kl_usb_map_service_pipe, .pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number, + .cleanup_scatter = ath6kl_usb_cleanup_scatter, }; /* ath6kl usb driver registered functions */ @@ -1208,3 +1217,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE); MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE); +MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 7c8a9977faf..ee8ec2394c2 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -16,6 +16,7 @@ */ #include <linux/ip.h> +#include <linux/in.h> #include "core.h" #include "debug.h" #include "testmode.h" @@ -289,6 +290,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx, layer2_priority); } else usr_pri = layer2_priority & 0x7; + + /* + * Queue the EAPOL frames in the same WMM_AC_VO queue + * as that of management frames. + */ + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + usr_pri = WMI_VOICE_USER_PRIORITY; } /* @@ -460,8 +468,9 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, freq, dur); chan = ieee80211_get_channel(ar->wiphy, freq); if (!chan) { - ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel " - "(freq=%u)\n", freq); + ath6kl_dbg(ATH6KL_DBG_WMI, + "remain_on_chnl: Unknown channel (freq=%u)\n", + freq); return -EINVAL; } id = vif->last_roc_id; @@ -488,12 +497,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, ev = (struct wmi_cancel_remain_on_chnl_event *) datap; freq = le32_to_cpu(ev->freq); dur = le32_to_cpu(ev->duration); - ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u " - "status=%u\n", freq, dur, ev->status); + ath6kl_dbg(ATH6KL_DBG_WMI, + "cancel_remain_on_chnl: freq=%u dur=%u status=%u\n", + freq, dur, ev->status); chan = ieee80211_get_channel(ar->wiphy, freq); if (!chan) { - ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown " - "channel (freq=%u)\n", freq); + ath6kl_dbg(ATH6KL_DBG_WMI, + "cancel_remain_on_chnl: Unknown channel (freq=%u)\n", + freq); return -EINVAL; } if (vif->last_cancel_roc_id && @@ -548,12 +559,12 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); if (datap + len < ev->data + dlen) { - ath6kl_err("invalid wmi_p2p_rx_probe_req_event: " - "len=%d dlen=%u\n", len, dlen); + ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n", + len, dlen); return -EINVAL; } - ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u " - "probe_req_report=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "rx_probe_req: len=%u freq=%u probe_req_report=%d\n", dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) @@ -592,8 +603,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, freq = le32_to_cpu(ev->freq); dlen = le16_to_cpu(ev->len); if (datap + len < ev->data + dlen) { - ath6kl_err("invalid wmi_rx_action_event: " - "len=%d dlen=%u\n", len, dlen); + ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n", + len, dlen); return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); @@ -687,7 +698,7 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len) ath6kl_ready_event(wmi->parent_dev, ev->mac_addr, le32_to_cpu(ev->sw_version), - le32_to_cpu(ev->abi_version)); + le32_to_cpu(ev->abi_version), ev->phy_cap); return 0; } @@ -777,16 +788,15 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len, /* AP mode start/STA connected event */ struct net_device *dev = vif->ndev; if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) { - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM " - "(AP started)\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: freq %d bssid %pM (AP started)\n", __func__, le16_to_cpu(ev->u.ap_bss.ch), ev->u.ap_bss.bssid); ath6kl_connect_ap_mode_bss( vif, le16_to_cpu(ev->u.ap_bss.ch)); } else { - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM " - "auth=%u keymgmt=%u cipher=%u apsd_info=%u " - "(STA connected)\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n", __func__, ev->u.ap_sta.aid, ev->u.ap_sta.mac_addr, ev->u.ap_sta.auth, @@ -1229,8 +1239,9 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap, ev = (struct wmi_neighbor_report_event *) datap; if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info) > len) { - ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event " - "(num=%d len=%d)\n", ev->num_neighbors, len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "truncated neighbor event (num=%d len=%d)\n", + ev->num_neighbors, len); return -EINVAL; } for (i = 0; i < ev->num_neighbors; i++) { @@ -1814,12 +1825,14 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, u32 home_dwell_time, u32 force_scan_interval, s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates) { + struct ieee80211_supported_band *sband; struct sk_buff *skb; struct wmi_begin_scan_cmd *sc; - s8 size; + s8 size, *supp_rates; int i, band, ret; struct ath6kl *ar = wmi->parent_dev; int num_rates; + u32 ratemask; size = sizeof(struct wmi_begin_scan_cmd); @@ -1846,10 +1859,13 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx, sc->num_ch = num_chan; for (band = 0; band < IEEE80211_NUM_BANDS; band++) { - struct ieee80211_supported_band *sband = - ar->wiphy->bands[band]; - u32 ratemask = rates[band]; - u8 *supp_rates = sc->supp_rates[band].rates; + sband = ar->wiphy->bands[band]; + + if (!sband) + continue; + + ratemask = rates[band]; + supp_rates = sc->supp_rates[band].rates; num_rates = 0; for (i = 0; i < sband->n_bitrates; i++) { @@ -2129,8 +2145,8 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index, struct wmi_add_cipher_key_cmd *cmd; int ret; - ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d " - "key_usage=%d key_len=%d key_op_ctrl=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n", key_index, key_type, key_usage, key_len, key_op_ctrl); if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) || @@ -3047,8 +3063,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx, res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID, NO_SYNC_WMIFLAG); - ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u " - "ctrl_flags=0x%x-> res=%d\n", + ath6kl_dbg(ATH6KL_DBG_WMI, + "%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n", __func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch), le32_to_cpu(p->ctrl_flags), res); return res; @@ -3208,8 +3224,9 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, if (!skb) return -ENOMEM; - ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u " - "ie_len=%u\n", mgmt_frm_type, ie_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n", + mgmt_frm_type, ie_len); p = (struct wmi_set_appie_cmd *) skb->data; p->mgmt_frm_type = mgmt_frm_type; p->ie_len = ie_len; @@ -3310,8 +3327,9 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " - "len=%u\n", id, freq, wait, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_action_cmd: id=%u freq=%u wait=%u len=%u\n", + id, freq, wait, data_len); p = (struct wmi_send_action_cmd *) skb->data; p->id = cpu_to_le32(id); p->freq = cpu_to_le32(freq); @@ -3348,8 +3366,9 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, wmi->last_mgmt_tx_frame = buf; wmi->last_mgmt_tx_frame_len = data_len; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u " - "len=%u\n", id, freq, wait, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_action_cmd: id=%u freq=%u wait=%u len=%u\n", + id, freq, wait, data_len); p = (struct wmi_send_mgmt_cmd *) skb->data; p->id = cpu_to_le32(id); p->freq = cpu_to_le32(freq); @@ -3402,8 +3421,9 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, if (!skb) return -ENOMEM; - ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM " - "len=%u\n", freq, dst, data_len); + ath6kl_dbg(ATH6KL_DBG_WMI, + "send_probe_response_cmd: freq=%u dst=%pM len=%u\n", + freq, dst, data_len); p = (struct wmi_p2p_probe_response_cmd *) skb->data; p->freq = cpu_to_le32(freq); memcpy(p->destination_addr, dst, ETH_ALEN); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index d3d2ab5c168..9076bec3a2b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -106,6 +106,8 @@ struct wmi_data_sync_bufs { #define WMM_AC_VI 2 /* video */ #define WMM_AC_VO 3 /* voice */ +#define WMI_VOICE_USER_PRIORITY 0x7 + struct wmi { u16 stream_exist_for_ac[WMM_NUM_AC]; u8 fat_pipe_exist; @@ -1151,6 +1153,7 @@ enum wmi_phy_mode { WMI_11AG_MODE = 0x3, WMI_11B_MODE = 0x4, WMI_11GONLY_MODE = 0x5, + WMI_11G_HT20 = 0x6, }; #define WMI_MAX_CHANNELS 32 @@ -1416,6 +1419,16 @@ struct wmi_ready_event_2 { u8 phy_cap; } __packed; +/* WMI_PHY_CAPABILITY */ +enum wmi_phy_cap { + WMI_11A_CAP = 0x01, + WMI_11G_CAP = 0x02, + WMI_11AG_CAP = 0x03, + WMI_11AN_CAP = 0x04, + WMI_11GN_CAP = 0x05, + WMI_11AGN_CAP = 0x06, +}; + /* Connect Event */ struct wmi_connect_event { union { @@ -1468,6 +1481,17 @@ enum wmi_disconnect_reason { IBSS_MERGE = 0xe, }; +/* AP mode disconnect proto_reasons */ +enum ap_disconnect_reason { + WMI_AP_REASON_STA_LEFT = 101, + WMI_AP_REASON_FROM_HOST = 102, + WMI_AP_REASON_COMM_TIMEOUT = 103, + WMI_AP_REASON_MAX_STA = 104, + WMI_AP_REASON_ACL = 105, + WMI_AP_REASON_STA_ROAM = 106, + WMI_AP_REASON_DFS_CHANNEL = 107, +}; + #define ATH6KL_COUNTRY_RD_SHIFT 16 struct ath6kl_wmi_regdomain { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c index a0387a027db..9fdd70fcaf5 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c @@ -892,34 +892,6 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah) AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1); } -static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) -{ - struct ath9k_rtt_hist *hist; - u32 *table; - int i; - bool restore; - - if (!ah->caldata) - return false; - - hist = &ah->caldata->rtt_hist; - if (!hist->num_readings) - return false; - - ar9003_hw_rtt_enable(ah); - ar9003_hw_rtt_set_mask(ah, 0x00); - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->rxchainmask & (1 << i))) - continue; - table = &hist->table[i][hist->num_readings][0]; - ar9003_hw_rtt_load_hist(ah, i, table); - } - restore = ar9003_hw_rtt_force_restore(ah); - ar9003_hw_rtt_disable(ah); - - return restore; -} - static bool ar9003_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan) { @@ -942,9 +914,10 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah, if (!ar9003_hw_rtt_restore(ah, chan)) run_rtt_cal = true; - ath_dbg(common, CALIBRATE, "RTT restore %s\n", - run_rtt_cal ? "failed" : "succeed"); + if (run_rtt_cal) + ath_dbg(common, CALIBRATE, "RTT calibration to be done\n"); } + run_agc_cal = run_rtt_cal; if (run_rtt_cal) { @@ -1069,17 +1042,14 @@ skip_tx_iqcal: #undef CL_TAB_ENTRY if (run_rtt_cal && caldata) { - struct ath9k_rtt_hist *hist = &caldata->rtt_hist; - if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) { - u32 *table; + if (is_reusable) { + if (!ath9k_hw_rfbus_req(ah)) + ath_err(ath9k_hw_common(ah), + "Could not stop baseband\n"); + else + ar9003_hw_rtt_fill_hist(ah); - hist->num_readings++; - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->rxchainmask & (1 << i))) - continue; - table = &hist->table[i][hist->num_readings][0]; - ar9003_hw_rtt_fill_hist(ah, i, table); - } + ath9k_hw_rfbus_done(ah); } ar9003_hw_rtt_disable(ah); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_mci.c b/drivers/net/wireless/ath/ath9k/ar9003_mci.c index 3cac293a284..ffbb180f91e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_mci.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_mci.c @@ -756,7 +756,7 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (caldata) { caldata->done_txiqcal_once = false; caldata->done_txclcal_once = false; - caldata->rtt_hist.num_readings = 0; + caldata->rtt_done = false; } if (!ath9k_hw_init_cal(ah, chan)) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c index 458bedf0b0a..74de3539c2c 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.c @@ -15,6 +15,7 @@ */ #include "hw.h" +#include "hw-ops.h" #include "ar9003_phy.h" #include "ar9003_rtt.h" @@ -69,7 +70,7 @@ bool ar9003_hw_rtt_force_restore(struct ath_hw *ah) } static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain, - u32 index, u32 data28) + u32 index, u32 data28) { u32 val; @@ -100,12 +101,21 @@ static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain, RTT_ACCESS_TIMEOUT); } -void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table) +void ar9003_hw_rtt_load_hist(struct ath_hw *ah) { - int i; + int chain, i; - for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) - ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]); + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if (!(ah->rxchainmask & (1 << chain))) + continue; + for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { + ar9003_hw_rtt_load_hist_entry(ah, chain, i, + ah->caldata->rtt_table[chain][i]); + ath_dbg(ath9k_hw_common(ah), CALIBRATE, + "Load RTT value at idx %d, chain %d: 0x%x\n", + i, chain, ah->caldata->rtt_table[chain][i]); + } + } } static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index) @@ -128,27 +138,71 @@ static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index) RTT_ACCESS_TIMEOUT)) return RTT_BAD_VALUE; - val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)); + val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)), + AR_PHY_RTT_SW_RTT_TABLE_DATA); + return val; } -void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table) +void ar9003_hw_rtt_fill_hist(struct ath_hw *ah) { - int i; + int chain, i; + + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if (!(ah->rxchainmask & (1 << chain))) + continue; + for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) { + ah->caldata->rtt_table[chain][i] = + ar9003_hw_rtt_fill_hist_entry(ah, chain, i); + ath_dbg(ath9k_hw_common(ah), CALIBRATE, + "RTT value at idx %d, chain %d is: 0x%x\n", + i, chain, ah->caldata->rtt_table[chain][i]); + } + } - for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) - table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i); + ah->caldata->rtt_done = true; } void ar9003_hw_rtt_clear_hist(struct ath_hw *ah) { - int i, j; + int chain, i; - for (i = 0; i < AR9300_MAX_CHAINS; i++) { - if (!(ah->rxchainmask & (1 << i))) + for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { + if (!(ah->rxchainmask & (1 << chain))) continue; - for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++) - ar9003_hw_rtt_load_hist_entry(ah, i, j, 0); + for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) + ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0); } + + if (ah->caldata) + ah->caldata->rtt_done = false; +} + +bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan) +{ + bool restore; + + if (!ah->caldata) + return false; + + if (!ah->caldata->rtt_done) + return false; + + ar9003_hw_rtt_enable(ah); + ar9003_hw_rtt_set_mask(ah, 0x10); + + if (!ath9k_hw_rfbus_req(ah)) { + ath_err(ath9k_hw_common(ah), "Could not stop baseband\n"); + restore = false; + goto fail; + } + + ar9003_hw_rtt_load_hist(ah); + restore = ar9003_hw_rtt_force_restore(ah); + +fail: + ath9k_hw_rfbus_done(ah); + ar9003_hw_rtt_disable(ah); + return restore; } diff --git a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h index 030758d087d..a43b30d723a 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_rtt.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_rtt.h @@ -21,8 +21,9 @@ void ar9003_hw_rtt_enable(struct ath_hw *ah); void ar9003_hw_rtt_disable(struct ath_hw *ah); void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask); bool ar9003_hw_rtt_force_restore(struct ath_hw *ah); -void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table); -void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table); +void ar9003_hw_rtt_load_hist(struct ath_hw *ah); +void ar9003_hw_rtt_fill_hist(struct ath_hw *ah); void ar9003_hw_rtt_clear_hist(struct ath_hw *ah); +bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan); #endif diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index f84477c5ebb..abe05ec85d5 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -1702,10 +1702,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan) * For AR9462, make sure that calibration data for * re-using are present. */ - if (AR_SREV_9462(ah) && (!ah->caldata || - !ah->caldata->done_txiqcal_once || - !ah->caldata->done_txclcal_once || - !ah->caldata->rtt_hist.num_readings)) + if (AR_SREV_9462(ah) && (ah->caldata && + (!ah->caldata->done_txiqcal_once || + !ah->caldata->done_txclcal_once || + !ah->caldata->rtt_done))) goto fail; ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n", @@ -1941,7 +1941,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan, if (caldata) { caldata->done_txiqcal_once = false; caldata->done_txclcal_once = false; - caldata->rtt_hist.num_readings = 0; } if (!ath9k_hw_init_cal(ah, chan)) return -EIO; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 828b9bbc456..b620c557c2a 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -348,12 +348,6 @@ enum ath9k_int { CHANNEL_HT40MINUS) #define MAX_RTT_TABLE_ENTRY 6 -#define RTT_HIST_MAX 3 -struct ath9k_rtt_hist { - u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY]; - u8 num_readings; -}; - #define MAX_IQCAL_MEASUREMENT 8 #define MAX_CL_TAB_ENTRY 16 @@ -363,6 +357,7 @@ struct ath9k_hw_cal_data { int32_t CalValid; int8_t iCoff; int8_t qCoff; + bool rtt_done; bool paprd_done; bool nfcal_pending; bool nfcal_interference; @@ -373,8 +368,8 @@ struct ath9k_hw_cal_data { u32 num_measures[AR9300_MAX_CHAINS]; int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS]; u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY]; + u32 rtt_table[AR9300_MAX_CHAINS][MAX_RTT_TABLE_ENTRY]; struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS]; - struct ath9k_rtt_hist rtt_hist; }; struct ath9k_channel { diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c index 424692df239..565fdbdd691 100644 --- a/drivers/net/wireless/b43/bus.c +++ b/drivers/net/wireless/b43/bus.c @@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core) dev->dma_dev = core->dma_dev; dev->irq = core->irq; - /* dev->board_vendor = core->bus->boardinfo.vendor; dev->board_type = core->bus->boardinfo.type; - dev->board_rev = core->bus->boardinfo.rev; - */ + dev->board_rev = core->bus->sprom.board_rev; dev->chip_id = core->bus->chipinfo.id; dev->chip_rev = core->bus->chipinfo.rev; @@ -210,7 +208,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev) dev->board_vendor = sdev->bus->boardinfo.vendor; dev->board_type = sdev->bus->boardinfo.type; - dev->board_rev = sdev->bus->boardinfo.rev; + dev->board_rev = sdev->bus->sprom.board_rev; dev->chip_id = sdev->bus->chip_id; dev->chip_rev = sdev->bus->chip_rev; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index b5f1b91002b..777cd74921d 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1109,7 +1109,7 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev, #ifdef CONFIG_B43_SSB if (dev->dev->bus_type == B43_BUS_SSB && dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && - !(dev->dev->sdev->bus->host_pci->is_pcie && + !(pci_is_pcie(dev->dev->sdev->bus->host_pci) && ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64)) return 1; #endif diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 617afc8211b..5a39b226b2e 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL && - bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74) + bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74) bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST; if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && - bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40) + bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43_BFL_PACTRL; if (bus->bustype == SSB_BUSTYPE_PCI) { pdev = bus->host_pci; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index 1be214b815f..cd9c9bc186d 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -1573,8 +1573,6 @@ static void b43legacy_request_firmware(struct work_struct *work) const char *filename; int err; - /* do dummy read */ - ssb_read32(dev->dev, SSB_TMSHIGH); if (!fw->ucode) { if (rev == 2) filename = "ucode2"; @@ -3781,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus) /* boardflags workarounds */ if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE && bus->boardinfo.type == 0x4E && - bus->boardinfo.rev > 0x40) + bus->sprom.board_rev > 0x40) bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL; } diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 950334197f4..995c7d0c212 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x5001, 0x0002); @@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev) if (is_bcm_board_vendor(dev) && (dev->dev->bus->boardinfo.type == 0x0416) && - (dev->dev->bus->boardinfo.rev == 0x0017)) + (dev->dev->bus->sprom.board_rev == 0x0017)) return; b43legacy_ilt_write(dev, 0x0401, 0x0002); diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c index fcbafcd603c..89617769039 100644 --- a/drivers/net/wireless/b43legacy/radio.c +++ b/drivers/net/wireless/b43legacy/radio.c @@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x416) @@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } else { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 7; else att = 6; @@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) if (phy->type == B43legacy_PHYTYPE_G) { if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421 && - dev->dev->bus->boardinfo.rev >= 30) + dev->dev->bus->sprom.board_rev >= 30) att = 3; else if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == @@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev) } if (is_bcm_board_vendor(dev) && dev->dev->bus->boardinfo.type == 0x421) { - if (dev->dev->bus->boardinfo.rev < 0x43) + if (dev->dev->bus->sprom.board_rev < 0x43) att = 2; - else if (dev->dev->bus->boardinfo.rev < 0x51) + else if (dev->dev->bus->sprom.board_rev < 0x51) att = 3; } if (att == 0xFFFF) diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c index 4add7da2468..e2480d19627 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c @@ -85,18 +85,15 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev) sdiodev->irq_wake = true; /* must configure SDIO_CCCR_IENx to enable irq */ - data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0, - SDIO_CCCR_IENx, &ret); + data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret); data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, - data, &ret); + brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret); /* redirect, configure ane enable io for interrupt signal */ data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE; if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH) data |= SDIO_SEPINT_ACT_HI; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT, - data, &ret); + brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret); return 0; } @@ -105,9 +102,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) { brcmf_dbg(TRACE, "Entering\n"); - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT, - 0, NULL); - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL); + brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL); + brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL); if (sdiodev->irq_wake) { disable_irq_wake(sdiodev->irq); @@ -158,153 +154,147 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev) } #endif /* CONFIG_BRCMFMAC_SDIO_OOB */ -u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, - int *err) -{ - int status; - s32 retry = 0; - u8 data = 0; - - do { - if (retry) /* wait for 1 ms till bus get settled down */ - udelay(1000); - status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num, - addr, (u8 *) &data); - } while (status != 0 - && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); - if (err) - *err = status; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", - fnc_num, addr, data); - - return data; -} - -void -brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr, - u8 data, int *err) -{ - int status; - s32 retry = 0; - - do { - if (retry) /* wait for 1 ms till bus get settled down */ - udelay(1000); - status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num, - addr, (u8 *) &data); - } while (status != 0 - && (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT)); - if (err) - *err = status; - - brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n", - fnc_num, addr, data); -} - int brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address) { - int err = 0; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW, - (address >> 8) & SBSDIO_SBADDRLOW_MASK, &err); - if (!err) - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SBADDRMID, - (address >> 16) & SBSDIO_SBADDRMID_MASK, - &err); - if (!err) - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SBADDRHIGH, - (address >> 24) & SBSDIO_SBADDRHIGH_MASK, - &err); + int err = 0, i; + u8 addr[3]; + s32 retry; + + addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK; + addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK; + addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK; + + for (i = 0; i < 3; i++) { + retry = 0; + do { + if (retry) + usleep_range(1000, 2000); + err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, + SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i, + &addr[i]); + } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); + + if (err) { + brcmf_dbg(ERROR, "failed at addr:0x%0x\n", + SBSDIO_FUNC1_SBADDRLOW + i); + break; + } + } return err; } -u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size) +static int +brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr, + void *data, bool write) { - int status; - u32 word = 0; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - - brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr); - - if (bar0 != sdiodev->sbwad) { - if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0)) - return 0xFFFFFFFF; + u8 func_num, reg_size; + u32 bar; + s32 retry = 0; + int ret; - sdiodev->sbwad = bar0; + /* + * figure out how to read the register based on address range + * 0x00 ~ 0x7FF: function 0 CCCR and FBR + * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers + * The rest: function 1 silicon backplane core registers + */ + if ((addr & ~REG_F0_REG_MASK) == 0) { + func_num = SDIO_FUNC_0; + reg_size = 1; + } else if ((addr & ~REG_F1_MISC_MASK) == 0) { + func_num = SDIO_FUNC_1; + reg_size = 1; + } else { + func_num = SDIO_FUNC_1; + reg_size = 4; + + /* Set the window for SB core register */ + bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK; + if (bar != sdiodev->sbwad) { + ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar); + if (ret != 0) { + memset(data, 0xFF, reg_size); + return ret; + } + sdiodev->sbwad = bar; + } + addr &= SBSDIO_SB_OFT_ADDR_MASK; + addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; } - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; + do { + if (!write) + memset(data, 0, reg_size); + if (retry) /* wait for 1 ms till bus get settled down */ + usleep_range(1000, 2000); + if (reg_size == 1) + ret = brcmf_sdioh_request_byte(sdiodev, write, + func_num, addr, data); + else + ret = brcmf_sdioh_request_word(sdiodev, write, + func_num, addr, data, 4); + } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT); - status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1, - addr, &word, size); + if (ret != 0) + brcmf_dbg(ERROR, "failed with %d\n", ret); - sdiodev->regfail = (status != 0); + return ret; +} - brcmf_dbg(INFO, "u32data = 0x%x\n", word); +u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) +{ + u8 data; + int retval; - /* if ok, return appropriately masked word */ - if (status == 0) { - switch (size) { - case sizeof(u8): - return word & 0xff; - case sizeof(u16): - return word & 0xffff; - case sizeof(u32): - return word; - default: - sdiodev->regfail = true; + brcmf_dbg(INFO, "addr:0x%08x\n", addr); + retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); + brcmf_dbg(INFO, "data:0x%02x\n", data); - } - } + if (ret) + *ret = retval; - /* otherwise, bad sdio access or invalid size */ - brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size); - return 0xFFFFFFFF; + return data; } -u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, - u32 data) +u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret) { - int status; - uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK; - int err = 0; + u32 data; + int retval; - brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n", - addr, size * 8, data); + brcmf_dbg(INFO, "addr:0x%08x\n", addr); + retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false); + brcmf_dbg(INFO, "data:0x%08x\n", data); - if (bar0 != sdiodev->sbwad) { - err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0); - if (err) - return err; + if (ret) + *ret = retval; - sdiodev->sbwad = bar0; - } + return data; +} - addr &= SBSDIO_SB_OFT_ADDR_MASK; - if (size == 4) - addr |= SBSDIO_SB_ACCESS_2_4B_FLAG; - status = - brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1, - addr, &data, size); - sdiodev->regfail = (status != 0); +void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, + u8 data, int *ret) +{ + int retval; - if (status == 0) - return 0; + brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data); + retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); - brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n", - data, addr, size); - return 0xFFFFFFFF; + if (ret) + *ret = retval; } -bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev) +void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, + u32 data, int *ret) { - return sdiodev->regfail; + int retval; + + brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data); + retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true); + + if (ret) + *ret = retval; } static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn, diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c index dd07d33a927..82f51dbd0d6 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c @@ -346,43 +346,17 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev, return status; } -/* Read client card reg */ -static int -brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr, - int regsize, u32 *data) -{ - - if ((func == 0) || (regsize == 1)) { - u8 temp = 0; - - brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr, - &temp); - *data = temp; - *data &= 0xff; - brcmf_dbg(DATA, "byte read data=0x%02x\n", *data); - } else { - brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr, - data, regsize); - if (regsize == 2) - *data &= 0xffff; - - brcmf_dbg(DATA, "word read data=0x%08x\n", *data); - } - - return SUCCESS; -} - static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr) { /* read 24 bits and return valid 17 bit addr */ - int i; + int i, ret; u32 scratch, regdata; __le32 scratch_le; u8 *ptr = (u8 *)&scratch_le; for (i = 0; i < 3; i++) { - if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1, - ®data)) != SUCCESS) + regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret); + if (ret != 0) brcmf_dbg(ERROR, "Can't read!\n"); *ptr++ = (u8) regdata; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c index 149ee67beb2..1dbf2be478c 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c @@ -629,43 +629,29 @@ static bool data_ok(struct brcmf_sdio *bus) * Reads a register in the SDIO hardware block. This block occupies a series of * adresses on the 32 bit backplane bus. */ -static void -r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar) +static int +r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset) { u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); - *retryvar = 0; - do { - *regvar = brcmf_sdcard_reg_read(bus->sdiodev, - bus->ci->c_inf[idx].base + reg_offset, - sizeof(u32)); - } while (brcmf_sdcard_regfail(bus->sdiodev) && - (++(*retryvar) <= retry_limit)); - if (*retryvar) { - bus->regfails += (*retryvar-1); - if (*retryvar > retry_limit) { - brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset); - *regvar = 0; - } - } + int ret; + + *regvar = brcmf_sdio_regrl(bus->sdiodev, + bus->ci->c_inf[idx].base + offset, &ret); + + return ret; } -static void -w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar) +static int +w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset) { u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); - *retryvar = 0; - do { - brcmf_sdcard_reg_write(bus->sdiodev, - bus->ci->c_inf[idx].base + reg_offset, - sizeof(u32), regval); - } while (brcmf_sdcard_regfail(bus->sdiodev) && - (++(*retryvar) <= retry_limit)); - if (*retryvar) { - bus->regfails += (*retryvar-1); - if (*retryvar > retry_limit) - brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n", - reg_offset); - } + int ret; + + brcmf_sdio_regwl(bus->sdiodev, + bus->ci->c_inf[idx].base + reg_offset, + regval, &ret); + + return ret; } #define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND) @@ -697,16 +683,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) clkreq = bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + clkreq, &err); if (err) { brcmf_dbg(ERROR, "HT Avail request error: %d\n", err); return -EBADE; } /* Check current status */ - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); + clkctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, &err); if (err) { brcmf_dbg(ERROR, "HT Avail read error: %d\n", err); return -EBADE; @@ -715,9 +701,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) /* Go to pending and await interrupt if appropriate */ if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) { /* Allow only clock-available interrupt */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); + devctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_DEVICE_CTL, &err); if (err) { brcmf_dbg(ERROR, "Devctl error setting CA: %d\n", err); @@ -725,30 +710,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) } devctl |= SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, + devctl, &err); brcmf_dbg(INFO, "CLKCTL: set PENDING\n"); bus->clkstate = CLK_PENDING; return 0; } else if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ - devctl = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + devctl = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_DEVICE_CTL, &err); devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, + devctl, &err); } /* Otherwise, wait here (polling) for HT Avail */ timeout = jiffies + msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000); while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) { - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - &err); + clkctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, + &err); if (time_after(jiffies, timeout)) break; else @@ -781,17 +764,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok) if (bus->clkstate == CLK_PENDING) { /* Cancel CA-only interrupt filter */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); + devctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_DEVICE_CTL, &err); devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, + devctl, &err); } bus->clkstate = CLK_SDONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + clkreq, &err); brcmf_dbg(INFO, "CLKCTL: turned OFF\n"); if (err) { brcmf_dbg(ERROR, "Failed access turning clock off: %d\n", @@ -874,7 +856,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok) static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) { - uint retries = 0; + int ret; brcmf_dbg(INFO, "request %s (currently %s)\n", sleep ? "SLEEP" : "WAKE", @@ -894,22 +876,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); /* Tell device to start using OOB wakeup */ - w_sdreg32(bus, SMB_USE_OOB, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); - if (retries > retry_limit) + ret = w_sdreg32(bus, SMB_USE_OOB, + offsetof(struct sdpcmd_regs, tosbmailbox)); + if (ret != 0) brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n"); /* Turn off our contribution to the HT clock request */ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + SBSDIO_FORCE_HW_CLKREQ_OFF, NULL); /* Isolate the bus */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, - SBSDIO_DEVCTL_PADS_ISO, NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, + SBSDIO_DEVCTL_PADS_ISO, NULL); /* Change state */ bus->sleeping = true; @@ -917,21 +897,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep) } else { /* Waking up: bus power up is ok, set local state */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + 0, NULL); /* Make sure the controller has the bus up */ brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); /* Send misc interrupt to indicate OOB not needed */ - w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata), - &retries); - if (retries <= retry_limit) - w_sdreg32(bus, SMB_DEV_INT, - offsetof(struct sdpcmd_regs, tosbmailbox), - &retries); - - if (retries > retry_limit) + ret = w_sdreg32(bus, 0, + offsetof(struct sdpcmd_regs, tosbmailboxdata)); + if (ret == 0) + ret = w_sdreg32(bus, SMB_DEV_INT, + offsetof(struct sdpcmd_regs, tosbmailbox)); + + if (ret != 0) brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n"); /* Make sure we have SD bus access */ @@ -955,17 +934,17 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus) u32 intstatus = 0; u32 hmb_data; u8 fcbits; - uint retries = 0; + int ret; brcmf_dbg(TRACE, "Enter\n"); /* Read mailbox data and ack that we did so */ - r_sdreg32(bus, &hmb_data, - offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries); + ret = r_sdreg32(bus, &hmb_data, + offsetof(struct sdpcmd_regs, tohostmailboxdata)); - if (retries <= retry_limit) + if (ret == 0) w_sdreg32(bus, SMB_INT_ACK, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); + offsetof(struct sdpcmd_regs, tosbmailbox)); bus->f1regdata += 2; /* Dongle recomposed rx frames, accept them again */ @@ -1040,17 +1019,16 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) if (abort) brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, - SFC_RF_TERM, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, + SFC_RF_TERM, &err); bus->f1regdata++; /* Wait until the packet has been flushed (device/FIFO stable) */ for (lastrbc = retries = 0xffff; retries > 0; retries--) { - hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_RFRAMEBCHI, NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_RFRAMEBCLO, NULL); + hi = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_RFRAMEBCHI, &err); + lo = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_RFRAMEBCLO, &err); bus->f1regdata += 2; if ((hi == 0) && (lo == 0)) @@ -1070,11 +1048,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) if (rtx) { bus->rxrtx++; - w_sdreg32(bus, SMB_NAK, - offsetof(struct sdpcmd_regs, tosbmailbox), &retries); + err = w_sdreg32(bus, SMB_NAK, + offsetof(struct sdpcmd_regs, tosbmailbox)); bus->f1regdata++; - if (retries <= retry_limit) + if (err == 0) bus->rxskip = true; } @@ -1082,7 +1060,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx) bus->nextlen = 0; /* If we can't reach the device, signal failure */ - if (err || brcmf_sdcard_regfail(bus->sdiodev)) + if (err) bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; } @@ -2178,21 +2156,16 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt, bus->tx_sderrs++; brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, - NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); bus->f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); + hi = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCLO, NULL); bus->f1regdata += 2; if ((hi == 0) && (lo == 0)) break; @@ -2219,7 +2192,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) { struct sk_buff *pkt; u32 intstatus = 0; - uint retries = 0; int ret = 0, prec_out; uint cnt = 0; uint datalen; @@ -2249,11 +2221,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes) /* In poll mode, need to check for other events */ if (!bus->intr && cnt) { /* Check device status, signal pending interrupt */ - r_sdreg32(bus, &intstatus, - offsetof(struct sdpcmd_regs, intstatus), - &retries); + ret = r_sdreg32(bus, &intstatus, + offsetof(struct sdpcmd_regs, + intstatus)); bus->f2txdata++; - if (brcmf_sdcard_regfail(bus->sdiodev)) + if (ret != 0) break; if (intstatus & bus->hostintmask) bus->ipend = true; @@ -2275,7 +2247,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) { u32 local_hostintmask; u8 saveclk; - uint retries; int err; struct brcmf_bus *bus_if = dev_get_drvdata(dev); struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; @@ -2303,7 +2274,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false); /* Disable and clear interrupts at the chip level also */ - w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries); + w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask)); local_hostintmask = bus->hostintmask; bus->hostintmask = 0; @@ -2311,24 +2282,23 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev) bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); + saveclk = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, &err); if (!err) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); } if (err) brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); /* Turn off the bus (F2), free any pending packets */ brcmf_dbg(INTR, "disable SDIO interrupts\n"); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); + brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1, + NULL); /* Clear any pending interrupts now that F2 is disabled */ w_sdreg32(bus, local_hostintmask, - offsetof(struct sdpcmd_regs, intstatus), &retries); + offsetof(struct sdpcmd_regs, intstatus)); /* Turn off the backplane clock (only) */ brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false); @@ -2373,12 +2343,12 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus) static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) { u32 intstatus, newstatus = 0; - uint retries = 0; uint rxlimit = bus->rxbound; /* Rx frames to read before resched */ uint txlimit = bus->txbound; /* Tx frames to send before resched */ uint framecnt = 0; /* Temporary counter of tx/rx frames */ bool rxdone = true; /* Flag for no more read data */ bool resched = false; /* Flag indicating resched wanted */ + int err; brcmf_dbg(TRACE, "Enter\n"); @@ -2389,13 +2359,12 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* If waiting for HTAVAIL, check status */ if (bus->clkstate == CLK_PENDING) { - int err; u8 clkctl, devctl = 0; #ifdef DEBUG /* Check for inconsistent device control */ - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); + devctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_DEVICE_CTL, &err); if (err) { brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; @@ -2403,8 +2372,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) #endif /* DEBUG */ /* Read CSR, if clock on switch to AVAIL, else ignore */ - clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); + clkctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, &err); if (err) { brcmf_dbg(ERROR, "error reading CSR: %d\n", err); @@ -2415,17 +2384,16 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) devctl, clkctl); if (SBSDIO_HTAV(clkctl)) { - devctl = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, &err); + devctl = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_DEVICE_CTL, &err); if (err) { brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; } devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_DEVICE_CTL, devctl, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL, + devctl, &err); if (err) { brcmf_dbg(ERROR, "error writing DEVCTL: %d\n", err); @@ -2447,17 +2415,17 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) /* Pending interrupt indicates new device status */ if (bus->ipend) { bus->ipend = false; - r_sdreg32(bus, &newstatus, - offsetof(struct sdpcmd_regs, intstatus), &retries); + err = r_sdreg32(bus, &newstatus, + offsetof(struct sdpcmd_regs, intstatus)); bus->f1regdata++; - if (brcmf_sdcard_regfail(bus->sdiodev)) + if (err != 0) newstatus = 0; newstatus &= bus->hostintmask; bus->fcstate = !!(newstatus & I_HMB_FC_STATE); if (newstatus) { - w_sdreg32(bus, newstatus, - offsetof(struct sdpcmd_regs, intstatus), - &retries); + err = w_sdreg32(bus, newstatus, + offsetof(struct sdpcmd_regs, + intstatus)); bus->f1regdata++; } } @@ -2472,11 +2440,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus) */ if (intstatus & I_HMB_FC_CHANGE) { intstatus &= ~I_HMB_FC_CHANGE; - w_sdreg32(bus, I_HMB_FC_CHANGE, - offsetof(struct sdpcmd_regs, intstatus), &retries); + err = w_sdreg32(bus, I_HMB_FC_CHANGE, + offsetof(struct sdpcmd_regs, intstatus)); - r_sdreg32(bus, &newstatus, - offsetof(struct sdpcmd_regs, intstatus), &retries); + err = r_sdreg32(bus, &newstatus, + offsetof(struct sdpcmd_regs, intstatus)); bus->f1regdata += 2; bus->fcstate = !!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE)); @@ -2546,21 +2514,18 @@ clkwait: brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM, - NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, &err); bus->f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); + hi = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCHI, + &err); + lo = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCLO, + &err); bus->f1regdata += 2; if ((hi == 0) && (lo == 0)) break; @@ -2587,10 +2552,8 @@ clkwait: else await next interrupt */ /* On failed register access, all bets are off: no resched or interrupts */ - if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || - brcmf_sdcard_regfail(bus->sdiodev)) { - brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n", - brcmf_sdcard_regfail(bus->sdiodev)); + if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) { + brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n"); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; bus->intstatus = 0; } else if (bus->clkstate == CLK_PENDING) { @@ -2886,19 +2849,16 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len) brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_FRAMECTRL, - SFC_WF_TERM, NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL, + SFC_WF_TERM, NULL); bus->f1regdata++; for (i = 0; i < 3; i++) { u8 hi, lo; - hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCHI, - NULL); - lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_WFRAMEBCLO, - NULL); + hi = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCHI, NULL); + lo = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_WFRAMEBCLO, NULL); bus->f1regdata += 2; if (hi == 0 && lo == 0) break; @@ -3188,7 +3148,6 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus) static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) { - uint retries; int bcmerror = 0; struct chip_info *ci = bus->ci; @@ -3222,7 +3181,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter) } w_sdreg32(bus, 0xFFFFFFFF, - offsetof(struct sdpcmd_regs, intstatus), &retries); + offsetof(struct sdpcmd_regs, intstatus)); ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3); @@ -3444,7 +3403,6 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; struct brcmf_sdio *bus = sdiodev->bus; unsigned long timeout; - uint retries = 0; u8 ready, enable; int err, ret = 0; u8 saveclk; @@ -3472,13 +3430,11 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) goto exit; /* Force clocks on backplane to be sure F2 interrupt propagates */ - saveclk = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, &err); + saveclk = brcmf_sdio_regrb(bus->sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, &err); if (!err) { - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - (saveclk | SBSDIO_FORCE_HT), &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + (saveclk | SBSDIO_FORCE_HT), &err); } if (err) { brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err); @@ -3487,17 +3443,16 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) /* Enable function 2 (frame transfers) */ w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT, - offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries); + offsetof(struct sdpcmd_regs, tosbmailboxdata)); enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - enable, NULL); + brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL); timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY); ready = 0; while (enable != ready) { - ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0, - SDIO_CCCR_IORx, NULL); + ready = brcmf_sdio_regrb(bus->sdiodev, + SDIO_CCCR_IORx, NULL); if (time_after(jiffies, timeout)) break; else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50)) @@ -3512,21 +3467,18 @@ static int brcmf_sdbrcm_bus_init(struct device *dev) /* Set up the interrupt mask and enable interrupts */ bus->hostintmask = HOSTINTMASK; w_sdreg32(bus, bus->hostintmask, - offsetof(struct sdpcmd_regs, hostintmask), &retries); + offsetof(struct sdpcmd_regs, hostintmask)); - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_WATERMARK, 8, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err); } else { /* Disable F2 again */ enable = SDIO_FUNC_ENABLE_1; - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, - SDIO_CCCR_IOEx, enable, NULL); + brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL); ret = -ENODEV; } /* Restore previous clock setting */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err); if (ret == 0) { ret = brcmf_sdio_intr_register(bus->sdiodev); @@ -3606,9 +3558,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus) if (!bus->dpc_sched) { u8 devpend; - devpend = brcmf_sdcard_cfg_read(bus->sdiodev, - SDIO_FUNC_0, SDIO_CCCR_INTx, - NULL); + devpend = brcmf_sdio_regrb(bus->sdiodev, + SDIO_CCCR_INTx, + NULL); intstatus = devpend & (INTR_STATUS_FUNC1 | INTR_STATUS_FUNC2); @@ -3732,24 +3684,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) bus->alp_only = true; - /* Return the window to backplane enumeration space for core access */ - if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE)) - brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n"); - pr_debug("F1 signature read @0x18000000=0x%4x\n", - brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4)); + brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL)); /* * Force PLL off until brcmf_sdio_chip_attach() * programs PLL control regs */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, - BRCMF_INIT_CLKCTL1, &err); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, + BRCMF_INIT_CLKCTL1, &err); if (!err) - clkctl = - brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1, + clkctl = brcmf_sdio_regrb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, &err); if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) { @@ -3782,9 +3728,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva) idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV); reg_addr = bus->ci->c_inf[idx].base + offsetof(struct sdpcmd_regs, corecontrol); - reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32)); - brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32), - reg_val | CC_BPRESEN); + reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL); + brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL); brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN); @@ -3809,16 +3754,15 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus) brcmf_dbg(TRACE, "Enter\n"); /* Disable F2 to clear any intermediate frame state on the dongle */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx, - SDIO_FUNC_ENABLE_1, NULL); + brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, + SDIO_FUNC_ENABLE_1, NULL); bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN; bus->sleeping = false; bus->rxflow = false; /* Done with backplane-dependent accesses, can drop clock... */ - brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); + brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL); /* ...and initialize clock/power states */ bus->clkstate = CLK_SDONLY; diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c index 1534efc2163..f8e1f1c84d0 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c @@ -93,8 +93,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev, idx = brcmf_sdio_chip_getinfidx(ci, coreid); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbidhigh), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbidhigh), + NULL); return SBCOREREV(regdata); } @@ -118,8 +119,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev, idx = brcmf_sdio_chip_getinfidx(ci, coreid); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + NULL); regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT | SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK); return (SSB_TMSLOW_CLOCK == regdata); @@ -135,13 +137,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev, idx = brcmf_sdio_chip_getinfidx(ci, coreid); - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + NULL); ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK; - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, - 4); + regdata = brcmf_sdio_regrl(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + NULL); ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0); return ret; @@ -151,84 +153,85 @@ static void brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci, u16 coreid) { - u32 regdata; + u32 regdata, base; u8 idx; idx = brcmf_sdio_chip_getinfidx(ci, coreid); + base = ci->c_inf[idx].base; - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); if (regdata & SSB_TMSLOW_RESET) return; - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL); if ((regdata & SSB_TMSLOW_CLOCK) != 0) { /* * set target reject and spin until busy is clear * (preserve core-specific bits) */ - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), - 4, regdata | SSB_TMSLOW_REJECT); - - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), + NULL); + brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), + regdata | SSB_TMSLOW_REJECT, NULL); + + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), + NULL); udelay(1); - SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) & + SPINWAIT((brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbtmstatehigh), + NULL) & SSB_TMSHIGH_BUSY), 100000); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbtmstatehigh), + NULL); if (regdata & SSB_TMSHIGH_BUSY) brcmf_dbg(ERROR, "core state still busy\n"); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbidlow), 4); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), + NULL); if (regdata & SSB_IDLOW_INITIATOR) { - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4) | - SSB_IMSTATE_REJECT; - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4, - regdata); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbimstate), + NULL); + regdata |= SSB_IMSTATE_REJECT; + brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), + regdata, NULL); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbimstate), + NULL); udelay(1); - SPINWAIT((brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4) & + SPINWAIT((brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbimstate), + NULL) & SSB_IMSTATE_BUSY), 100000); } /* set reset and reject while enabling the clocks */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, - (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | - SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | + SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET; + brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), + regdata, NULL); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), + NULL); udelay(10); /* clear the initiator reject bit */ - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbidlow), 4); + regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow), + NULL); if (regdata & SSB_IDLOW_INITIATOR) { - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4) & - ~SSB_IMSTATE_REJECT; - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4, - regdata); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(base, sbimstate), + NULL); + regdata &= ~SSB_IMSTATE_REJECT; + brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate), + regdata, NULL); } } /* leave reset and reject asserted */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, - (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET)); + brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow), + (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL); udelay(1); } @@ -242,20 +245,19 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev, idx = brcmf_sdio_chip_getinfidx(ci, coreid); /* if core is already in reset, just return */ - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, - 4); + regdata = brcmf_sdio_regrl(sdiodev, + ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + NULL); if ((regdata & BCMA_RESET_CTL_RESET) != 0) return; - brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, - 4, 0); - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0, NULL); + regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + NULL); udelay(10); - brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, - 4, BCMA_RESET_CTL_RESET); + brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + BCMA_RESET_CTL_RESET, NULL); udelay(1); } @@ -279,41 +281,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev, * set reset while enabling the clock and * forcing them on throughout the core */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, - SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + brcmf_sdio_regwl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET, + NULL); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + NULL); udelay(1); /* clear any serror */ - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), + NULL); if (regdata & SSB_TMSHIGH_SERR) - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0); + brcmf_sdio_regwl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), + 0, NULL); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbimstate), + NULL); if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO)) - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbimstate), 4, - regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO)); + brcmf_sdio_regwl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbimstate), + regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO), + NULL); /* clear reset and allow it to propagate throughout the core */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4, - SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + NULL); udelay(1); /* leave clock enabled */ - brcmf_sdcard_reg_write(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), - 4, SSB_TMSLOW_CLOCK); - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4); + brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + SSB_TMSLOW_CLOCK, NULL); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_SB(ci->c_inf[idx].base, sbtmstatelow), + NULL); udelay(1); } @@ -330,18 +338,18 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev, brcmf_sdio_ai_coredisable(sdiodev, ci, coreid); /* now do initialization sequence */ - brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, - 4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK); - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); - brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, - 4, 0); + brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL); + regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + NULL); + brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL, + 0, NULL); udelay(1); - brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, - 4, BCMA_IOCTL_CLK); - regdata = brcmf_sdcard_reg_read(sdiodev, - ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4); + brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + BCMA_IOCTL_CLK, NULL); + regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, + NULL); udelay(1); } @@ -358,8 +366,9 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev, */ ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON; ci->c_inf[0].base = regs; - regdata = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, chipid), 4); + regdata = brcmf_sdio_regrl(sdiodev, + CORE_CC_REG(ci->c_inf[0].base, chipid), + NULL); ci->chip = regdata & CID_ID_MASK; ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT; ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT; @@ -428,8 +437,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) /* Try forcing SDIO core to do ALPAvail request only */ clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); + brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); if (err) { brcmf_dbg(ERROR, "error writing for HT off\n"); return err; @@ -437,8 +445,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) /* If register supported, wait for ALPAvail and then force ALP */ /* This may take up to 15 milliseconds */ - clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL); + clkval = brcmf_sdio_regrb(sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, NULL); if ((clkval & ~SBSDIO_AVBITS) != clkset) { brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n", @@ -446,8 +454,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) return -EACCES; } - SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, NULL)), + SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev, + SBSDIO_FUNC1_CHIPCLKCSR, NULL)), !SBSDIO_ALPAV(clkval)), PMU_MAX_TRANSITION_DLY); if (!SBSDIO_ALPAV(clkval)) { @@ -457,13 +465,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev) } clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP; - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); + brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err); udelay(65); /* Also, disable the extra SDIO pull-ups */ - brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, - SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); + brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL); return 0; } @@ -472,18 +478,22 @@ static void brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci) { + u32 base = ci->c_inf[0].base; + /* get chipcommon rev */ ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id); /* get chipcommon capabilites */ - ci->c_inf[0].caps = - brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, capabilities), 4); + ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev, + CORE_CC_REG(base, capabilities), + NULL); /* get pmu caps & rev */ if (ci->c_inf[0].caps & CC_CAP_PMU) { - ci->pmucaps = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4); + ci->pmucaps = + brcmf_sdio_regrl(sdiodev, + CORE_CC_REG(base, pmucapabilities), + NULL); ci->pmurev = ci->pmucaps & PCAP_REV_MASK; } @@ -523,10 +533,10 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev, brcmf_sdio_chip_buscoresetup(sdiodev, ci); - brcmf_sdcard_reg_write(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0); - brcmf_sdcard_reg_write(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0); + brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup), + 0, NULL); + brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), + 0, NULL); *ci_ptr = ci; return 0; @@ -562,6 +572,7 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, u32 str_mask = 0; u32 str_shift = 0; char chn[8]; + u32 base = ci->c_inf[0].base; if (!(ci->c_inf[0].caps & CC_CAP_PMU)) return; @@ -591,17 +602,17 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev, } } - brcmf_sdcard_reg_write(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), - 4, 1); - cc_data_temp = brcmf_sdcard_reg_read(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4); + brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr), + 1, NULL); + cc_data_temp = + brcmf_sdio_regrl(sdiodev, + CORE_CC_REG(base, chipcontrol_addr), + NULL); cc_data_temp &= ~str_mask; drivestrength_sel <<= str_shift; cc_data_temp |= drivestrength_sel; - brcmf_sdcard_reg_write(sdiodev, - CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), - 4, cc_data_temp); + brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr), + cc_data_temp, NULL); brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n", drivestrength, cc_data_temp); diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h index 7010eaf71f9..29bf78d264e 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h +++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h @@ -40,6 +40,10 @@ /* Maximum number of I/O funcs */ #define SDIOD_MAX_IOFUNCS 7 +/* mask of register map */ +#define REG_F0_REG_MASK 0x7FF +#define REG_F1_MISC_MASK 0x1FFFF + /* as of sdiod rev 0, supports 3 functions */ #define SBSDIO_NUM_FUNCTION 3 @@ -142,7 +146,6 @@ struct brcmf_sdio_dev { u8 num_funcs; /* Supported funcs on client */ u32 func_cis_ptr[SDIOD_MAX_IOFUNCS]; u32 sbwad; /* Save backplane window address */ - bool regfail; /* status of last reg_r/w call */ void *bus; atomic_t suspend; /* suspend flag */ wait_queue_head_t request_byte_wait; @@ -164,31 +167,13 @@ struct brcmf_sdio_dev { extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev); extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev); -/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface). - * fn: function number - * addr: unmodified SDIO-space address - * data: data byte to write - * err: pointer to error code (or NULL) - */ -extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func, - u32 addr, int *err); -extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func, - u32 addr, u8 data, int *err); - -/* Synchronous access to device (client) core registers via CMD53 to F1. - * addr: backplane address (i.e. >= regsva from attach) - * size: register width in bytes (2 or 4) - * data: data for register write - */ -extern u32 -brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size); - -extern u32 -brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size, - u32 data); - -/* Indicate if last reg read/write failed */ -extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev); +/* sdio device register access interface */ +extern u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); +extern u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret); +extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr, + u8 data, int *ret); +extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr, + u32 data, int *ret); /* Buffer transfer to/from device (client) core via cmd53. * fn: function number diff --git a/drivers/net/wireless/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/brcm80211/brcmsmac/Makefile index c2eb2d0af38..e227c4c68ef 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/brcm80211/brcmsmac/Makefile @@ -39,10 +39,7 @@ BRCMSMAC_OFILES := \ phy/phytbl_lcn.o \ phy/phytbl_n.o \ phy/phy_qmath.o \ - otp.o \ - srom.o \ dma.o \ - nicpci.o \ brcms_trace_events.o MODULEPFX := brcmsmac diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c index c93ea35bcee..6d8b7213643 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.c @@ -19,7 +19,6 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/delay.h> -#include <linux/pci.h> #include <defs.h> #include <chipcommon.h> @@ -29,8 +28,6 @@ #include "types.h" #include "pub.h" #include "pmu.h" -#include "srom.h" -#include "nicpci.h" #include "aiutils.h" /* slow_clk_ctl */ @@ -321,7 +318,6 @@ #define IS_SIM(chippkg) \ ((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID)) -#define PCI(sih) (ai_get_buscoretype(sih) == PCI_CORE_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)) @@ -454,36 +450,9 @@ struct aidmp { u32 componentid3; /* 0xffc */ }; -/* return true if PCIE capability exists in the pci config space */ -static bool ai_ispcie(struct si_info *sii) -{ - u8 cap_ptr; - - cap_ptr = - pcicore_find_pci_capability(sii->pcibus, PCI_CAP_ID_EXP, NULL, - NULL); - if (!cap_ptr) - return false; - - return true; -} - -static bool ai_buscore_prep(struct si_info *sii) -{ - /* kludge to enable the clock on the 4306 which lacks a slowclock */ - if (!ai_ispcie(sii)) - ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON); - return true; -} - static bool ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) { - struct bcma_device *pci = NULL; - struct bcma_device *pcie = NULL; - struct bcma_device *core; - - /* no cores found, bail out */ if (cc->bus->nr_cores == 0) return false; @@ -492,8 +461,7 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) sii->pub.ccrev = cc->id.rev; /* get chipcommon chipstatus */ - if (ai_get_ccrev(&sii->pub) >= 11) - sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus)); + sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus)); /* get chipcommon capabilites */ sii->pub.cccaps = bcma_read32(cc, CHIPCREGOFFS(capabilities)); @@ -506,64 +474,18 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc) } /* figure out buscore */ - list_for_each_entry(core, &cc->bus->cores, list) { - uint cid, crev; - - cid = core->id.id; - crev = core->id.rev; - - if (cid == PCI_CORE_ID) { - pci = core; - } else if (cid == PCIE_CORE_ID) { - pcie = core; - } - } - - if (pci && pcie) { - if (ai_ispcie(sii)) - pci = NULL; - else - pcie = NULL; - } - if (pci) { - sii->buscore = pci; - } else if (pcie) { - sii->buscore = pcie; - } - - /* fixup necessary chip/core configurations */ - if (!sii->pch) { - sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core); - if (sii->pch == NULL) - return false; - } - if (ai_pci_fixcfg(&sii->pub)) - return false; + sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0); return true; } -/* - * get boardtype and boardrev - */ -static __used void ai_nvram_process(struct si_info *sii) -{ - uint w = 0; - - /* do a pci config read to get subsystem id and subvendor id */ - pci_read_config_dword(sii->pcibus, PCI_SUBSYSTEM_VENDOR_ID, &w); - - sii->pub.boardvendor = w & 0xffff; - sii->pub.boardtype = (w >> 16) & 0xffff; -} - 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; - uint socitype; + struct ssb_sprom *sprom = &pbus->sprom; savewin = 0; @@ -573,38 +495,15 @@ static struct si_info *ai_doattach(struct si_info *sii, /* switch to Chipcommon core */ cc = pbus->drv_cc.core; - /* bus/core/clk setup for register access */ - if (!ai_buscore_prep(sii)) - return NULL; + sih->chip = pbus->chipinfo.id; + sih->chiprev = pbus->chipinfo.rev; + sih->chippkg = pbus->chipinfo.pkg; + sih->boardvendor = pbus->boardinfo.vendor; + sih->boardtype = pbus->boardinfo.type; - /* - * ChipID recognition. - * We assume we can read chipid at offset 0 from the regs arg. - * If we add other chiptypes (or if we need to support old sdio - * hosts w/o chipcommon), some way of recognizing them needs to - * be added here. - */ - w = bcma_read32(cc, CHIPCREGOFFS(chipid)); - socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT; - /* Might as wll fill in chip id rev & pkg */ - sih->chip = w & CID_ID_MASK; - sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT; - sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT; - - /* scan for cores */ - if (socitype != SOCI_AI) - return NULL; - - SI_MSG("Found chip type AI (0x%08x)\n", w); if (!ai_buscore_setup(sii, cc)) goto exit; - /* Init nvram from sprom/otp if they exist */ - if (srom_var_init(&sii->pub)) - goto exit; - - ai_nvram_process(sii); - /* === NVRAM, clock is ready === */ bcma_write32(cc, CHIPCREGOFFS(gpiopullup), 0); bcma_write32(cc, CHIPCREGOFFS(gpiopulldown), 0); @@ -617,15 +516,13 @@ static struct si_info *ai_doattach(struct si_info *sii, } /* setup the GPIO based LED powersave register */ - w = getintvar(sih, BRCMS_SROM_LEDDC); + 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 (PCIE(sih)) - pcicore_attach(sii->pch, SI_DOATTACH); - if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) { /* * enable 12 mA drive strenth for 43224 and @@ -659,9 +556,6 @@ static struct si_info *ai_doattach(struct si_info *sii, return sii; exit: - if (sii->pch) - pcicore_deinit(sii->pch); - sii->pch = NULL; return NULL; } @@ -700,11 +594,6 @@ void ai_detach(struct si_pub *sih) if (sii == NULL) return; - if (sii->pch) - pcicore_deinit(sii->pch); - sii->pch = NULL; - - srom_free_vars(sih); kfree(sii); } @@ -755,21 +644,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val) /* return the slow clock source - LPO, XTAL, or PCI */ static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc) { - struct si_info *sii; - u32 val; - - sii = (struct si_info *)sih; - if (ai_get_ccrev(&sii->pub) < 6) { - pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, - &val); - if (val & PCI_CFG_GPIO_SCS) - return SCC_SS_PCI; - return SCC_SS_XTAL; - } else if (ai_get_ccrev(&sii->pub) < 10) { - return bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) & - SCC_SS_MASK; - } else /* Insta-clock */ - return SCC_SS_XTAL; + return SCC_SS_XTAL; } /* @@ -779,36 +654,12 @@ static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc) static uint ai_slowclk_freq(struct si_pub *sih, bool max_freq, struct bcma_device *cc) { - u32 slowclk; uint div; - slowclk = ai_slowclk_src(sih, cc); - if (ai_get_ccrev(sih) < 6) { - if (slowclk == SCC_SS_PCI) - return max_freq ? (PCIMAXFREQ / 64) - : (PCIMINFREQ / 64); - else - return max_freq ? (XTALMAXFREQ / 32) - : (XTALMINFREQ / 32); - } else if (ai_get_ccrev(sih) < 10) { - div = 4 * - (((bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) & - SCC_CD_MASK) >> SCC_CD_SHIFT) + 1); - if (slowclk == SCC_SS_LPO) - return max_freq ? LPOMAXFREQ : LPOMINFREQ; - else if (slowclk == SCC_SS_XTAL) - return max_freq ? (XTALMAXFREQ / div) - : (XTALMINFREQ / div); - else if (slowclk == SCC_SS_PCI) - return max_freq ? (PCIMAXFREQ / div) - : (PCIMINFREQ / div); - } else { - /* Chipc rev 10 is InstaClock */ - div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl)); - div = 4 * ((div >> SYCC_CD_SHIFT) + 1); - return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); - } - return 0; + /* Chipc rev 10 is InstaClock */ + div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl)); + div = 4 * ((div >> SYCC_CD_SHIFT) + 1); + return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div); } static void @@ -831,8 +682,7 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc) /* Starting with 4318 it is ILP that is used for the delays */ slowmaxfreq = - ai_slowclk_freq(sih, - (ai_get_ccrev(sih) >= 10) ? false : true, cc); + ai_slowclk_freq(sih, false, cc); pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000; fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000; @@ -854,9 +704,8 @@ void ai_clkctl_init(struct si_pub *sih) return; /* set all Instaclk chip ILP to 1 MHz */ - if (ai_get_ccrev(sih) >= 10) - bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK, - (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); + bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK, + (ILP_DIV_1MHZ << SYCC_CD_SHIFT)); ai_clkctl_setdelay(sih, cc); } @@ -891,140 +740,6 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih) return fpdelay; } -/* turn primary xtal and/or pll off/on */ -int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on) -{ - struct si_info *sii; - u32 in, out, outen; - - sii = (struct si_info *)sih; - - /* pcie core doesn't have any mapping to control the xtal pu */ - if (PCIE(sih)) - return -1; - - pci_read_config_dword(sii->pcibus, PCI_GPIO_IN, &in); - pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &out); - pci_read_config_dword(sii->pcibus, PCI_GPIO_OUTEN, &outen); - - /* - * Avoid glitching the clock if GPRS is already using it. - * We can't actually read the state of the PLLPD so we infer it - * by the value of XTAL_PU which *is* readable via gpioin. - */ - if (on && (in & PCI_CFG_GPIO_XTAL)) - return 0; - - if (what & XTAL) - outen |= PCI_CFG_GPIO_XTAL; - if (what & PLL) - outen |= PCI_CFG_GPIO_PLL; - - if (on) { - /* turn primary xtal on */ - if (what & XTAL) { - out |= PCI_CFG_GPIO_XTAL; - if (what & PLL) - out |= PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pcibus, - PCI_GPIO_OUT, out); - pci_write_config_dword(sii->pcibus, - PCI_GPIO_OUTEN, outen); - udelay(XTAL_ON_DELAY); - } - - /* turn pll on */ - if (what & PLL) { - out &= ~PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pcibus, - PCI_GPIO_OUT, out); - mdelay(2); - } - } else { - if (what & XTAL) - out &= ~PCI_CFG_GPIO_XTAL; - if (what & PLL) - out |= PCI_CFG_GPIO_PLL; - pci_write_config_dword(sii->pcibus, - PCI_GPIO_OUT, out); - pci_write_config_dword(sii->pcibus, - PCI_GPIO_OUTEN, outen); - } - - return 0; -} - -/* clk control mechanism through chipcommon, no policy checking */ -static bool _ai_clkctl_cc(struct si_info *sii, uint mode) -{ - struct bcma_device *cc; - u32 scc; - - /* chipcommon cores prior to rev6 don't support dynamic clock control */ - if (ai_get_ccrev(&sii->pub) < 6) - return false; - - cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); - - if (!(ai_get_cccaps(&sii->pub) & CC_CAP_PWR_CTL) && - (ai_get_ccrev(&sii->pub) < 20)) - return mode == CLK_FAST; - - switch (mode) { - case CLK_FAST: /* FORCEHT, fast (pll) clock */ - if (ai_get_ccrev(&sii->pub) < 10) { - /* - * don't forget to force xtal back - * on before we clear SCC_DYN_XTAL.. - */ - ai_clkctl_xtal(&sii->pub, XTAL, ON); - bcma_maskset32(cc, CHIPCREGOFFS(slow_clk_ctl), - (SCC_XC | SCC_FS | SCC_IP), SCC_IP); - } else if (ai_get_ccrev(&sii->pub) < 20) { - bcma_set32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_HR); - } else { - bcma_set32(cc, CHIPCREGOFFS(clk_ctl_st), CCS_FORCEHT); - } - - /* wait for the PLL */ - if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) { - u32 htavail = CCS_HTAVAIL; - SPINWAIT(((bcma_read32(cc, CHIPCREGOFFS(clk_ctl_st)) & - htavail) == 0), PMU_MAX_TRANSITION_DLY); - } else { - udelay(PLL_DELAY); - } - break; - - case CLK_DYNAMIC: /* enable dynamic clock control */ - if (ai_get_ccrev(&sii->pub) < 10) { - scc = bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)); - scc &= ~(SCC_FS | SCC_IP | SCC_XC); - if ((scc & SCC_SS_MASK) != SCC_SS_XTAL) - scc |= SCC_XC; - bcma_write32(cc, CHIPCREGOFFS(slow_clk_ctl), scc); - - /* - * for dynamic control, we have to - * release our xtal_pu "force on" - */ - if (scc & SCC_XC) - ai_clkctl_xtal(&sii->pub, XTAL, OFF); - } else if (ai_get_ccrev(&sii->pub) < 20) { - /* Instaclock */ - bcma_mask32(cc, CHIPCREGOFFS(system_clk_ctl), ~SYCC_HR); - } else { - bcma_mask32(cc, CHIPCREGOFFS(clk_ctl_st), ~CCS_FORCEHT); - } - break; - - default: - break; - } - - return mode == CLK_FAST; -} - /* * clock control policy function throught chipcommon * @@ -1033,133 +748,53 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode) * this is a wrapper over the next internal function * to allow flexible policy settings for outside caller */ -bool ai_clkctl_cc(struct si_pub *sih, uint mode) +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; - /* chipcommon cores prior to rev6 don't support dynamic clock control */ - if (ai_get_ccrev(sih) < 6) - return false; - if (PCI_FORCEHT(sih)) - return mode == CLK_FAST; + return mode == BCMA_CLKMODE_FAST; - return _ai_clkctl_cc(sii, mode); + cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); + bcma_core_set_clockmode(cc, mode); + return mode == BCMA_CLKMODE_FAST; } void ai_pci_up(struct si_pub *sih) { struct si_info *sii; + struct bcma_device *cc; sii = (struct si_info *)sih; - if (PCI_FORCEHT(sih)) - _ai_clkctl_cc(sii, CLK_FAST); + if (PCI_FORCEHT(sih)) { + cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); + bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST); + } if (PCIE(sih)) - pcicore_up(sii->pch, SI_PCIUP); - -} - -/* Unconfigure and/or apply various WARs when system is going to sleep mode */ -void ai_pci_sleep(struct si_pub *sih) -{ - struct si_info *sii; - - sii = (struct si_info *)sih; - - pcicore_sleep(sii->pch); + bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true); } /* Unconfigure and/or apply various WARs when going down */ void ai_pci_down(struct si_pub *sih) { struct si_info *sii; + struct bcma_device *cc; sii = (struct si_info *)sih; /* release FORCEHT since chip is going to "down" state */ - if (PCI_FORCEHT(sih)) - _ai_clkctl_cc(sii, CLK_DYNAMIC); - - pcicore_down(sii->pch, SI_PCIDOWN); -} - -/* - * Configure the pci core for pci client (NIC) action - * coremask is the bitvec of cores by index to be enabled. - */ -void ai_pci_setup(struct si_pub *sih, uint coremask) -{ - struct si_info *sii; - u32 w; - - sii = (struct si_info *)sih; - - /* - * Enable sb->pci interrupts. Assume - * PCI rev 2.3 support was added in pci core rev 6 and things changed.. - */ - if (PCIE(sih) || (PCI(sih) && (ai_get_buscorerev(sih) >= 6))) { - /* pci config write to set this core bit in PCIIntMask */ - pci_read_config_dword(sii->pcibus, PCI_INT_MASK, &w); - w |= (coremask << PCI_SBIM_SHIFT); - pci_write_config_dword(sii->pcibus, PCI_INT_MASK, w); - } - - if (PCI(sih)) { - pcicore_pci_setup(sii->pch); + if (PCI_FORCEHT(sih)) { + cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0); + bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC); } -} -/* - * Fixup SROMless PCI device's configuration. - * The current core may be changed upon return. - */ -int ai_pci_fixcfg(struct si_pub *sih) -{ - struct si_info *sii = (struct si_info *)sih; - - /* Fixup PI in SROM shadow area to enable the correct PCI core access */ - /* check 'pi' is correct and fix it if not */ - pcicore_fixcfg(sii->pch); - pcicore_hwup(sii->pch); - return 0; -} - -/* mask&set gpiocontrol bits */ -u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority) -{ - uint regoff; - - regoff = offsetof(struct chipcregs, gpiocontrol); - return ai_cc_reg(sih, regoff, mask, val); -} - -void ai_chipcontrl_epa4331(struct si_pub *sih, bool on) -{ - struct bcma_device *cc; - u32 val; - - cc = ai_findcore(sih, CC_CORE_ID, 0); - - if (on) { - if (ai_get_chippkg(sih) == 9 || ai_get_chippkg(sih) == 0xb) - /* Ext PA Controls for 4331 12x9 Package */ - bcma_set32(cc, CHIPCREGOFFS(chipcontrol), - CCTRL4331_EXTPA_EN | - CCTRL4331_EXTPA_ON_GPIO2_5); - else - /* Ext PA Controls for 4331 12x12 Package */ - bcma_set32(cc, CHIPCREGOFFS(chipcontrol), - CCTRL4331_EXTPA_EN); - } else { - val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5); - bcma_mask32(cc, CHIPCREGOFFS(chipcontrol), - ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5)); - } + if (PCIE(sih)) + bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false); } /* Enable BT-COEX & Ex-PA for 4313 */ @@ -1181,6 +816,9 @@ bool ai_deviceremoved(struct si_pub *sih) sii = (struct si_info *)sih; + if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI) + return false; + pci_read_config_dword(sii->pcibus, PCI_VENDOR_ID, &w); if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM) return true; @@ -1188,45 +826,6 @@ bool ai_deviceremoved(struct si_pub *sih) return false; } -bool ai_is_sprom_available(struct si_pub *sih) -{ - struct si_info *sii = (struct si_info *)sih; - - if (ai_get_ccrev(sih) >= 31) { - struct bcma_device *cc; - u32 sromctrl; - - if ((ai_get_cccaps(sih) & CC_CAP_SROM) == 0) - return false; - - cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - sromctrl = bcma_read32(cc, CHIPCREGOFFS(sromcontrol)); - return sromctrl & SRC_PRESENT; - } - - switch (ai_get_chip_id(sih)) { - case BCM4313_CHIP_ID: - return (sii->chipst & CST4313_SPROM_PRESENT) != 0; - default: - return true; - } -} - -bool ai_is_otp_disabled(struct si_pub *sih) -{ - struct si_info *sii = (struct si_info *)sih; - - switch (ai_get_chip_id(sih)) { - case BCM4313_CHIP_ID: - return (sii->chipst & CST4313_OTP_PRESENT) == 0; - /* These chips always have their OTP on */ - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - default: - return false; - } -} - uint ai_get_buscoretype(struct si_pub *sih) { struct si_info *sii = (struct si_info *)sih; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h index f84c6f78169..d9f04a683bd 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/aiutils.h @@ -113,10 +113,6 @@ #define XTAL 0x1 /* primary crystal oscillator (2050) */ #define PLL 0x2 /* main chip pll */ -/* clkctl clk mode */ -#define CLK_FAST 0 /* force fast (pll) clock */ -#define CLK_DYNAMIC 2 /* enable dynamic clock control */ - /* GPIO usage priorities */ #define GPIO_DRV_PRIORITY 0 /* Driver */ #define GPIO_APP_PRIORITY 1 /* Application */ @@ -172,9 +168,7 @@ 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 pcicore_info *pch; /* PCI/E core handle */ struct bcma_device *buscore; - struct list_head var_list; /* list of srom variables */ u32 chipst; /* chip status */ }; @@ -197,38 +191,20 @@ extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val); extern struct si_pub *ai_attach(struct bcma_bus *pbus); extern void ai_detach(struct si_pub *sih); extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val); -extern void ai_pci_setup(struct si_pub *sih, uint coremask); extern void ai_clkctl_init(struct si_pub *sih); extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih); extern bool ai_clkctl_cc(struct si_pub *sih, uint mode); -extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on); extern bool ai_deviceremoved(struct si_pub *sih); -extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, - u8 priority); - -/* OTP status */ -extern bool ai_is_otp_disabled(struct si_pub *sih); - -/* SPROM availability */ -extern bool ai_is_sprom_available(struct si_pub *sih); -extern void ai_pci_sleep(struct si_pub *sih); extern void ai_pci_down(struct si_pub *sih); extern void ai_pci_up(struct si_pub *sih); -extern int ai_pci_fixcfg(struct si_pub *sih); -extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on); /* 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 int ai_get_ccrev(struct si_pub *sih) -{ - return sih->ccrev; -} - static inline u32 ai_get_cccaps(struct si_pub *sih) { return sih->cccaps; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c index a47ce25cb9a..55e12c32791 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/antsel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/antsel.c @@ -108,7 +108,7 @@ brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel, struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) { struct antsel_info *asi; - struct si_pub *sih = wlc->hw->sih; + struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC); if (!asi) @@ -118,7 +118,7 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) asi->pub = wlc->pub; asi->antsel_type = ANTSEL_NA; asi->antsel_avail = false; - asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH); + asi->antsel_antswitch = sprom->antswitch; if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) { switch (asi->antsel_antswitch) { @@ -128,12 +128,12 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) /* 4321/2 board with 2x3 switch logic */ asi->antsel_type = ANTSEL_2x3; /* Antenna selection availability */ - if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) || - ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) { + if ((sprom->ant_available_bg == 7) || + (sprom->ant_available_a == 7)) { asi->antsel_avail = true; } else if ( - (u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 || - (u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) { + sprom->ant_available_bg == 3 || + sprom->ant_available_a == 3) { asi->antsel_avail = false; } else { asi->antsel_avail = false; @@ -146,8 +146,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc) break; } } else if ((asi->pub->sromrev == 4) && - ((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) && - ((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) { + (sprom->ant_available_bg == 7) && + (sprom->ant_available_a == 0)) { /* hack to match old 4321CB2 cards with 2of3 antenna switch */ asi->antsel_type = ANTSEL_2x3; asi->antsel_avail = true; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/brcm80211/brcmsmac/channel.c index 0efe88e25a9..eb77ac3cfb6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/channel.c @@ -1110,7 +1110,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) char country_abbrev[BRCM_CNTRY_BUF_SZ]; const struct country_info *country; struct brcms_pub *pub = wlc->pub; - char *ccode; + struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit); @@ -1122,9 +1122,8 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc) wlc->cmi = wlc_cm; /* store the country code for passing up as a regulatory hint */ - ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE); - if (ccode && brcms_c_country_valid(ccode)) - strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1); + if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2)) + strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2)); /* * internal country information which must match diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index aa15558f75c..50f92a0b7c4 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -25,7 +25,6 @@ #include <linux/bcma/bcma.h> #include <net/mac80211.h> #include <defs.h> -#include "nicpci.h" #include "phy/phy_int.h" #include "d11.h" #include "channel.h" @@ -770,7 +769,7 @@ void brcms_dpc(unsigned long data) * Precondition: Since this function is called in brcms_pci_probe() context, * no locking is required. */ -static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev) +static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev) { int status; struct device *device = &pdev->dev; @@ -1022,7 +1021,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) spin_lock_init(&wl->isr_lock); /* prepare ucode */ - if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) { + if (brcms_request_fw(wl, pdev) < 0) { wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in " "%s\n", KBUILD_MODNAME, "/lib/firmware/brcm"); brcms_release_fw(wl); @@ -1043,12 +1042,12 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev) wl->pub->ieee_hw = hw; /* register our interrupt handler */ - if (request_irq(pdev->bus->host_pci->irq, brcms_isr, + if (request_irq(pdev->irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) { wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit); goto fail; } - wl->irq = pdev->bus->host_pci->irq; + wl->irq = pdev->irq; /* register module */ brcms_c_module_register(wl->pub, "linux", wl, NULL); @@ -1098,7 +1097,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev) dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n", pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class, - pdev->bus->host_pci->irq); + pdev->irq); if ((pdev->id.manuf != BCMA_MANUF_BCM) || (pdev->id.id != BCMA_CORE_80211)) diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index b4d92792c50..19db4052c44 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -1219,7 +1219,7 @@ static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw) } /* control chip clock to save power, enable dynamic clock or force fast clock */ -static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) +static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode) { if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) { /* new chips with PMU, CCS_FORCEHT will distribute the HT clock @@ -1229,7 +1229,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) */ if (wlc_hw->clk) { - if (mode == CLK_FAST) { + if (mode == BCMA_CLKMODE_FAST) { bcma_set32(wlc_hw->d11core, D11REGOFFS(clk_ctl_st), CCS_FORCEHT); @@ -1260,7 +1260,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode) ~CCS_FORCEHT); } } - wlc_hw->forcefastclk = (mode == CLK_FAST); + wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST); } else { /* old chips w/o PMU, force HT through cc, @@ -1567,7 +1567,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); wlc_phy_bw_state_set(wlc_hw->band->pi, bw); @@ -1576,7 +1576,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw) /* restore the clk */ if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC); } static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw) @@ -1882,27 +1882,20 @@ static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw) return true; } -static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw) +static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN]) { - enum brcms_srom_id var_id = BRCMS_SROM_MACADDR; - char *macaddr; + struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom; /* If macaddr exists, use it (Sromrev4, CIS, ...). */ - macaddr = getvar(wlc_hw->sih, var_id); - if (macaddr != NULL) - return macaddr; + if (!is_zero_ether_addr(sprom->il0mac)) { + memcpy(etheraddr, sprom->il0mac, 6); + return; + } if (wlc_hw->_nbands > 1) - var_id = BRCMS_SROM_ET1MACADDR; + memcpy(etheraddr, sprom->et1mac, 6); else - var_id = BRCMS_SROM_IL0MACADDR; - - macaddr = getvar(wlc_hw->sih, var_id); - if (macaddr == NULL) - wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr " - "getvar(%d) not found\n", wlc_hw->unit, var_id); - - return macaddr; + memcpy(etheraddr, sprom->il0mac, 6); } /* power both the pll and external oscillator on/off */ @@ -1917,9 +1910,6 @@ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want) if (!want && wlc_hw->pllreq) return; - if (wlc_hw->sih) - ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want); - wlc_hw->sbclk = want; if (!wlc_hw->sbclk) { wlc_hw->clk = false; @@ -2004,7 +1994,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); /* reset the dma engines except first time thru */ if (bcma_core_is_enabled(wlc_hw->d11core)) { @@ -2053,7 +2043,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) brcms_c_mctrl_reset(wlc_hw); if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); brcms_b_phy_reset(wlc_hw); @@ -2065,7 +2055,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags) /* restore the clk setting */ if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC); } /* txfifo sizes needs to be modified(increased) since the newer cores @@ -2218,7 +2208,7 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc) gm |= gc |= BOARD_GPIO_PACTRL; /* apply to gpiocontrol register */ - ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY); + bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc); } static void brcms_ucode_write(struct brcms_hardware *wlc_hw, @@ -3371,7 +3361,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) { /* request FAST clock if not on */ fastclk = wlc_hw->forcefastclk; if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); /* disable interrupts */ macintmask = brcms_intrsoff(wlc->wl); @@ -3405,7 +3395,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) { /* restore the clk */ if (!fastclk) - brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC); } static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc, @@ -4436,17 +4426,22 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, uint unit, bool piomode) { struct brcms_hardware *wlc_hw; - char *macaddr = NULL; uint err = 0; uint j; bool wme = false; struct shared_phy_params sha_params; struct wiphy *wiphy = wlc->wiphy; struct pci_dev *pcidev = core->bus->host_pci; + struct ssb_sprom *sprom = &core->bus->sprom; - BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, - pcidev->vendor, - pcidev->device); + if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) + BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, + pcidev->vendor, + pcidev->device); + else + BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit, + core->bus->boardinfo.vendor, + core->bus->boardinfo.type); wme = true; @@ -4472,7 +4467,8 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, } /* verify again the device is supported */ - if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) { + 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); @@ -4480,8 +4476,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, goto fail; } - wlc_hw->vendorid = pcidev->vendor; - wlc_hw->deviceid = pcidev->device; + if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) { + wlc_hw->vendorid = pcidev->vendor; + wlc_hw->deviceid = pcidev->device; + } else { + wlc_hw->vendorid = core->bus->boardinfo.vendor; + wlc_hw->deviceid = core->bus->boardinfo.type; + } wlc_hw->d11core = core; wlc_hw->corerev = core->id.rev; @@ -4501,7 +4502,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, * is still false; But it will be called again inside wlc_corereset, * after d11 is out of reset. */ - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS); if (!brcms_b_validate_chip_access(wlc_hw)) { @@ -4512,7 +4513,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, } /* get the board rev, used just below */ - j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV); + j = sprom->board_rev; /* promote srom boardrev of 0xFF to 1 */ if (j == BOARDREV_PROMOTABLE) j = BOARDREV_PROMOTED; @@ -4525,11 +4526,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, err = 15; goto fail; } - wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV); - wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih, - BRCMS_SROM_BOARDFLAGS); - wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih, - BRCMS_SROM_BOARDFLAGS2); + wlc_hw->sromrev = sprom->revision; + wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16); + wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16); if (wlc_hw->boardflags & BFL_NOPLLDOWN) brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED); @@ -4702,25 +4701,18 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core, */ /* init etheraddr state variables */ - macaddr = brcms_c_get_macaddr(wlc_hw); - if (macaddr == NULL) { - wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n", - unit); - err = 21; - goto fail; - } - if (!mac_pton(macaddr, wlc_hw->etheraddr) || - is_broadcast_ether_addr(wlc_hw->etheraddr) || + brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr); + + if (is_broadcast_ether_addr(wlc_hw->etheraddr) || is_zero_ether_addr(wlc_hw->etheraddr)) { - wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n", - unit, macaddr); + wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n", + unit); err = 22; goto fail; } - BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n", - wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih), - macaddr); + BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n", + wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih)); return err; @@ -4770,16 +4762,16 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) int aa; uint unit; int bandtype; - struct si_pub *sih = wlc->hw->sih; + struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; unit = wlc->pub->unit; bandtype = wlc->band->bandtype; /* get antennas available */ if (bandtype == BRCM_BAND_5G) - aa = (s8) getintvar(sih, BRCMS_SROM_AA5G); + aa = sprom->ant_available_a; else - aa = (s8) getintvar(sih, BRCMS_SROM_AA2G); + aa = sprom->ant_available_bg; if ((aa < 1) || (aa > 15)) { wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in" @@ -4799,9 +4791,9 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc) /* Compute Antenna Gain */ if (bandtype == BRCM_BAND_5G) - wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1); + wlc->band->antgain = sprom->antenna_gain.a1; else - wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0); + wlc->band->antgain = sprom->antenna_gain.a0; brcms_c_attach_antgain_init(wlc); @@ -4952,15 +4944,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc) callbacks = 0; - if (wlc_hw->sih) { - /* - * detach interrupt sync mechanism since interrupt is disabled - * and per-port interrupt object may has been freed. this must - * be done before sb core switch - */ - ai_pci_sleep(wlc_hw->sih); - } - brcms_b_detach_dmapio(wlc_hw); band = wlc_hw->band; @@ -5047,9 +5030,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) */ brcms_b_xtal(wlc_hw, ON); ai_clkctl_init(wlc_hw->sih); - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); - - ai_pci_fixcfg(wlc_hw->sih); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); /* * TODO: test suspend/resume @@ -5078,8 +5059,6 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw) static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) { - uint coremask; - BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit); /* @@ -5088,15 +5067,14 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw) */ brcms_b_xtal(wlc_hw, ON); ai_clkctl_init(wlc_hw->sih); - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); /* * Configure pci/pcmcia here instead of in brcms_c_attach() * to allow mfg hotswap: down, hotswap (chip power cycle), up. */ - coremask = (1 << wlc_hw->wlc->core->coreidx); - - ai_pci_setup(wlc_hw->sih, coremask); + bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core, + true); /* * Need to read the hwradio status here to cover the case where the @@ -5126,7 +5104,7 @@ static int brcms_b_up_finish(struct brcms_hardware *wlc_hw) wlc_phy_hw_state_upd(wlc_hw->band->pi, true); /* FULLY enable dynamic power control and d11 core interrupt */ - brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC); brcms_intrson(wlc_hw->wlc->wl); return 0; } @@ -5267,7 +5245,7 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw) brcms_intrsoff(wlc_hw->wlc->wl); /* ensure we're running on the pll clock again */ - brcms_b_clkctl_clk(wlc_hw, CLK_FAST); + brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST); } /* down phy at the last of this stage */ callbacks += wlc_phy_down(wlc_hw->band->pi); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c deleted file mode 100644 index 7fad6dc1925..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.c +++ /dev/null @@ -1,826 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/slab.h> -#include <linux/delay.h> -#include <linux/pci.h> - -#include <defs.h> -#include <soc.h> -#include <chipcommon.h> -#include "aiutils.h" -#include "pub.h" -#include "nicpci.h" - -/* SPROM offsets */ -#define SRSH_ASPM_OFFSET 4 /* word 4 */ -#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */ -#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */ -#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */ - -#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */ -#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ -#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ -#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ -#define SRSH_BD_OFFSET 6 /* word 6 */ - -/* chipcontrol */ -#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */ - -/* MDIO control */ -#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */ -#define MDIOCTL_DIVISOR_VAL 0x2 -#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */ -#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */ - -/* MDIO Data */ -#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */ -#define MDIODATA_TA 0x00020000 /* Turnaround */ - -#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */ -#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */ -#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */ -#define MDIODATA_DEVADDR_MASK 0x0f800000 - /* Physmedia devaddr Mask */ - -/* MDIO Data for older revisions < 10 */ -#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */ -#define MDIODATA_REGADDR_MASK_OLD 0x003c0000 - /* Regaddr Mask */ -#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */ -#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000 - /* Physmedia devaddr Mask */ - -/* Transactions flags */ -#define MDIODATA_WRITE 0x10000000 -#define MDIODATA_READ 0x20000000 -#define MDIODATA_START 0x40000000 - -#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */ -#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */ - -/* serdes regs (rev < 10) */ -#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */ -#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */ -#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */ - -/* SERDES RX registers */ -#define SERDES_RX_CTRL 1 /* Rx cntrl */ -#define SERDES_RX_TIMER1 2 /* Rx Timer1 */ -#define SERDES_RX_CDR 6 /* CDR */ -#define SERDES_RX_CDRBW 7 /* CDR BW */ -/* SERDES RX control register */ -#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */ -#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */ - -/* SERDES PLL registers */ -#define SERDES_PLL_CTRL 1 /* PLL control reg */ -#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */ - -/* Linkcontrol reg offset in PCIE Cap */ -#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */ -#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */ -#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */ -#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */ - -#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */ -#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */ -#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */ -#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */ - -/* Power management threshold */ -#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */ -#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */ -#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */ -#define PCIE_ASPMTIMER_EXTEND 0x01000000 - /* > rev7: - * enable extend ASPM timer - */ - -/* different register spaces to access thru pcie indirect access */ -#define PCIE_CONFIGREGS 1 /* Access to config space */ -#define PCIE_PCIEREGS 2 /* Access to pcie registers */ - -/* PCIE protocol PHY diagnostic registers */ -#define PCIE_PLP_STATUSREG 0x204 /* Status */ - -/* Status reg PCIE_PLP_STATUSREG */ -#define PCIE_PLP_POLARITYINV_STAT 0x10 - -/* PCIE protocol DLLP diagnostic registers */ -#define PCIE_DLLP_LCREG 0x100 /* Link Control */ -#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ - -/* PCIE protocol TLP diagnostic registers */ -#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ - -/* Sonics to PCI translation types */ -#define SBTOPCI_PREF 0x4 /* prefetch enable */ -#define SBTOPCI_BURST 0x8 /* burst enable */ -#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */ - -#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */ - -/* PCI core index in SROM shadow area */ -#define SRSH_PI_OFFSET 0 /* first word */ -#define SRSH_PI_MASK 0xf000 /* bit 15:12 */ -#define SRSH_PI_SHIFT 12 /* bit 15:12 */ - -#define PCIREGOFFS(field) offsetof(struct sbpciregs, field) -#define PCIEREGOFFS(field) offsetof(struct sbpcieregs, field) - -/* Sonics side: PCI core and host control registers */ -struct sbpciregs { - u32 control; /* PCI control */ - u32 PAD[3]; - u32 arbcontrol; /* PCI arbiter control */ - u32 clkrun; /* Clkrun Control (>=rev11) */ - u32 PAD[2]; - u32 intstatus; /* Interrupt status */ - u32 intmask; /* Interrupt mask */ - u32 sbtopcimailbox; /* Sonics to PCI mailbox */ - u32 PAD[9]; - u32 bcastaddr; /* Sonics broadcast address */ - u32 bcastdata; /* Sonics broadcast data */ - u32 PAD[2]; - u32 gpioin; /* ro: gpio input (>=rev2) */ - u32 gpioout; /* rw: gpio output (>=rev2) */ - u32 gpioouten; /* rw: gpio output enable (>= rev2) */ - u32 gpiocontrol; /* rw: gpio control (>= rev2) */ - u32 PAD[36]; - u32 sbtopci0; /* Sonics to PCI translation 0 */ - u32 sbtopci1; /* Sonics to PCI translation 1 */ - u32 sbtopci2; /* Sonics to PCI translation 2 */ - u32 PAD[189]; - u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */ - u16 sprom[36]; /* SPROM shadow Area */ - u32 PAD[46]; -}; - -/* SB side: PCIE core and host control registers */ -struct sbpcieregs { - u32 control; /* host mode only */ - u32 PAD[2]; - u32 biststatus; /* bist Status: 0x00C */ - u32 gpiosel; /* PCIE gpio sel: 0x010 */ - u32 gpioouten; /* PCIE gpio outen: 0x14 */ - u32 PAD[2]; - u32 intstatus; /* Interrupt status: 0x20 */ - u32 intmask; /* Interrupt mask: 0x24 */ - u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */ - u32 PAD[53]; - u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */ - u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */ - u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */ - u32 PAD[5]; - - /* pcie core supports in direct access to config space */ - u32 configaddr; /* pcie config space access: Address field: 0x120 */ - u32 configdata; /* pcie config space access: Data field: 0x124 */ - - /* mdio access to serdes */ - u32 mdiocontrol; /* controls the mdio access: 0x128 */ - u32 mdiodata; /* Data to the mdio access: 0x12c */ - - /* pcie protocol phy/dllp/tlp register indirect access mechanism */ - u32 pcieindaddr; /* indirect access to - * the internal register: 0x130 - */ - u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */ - - u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */ - u32 PAD[177]; - u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */ - u16 sprom[64]; /* SPROM shadow Area */ -}; - -struct pcicore_info { - struct bcma_device *core; - struct si_pub *sih; /* System interconnect handle */ - struct pci_dev *dev; - u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset - * in the config space - */ - bool pcie_pr42767; - u8 pcie_polarity; - u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */ - - u8 pmecap_offset; /* PM Capability offset in the config space */ - bool pmecap; /* Capable of generating PME */ -}; - -#define PCIE_ASPM(sih) \ - ((ai_get_buscoretype(sih) == PCIE_CORE_ID) && \ - ((ai_get_buscorerev(sih) >= 3) && \ - (ai_get_buscorerev(sih) <= 5))) - - -/* delay needed between the mdio control/ mdiodata register data access */ -static void pr28829_delay(void) -{ - udelay(10); -} - -/* Initialize the PCI core. - * It's caller's responsibility to make sure that this is done only once - */ -struct pcicore_info *pcicore_init(struct si_pub *sih, struct bcma_device *core) -{ - struct pcicore_info *pi; - - /* alloc struct pcicore_info */ - pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC); - if (pi == NULL) - return NULL; - - pi->sih = sih; - pi->dev = core->bus->host_pci; - pi->core = core; - - if (core->id.id == PCIE_CORE_ID) { - u8 cap_ptr; - cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP, - NULL, NULL); - pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET; - } - return pi; -} - -void pcicore_deinit(struct pcicore_info *pch) -{ - kfree(pch); -} - -/* return cap_offset if requested capability exists in the PCI config space */ -/* Note that it's caller's responsibility to make sure it's a pci bus */ -u8 -pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, - unsigned char *buf, u32 *buflen) -{ - u8 cap_id; - u8 cap_ptr = 0; - u32 bufsize; - u8 byte_val; - - /* check for Header type 0 */ - pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val); - if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL) - goto end; - - /* check if the capability pointer field exists */ - pci_read_config_byte(dev, PCI_STATUS, &byte_val); - if (!(byte_val & PCI_STATUS_CAP_LIST)) - goto end; - - pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr); - /* check if the capability pointer is 0x00 */ - if (cap_ptr == 0x00) - goto end; - - /* loop thru the capability list - * and see if the pcie capability exists - */ - - pci_read_config_byte(dev, cap_ptr, &cap_id); - - while (cap_id != req_cap_id) { - pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr); - if (cap_ptr == 0x00) - break; - pci_read_config_byte(dev, cap_ptr, &cap_id); - } - if (cap_id != req_cap_id) - goto end; - - /* found the caller requested capability */ - if (buf != NULL && buflen != NULL) { - u8 cap_data; - - bufsize = *buflen; - if (!bufsize) - goto end; - *buflen = 0; - /* copy the capability data excluding cap ID and next ptr */ - cap_data = cap_ptr + 2; - if ((bufsize + cap_data) > PCI_SZPCR) - bufsize = PCI_SZPCR - cap_data; - *buflen = bufsize; - while (bufsize--) { - pci_read_config_byte(dev, cap_data, buf); - cap_data++; - buf++; - } - } -end: - return cap_ptr; -} - -/* ***** Register Access API */ -static uint -pcie_readreg(struct bcma_device *core, uint addrtype, uint offset) -{ - uint retval = 0xFFFFFFFF; - - switch (addrtype) { - case PCIE_CONFIGREGS: - bcma_write32(core, PCIEREGOFFS(configaddr), offset); - (void)bcma_read32(core, PCIEREGOFFS(configaddr)); - retval = bcma_read32(core, PCIEREGOFFS(configdata)); - break; - case PCIE_PCIEREGS: - bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset); - (void)bcma_read32(core, PCIEREGOFFS(pcieindaddr)); - retval = bcma_read32(core, PCIEREGOFFS(pcieinddata)); - break; - } - - return retval; -} - -static uint pcie_writereg(struct bcma_device *core, uint addrtype, - uint offset, uint val) -{ - switch (addrtype) { - case PCIE_CONFIGREGS: - bcma_write32(core, PCIEREGOFFS(configaddr), offset); - bcma_write32(core, PCIEREGOFFS(configdata), val); - break; - case PCIE_PCIEREGS: - bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset); - bcma_write32(core, PCIEREGOFFS(pcieinddata), val); - break; - default: - break; - } - return 0; -} - -static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk) -{ - uint mdiodata, i = 0; - uint pcie_serdes_spinwait = 200; - - mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | - (MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | - (MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) | - (blk << 4)); - bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); - - pr28829_delay(); - /* retry till the transaction is complete */ - while (i < pcie_serdes_spinwait) { - if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & - MDIOCTL_ACCESS_DONE) - break; - - udelay(1000); - i++; - } - - if (i >= pcie_serdes_spinwait) - return false; - - return true; -} - -static int -pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write, - uint *val) -{ - uint mdiodata; - uint i = 0; - uint pcie_serdes_spinwait = 10; - - /* enable mdio access to SERDES */ - bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), - MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL); - - if (ai_get_buscorerev(pi->sih) >= 10) { - /* new serdes is slower in rw, - * using two layers of reg address mapping - */ - if (!pcie_mdiosetblock(pi, physmedia)) - return 1; - mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) | - (regaddr << MDIODATA_REGADDR_SHF)); - pcie_serdes_spinwait *= 20; - } else { - mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) | - (regaddr << MDIODATA_REGADDR_SHF_OLD)); - } - - if (!write) - mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA); - else - mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA | - *val); - - bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata); - - pr28829_delay(); - - /* retry till the transaction is complete */ - while (i < pcie_serdes_spinwait) { - if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) & - MDIOCTL_ACCESS_DONE) { - if (!write) { - pr28829_delay(); - *val = (bcma_read32(pi->core, - PCIEREGOFFS(mdiodata)) & - MDIODATA_MASK); - } - /* Disable mdio access to SERDES */ - bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); - return 0; - } - udelay(1000); - i++; - } - - /* Timed out. Disable mdio access to SERDES. */ - bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0); - return 1; -} - -/* use the mdio interface to read from mdio slaves */ -static int -pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr, - uint *regval) -{ - return pcie_mdioop(pi, physmedia, regaddr, false, regval); -} - -/* use the mdio interface to write to mdio slaves */ -static int -pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val) -{ - return pcie_mdioop(pi, physmedia, regaddr, true, &val); -} - -/* ***** Support functions ***** */ -static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val) -{ - u32 reg_val; - u8 offset; - - offset = pi->pciecap_lcreg_offset; - if (!offset) - return 0; - - pci_read_config_dword(pi->dev, offset, ®_val); - /* set operation */ - if (mask) { - if (val) - reg_val |= PCIE_CLKREQ_ENAB; - else - reg_val &= ~PCIE_CLKREQ_ENAB; - pci_write_config_dword(pi->dev, offset, reg_val); - pci_read_config_dword(pi->dev, offset, ®_val); - } - if (reg_val & PCIE_CLKREQ_ENAB) - return 1; - else - return 0; -} - -static void pcie_extendL1timer(struct pcicore_info *pi, bool extend) -{ - u32 w; - struct si_pub *sih = pi->sih; - - if (ai_get_buscoretype(sih) != PCIE_CORE_ID || - ai_get_buscorerev(sih) < 7) - return; - - w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); - if (extend) - w |= PCIE_ASPMTIMER_EXTEND; - else - w &= ~PCIE_ASPMTIMER_EXTEND; - pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w); - w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG); -} - -/* centralized clkreq control policy */ -static void pcie_clkreq_upd(struct pcicore_info *pi, uint state) -{ - struct si_pub *sih = pi->sih; - - switch (state) { - case SI_DOATTACH: - if (PCIE_ASPM(sih)) - pcie_clkreq(pi, 1, 0); - break; - case SI_PCIDOWN: - /* turn on serdes PLL down */ - if (ai_get_buscorerev(sih) == 6) { - ai_cc_reg(sih, - offsetof(struct chipcregs, chipcontrol_addr), - ~0, 0); - ai_cc_reg(sih, - offsetof(struct chipcregs, chipcontrol_data), - ~0x40, 0); - } else if (pi->pcie_pr42767) { - pcie_clkreq(pi, 1, 1); - } - break; - case SI_PCIUP: - /* turn off serdes PLL down */ - if (ai_get_buscorerev(sih) == 6) { - ai_cc_reg(sih, - offsetof(struct chipcregs, chipcontrol_addr), - ~0, 0); - ai_cc_reg(sih, - offsetof(struct chipcregs, chipcontrol_data), - ~0x40, 0x40); - } else if (PCIE_ASPM(sih)) { /* disable clkreq */ - pcie_clkreq(pi, 1, 0); - } - break; - } -} - -/* ***** PCI core WARs ***** */ -/* Done only once at attach time */ -static void pcie_war_polarity(struct pcicore_info *pi) -{ - u32 w; - - if (pi->pcie_polarity != 0) - return; - - w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_PLP_STATUSREG); - - /* Detect the current polarity at attach and force that polarity and - * disable changing the polarity - */ - if ((w & PCIE_PLP_POLARITYINV_STAT) == 0) - pi->pcie_polarity = SERDES_RX_CTRL_FORCE; - else - pi->pcie_polarity = (SERDES_RX_CTRL_FORCE | - SERDES_RX_CTRL_POLARITY); -} - -/* enable ASPM and CLKREQ if srom doesn't have it */ -/* Needs to happen when update to shadow SROM is needed - * : Coming out of 'standby'/'hibernate' - * : If pcie_war_aspm_ovr state changed - */ -static void pcie_war_aspm_clkreq(struct pcicore_info *pi) -{ - struct si_pub *sih = pi->sih; - u16 val16; - u32 w; - - if (!PCIE_ASPM(sih)) - return; - - /* bypass this on QT or VSIM */ - val16 = bcma_read16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET])); - - val16 &= ~SRSH_ASPM_ENB; - if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB) - val16 |= SRSH_ASPM_ENB; - else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB) - val16 |= SRSH_ASPM_L1_ENB; - else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB) - val16 |= SRSH_ASPM_L0s_ENB; - - bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]), val16); - - pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); - w &= ~PCIE_ASPM_ENAB; - w |= pi->pcie_war_aspm_ovr; - pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); - - val16 = bcma_read16(pi->core, - PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5])); - - if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) { - val16 |= SRSH_CLKREQ_ENB; - pi->pcie_pr42767 = true; - } else - val16 &= ~SRSH_CLKREQ_ENB; - - bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]), - val16); -} - -/* Apply the polarity determined at the start */ -/* Needs to happen when coming out of 'standby'/'hibernate' */ -static void pcie_war_serdes(struct pcicore_info *pi) -{ - u32 w = 0; - - if (pi->pcie_polarity != 0) - pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL, - pi->pcie_polarity); - - pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w); - if (w & PLL_CTRL_FREQDET_EN) { - w &= ~PLL_CTRL_FREQDET_EN; - pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w); - } -} - -/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */ -/* Needs to happen when coming out of 'standby'/'hibernate' */ -static void pcie_misc_config_fixup(struct pcicore_info *pi) -{ - u16 val16; - - val16 = bcma_read16(pi->core, - PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG])); - - if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) { - val16 |= SRSH_L23READY_EXIT_NOPERST; - bcma_write16(pi->core, - PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]), val16); - } -} - -/* quick hack for testing */ -/* Needs to happen when coming out of 'standby'/'hibernate' */ -static void pcie_war_noplldown(struct pcicore_info *pi) -{ - /* turn off serdes PLL down */ - ai_cc_reg(pi->sih, offsetof(struct chipcregs, chipcontrol), - CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN); - - /* clear srom shadow backdoor */ - bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_BD_OFFSET]), 0); -} - -/* Needs to happen when coming out of 'standby'/'hibernate' */ -static void pcie_war_pci_setup(struct pcicore_info *pi) -{ - struct si_pub *sih = pi->sih; - u32 w; - - if (ai_get_buscorerev(sih) == 0 || ai_get_buscorerev(sih) == 1) { - w = pcie_readreg(pi->core, PCIE_PCIEREGS, - PCIE_TLP_WORKAROUNDSREG); - w |= 0x8; - pcie_writereg(pi->core, PCIE_PCIEREGS, - PCIE_TLP_WORKAROUNDSREG, w); - } - - if (ai_get_buscorerev(sih) == 1) { - w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG); - w |= 0x40; - pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w); - } - - if (ai_get_buscorerev(sih) == 0) { - pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128); - pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100); - pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466); - } else if (PCIE_ASPM(sih)) { - /* Change the L1 threshold for better performance */ - w = pcie_readreg(pi->core, PCIE_PCIEREGS, - PCIE_DLLP_PMTHRESHREG); - w &= ~PCIE_L1THRESHOLDTIME_MASK; - w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT; - pcie_writereg(pi->core, PCIE_PCIEREGS, - PCIE_DLLP_PMTHRESHREG, w); - - pcie_war_serdes(pi); - - pcie_war_aspm_clkreq(pi); - } else if (ai_get_buscorerev(pi->sih) == 7) - pcie_war_noplldown(pi); - - /* Note that the fix is actually in the SROM, - * that's why this is open-ended - */ - if (ai_get_buscorerev(pi->sih) >= 6) - pcie_misc_config_fixup(pi); -} - -/* ***** Functions called during driver state changes ***** */ -void pcicore_attach(struct pcicore_info *pi, int state) -{ - struct si_pub *sih = pi->sih; - u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2); - - /* Determine if this board needs override */ - if (PCIE_ASPM(sih)) { - if (bfl2 & BFL2_PCIEWAR_OVR) - pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB; - else - pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB; - } - - /* These need to happen in this order only */ - pcie_war_polarity(pi); - - pcie_war_serdes(pi); - - pcie_war_aspm_clkreq(pi); - - pcie_clkreq_upd(pi, state); - -} - -void pcicore_hwup(struct pcicore_info *pi) -{ - if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) - return; - - pcie_war_pci_setup(pi); -} - -void pcicore_up(struct pcicore_info *pi, int state) -{ - if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) - return; - - /* Restore L1 timer for better performance */ - pcie_extendL1timer(pi, true); - - pcie_clkreq_upd(pi, state); -} - -/* When the device is going to enter D3 state - * (or the system is going to enter S3/S4 states) - */ -void pcicore_sleep(struct pcicore_info *pi) -{ - u32 w; - - if (!pi || !PCIE_ASPM(pi->sih)) - return; - - pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w); - w &= ~PCIE_CAP_LCREG_ASPML1; - pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w); - - pi->pcie_pr42767 = false; -} - -void pcicore_down(struct pcicore_info *pi, int state) -{ - if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID) - return; - - pcie_clkreq_upd(pi, state); - - /* Reduce L1 timer for better power savings */ - pcie_extendL1timer(pi, false); -} - -void pcicore_fixcfg(struct pcicore_info *pi) -{ - struct bcma_device *core = pi->core; - u16 val16; - uint regoff; - - switch (pi->core->id.id) { - case BCMA_CORE_PCI: - regoff = PCIREGOFFS(sprom[SRSH_PI_OFFSET]); - break; - - case BCMA_CORE_PCIE: - regoff = PCIEREGOFFS(sprom[SRSH_PI_OFFSET]); - break; - - default: - return; - } - - val16 = bcma_read16(pi->core, regoff); - if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) != - (u16)core->core_index) { - val16 = ((u16)core->core_index << SRSH_PI_SHIFT) | - (val16 & ~SRSH_PI_MASK); - bcma_write16(pi->core, regoff, val16); - } -} - -/* precondition: current core is pci core */ -void -pcicore_pci_setup(struct pcicore_info *pi) -{ - bcma_set32(pi->core, PCIREGOFFS(sbtopci2), - SBTOPCI_PREF | SBTOPCI_BURST); - - if (pi->core->id.rev >= 11) { - bcma_set32(pi->core, PCIREGOFFS(sbtopci2), - SBTOPCI_RC_READMULTI); - bcma_set32(pi->core, PCIREGOFFS(clkrun), PCI_CLKRUN_DSBL); - (void)bcma_read32(pi->core, PCIREGOFFS(clkrun)); - } -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h b/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h deleted file mode 100644 index 9fc3ead540a..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/nicpci.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCM_NICPCI_H_ -#define _BRCM_NICPCI_H_ - -#include "types.h" - -/* PCI configuration address space size */ -#define PCI_SZPCR 256 - -/* Brcm PCI configuration registers */ -/* backplane address space accessed by BAR0 */ -#define PCI_BAR0_WIN 0x80 -/* sprom property control */ -#define PCI_SPROM_CONTROL 0x88 -/* mask of PCI and other cores interrupts */ -#define PCI_INT_MASK 0x94 -/* backplane core interrupt mask bits offset */ -#define PCI_SBIM_SHIFT 8 -/* backplane address space accessed by second 4KB of BAR0 */ -#define PCI_BAR0_WIN2 0xac -/* pci config space gpio input (>=rev3) */ -#define PCI_GPIO_IN 0xb0 -/* pci config space gpio output (>=rev3) */ -#define PCI_GPIO_OUT 0xb4 -/* pci config space gpio output enable (>=rev3) */ -#define PCI_GPIO_OUTEN 0xb8 - -/* bar0 + 4K accesses external sprom */ -#define PCI_BAR0_SPROM_OFFSET (4 * 1024) -/* bar0 + 6K accesses pci core registers */ -#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024) -/* - * pci core SB registers are at the end of the - * 8KB window, so their address is the "regular" - * address plus 4K - */ -#define PCI_BAR0_PCISBR_OFFSET (4 * 1024) -/* bar0 window size Match with corerev 13 */ -#define PCI_BAR0_WINSZ (16 * 1024) -/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */ -/* bar0 + 8K accesses pci/pcie core registers */ -#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024) -/* bar0 + 12K accesses chipc core registers */ -#define PCI_16KB0_CCREGS_OFFSET (12 * 1024) - -struct sbpciregs; -struct sbpcieregs; - -extern struct pcicore_info *pcicore_init(struct si_pub *sih, - struct bcma_device *core); -extern void pcicore_deinit(struct pcicore_info *pch); -extern void pcicore_attach(struct pcicore_info *pch, int state); -extern void pcicore_hwup(struct pcicore_info *pch); -extern void pcicore_up(struct pcicore_info *pch, int state); -extern void pcicore_sleep(struct pcicore_info *pch); -extern void pcicore_down(struct pcicore_info *pch, int state); -extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id, - unsigned char *buf, u32 *buflen); -extern void pcicore_fixcfg(struct pcicore_info *pch); -extern void pcicore_pci_setup(struct pcicore_info *pch); - -#endif /* _BRCM_NICPCI_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.c b/drivers/net/wireless/brcm80211/brcmsmac/otp.c deleted file mode 100644 index f1ca1262586..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/otp.c +++ /dev/null @@ -1,410 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/io.h> -#include <linux/errno.h> -#include <linux/string.h> - -#include <brcm_hw_ids.h> -#include <chipcommon.h> -#include "aiutils.h" -#include "otp.h" - -#define OTPS_GUP_MASK 0x00000f00 -#define OTPS_GUP_SHIFT 8 -/* h/w subregion is programmed */ -#define OTPS_GUP_HW 0x00000100 -/* s/w subregion is programmed */ -#define OTPS_GUP_SW 0x00000200 -/* chipid/pkgopt subregion is programmed */ -#define OTPS_GUP_CI 0x00000400 -/* fuse subregion is programmed */ -#define OTPS_GUP_FUSE 0x00000800 - -/* Fields in otpprog in rev >= 21 */ -#define OTPP_COL_MASK 0x000000ff -#define OTPP_COL_SHIFT 0 -#define OTPP_ROW_MASK 0x0000ff00 -#define OTPP_ROW_SHIFT 8 -#define OTPP_OC_MASK 0x0f000000 -#define OTPP_OC_SHIFT 24 -#define OTPP_READERR 0x10000000 -#define OTPP_VALUE_MASK 0x20000000 -#define OTPP_VALUE_SHIFT 29 -#define OTPP_START_BUSY 0x80000000 -#define OTPP_READ 0x40000000 - -/* Opcodes for OTPP_OC field */ -#define OTPPOC_READ 0 -#define OTPPOC_BIT_PROG 1 -#define OTPPOC_VERIFY 3 -#define OTPPOC_INIT 4 -#define OTPPOC_SET 5 -#define OTPPOC_RESET 6 -#define OTPPOC_OCST 7 -#define OTPPOC_ROW_LOCK 8 -#define OTPPOC_PRESCN_TEST 9 - -#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23) - -#define OTPP_TRIES 10000000 /* # of tries for OTPP */ - -#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */ - -/* Fixed size subregions sizes in words */ -#define OTPGU_CI_SZ 2 - -struct otpinfo; - -/* OTP function struct */ -struct otp_fn_s { - int (*init)(struct si_pub *sih, struct otpinfo *oi); - int (*read_region)(struct otpinfo *oi, int region, u16 *data, - uint *wlen); -}; - -struct otpinfo { - struct bcma_device *core; /* chipc core */ - const struct otp_fn_s *fn; /* OTP functions */ - struct si_pub *sih; /* Saved sb handle */ - - /* IPX OTP section */ - u16 wsize; /* Size of otp in words */ - u16 rows; /* Geometry */ - u16 cols; /* Geometry */ - u32 status; /* Flag bits (lock/prog/rv). - * (Reflected only when OTP is power cycled) - */ - u16 hwbase; /* hardware subregion offset */ - u16 hwlim; /* hardware subregion boundary */ - u16 swbase; /* software subregion offset */ - u16 swlim; /* software subregion boundary */ - u16 fbase; /* fuse subregion offset */ - u16 flim; /* fuse subregion boundary */ - int otpgu_base; /* offset to General Use Region */ -}; - -/* OTP layout */ -/* CC revs 21, 24 and 27 OTP General Use Region word offset */ -#define REVA4_OTPGU_BASE 12 - -/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */ -#define REVB8_OTPGU_BASE 20 - -/* CC rev 36 OTP General Use Region word offset */ -#define REV36_OTPGU_BASE 12 - -/* Subregion word offsets in General Use region */ -#define OTPGU_HSB_OFF 0 -#define OTPGU_SFB_OFF 1 -#define OTPGU_CI_OFF 2 -#define OTPGU_P_OFF 3 -#define OTPGU_SROM_OFF 4 - -/* Flag bit offsets in General Use region */ -#define OTPGU_HWP_OFF 60 -#define OTPGU_SWP_OFF 61 -#define OTPGU_CIP_OFF 62 -#define OTPGU_FUSEP_OFF 63 -#define OTPGU_CIP_MSK 0x4000 -#define OTPGU_P_MSK 0xf000 -#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16) - -/* OTP Size */ -#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */ -#define OTP_SZ_FU_288 (288/8) /* 288 bits */ -#define OTP_SZ_FU_216 (216/8) /* 216 bits */ -#define OTP_SZ_FU_72 (72/8) /* 72 bits */ -#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */ -#define OTP4315_SWREG_SZ 178 /* 178 bytes */ -#define OTP_SZ_FU_144 (144/8) /* 144 bits */ - -static u16 -ipxotp_otpr(struct otpinfo *oi, uint wn) -{ - return bcma_read16(oi->core, - CHIPCREGOFFS(sromotp[wn])); -} - -/* - * Calculate max HW/SW region byte size by subtracting fuse region - * and checksum size, osizew is oi->wsize (OTP size - GU size) in words - */ -static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew) -{ - int ret = 0; - - switch (ai_get_chip_id(sih)) { - case BCM43224_CHIP_ID: - case BCM43225_CHIP_ID: - ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; - break; - case BCM4313_CHIP_ID: - ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM; - break; - default: - break; /* Don't know about this chip */ - } - - return ret; -} - -static void _ipxotp_init(struct otpinfo *oi) -{ - uint k; - u32 otpp, st; - int ccrev = ai_get_ccrev(oi->sih); - - - /* - * record word offset of General Use Region - * for various chipcommon revs - */ - if (ccrev == 21 || ccrev == 24 - || ccrev == 27) { - oi->otpgu_base = REVA4_OTPGU_BASE; - } else if (ccrev == 36) { - /* - * OTP size greater than equal to 2KB (128 words), - * otpgu_base is similar to rev23 - */ - if (oi->wsize >= 128) - oi->otpgu_base = REVB8_OTPGU_BASE; - else - oi->otpgu_base = REV36_OTPGU_BASE; - } else if (ccrev == 23 || ccrev >= 25) { - oi->otpgu_base = REVB8_OTPGU_BASE; - } - - /* First issue an init command so the status is up to date */ - otpp = - OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK); - - bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp); - st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog)); - for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++) - st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog)); - if (k >= OTPP_TRIES) - return; - - /* Read OTP lock bits and subregion programmed indication bits */ - oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus)); - - if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID) - || (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) { - u32 p_bits; - p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) & - OTPGU_P_MSK) >> OTPGU_P_SHIFT; - oi->status |= (p_bits << OTPS_GUP_SHIFT); - } - - /* - * h/w region base and fuse region limit are fixed to - * the top and the bottom of the general use region. - * Everything else can be flexible. - */ - oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF; - oi->hwlim = oi->wsize; - if (oi->status & OTPS_GUP_HW) { - oi->hwlim = - ipxotp_otpr(oi, oi->otpgu_base + OTPGU_HSB_OFF) / 16; - oi->swbase = oi->hwlim; - } else - oi->swbase = oi->hwbase; - - /* subtract fuse and checksum from beginning */ - oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2; - - if (oi->status & OTPS_GUP_SW) { - oi->swlim = - ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16; - oi->fbase = oi->swlim; - } else - oi->fbase = oi->swbase; - - oi->flim = oi->wsize; -} - -static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi) -{ - /* Make sure we're running IPX OTP */ - if (!OTPTYPE_IPX(ai_get_ccrev(sih))) - return -EBADE; - - /* Make sure OTP is not disabled */ - if (ai_is_otp_disabled(sih)) - return -EBADE; - - /* Check for otp size */ - switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) { - case 0: - /* Nothing there */ - return -EBADE; - case 1: /* 32x64 */ - oi->rows = 32; - oi->cols = 64; - oi->wsize = 128; - break; - case 2: /* 64x64 */ - oi->rows = 64; - oi->cols = 64; - oi->wsize = 256; - break; - case 5: /* 96x64 */ - oi->rows = 96; - oi->cols = 64; - oi->wsize = 384; - break; - case 7: /* 16x64 *//* 1024 bits */ - oi->rows = 16; - oi->cols = 64; - oi->wsize = 64; - break; - default: - /* Don't know the geometry */ - return -EBADE; - } - - /* Retrieve OTP region info */ - _ipxotp_init(oi); - return 0; -} - -static int -ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen) -{ - uint base, i, sz; - - /* Validate region selection */ - switch (region) { - case OTP_HW_RGN: - sz = (uint) oi->hwlim - oi->hwbase; - if (!(oi->status & OTPS_GUP_HW)) { - *wlen = sz; - return -ENODATA; - } - if (*wlen < sz) { - *wlen = sz; - return -EOVERFLOW; - } - base = oi->hwbase; - break; - case OTP_SW_RGN: - sz = ((uint) oi->swlim - oi->swbase); - if (!(oi->status & OTPS_GUP_SW)) { - *wlen = sz; - return -ENODATA; - } - if (*wlen < sz) { - *wlen = sz; - return -EOVERFLOW; - } - base = oi->swbase; - break; - case OTP_CI_RGN: - sz = OTPGU_CI_SZ; - if (!(oi->status & OTPS_GUP_CI)) { - *wlen = sz; - return -ENODATA; - } - if (*wlen < sz) { - *wlen = sz; - return -EOVERFLOW; - } - base = oi->otpgu_base + OTPGU_CI_OFF; - break; - case OTP_FUSE_RGN: - sz = (uint) oi->flim - oi->fbase; - if (!(oi->status & OTPS_GUP_FUSE)) { - *wlen = sz; - return -ENODATA; - } - if (*wlen < sz) { - *wlen = sz; - return -EOVERFLOW; - } - base = oi->fbase; - break; - case OTP_ALL_RGN: - sz = ((uint) oi->flim - oi->hwbase); - if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) { - *wlen = sz; - return -ENODATA; - } - if (*wlen < sz) { - *wlen = sz; - return -EOVERFLOW; - } - base = oi->hwbase; - break; - default: - return -EINVAL; - } - - /* Read the data */ - for (i = 0; i < sz; i++) - data[i] = ipxotp_otpr(oi, base + i); - - *wlen = sz; - return 0; -} - -static const struct otp_fn_s ipxotp_fn = { - (int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init, - (int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region, -}; - -static int otp_init(struct si_pub *sih, struct otpinfo *oi) -{ - int ret; - - memset(oi, 0, sizeof(struct otpinfo)); - - oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - - if (OTPTYPE_IPX(ai_get_ccrev(sih))) - oi->fn = &ipxotp_fn; - - if (oi->fn == NULL) - return -EBADE; - - oi->sih = sih; - - ret = (oi->fn->init)(sih, oi); - - return ret; -} - -int -otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) { - struct otpinfo otpinfo; - struct otpinfo *oi = &otpinfo; - int err = 0; - - if (ai_is_otp_disabled(sih)) { - err = -EPERM; - goto out; - } - - err = otp_init(sih, oi); - if (err) - goto out; - - err = ((oi)->fn->read_region)(oi, region, data, wlen); - - out: - return err; -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/otp.h b/drivers/net/wireless/brcm80211/brcmsmac/otp.h deleted file mode 100644 index 6b6d31cf956..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/otp.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCM_OTP_H_ -#define _BRCM_OTP_H_ - -#include "types.h" - -/* OTP regions */ -#define OTP_HW_RGN 1 -#define OTP_SW_RGN 2 -#define OTP_CI_RGN 4 -#define OTP_FUSE_RGN 8 -/* From h/w region to end of OTP including checksum */ -#define OTP_ALL_RGN 0xf - -/* OTP Size */ -#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */ - -extern int otp_read_region(struct si_pub *sih, int region, u16 *data, - uint *wlen); - -#endif /* _BRCM_OTP_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c index 0fce56235f3..abfd78822fb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_lcn.c @@ -4817,28 +4817,23 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) s8 txpwr = 0; int i; struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy; - struct phy_shim_info *shim = pi->sh->physhim; + struct ssb_sprom *sprom = &pi->d11core->bus->sprom; if (CHSPEC_IS2G(pi->radio_chanspec)) { u16 cckpo = 0; u32 offset_ofdm, offset_mcs; - pi_lcn->lcnphy_tr_isolation_mid = - (u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); + pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso; - pi_lcn->lcnphy_rx_power_offset = - (u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G); + pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g; - pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0); - pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1); - pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2); + pi->txpa_2g[0] = sprom->pa0b0; + pi->txpa_2g[1] = sprom->pa0b1; + pi->txpa_2g[2] = sprom->pa0b2; - pi_lcn->lcnphy_rssi_vf = - (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G); - pi_lcn->lcnphy_rssi_vc = - (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G); - pi_lcn->lcnphy_rssi_gs = - (u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G); + pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g; + pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g; + pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g; pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf; pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc; @@ -4848,7 +4843,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc; pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs; - txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0); + txpwr = sprom->core_pwr_info[0].maxpwr_2g; pi->tx_srom_max_2g = txpwr; for (i = 0; i < PWRTBL_NUM_COEFF; i++) { @@ -4856,8 +4851,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) pi->txpa_2g_high_temp[i] = pi->txpa_2g[i]; } - cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO); - offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO); + cckpo = sprom->cck2gpo; + offset_ofdm = sprom->ofdm2gpo; if (cckpo) { uint max_pwr_chan = txpwr; @@ -4876,7 +4871,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) } else { u8 opo = 0; - opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO); + opo = sprom->opo; for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++) pi->tx_srom_max_rate_2g[i] = txpwr; @@ -4886,12 +4881,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) ((offset_ofdm & 0xf) * 2); offset_ofdm >>= 4; } - offset_mcs = - wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO1) << 16; - offset_mcs |= - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO0); + offset_mcs = sprom->mcs2gpo[1] << 16; + offset_mcs |= sprom->mcs2gpo[0]; pi_lcn->lcnphy_mcs20_po = offset_mcs; for (i = TXP_FIRST_SISO_MCS_20; i <= TXP_LAST_SISO_MCS_20; i++) { @@ -4901,25 +4892,17 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi) } } - pi_lcn->lcnphy_rawtempsense = - (u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE); - pi_lcn->lcnphy_measPower = - (u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER); - pi_lcn->lcnphy_tempsense_slope = - (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE); - pi_lcn->lcnphy_hw_iqcal_en = - (bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN); - pi_lcn->lcnphy_iqcal_swp_dis = - (bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS); - pi_lcn->lcnphy_tempcorrx = - (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX); - pi_lcn->lcnphy_tempsense_option = - (u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION); - pi_lcn->lcnphy_freqoffset_corr = - (u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR); - if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1) + pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense; + pi_lcn->lcnphy_measPower = sprom->measpower; + pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope; + pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en; + pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis; + pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx; + pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option; + pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr; + if (sprom->ant_available_bg > 1) wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi, - (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G)); + sprom->ant_available_bg); } pi_lcn->lcnphy_cck_dig_filt_type = -1; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c index 812b6e38526..13b261517cc 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c @@ -14386,30 +14386,30 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) { u16 bw40po, cddpo, stbcpo, bwduppo; uint band_num; - struct phy_shim_info *shim = pi->sh->physhim; + struct ssb_sprom *sprom = &pi->d11core->bus->sprom; if (pi->sh->sromrev >= 9) return; - bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO); + bw40po = sprom->bw40po; pi->bw402gpo = bw40po & 0xf; pi->bw405gpo = (bw40po & 0xf0) >> 4; pi->bw405glpo = (bw40po & 0xf00) >> 8; pi->bw405ghpo = (bw40po & 0xf000) >> 12; - cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO); + cddpo = sprom->cddpo; pi->cdd2gpo = cddpo & 0xf; pi->cdd5gpo = (cddpo & 0xf0) >> 4; pi->cdd5glpo = (cddpo & 0xf00) >> 8; pi->cdd5ghpo = (cddpo & 0xf000) >> 12; - stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO); + stbcpo = sprom->stbcpo; pi->stbc2gpo = stbcpo & 0xf; pi->stbc5gpo = (stbcpo & 0xf0) >> 4; pi->stbc5glpo = (stbcpo & 0xf00) >> 8; pi->stbc5ghpo = (stbcpo & 0xf000) >> 12; - bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO); + bwduppo = sprom->bwduppo; pi->bwdup2gpo = bwduppo & 0xf; pi->bwdup5gpo = (bwduppo & 0xf0) >> 4; pi->bwdup5glpo = (bwduppo & 0xf00) >> 8; @@ -14419,242 +14419,137 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) band_num++) { switch (band_num) { case 0: - pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP2GA0); + sprom->core_pwr_info[0].maxpwr_2g; pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP2GA1); + sprom->core_pwr_info[1].maxpwr_2g; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW0A0); + sprom->core_pwr_info[0].pa_2g[0]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW0A1); + sprom->core_pwr_info[1].pa_2g[0]; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW1A0); + sprom->core_pwr_info[0].pa_2g[1]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW1A1); + sprom->core_pwr_info[1].pa_2g[1]; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW2A0); + sprom->core_pwr_info[0].pa_2g[2]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA2GW2A1); + sprom->core_pwr_info[1].pa_2g[2]; pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g = - (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0); + sprom->core_pwr_info[0].itssi_2g; pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g = - (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1); - - pi->cck2gpo = (u16) wlapi_getintvar(shim, - BRCMS_SROM_CCK2GPO); - - pi->ofdm2gpo = - (u32) wlapi_getintvar(shim, - BRCMS_SROM_OFDM2GPO); - - pi->mcs2gpo[0] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO0); - pi->mcs2gpo[1] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO1); - pi->mcs2gpo[2] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO2); - pi->mcs2gpo[3] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO3); - pi->mcs2gpo[4] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO4); - pi->mcs2gpo[5] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO5); - pi->mcs2gpo[6] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO6); - pi->mcs2gpo[7] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS2GPO7); + sprom->core_pwr_info[1].itssi_2g; + + pi->cck2gpo = sprom->cck2gpo; + + pi->ofdm2gpo = sprom->ofdm2gpo; + + pi->mcs2gpo[0] = sprom->mcs2gpo[0]; + pi->mcs2gpo[1] = sprom->mcs2gpo[1]; + pi->mcs2gpo[2] = sprom->mcs2gpo[2]; + pi->mcs2gpo[3] = sprom->mcs2gpo[3]; + pi->mcs2gpo[4] = sprom->mcs2gpo[4]; + pi->mcs2gpo[5] = sprom->mcs2gpo[5]; + pi->mcs2gpo[6] = sprom->mcs2gpo[6]; + pi->mcs2gpo[7] = sprom->mcs2gpo[7]; break; case 1: pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm = - (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0); + sprom->core_pwr_info[0].maxpwr_5g; pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP5GA1); + sprom->core_pwr_info[1].maxpwr_5g; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW0A0); + sprom->core_pwr_info[0].pa_5g[0]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW0A1); + sprom->core_pwr_info[1].pa_5g[0]; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW1A0); + sprom->core_pwr_info[0].pa_5g[1]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW1A1); + sprom->core_pwr_info[1].pa_5g[1]; pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW2A0); + sprom->core_pwr_info[0].pa_5g[2]; pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GW2A1); + sprom->core_pwr_info[1].pa_5g[2]; pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm = - (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0); + sprom->core_pwr_info[0].itssi_5g; pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm = - (s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1); - - pi->ofdm5gpo = - (u32) wlapi_getintvar(shim, - BRCMS_SROM_OFDM5GPO); - - pi->mcs5gpo[0] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO0); - pi->mcs5gpo[1] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO1); - pi->mcs5gpo[2] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO2); - pi->mcs5gpo[3] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO3); - pi->mcs5gpo[4] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO4); - pi->mcs5gpo[5] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO5); - pi->mcs5gpo[6] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO6); - pi->mcs5gpo[7] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GPO7); + sprom->core_pwr_info[1].itssi_5g; + + pi->ofdm5gpo = sprom->ofdm5gpo; + + pi->mcs5gpo[0] = sprom->mcs5gpo[0]; + pi->mcs5gpo[1] = sprom->mcs5gpo[1]; + pi->mcs5gpo[2] = sprom->mcs5gpo[2]; + pi->mcs5gpo[3] = sprom->mcs5gpo[3]; + pi->mcs5gpo[4] = sprom->mcs5gpo[4]; + pi->mcs5gpo[5] = sprom->mcs5gpo[5]; + pi->mcs5gpo[6] = sprom->mcs5gpo[6]; + pi->mcs5gpo[7] = sprom->mcs5gpo[7]; break; case 2: pi->nphy_pwrctrl_info[0].max_pwr_5gl = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP5GLA0); + sprom->core_pwr_info[0].maxpwr_5gl; pi->nphy_pwrctrl_info[1].max_pwr_5gl = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP5GLA1); + sprom->core_pwr_info[1].maxpwr_5gl; pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW0A0); + sprom->core_pwr_info[0].pa_5gl[0]; pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW0A1); + sprom->core_pwr_info[1].pa_5gl[0]; pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW1A0); + sprom->core_pwr_info[0].pa_5gl[1]; pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW1A1); + sprom->core_pwr_info[1].pa_5gl[1]; pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW2A0); + sprom->core_pwr_info[0].pa_5gl[2]; pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GLW2A1); + sprom->core_pwr_info[1].pa_5gl[2]; pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0; pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0; - pi->ofdm5glpo = - (u32) wlapi_getintvar(shim, - BRCMS_SROM_OFDM5GLPO); - - pi->mcs5glpo[0] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO0); - pi->mcs5glpo[1] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO1); - pi->mcs5glpo[2] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO2); - pi->mcs5glpo[3] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO3); - pi->mcs5glpo[4] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO4); - pi->mcs5glpo[5] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO5); - pi->mcs5glpo[6] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO6); - pi->mcs5glpo[7] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GLPO7); + pi->ofdm5glpo = sprom->ofdm5glpo; + + pi->mcs5glpo[0] = sprom->mcs5glpo[0]; + pi->mcs5glpo[1] = sprom->mcs5glpo[1]; + pi->mcs5glpo[2] = sprom->mcs5glpo[2]; + pi->mcs5glpo[3] = sprom->mcs5glpo[3]; + pi->mcs5glpo[4] = sprom->mcs5glpo[4]; + pi->mcs5glpo[5] = sprom->mcs5glpo[5]; + pi->mcs5glpo[6] = sprom->mcs5glpo[6]; + pi->mcs5glpo[7] = sprom->mcs5glpo[7]; break; case 3: pi->nphy_pwrctrl_info[0].max_pwr_5gh = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP5GHA0); + sprom->core_pwr_info[0].maxpwr_5gh; pi->nphy_pwrctrl_info[1].max_pwr_5gh = - (s8) wlapi_getintvar(shim, - BRCMS_SROM_MAXP5GHA1); + sprom->core_pwr_info[1].maxpwr_5gh; pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW0A0); + sprom->core_pwr_info[0].pa_5gh[0]; pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW0A1); + sprom->core_pwr_info[1].pa_5gh[0]; pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW1A0); + sprom->core_pwr_info[0].pa_5gh[1]; pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW1A1); + sprom->core_pwr_info[1].pa_5gh[1]; pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW2A0); + sprom->core_pwr_info[0].pa_5gh[2]; pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 = - (s16) wlapi_getintvar(shim, - BRCMS_SROM_PA5GHW2A1); + sprom->core_pwr_info[1].pa_5gh[2]; pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0; pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0; - pi->ofdm5ghpo = - (u32) wlapi_getintvar(shim, - BRCMS_SROM_OFDM5GHPO); - - pi->mcs5ghpo[0] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO0); - pi->mcs5ghpo[1] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO1); - pi->mcs5ghpo[2] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO2); - pi->mcs5ghpo[3] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO3); - pi->mcs5ghpo[4] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO4); - pi->mcs5ghpo[5] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO5); - pi->mcs5ghpo[6] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO6); - pi->mcs5ghpo[7] = - (u16) wlapi_getintvar(shim, - BRCMS_SROM_MCS5GHPO7); + pi->ofdm5ghpo = sprom->ofdm5ghpo; + + pi->mcs5ghpo[0] = sprom->mcs5ghpo[0]; + pi->mcs5ghpo[1] = sprom->mcs5ghpo[1]; + pi->mcs5ghpo[2] = sprom->mcs5ghpo[2]; + pi->mcs5ghpo[3] = sprom->mcs5ghpo[3]; + pi->mcs5ghpo[4] = sprom->mcs5ghpo[4]; + pi->mcs5ghpo[5] = sprom->mcs5ghpo[5]; + pi->mcs5ghpo[6] = sprom->mcs5ghpo[6]; + pi->mcs5ghpo[7] = sprom->mcs5ghpo[7]; break; } } @@ -14664,45 +14559,34 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi) static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) { - struct phy_shim_info *shim = pi->sh->physhim; - - pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH); - pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G); - pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G); - - pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim, - BRCMS_SROM_TSSIPOS2G); - pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim, - BRCMS_SROM_EXTPAGAIN2G); - pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim, - BRCMS_SROM_PDETRANGE2G); - pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G); - pi->srom_fem2g.antswctrllut = - (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); - - pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim, - BRCMS_SROM_TSSIPOS5G); - pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim, - BRCMS_SROM_EXTPAGAIN5G); - pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim, - BRCMS_SROM_PDETRANGE5G); - pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G); - if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G)) - pi->srom_fem5g.antswctrllut = - (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G); + struct ssb_sprom *sprom = &pi->d11core->bus->sprom; + + pi->antswitch = sprom->antswitch; + pi->aa2g = sprom->ant_available_bg; + pi->aa5g = sprom->ant_available_a; + + pi->srom_fem2g.tssipos = sprom->fem.ghz2.tssipos; + pi->srom_fem2g.extpagain = sprom->fem.ghz2.extpa_gain; + pi->srom_fem2g.pdetrange = sprom->fem.ghz2.pdet_range; + pi->srom_fem2g.triso = sprom->fem.ghz2.tr_iso; + pi->srom_fem2g.antswctrllut = sprom->fem.ghz2.antswlut; + + pi->srom_fem5g.tssipos = sprom->fem.ghz5.tssipos; + pi->srom_fem5g.extpagain = sprom->fem.ghz5.extpa_gain; + pi->srom_fem5g.pdetrange = sprom->fem.ghz5.pdet_range; + pi->srom_fem5g.triso = sprom->fem.ghz5.tr_iso; + if (sprom->fem.ghz5.antswlut) + pi->srom_fem5g.antswctrllut = sprom->fem.ghz5.antswlut; else - pi->srom_fem5g.antswctrllut = - (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G); + pi->srom_fem5g.antswctrllut = sprom->fem.ghz2.antswlut; wlc_phy_txpower_ipa_upd(pi); - pi->phy_txcore_disable_temp = - (s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH); + pi->phy_txcore_disable_temp = sprom->tempthresh; if (pi->phy_txcore_disable_temp == 0) pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP; - pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim, - BRCMS_SROM_TEMPOFFSET); + pi->phy_tempsense_offset = sprom->tempoffset; if (pi->phy_tempsense_offset != 0) { if (pi->phy_tempsense_offset > (NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET)) @@ -14717,8 +14601,7 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi) pi->phy_txcore_enable_temp = pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP; - pi->phycal_tempdelta = - (u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA); + pi->phycal_tempdelta = sprom->phycal_tempdelta; if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA) pi->phycal_tempdelta = 0; @@ -21460,7 +21343,7 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init) write_phy_reg(pi, 0xc8, 0x0); write_phy_reg(pi, 0xc9, 0x0); - ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY); + bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, mask, mask); mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol)); mc &= ~MCTL_GPOUT_SEL_MASK; diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c index 5926854f62e..a0de5db0cd6 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.c @@ -214,12 +214,3 @@ wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf, { brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel); } - -char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id) -{ - return getvar(physhim->wlc_hw->sih, id); -} -int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id) -{ - return getintvar(physhim->wlc_hw->sih, id); -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h index 9168c459b18..2c5b66b7597 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/phy_shim.h @@ -175,8 +175,5 @@ extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint, extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim, u32 phy_mode); extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim); -extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id); -extern int wlapi_getintvar(struct phy_shim_info *physhim, - enum brcms_srom_id id); #endif /* _BRCM_PHY_SHIM_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/pub.h b/drivers/net/wireless/brcm80211/brcmsmac/pub.h index f0038ad7d7b..aa5d67f8d87 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/pub.h +++ b/drivers/net/wireless/brcm80211/brcmsmac/pub.h @@ -22,232 +22,6 @@ #include "types.h" #include "defs.h" -enum brcms_srom_id { - BRCMS_SROM_NULL, - BRCMS_SROM_CONT, - BRCMS_SROM_AA2G, - BRCMS_SROM_AA5G, - BRCMS_SROM_AG0, - BRCMS_SROM_AG1, - BRCMS_SROM_AG2, - BRCMS_SROM_AG3, - BRCMS_SROM_ANTSWCTL2G, - BRCMS_SROM_ANTSWCTL5G, - BRCMS_SROM_ANTSWITCH, - BRCMS_SROM_BOARDFLAGS2, - BRCMS_SROM_BOARDFLAGS, - BRCMS_SROM_BOARDNUM, - BRCMS_SROM_BOARDREV, - BRCMS_SROM_BOARDTYPE, - BRCMS_SROM_BW40PO, - BRCMS_SROM_BWDUPPO, - BRCMS_SROM_BXA2G, - BRCMS_SROM_BXA5G, - BRCMS_SROM_CC, - BRCMS_SROM_CCK2GPO, - BRCMS_SROM_CCKBW202GPO, - BRCMS_SROM_CCKBW20UL2GPO, - BRCMS_SROM_CCODE, - BRCMS_SROM_CDDPO, - BRCMS_SROM_DEVID, - BRCMS_SROM_ET1MACADDR, - BRCMS_SROM_EXTPAGAIN2G, - BRCMS_SROM_EXTPAGAIN5G, - BRCMS_SROM_FREQOFFSET_CORR, - BRCMS_SROM_HW_IQCAL_EN, - BRCMS_SROM_IL0MACADDR, - BRCMS_SROM_IQCAL_SWP_DIS, - BRCMS_SROM_LEDBH0, - BRCMS_SROM_LEDBH1, - BRCMS_SROM_LEDBH2, - BRCMS_SROM_LEDBH3, - BRCMS_SROM_LEDDC, - BRCMS_SROM_LEGOFDM40DUPPO, - BRCMS_SROM_LEGOFDMBW202GPO, - BRCMS_SROM_LEGOFDMBW205GHPO, - BRCMS_SROM_LEGOFDMBW205GLPO, - BRCMS_SROM_LEGOFDMBW205GMPO, - BRCMS_SROM_LEGOFDMBW20UL2GPO, - BRCMS_SROM_LEGOFDMBW20UL5GHPO, - BRCMS_SROM_LEGOFDMBW20UL5GLPO, - BRCMS_SROM_LEGOFDMBW20UL5GMPO, - BRCMS_SROM_MACADDR, - BRCMS_SROM_MCS2GPO0, - BRCMS_SROM_MCS2GPO1, - BRCMS_SROM_MCS2GPO2, - BRCMS_SROM_MCS2GPO3, - BRCMS_SROM_MCS2GPO4, - BRCMS_SROM_MCS2GPO5, - BRCMS_SROM_MCS2GPO6, - BRCMS_SROM_MCS2GPO7, - BRCMS_SROM_MCS32PO, - BRCMS_SROM_MCS5GHPO0, - BRCMS_SROM_MCS5GHPO1, - BRCMS_SROM_MCS5GHPO2, - BRCMS_SROM_MCS5GHPO3, - BRCMS_SROM_MCS5GHPO4, - BRCMS_SROM_MCS5GHPO5, - BRCMS_SROM_MCS5GHPO6, - BRCMS_SROM_MCS5GHPO7, - BRCMS_SROM_MCS5GLPO0, - BRCMS_SROM_MCS5GLPO1, - BRCMS_SROM_MCS5GLPO2, - BRCMS_SROM_MCS5GLPO3, - BRCMS_SROM_MCS5GLPO4, - BRCMS_SROM_MCS5GLPO5, - BRCMS_SROM_MCS5GLPO6, - BRCMS_SROM_MCS5GLPO7, - BRCMS_SROM_MCS5GPO0, - BRCMS_SROM_MCS5GPO1, - BRCMS_SROM_MCS5GPO2, - BRCMS_SROM_MCS5GPO3, - BRCMS_SROM_MCS5GPO4, - BRCMS_SROM_MCS5GPO5, - BRCMS_SROM_MCS5GPO6, - BRCMS_SROM_MCS5GPO7, - BRCMS_SROM_MCSBW202GPO, - BRCMS_SROM_MCSBW205GHPO, - BRCMS_SROM_MCSBW205GLPO, - BRCMS_SROM_MCSBW205GMPO, - BRCMS_SROM_MCSBW20UL2GPO, - BRCMS_SROM_MCSBW20UL5GHPO, - BRCMS_SROM_MCSBW20UL5GLPO, - BRCMS_SROM_MCSBW20UL5GMPO, - BRCMS_SROM_MCSBW402GPO, - BRCMS_SROM_MCSBW405GHPO, - BRCMS_SROM_MCSBW405GLPO, - BRCMS_SROM_MCSBW405GMPO, - BRCMS_SROM_MEASPOWER, - BRCMS_SROM_OFDM2GPO, - BRCMS_SROM_OFDM5GHPO, - BRCMS_SROM_OFDM5GLPO, - BRCMS_SROM_OFDM5GPO, - BRCMS_SROM_OPO, - BRCMS_SROM_PA0B0, - BRCMS_SROM_PA0B1, - BRCMS_SROM_PA0B2, - BRCMS_SROM_PA0ITSSIT, - BRCMS_SROM_PA0MAXPWR, - BRCMS_SROM_PA1B0, - BRCMS_SROM_PA1B1, - BRCMS_SROM_PA1B2, - BRCMS_SROM_PA1HIB0, - BRCMS_SROM_PA1HIB1, - BRCMS_SROM_PA1HIB2, - BRCMS_SROM_PA1HIMAXPWR, - BRCMS_SROM_PA1ITSSIT, - BRCMS_SROM_PA1LOB0, - BRCMS_SROM_PA1LOB1, - BRCMS_SROM_PA1LOB2, - BRCMS_SROM_PA1LOMAXPWR, - BRCMS_SROM_PA1MAXPWR, - BRCMS_SROM_PDETRANGE2G, - BRCMS_SROM_PDETRANGE5G, - BRCMS_SROM_PHYCAL_TEMPDELTA, - BRCMS_SROM_RAWTEMPSENSE, - BRCMS_SROM_REGREV, - BRCMS_SROM_REV, - BRCMS_SROM_RSSISAV2G, - BRCMS_SROM_RSSISAV5G, - BRCMS_SROM_RSSISMC2G, - BRCMS_SROM_RSSISMC5G, - BRCMS_SROM_RSSISMF2G, - BRCMS_SROM_RSSISMF5G, - BRCMS_SROM_RXCHAIN, - BRCMS_SROM_RXPO2G, - BRCMS_SROM_RXPO5G, - BRCMS_SROM_STBCPO, - BRCMS_SROM_TEMPCORRX, - BRCMS_SROM_TEMPOFFSET, - BRCMS_SROM_TEMPSENSE_OPTION, - BRCMS_SROM_TEMPSENSE_SLOPE, - BRCMS_SROM_TEMPTHRESH, - BRCMS_SROM_TRI2G, - BRCMS_SROM_TRI5GH, - BRCMS_SROM_TRI5GL, - BRCMS_SROM_TRI5G, - BRCMS_SROM_TRISO2G, - BRCMS_SROM_TRISO5G, - BRCMS_SROM_TSSIPOS2G, - BRCMS_SROM_TSSIPOS5G, - BRCMS_SROM_TXCHAIN, - /* - * per-path identifiers (see srom.c) - */ - BRCMS_SROM_ITT2GA0, - BRCMS_SROM_ITT2GA1, - BRCMS_SROM_ITT2GA2, - BRCMS_SROM_ITT2GA3, - BRCMS_SROM_ITT5GA0, - BRCMS_SROM_ITT5GA1, - BRCMS_SROM_ITT5GA2, - BRCMS_SROM_ITT5GA3, - BRCMS_SROM_MAXP2GA0, - BRCMS_SROM_MAXP2GA1, - BRCMS_SROM_MAXP2GA2, - BRCMS_SROM_MAXP2GA3, - BRCMS_SROM_MAXP5GA0, - BRCMS_SROM_MAXP5GA1, - BRCMS_SROM_MAXP5GA2, - BRCMS_SROM_MAXP5GA3, - BRCMS_SROM_MAXP5GHA0, - BRCMS_SROM_MAXP5GHA1, - BRCMS_SROM_MAXP5GHA2, - BRCMS_SROM_MAXP5GHA3, - BRCMS_SROM_MAXP5GLA0, - BRCMS_SROM_MAXP5GLA1, - BRCMS_SROM_MAXP5GLA2, - BRCMS_SROM_MAXP5GLA3, - BRCMS_SROM_PA2GW0A0, - BRCMS_SROM_PA2GW0A1, - BRCMS_SROM_PA2GW0A2, - BRCMS_SROM_PA2GW0A3, - BRCMS_SROM_PA2GW1A0, - BRCMS_SROM_PA2GW1A1, - BRCMS_SROM_PA2GW1A2, - BRCMS_SROM_PA2GW1A3, - BRCMS_SROM_PA2GW2A0, - BRCMS_SROM_PA2GW2A1, - BRCMS_SROM_PA2GW2A2, - BRCMS_SROM_PA2GW2A3, - BRCMS_SROM_PA5GHW0A0, - BRCMS_SROM_PA5GHW0A1, - BRCMS_SROM_PA5GHW0A2, - BRCMS_SROM_PA5GHW0A3, - BRCMS_SROM_PA5GHW1A0, - BRCMS_SROM_PA5GHW1A1, - BRCMS_SROM_PA5GHW1A2, - BRCMS_SROM_PA5GHW1A3, - BRCMS_SROM_PA5GHW2A0, - BRCMS_SROM_PA5GHW2A1, - BRCMS_SROM_PA5GHW2A2, - BRCMS_SROM_PA5GHW2A3, - BRCMS_SROM_PA5GLW0A0, - BRCMS_SROM_PA5GLW0A1, - BRCMS_SROM_PA5GLW0A2, - BRCMS_SROM_PA5GLW0A3, - BRCMS_SROM_PA5GLW1A0, - BRCMS_SROM_PA5GLW1A1, - BRCMS_SROM_PA5GLW1A2, - BRCMS_SROM_PA5GLW1A3, - BRCMS_SROM_PA5GLW2A0, - BRCMS_SROM_PA5GLW2A1, - BRCMS_SROM_PA5GLW2A2, - BRCMS_SROM_PA5GLW2A3, - BRCMS_SROM_PA5GW0A0, - BRCMS_SROM_PA5GW0A1, - BRCMS_SROM_PA5GW0A2, - BRCMS_SROM_PA5GW0A3, - BRCMS_SROM_PA5GW1A0, - BRCMS_SROM_PA5GW1A1, - BRCMS_SROM_PA5GW1A2, - BRCMS_SROM_PA5GW1A3, - BRCMS_SROM_PA5GW2A0, - BRCMS_SROM_PA5GW2A1, - BRCMS_SROM_PA5GW2A2, - BRCMS_SROM_PA5GW2A3, -}; - #define BRCMS_NUMRATES 16 /* max # of rates in a rateset */ /* phy types */ @@ -565,8 +339,6 @@ extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc, struct ieee80211_sta *sta, u16 tid); extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid, u8 ba_wsize, uint max_rx_ampdu_bytes); -extern char *getvar(struct si_pub *sih, enum brcms_srom_id id); -extern int getintvar(struct si_pub *sih, enum brcms_srom_id id); extern int brcms_c_module_register(struct brcms_pub *pub, const char *name, struct brcms_info *hdl, int (*down_fn)(void *handle)); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.c b/drivers/net/wireless/brcm80211/brcmsmac/srom.c deleted file mode 100644 index b96f4b9d74b..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.c +++ /dev/null @@ -1,980 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include <linux/kernel.h> -#include <linux/string.h> -#include <linux/io.h> -#include <linux/etherdevice.h> -#include <linux/crc8.h> -#include <stdarg.h> - -#include <chipcommon.h> -#include <brcmu_utils.h> -#include "pub.h" -#include "nicpci.h" -#include "aiutils.h" -#include "otp.h" -#include "srom.h" -#include "soc.h" - -/* - * SROM CRC8 polynomial value: - * - * x^8 + x^7 +x^6 + x^4 + x^2 + 1 - */ -#define SROM_CRC8_POLY 0xAB - -/* Maximum srom: 6 Kilobits == 768 bytes */ -#define SROM_MAX 768 - -/* PCI fields */ -#define PCI_F0DEVID 48 - -#define SROM_WORDS 64 - -#define SROM_SSID 2 - -#define SROM_WL1LHMAXP 29 - -#define SROM_WL1LPAB0 30 -#define SROM_WL1LPAB1 31 -#define SROM_WL1LPAB2 32 - -#define SROM_WL1HPAB0 33 -#define SROM_WL1HPAB1 34 -#define SROM_WL1HPAB2 35 - -#define SROM_MACHI_IL0 36 -#define SROM_MACMID_IL0 37 -#define SROM_MACLO_IL0 38 -#define SROM_MACHI_ET1 42 -#define SROM_MACMID_ET1 43 -#define SROM_MACLO_ET1 44 - -#define SROM_BXARSSI2G 40 -#define SROM_BXARSSI5G 41 - -#define SROM_TRI52G 42 -#define SROM_TRI5GHL 43 - -#define SROM_RXPO52G 45 - -#define SROM_AABREV 46 -/* Fields in AABREV */ -#define SROM_BR_MASK 0x00ff -#define SROM_CC_MASK 0x0f00 -#define SROM_CC_SHIFT 8 -#define SROM_AA0_MASK 0x3000 -#define SROM_AA0_SHIFT 12 -#define SROM_AA1_MASK 0xc000 -#define SROM_AA1_SHIFT 14 - -#define SROM_WL0PAB0 47 -#define SROM_WL0PAB1 48 -#define SROM_WL0PAB2 49 - -#define SROM_LEDBH10 50 -#define SROM_LEDBH32 51 - -#define SROM_WL10MAXP 52 - -#define SROM_WL1PAB0 53 -#define SROM_WL1PAB1 54 -#define SROM_WL1PAB2 55 - -#define SROM_ITT 56 - -#define SROM_BFL 57 -#define SROM_BFL2 28 - -#define SROM_AG10 58 - -#define SROM_CCODE 59 - -#define SROM_OPO 60 - -#define SROM_CRCREV 63 - -#define SROM4_WORDS 220 - -#define SROM4_TXCHAIN_MASK 0x000f -#define SROM4_RXCHAIN_MASK 0x00f0 -#define SROM4_SWITCH_MASK 0xff00 - -/* Per-path fields */ -#define MAX_PATH_SROM 4 - -#define SROM4_CRCREV 219 - -/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. - * This is acombined srom for both MIMO and SISO boards, usable in - * the .130 4Kilobit OTP with hardware redundancy. - */ -#define SROM8_BREV 65 - -#define SROM8_BFL0 66 -#define SROM8_BFL1 67 -#define SROM8_BFL2 68 -#define SROM8_BFL3 69 - -#define SROM8_MACHI 70 -#define SROM8_MACMID 71 -#define SROM8_MACLO 72 - -#define SROM8_CCODE 73 -#define SROM8_REGREV 74 - -#define SROM8_LEDBH10 75 -#define SROM8_LEDBH32 76 - -#define SROM8_LEDDC 77 - -#define SROM8_AA 78 - -#define SROM8_AG10 79 -#define SROM8_AG32 80 - -#define SROM8_TXRXC 81 - -#define SROM8_BXARSSI2G 82 -#define SROM8_BXARSSI5G 83 -#define SROM8_TRI52G 84 -#define SROM8_TRI5GHL 85 -#define SROM8_RXPO52G 86 - -#define SROM8_FEM2G 87 -#define SROM8_FEM5G 88 -#define SROM8_FEM_ANTSWLUT_MASK 0xf800 -#define SROM8_FEM_ANTSWLUT_SHIFT 11 -#define SROM8_FEM_TR_ISO_MASK 0x0700 -#define SROM8_FEM_TR_ISO_SHIFT 8 -#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 -#define SROM8_FEM_PDET_RANGE_SHIFT 3 -#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 -#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 -#define SROM8_FEM_TSSIPOS_MASK 0x0001 -#define SROM8_FEM_TSSIPOS_SHIFT 0 - -#define SROM8_THERMAL 89 - -/* Temp sense related entries */ -#define SROM8_MPWR_RAWTS 90 -#define SROM8_TS_SLP_OPT_CORRX 91 -/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, - * IQSWP: IQ CAL swap disable */ -#define SROM8_FOC_HWIQ_IQSWP 92 - -/* Temperature delta for PHY calibration */ -#define SROM8_PHYCAL_TEMPDELTA 93 - -/* Per-path offsets & fields */ -#define SROM8_PATH0 96 -#define SROM8_PATH1 112 -#define SROM8_PATH2 128 -#define SROM8_PATH3 144 - -#define SROM8_2G_ITT_MAXP 0 -#define SROM8_2G_PA 1 -#define SROM8_5G_ITT_MAXP 4 -#define SROM8_5GLH_MAXP 5 -#define SROM8_5G_PA 6 -#define SROM8_5GL_PA 9 -#define SROM8_5GH_PA 12 - -/* All the miriad power offsets */ -#define SROM8_2G_CCKPO 160 - -#define SROM8_2G_OFDMPO 161 -#define SROM8_5G_OFDMPO 163 -#define SROM8_5GL_OFDMPO 165 -#define SROM8_5GH_OFDMPO 167 - -#define SROM8_2G_MCSPO 169 -#define SROM8_5G_MCSPO 177 -#define SROM8_5GL_MCSPO 185 -#define SROM8_5GH_MCSPO 193 - -#define SROM8_CDDPO 201 -#define SROM8_STBCPO 202 -#define SROM8_BW40PO 203 -#define SROM8_BWDUPPO 204 - -/* SISO PA parameters are in the path0 spaces */ -#define SROM8_SISO 96 - -/* Legacy names for SISO PA paramters */ -#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) -#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) -#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) -#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) -#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) -#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) -#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) -#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) -#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) -#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) -#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) -#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) -#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) -#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) -#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) - -/* SROM REV 9 */ -#define SROM9_2GPO_CCKBW20 160 -#define SROM9_2GPO_CCKBW20UL 161 -#define SROM9_2GPO_LOFDMBW20 162 -#define SROM9_2GPO_LOFDMBW20UL 164 - -#define SROM9_5GLPO_LOFDMBW20 166 -#define SROM9_5GLPO_LOFDMBW20UL 168 -#define SROM9_5GMPO_LOFDMBW20 170 -#define SROM9_5GMPO_LOFDMBW20UL 172 -#define SROM9_5GHPO_LOFDMBW20 174 -#define SROM9_5GHPO_LOFDMBW20UL 176 - -#define SROM9_2GPO_MCSBW20 178 -#define SROM9_2GPO_MCSBW20UL 180 -#define SROM9_2GPO_MCSBW40 182 - -#define SROM9_5GLPO_MCSBW20 184 -#define SROM9_5GLPO_MCSBW20UL 186 -#define SROM9_5GLPO_MCSBW40 188 -#define SROM9_5GMPO_MCSBW20 190 -#define SROM9_5GMPO_MCSBW20UL 192 -#define SROM9_5GMPO_MCSBW40 194 -#define SROM9_5GHPO_MCSBW20 196 -#define SROM9_5GHPO_MCSBW20UL 198 -#define SROM9_5GHPO_MCSBW40 200 - -#define SROM9_PO_MCS32 202 -#define SROM9_PO_LOFDM40DUP 203 - -/* SROM flags (see sromvar_t) */ - -/* value continues as described by the next entry */ -#define SRFL_MORE 1 -#define SRFL_NOFFS 2 /* value bits can't be all one's */ -#define SRFL_PRHEX 4 /* value is in hexdecimal format */ -#define SRFL_PRSIGN 8 /* value is in signed decimal format */ -#define SRFL_CCODE 0x10 /* value is in country code format */ -#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ -#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ -/* do not generate a nvram param, entry is for mfgc */ -#define SRFL_NOVAR 0x80 - -/* Max. nvram variable table size */ -#define MAXSZ_NVRAM_VARS 4096 - -/* - * indicates type of value. - */ -enum brcms_srom_var_type { - BRCMS_SROM_STRING, - BRCMS_SROM_SNUMBER, - BRCMS_SROM_UNUMBER -}; - -/* - * storage type for srom variable. - * - * var_list: for linked list operations. - * varid: identifier of the variable. - * var_type: type of variable. - * buf: variable value when var_type == BRCMS_SROM_STRING. - * uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER. - * sval: signed variable value when var_type == BRCMS_SROM_SNUMBER. - */ -struct brcms_srom_list_head { - struct list_head var_list; - enum brcms_srom_id varid; - enum brcms_srom_var_type var_type; - union { - char buf[0]; - u32 uval; - s32 sval; - }; -}; - -struct brcms_sromvar { - enum brcms_srom_id varid; - u32 revmask; - u32 flags; - u16 off; - u16 mask; -}; - -struct brcms_varbuf { - char *base; /* pointer to buffer base */ - char *buf; /* pointer to current position */ - unsigned int size; /* current (residual) size in bytes */ -}; - -/* - * Assumptions: - * - Ethernet address spans across 3 consecutive words - * - * Table rules: - * - Add multiple entries next to each other if a value spans across multiple - * words (even multiple fields in the same word) with each entry except the - * last having it's SRFL_MORE bit set. - * - Ethernet address entry does not follow above rule and must not have - * SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words. - * - The last entry's name field must be NULL to indicate the end of the table. - * Other entries must have non-NULL name. - */ -static const struct brcms_sromvar pci_sromvars[] = { - {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, - 0xffff}, - {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, - {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff}, - {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff}, - {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, - {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff}, - {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff}, - {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, - {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, - {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, - {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, - {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, - {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, - {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, - {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, - {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff}, - {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff}, - {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff}, - {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00}, - {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff}, - {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00}, - {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff}, - {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00}, - {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, - {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, - {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, - {BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, - {BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, - {BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, - {BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, - {BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, - {BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, - {BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, - {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff}, - {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, - {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, - {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, - {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, - {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, - {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, - {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, - {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, - {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, - {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, - {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff}, - {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00}, - {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff}, - {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, - {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, - {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, - {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, - SROM4_TXCHAIN_MASK}, - {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, - SROM4_RXCHAIN_MASK}, - {BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, - SROM4_SWITCH_MASK}, - {BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G, - SROM8_FEM_TSSIPOS_MASK}, - {BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G, - SROM8_FEM_EXTPA_GAIN_MASK}, - {BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G, - SROM8_FEM_PDET_RANGE_MASK}, - {BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, - {BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G, - SROM8_FEM_ANTSWLUT_MASK}, - {BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G, - SROM8_FEM_TSSIPOS_MASK}, - {BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G, - SROM8_FEM_EXTPA_GAIN_MASK}, - {BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G, - SROM8_FEM_PDET_RANGE_MASK}, - {BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, - {BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G, - SROM8_FEM_ANTSWLUT_MASK}, - {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00}, - {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff}, - - {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, - {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, - {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, - 0xffff}, - {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, - 0x01ff}, - {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, - 0xfe00}, - {BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX, - SROM8_TS_SLP_OPT_CORRX, 0x00ff}, - {BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, - 0xfc00}, - {BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX, - SROM8_TS_SLP_OPT_CORRX, 0x0300}, - {BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX, - SROM8_FOC_HWIQ_IQSWP, 0x000f}, - {BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, - 0x0010}, - {BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, - 0x0020}, - {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, - 0x00ff}, - - {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, - {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff}, - {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff}, - {BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff}, - {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff}, - {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, - {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff}, - {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff}, - {BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff}, - {BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff}, - {BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff}, - {BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff}, - {BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff}, - {BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, - {BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff}, - {BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff}, - {BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff}, - {BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff}, - {BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff}, - {BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff}, - {BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff}, - {BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, - {BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff}, - {BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff}, - {BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff}, - {BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff}, - {BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff}, - {BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff}, - {BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff}, - {BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, - {BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff}, - {BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff}, - {BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff}, - {BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff}, - {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff}, - {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff}, - {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff}, - {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff}, - {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff}, - {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff}, - {BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, - - /* power per rate from sromrev 9 */ - {BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff}, - {BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, - {BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE, - SROM9_2GPO_LOFDMBW20, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE, - SROM9_2GPO_LOFDMBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE, - SROM9_5GLPO_LOFDMBW20, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE, - SROM9_5GLPO_LOFDMBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE, - SROM9_5GMPO_LOFDMBW20, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE, - SROM9_5GMPO_LOFDMBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE, - SROM9_5GHPO_LOFDMBW20, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff}, - {BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE, - SROM9_5GHPO_LOFDMBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff}, - {BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff}, - {BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff}, - {BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff}, - {BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff}, - {BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE, - SROM9_5GLPO_MCSBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff}, - {BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff}, - {BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff}, - {BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE, - SROM9_5GMPO_MCSBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff}, - {BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff}, - {BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff}, - {BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE, - SROM9_5GHPO_MCSBW20UL, 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff}, - {BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, - 0xffff}, - {BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff}, - {BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff}, - {BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff}, - - {BRCMS_SROM_NULL, 0, 0, 0, 0} -}; - -static const struct brcms_sromvar perpath_pci_sromvars[] = { - {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff}, - {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, - {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, - {BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, - {BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff}, - {BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff}, - {BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff}, - {BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff}, - {BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, - {BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, - {BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff}, - {BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff}, - {BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, - {BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1, - 0xffff}, - {BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2, - 0xffff}, - {BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, - {BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1, - 0xffff}, - {BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2, - 0xffff}, - {BRCMS_SROM_NULL, 0, 0, 0, 0} -}; - -/* crc table has the same contents for every device instance, so it can be - * shared between devices. */ -static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE]; - -static uint mask_shift(u16 mask) -{ - uint i; - for (i = 0; i < (sizeof(mask) << 3); i++) { - if (mask & (1 << i)) - return i; - } - return 0; -} - -static uint mask_width(u16 mask) -{ - int i; - for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) { - if (mask & (1 << i)) - return (uint) (i - mask_shift(mask) + 1); - } - return 0; -} - -static inline void le16_to_cpu_buf(u16 *buf, uint nwords) -{ - while (nwords--) - *(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords)); -} - -static inline void cpu_to_le16_buf(u16 *buf, uint nwords) -{ - while (nwords--) - *(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords)); -} - -/* - * convert binary srom data into linked list of srom variable items. - */ -static int -_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list) -{ - struct brcms_srom_list_head *entry; - enum brcms_srom_id id; - u16 w; - u32 val = 0; - const struct brcms_sromvar *srv; - uint width; - uint flags; - u32 sr = (1 << sromrev); - uint p; - uint pb = SROM8_PATH0; - const uint psz = SROM8_PATH1 - SROM8_PATH0; - - /* first store the srom revision */ - entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - entry->varid = BRCMS_SROM_REV; - entry->var_type = BRCMS_SROM_UNUMBER; - entry->uval = sromrev; - list_add(&entry->var_list, var_list); - - for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) { - enum brcms_srom_var_type type; - u8 ea[ETH_ALEN]; - u8 extra_space = 0; - - if ((srv->revmask & sr) == 0) - continue; - - flags = srv->flags; - id = srv->varid; - - /* This entry is for mfgc only. Don't generate param for it, */ - if (flags & SRFL_NOVAR) - continue; - - if (flags & SRFL_ETHADDR) { - /* - * stored in string format XX:XX:XX:XX:XX:XX (17 chars) - */ - ea[0] = (srom[srv->off] >> 8) & 0xff; - ea[1] = srom[srv->off] & 0xff; - ea[2] = (srom[srv->off + 1] >> 8) & 0xff; - ea[3] = srom[srv->off + 1] & 0xff; - ea[4] = (srom[srv->off + 2] >> 8) & 0xff; - ea[5] = srom[srv->off + 2] & 0xff; - /* 17 characters + string terminator - union size */ - extra_space = 18 - sizeof(s32); - type = BRCMS_SROM_STRING; - } else { - w = srom[srv->off]; - val = (w & srv->mask) >> mask_shift(srv->mask); - width = mask_width(srv->mask); - - while (srv->flags & SRFL_MORE) { - srv++; - if (srv->off == 0) - continue; - - w = srom[srv->off]; - val += - ((w & srv->mask) >> mask_shift(srv-> - mask)) << - width; - width += mask_width(srv->mask); - } - - if ((flags & SRFL_NOFFS) - && ((int)val == (1 << width) - 1)) - continue; - - if (flags & SRFL_CCODE) { - type = BRCMS_SROM_STRING; - } else if (flags & SRFL_LEDDC) { - /* LED Powersave duty cycle has to be scaled: - *(oncount >> 24) (offcount >> 8) - */ - u32 w32 = /* oncount */ - (((val >> 8) & 0xff) << 24) | - /* offcount */ - (((val & 0xff)) << 8); - type = BRCMS_SROM_UNUMBER; - val = w32; - } else if ((flags & SRFL_PRSIGN) - && (val & (1 << (width - 1)))) { - type = BRCMS_SROM_SNUMBER; - val |= ~0 << width; - } else - type = BRCMS_SROM_UNUMBER; - } - - entry = kzalloc(sizeof(struct brcms_srom_list_head) + - extra_space, GFP_KERNEL); - if (!entry) - return -ENOMEM; - entry->varid = id; - entry->var_type = type; - if (flags & SRFL_ETHADDR) { - snprintf(entry->buf, 18, "%pM", ea); - } else if (flags & SRFL_CCODE) { - if (val == 0) - entry->buf[0] = '\0'; - else - snprintf(entry->buf, 3, "%c%c", - (val >> 8), (val & 0xff)); - } else { - entry->uval = val; - } - - list_add(&entry->var_list, var_list); - } - - for (p = 0; p < MAX_PATH_SROM; p++) { - for (srv = perpath_pci_sromvars; - srv->varid != BRCMS_SROM_NULL; srv++) { - if ((srv->revmask & sr) == 0) - continue; - - if (srv->flags & SRFL_NOVAR) - continue; - - w = srom[pb + srv->off]; - val = (w & srv->mask) >> mask_shift(srv->mask); - width = mask_width(srv->mask); - - /* Cheating: no per-path var is more than - * 1 word */ - if ((srv->flags & SRFL_NOFFS) - && ((int)val == (1 << width) - 1)) - continue; - - entry = - kzalloc(sizeof(struct brcms_srom_list_head), - GFP_KERNEL); - if (!entry) - return -ENOMEM; - entry->varid = srv->varid+p; - entry->var_type = BRCMS_SROM_UNUMBER; - entry->uval = val; - list_add(&entry->var_list, var_list); - } - pb += psz; - } - return 0; -} - -/* - * The crc check is done on a little-endian array, we need - * to switch the bytes around before checking crc (and - * then switch it back). - */ -static int do_crc_check(u16 *buf, unsigned nwords) -{ - u8 crc; - - cpu_to_le16_buf(buf, nwords); - crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE); - le16_to_cpu_buf(buf, nwords); - - return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table); -} - -/* - * Read in and validate sprom. - * Return 0 on success, nonzero on error. - */ -static int -sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc) -{ - int err = 0; - uint i; - struct bcma_device *core; - uint sprom_offset; - - /* determine core to read */ - if (ai_get_ccrev(sih) < 32) { - core = ai_findcore(sih, BCMA_CORE_80211, 0); - sprom_offset = PCI_BAR0_SPROM_OFFSET; - } else { - core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0); - sprom_offset = CHIPCREGOFFS(sromotp); - } - - /* read the sprom */ - for (i = 0; i < nwords; i++) - buf[i] = bcma_read16(core, sprom_offset+i*2); - - if (buf[0] == 0xffff) - /* - * The hardware thinks that an srom that starts with - * 0xffff is blank, regardless of the rest of the - * content, so declare it bad. - */ - return -ENODATA; - - if (check_crc && !do_crc_check(buf, nwords)) - err = -EIO; - - return err; -} - -static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords) -{ - u8 *otp; - uint sz = OTP_SZ_MAX / 2; /* size in words */ - int err = 0; - - otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC); - if (otp == NULL) - return -ENOMEM; - - err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz); - - sz = min_t(uint, sz, nwords); - memcpy(buf, otp, sz * 2); - - kfree(otp); - - /* Check CRC */ - if (buf[0] == 0xffff) - /* The hardware thinks that an srom that starts with 0xffff - * is blank, regardless of the rest of the content, so declare - * it bad. - */ - return -ENODATA; - - /* fixup the endianness so crc8 will pass */ - cpu_to_le16_buf(buf, sz); - if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2, - CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table)) - err = -EIO; - else - /* now correct the endianness of the byte array */ - le16_to_cpu_buf(buf, sz); - - return err; -} - -/* - * Initialize nonvolatile variable table from sprom. - * Return 0 on success, nonzero on error. - */ -int srom_var_init(struct si_pub *sih) -{ - u16 *srom; - u8 sromrev = 0; - u32 sr; - int err = 0; - - /* - * Apply CRC over SROM content regardless SROM is present or not. - */ - srom = kmalloc(SROM_MAX, GFP_ATOMIC); - if (!srom) - return -ENOMEM; - - crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY); - if (ai_is_sprom_available(sih)) { - err = sprom_read_pci(sih, srom, SROM4_WORDS, true); - - if (err == 0) - /* srom read and passed crc */ - /* top word of sprom contains version and crc8 */ - sromrev = srom[SROM4_CRCREV] & 0xff; - } else { - /* Use OTP if SPROM not available */ - err = otp_read_pci(sih, srom, SROM4_WORDS); - if (err == 0) - /* OTP only contain SROM rev8/rev9 for now */ - sromrev = srom[SROM4_CRCREV] & 0xff; - } - - if (!err) { - struct si_info *sii = (struct si_info *)sih; - - /* Bitmask for the sromrev */ - sr = 1 << sromrev; - - /* - * srom version check: Current valid versions: 8, 9 - */ - if ((sr & 0x300) == 0) { - err = -EINVAL; - goto errout; - } - - INIT_LIST_HEAD(&sii->var_list); - - /* parse SROM into name=value pairs. */ - err = _initvars_srom_pci(sromrev, srom, &sii->var_list); - if (err) - srom_free_vars(sih); - } - -errout: - kfree(srom); - return err; -} - -void srom_free_vars(struct si_pub *sih) -{ - struct si_info *sii; - struct brcms_srom_list_head *entry, *next; - - sii = (struct si_info *)sih; - list_for_each_entry_safe(entry, next, &sii->var_list, var_list) { - list_del(&entry->var_list); - kfree(entry); - } -} - -/* - * Search the name=value vars for a specific one and return its value. - * Returns NULL if not found. - */ -char *getvar(struct si_pub *sih, enum brcms_srom_id id) -{ - struct si_info *sii; - struct brcms_srom_list_head *entry; - - sii = (struct si_info *)sih; - - list_for_each_entry(entry, &sii->var_list, var_list) - if (entry->varid == id) - return &entry->buf[0]; - - /* nothing found */ - return NULL; -} - -/* - * Search the vars for a specific one and return its value as - * an integer. Returns 0 if not found.- - */ -int getintvar(struct si_pub *sih, enum brcms_srom_id id) -{ - struct si_info *sii; - struct brcms_srom_list_head *entry; - unsigned long res; - - sii = (struct si_info *)sih; - - list_for_each_entry(entry, &sii->var_list, var_list) - if (entry->varid == id) { - if (entry->var_type == BRCMS_SROM_SNUMBER || - entry->var_type == BRCMS_SROM_UNUMBER) - return (int)entry->sval; - else if (!kstrtoul(&entry->buf[0], 0, &res)) - return (int)res; - } - - return 0; -} diff --git a/drivers/net/wireless/brcm80211/brcmsmac/srom.h b/drivers/net/wireless/brcm80211/brcmsmac/srom.h deleted file mode 100644 index f2a58f262c9..00000000000 --- a/drivers/net/wireless/brcm80211/brcmsmac/srom.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (c) 2010 Broadcom Corporation - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BRCM_SROM_H_ -#define _BRCM_SROM_H_ - -#include "types.h" - -/* Prototypes */ -extern int srom_var_init(struct si_pub *sih); -extern void srom_free_vars(struct si_pub *sih); - -extern int srom_read(struct si_pub *sih, uint bus, void *curmap, - uint byteoff, uint nbytes, u16 *buf, bool check_crc); - -#endif /* _BRCM_SROM_H_ */ diff --git a/drivers/net/wireless/brcm80211/brcmsmac/stf.c b/drivers/net/wireless/brcm80211/brcmsmac/stf.c index d8f528eb180..ed1d1aa71d2 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/stf.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/stf.c @@ -370,9 +370,11 @@ void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc) void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc) { + struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom; + /* get available rx/tx chains */ - wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN); - wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN); + wlc->stf->hw_txchain = sprom->txchain; + wlc->stf->hw_rxchain = sprom->rxchain; /* these parameter are intended to be used for all PHY types */ if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) { diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c index 01dc4426731..e55ec6c8a92 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c @@ -31,6 +31,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/sched.h> +#include <net/mac80211.h> #include "iwl-dev.h" #include "iwl-io.h" @@ -273,9 +274,20 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) return; } + /* + * Possible situations when BT needs to take over for receive, + * at the same time where STA needs to response to AP's frame(s), + * reduce the tx power of the required response frames, by that, + * allow the concurrent BT receive & WiFi transmit + * (BT - ANT A, WiFi -ANT B), without interference to one another + * + * Reduced tx power apply to control frames only (ACK/Back/CTS) + * when indicated by the BT config command + */ basic.kill_ack_mask = priv->kill_ack_mask; basic.kill_cts_mask = priv->kill_cts_mask; - basic.reduce_txpower = priv->reduced_txpower; + if (priv->reduced_txpower) + basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR; basic.valid = priv->bt_valid; /* @@ -589,13 +601,31 @@ static bool iwlagn_set_kill_msk(struct iwl_priv *priv, return need_update; } +/* + * Upon RSSI changes, sends a bt config command with following changes + * 1. enable/disable "reduced control frames tx power + * 2. update the "kill)ack_mask" and "kill_cts_mask" + * + * If "reduced tx power" is enabled, uCode shall + * 1. ACK/Back/CTS rate shall reduced to 6Mbps + * 2. not use duplciate 20/40MHz mode + */ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, struct iwl_bt_uart_msg *uart_msg) { bool need_update = false; + struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS]; + int ave_rssi; + ave_rssi = ieee80211_ave_rssi(ctx->vif); + if (!ave_rssi) { + /* no rssi data, no changes to reduce tx power */ + IWL_DEBUG_COEX(priv, "no rssi data available\n"); + return need_update; + } if (!priv->reduced_txpower && !iwl_is_associated(priv, IWL_RXON_CTX_PAN) && + (ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) && (uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK | BT_UART_MSG_FRAME3OBEX_MSK)) && !(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK | @@ -606,13 +636,14 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv, need_update = true; } else if (priv->reduced_txpower && (iwl_is_associated(priv, IWL_RXON_CTX_PAN) || + (ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) || (uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK | BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) || !(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK | BT_UART_MSG_FRAME3OBEX_MSK)))) { /* disable reduced tx power */ priv->reduced_txpower = false; - priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR; + priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR; need_update = true; } diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c index 74fbee62730..0a3aa7c8300 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c @@ -61,6 +61,10 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv, RXON_FILTER_ACCEPT_GRP_MSK; break; + case NL80211_IFTYPE_MONITOR: + ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER; + break; + default: IWL_ERR(priv, "Unsupported interface type %d\n", ctx->vif->type); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index f2e9f298a94..3366e2e2f00 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -590,11 +590,17 @@ turn_off: spin_unlock_bh(&priv->sta_lock); if (test_bit(txq_id, priv->agg_q_alloc)) { - /* If the transport didn't know that we wanted to start - * agreggation, don't tell it that we want to stop them + /* + * If the transport didn't know that we wanted to start + * agreggation, don't tell it that we want to stop them. + * This can happen when we don't get the addBA response on + * time, or we hadn't time to drain the AC queues. */ - if (agg_state != IWL_AGG_STARTING) + if (agg_state == IWL_AGG_ON) iwl_trans_tx_agg_disable(priv->trans, txq_id); + else + IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n", + agg_state); iwlagn_dealloc_agg_txq(priv, txq_id); } @@ -1300,10 +1306,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, (u8 *) &ba_resp->sta_addr_lo32, ba_resp->sta_id); IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, " - "scd_flow = %d, scd_ssn = %d\n", + "scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n", ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl), (unsigned long long)le64_to_cpu(ba_resp->bitmap), - scd_flow, ba_resp_scd_ssn); + scd_flow, ba_resp_scd_ssn, ba_resp->txed, + ba_resp->txed_2_done); /* Mark that the expected block-ack response arrived */ agg->wait_for_ba = false; @@ -1319,8 +1326,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, */ ba_resp->txed = ba_resp->txed_2_done; } - IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n", - ba_resp->txed, ba_resp->txed_2_done); priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn; diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 8d7637083fc..ec36e2b020b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -603,7 +603,7 @@ void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags) priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY; priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID; priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes = - BIT(NL80211_IFTYPE_ADHOC); + BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR); priv->contexts[IWL_RXON_CTX_BSS].interface_modes = BIT(NL80211_IFTYPE_STATION); priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP; diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 83a6930f365..9af6a239b38 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -1910,6 +1910,8 @@ enum iwl_bt_kill_idx { IWLAGN_BT_VALID_REDUCED_TX_PWR | \ IWLAGN_BT_VALID_3W_LUT) +#define IWLAGN_BT_REDUCED_TX_PWR BIT(0) + #define IWLAGN_BT_DECISION_LUT_SIZE 12 struct iwl_basic_bt_cmd { @@ -1923,6 +1925,10 @@ struct iwl_basic_bt_cmd { u8 bt3_timer_t2_value; __le16 bt4_reaction_time; /* unused */ __le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE]; + /* + * bit 0: use reduced tx power for control frame + * bit 1 - 7: reserved + */ u8 reduce_txpower; u8 reserved; __le16 valid; @@ -2272,7 +2278,6 @@ struct iwl_ssid_ie { #define IWL_GOOD_CRC_TH_DISABLED 0 #define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1) #define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff) -#define IWL_MAX_SCAN_SIZE 1024 #define IWL_MAX_CMD_SIZE 4096 /* diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c index d33cc9cc7d3..ab2f4d7500a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-mac80211.c +++ b/drivers/net/wireless/iwlwifi/iwl-mac80211.c @@ -150,6 +150,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, IEEE80211_HW_QUEUE_CONTROL | IEEE80211_HW_SUPPORTS_PS | IEEE80211_HW_SUPPORTS_DYNAMIC_PS | + IEEE80211_HW_WANT_MONITOR_VIF | IEEE80211_HW_SCAN_WHILE_IDLE; hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE; @@ -223,8 +224,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv, hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT; hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX; - /* we create the 802.11 header and a zero-length SSID element */ - hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2; + /* we create the 802.11 header and a max-length SSID element */ + hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34; /* * We don't use all queues: 4 and 9 are unused and any diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 8352265dbc4..544ddf17f5b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -253,6 +253,8 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv, IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n", skip, period); + /* The power level here is 0-4 (used as array index), but user expects + to see 1-5 (according to spec). */ IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1); } @@ -308,10 +310,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv, priv->power_data.debug_sleep_level_override, dtimper); else { + /* Note that the user parameter is 1-5 (according to spec), + but we pass 0-4 because it acts as an array index. */ if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 && - iwlwifi_mod_params.power_level <= IWL_POWER_INDEX_5) + iwlwifi_mod_params.power_level <= IWL_POWER_NUM) iwl_static_sleep_cmd(priv, cmd, - iwlwifi_mod_params.power_level, dtimper); + iwlwifi_mod_params.power_level - 1, dtimper); else iwl_static_sleep_cmd(priv, cmd, IWL_POWER_INDEX_1, dtimper); diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index a8437a6bc18..031d8e21f82 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -52,6 +52,7 @@ #define IWL_PASSIVE_DWELL_TIME_52 (10) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 +#define MAX_SCAN_CHANNEL 50 static int iwl_send_scan_abort(struct iwl_priv *priv) { @@ -616,7 +617,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, */ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, - const u8 *ies, int ie_len, int left) + const u8 *ies, int ie_len, const u8 *ssid, + u8 ssid_len, int left) { int len = 0; u8 *pos = NULL; @@ -638,14 +640,18 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta, /* ...next IE... */ pos = &frame->u.probe_req.variable[0]; - /* fill in our indirect SSID IE */ - left -= 2; + /* fill in our SSID IE */ + left -= ssid_len + 2; if (left < 0) return 0; *pos++ = WLAN_EID_SSID; - *pos++ = 0; + *pos++ = ssid_len; + if (ssid && ssid_len) { + memcpy(pos, ssid, ssid_len); + pos += ssid_len; + } - len += 2; + len += ssid_len + 2; if (WARN_ON(left < ie_len)) return len; @@ -679,6 +685,15 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) u8 active_chains; u8 scan_tx_antennas = priv->hw_params.valid_tx_ant; int ret; + int scan_cmd_size = sizeof(struct iwl_scan_cmd) + + MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) + + priv->fw->ucode_capa.max_probe_length; + const u8 *ssid = NULL; + u8 ssid_len = 0; + + if (WARN_ON_ONCE(priv->scan_request && + priv->scan_request->n_channels > MAX_SCAN_CHANNEL)) + return -EINVAL; lockdep_assert_held(&priv->mutex); @@ -686,8 +701,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) ctx = iwl_rxon_ctx_from_vif(vif); if (!priv->scan_cmd) { - priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) + - IWL_MAX_SCAN_SIZE, GFP_KERNEL); + priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL); if (!priv->scan_cmd) { IWL_DEBUG_SCAN(priv, "fail to allocate memory for scan\n"); @@ -695,7 +709,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) } } scan = priv->scan_cmd; - memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE); + memset(scan, 0, scan_cmd_size); scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH; scan->quiet_time = IWL_ACTIVE_QUIET_TIME; @@ -746,10 +760,18 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) if (priv->scan_request->n_ssids) { int i, p = 0; IWL_DEBUG_SCAN(priv, "Kicking off active scan\n"); - for (i = 0; i < priv->scan_request->n_ssids; i++) { - /* always does wildcard anyway */ - if (!priv->scan_request->ssids[i].ssid_len) - continue; + /* + * The highest priority SSID is inserted to the + * probe request template. + */ + ssid_len = priv->scan_request->ssids[0].ssid_len; + ssid = priv->scan_request->ssids[0].ssid; + + /* + * Invert the order of ssids, the firmware will invert + * it back. + */ + for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) { scan->direct_scan[p].id = WLAN_EID_SSID; scan->direct_scan[p].len = priv->scan_request->ssids[i].ssid_len; @@ -883,7 +905,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) vif->addr, priv->scan_request->ie, priv->scan_request->ie_len, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + ssid, ssid_len, + scan_cmd_size - sizeof(*scan)); break; case IWL_SCAN_RADIO_RESET: case IWL_SCAN_ROC: @@ -891,7 +914,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif) cmd_len = iwl_fill_probe_req( (struct ieee80211_mgmt *)scan->data, iwl_bcast_addr, NULL, 0, - IWL_MAX_SCAN_SIZE - sizeof(*scan)); + NULL, 0, + scan_cmd_size - sizeof(*scan)); break; default: BUG(); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 03c0c6b1372..fb787df0166 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -746,6 +746,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) hwsim_check_sta_magic(txi->control.sta); ieee80211_tx_info_clear_status(txi); + + /* frame was transmitted at most favorable rate at first attempt */ + txi->control.rates[0].count = 1; + txi->control.rates[1].idx = -1; + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) txi->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile index 5c1a46bf1e1..3f66ebb0a63 100644 --- a/drivers/net/wireless/mwifiex/Makefile +++ b/drivers/net/wireless/mwifiex/Makefile @@ -29,6 +29,8 @@ mwifiex-y += scan.o mwifiex-y += join.o mwifiex-y += sta_ioctl.o mwifiex-y += sta_cmd.o +mwifiex-y += uap_cmd.o +mwifiex-y += ie.o mwifiex-y += sta_cmdresp.o mwifiex-y += sta_event.o mwifiex-y += sta_tx.o diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c78ea873a63..87671446e24 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -20,6 +20,23 @@ #include "cfg80211.h" #include "main.h" +static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = { + { + .max = 1, .types = BIT(NL80211_IFTYPE_STATION), + }, + { + .max = 1, .types = BIT(NL80211_IFTYPE_AP), + }, +}; + +static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { + .limits = mwifiex_ap_sta_limits, + .num_different_channels = 1, + .n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits), + .max_interfaces = MWIFIEX_MAX_BSS_NUM, + .beacon_int_infra_match = true, +}; + /* * This function maps the nl802.11 channel type into driver channel type. * @@ -67,7 +84,7 @@ mwifiex_is_alg_wep(u32 cipher) /* * This function retrieves the private structure from kernel wiphy structure. */ -static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy) +static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy) { return (void *) (*(unsigned long *) wiphy_priv(wiphy)); } @@ -80,8 +97,10 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); + const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; - if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) { + if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) { wiphy_err(wiphy, "deleting the crypto keys\n"); return -EFAULT; } @@ -98,7 +117,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, enum nl80211_tx_power_setting type, int mbm) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct mwifiex_power_cfg power_cfg; int dbm = MBM_TO_DBM(mbm); @@ -109,6 +129,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy, power_cfg.is_power_auto = 1; } + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + return mwifiex_set_tx_power(priv, &power_cfg); } @@ -148,7 +170,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev, if (!priv->sec_info.wep_enabled) return 0; - if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) { + if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) { wiphy_err(wiphy, "set default Tx key index\n"); return -EFAULT; } @@ -165,9 +187,11 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev, struct key_params *params) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev); + const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; + const u8 *peer_mac = pairwise ? mac_addr : bc_mac; if (mwifiex_set_encode(priv, params->key, params->key_len, - key_index, 0)) { + key_index, peer_mac, 0)) { wiphy_err(wiphy, "crypto keys added\n"); return -EFAULT; } @@ -192,13 +216,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) enum ieee80211_band band; struct ieee80211_supported_band *sband; struct ieee80211_channel *ch; - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg; /* Set country code */ - domain_info->country_code[0] = priv->country_code[0]; - domain_info->country_code[1] = priv->country_code[1]; + domain_info->country_code[0] = adapter->country_code[0]; + domain_info->country_code[1] = adapter->country_code[1]; domain_info->country_code[2] = ' '; band = mwifiex_band_to_radio_type(adapter->config_bands); @@ -250,6 +274,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) domain_info->no_of_triplet = no_of_triplet; + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO, HostCmd_ACT_GEN_SET, 0, NULL)) { wiphy_err(wiphy, "11D: setting domain info in FW\n"); @@ -272,12 +298,12 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy) static int mwifiex_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); - wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain" - " %c%c\n", request->alpha2[0], request->alpha2[1]); + wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n", + request->alpha2[0], request->alpha2[1]); - memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2)); switch (request->initiator) { case NL80211_REGDOM_SET_BY_DRIVER: @@ -361,33 +387,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv, if (mwifiex_bss_set_channel(priv, &cfp)) return -EFAULT; - return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); -} - -/* - * CFG802.11 operation handler to set channel. - * - * This function can only be used when station is not connected. - */ -static int -mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - struct mwifiex_private *priv; - - if (dev) - priv = mwifiex_netdev_get_priv(dev); + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) + return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); else - priv = mwifiex_cfg80211_get_priv(wiphy); - - if (priv->media_connected) { - wiphy_err(wiphy, "This setting is valid only when station " - "is not connected\n"); - return -EINVAL; - } - - return mwifiex_set_rf_channel(priv, chan, channel_type); + return mwifiex_uap_set_channel(priv, cfp.channel); } /* @@ -399,18 +402,13 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev, static int mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr) { - int ret; - if (frag_thr < MWIFIEX_FRAG_MIN_VALUE || frag_thr > MWIFIEX_FRAG_MAX_VALUE) - return -EINVAL; - - /* Send request to firmware */ - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, FRAG_THRESH_I, - &frag_thr); + frag_thr = MWIFIEX_FRAG_MAX_VALUE; - return ret; + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, FRAG_THRESH_I, + &frag_thr); } /* @@ -439,19 +437,85 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr) static int mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - int ret = 0; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; + struct mwifiex_uap_bss_param *bss_cfg; + int ret, bss_started, i; + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + + switch (priv->bss_role) { + case MWIFIEX_BSS_ROLE_UAP: + bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), + GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + mwifiex_set_sys_config_invalid_data(bss_cfg); + + if (changed & WIPHY_PARAM_RTS_THRESHOLD) + bss_cfg->rts_threshold = wiphy->rts_threshold; + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) + bss_cfg->frag_threshold = wiphy->frag_threshold; + if (changed & WIPHY_PARAM_RETRY_LONG) + bss_cfg->retry_limit = wiphy->retry_long; + + bss_started = priv->bss_started; + + ret = mwifiex_send_cmd_sync(priv, + HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, + NULL); + if (ret) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + kfree(bss_cfg); + return ret; + } - if (changed & WIPHY_PARAM_RTS_THRESHOLD) { - ret = mwifiex_set_rts(priv, wiphy->rts_threshold); - if (ret) - return ret; - } + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg); - if (changed & WIPHY_PARAM_FRAG_THRESHOLD) - ret = mwifiex_set_frag(priv, wiphy->frag_threshold); + kfree(bss_cfg); - return ret; + if (ret) { + wiphy_err(wiphy, "Failed to set bss config\n"); + return ret; + } + + if (!bss_started) + break; + + ret = mwifiex_send_cmd_async(priv, + HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, + NULL); + if (ret) { + wiphy_err(wiphy, "Failed to start BSS\n"); + return ret; + } + + break; + case MWIFIEX_BSS_ROLE_STA: + if (changed & WIPHY_PARAM_RTS_THRESHOLD) { + ret = mwifiex_set_rts(priv, + wiphy->rts_threshold); + if (ret) + return ret; + } + if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { + ret = mwifiex_set_frag(priv, + wiphy->frag_threshold); + if (ret) + return ret; + } + break; + } + } + + return 0; } /* @@ -466,31 +530,59 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy, int ret; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - if (priv->bss_mode == type) { - wiphy_warn(wiphy, "already set to required type\n"); - return 0; - } - - priv->bss_mode = type; - - switch (type) { + switch (dev->ieee80211_ptr->iftype) { case NL80211_IFTYPE_ADHOC: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC; - wiphy_dbg(wiphy, "info: setting interface type to adhoc\n"); + switch (type) { + case NL80211_IFTYPE_STATION: + break; + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name); + case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_AP: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } break; case NL80211_IFTYPE_STATION: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - wiphy_dbg(wiphy, "info: setting interface type to managed\n"); + switch (type) { + case NL80211_IFTYPE_ADHOC: + break; + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name); + case NL80211_IFTYPE_STATION: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_AP: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } + break; + case NL80211_IFTYPE_AP: + switch (type) { + case NL80211_IFTYPE_UNSPECIFIED: + wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name); + case NL80211_IFTYPE_AP: /* This shouldn't happen */ + return 0; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_STATION: + default: + wiphy_err(wiphy, "%s: changing to %d not supported\n", + dev->name, type); + return -EOPNOTSUPP; + } break; - case NL80211_IFTYPE_UNSPECIFIED: - dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION; - wiphy_dbg(wiphy, "info: setting interface type to auto\n"); - return 0; default: - wiphy_err(wiphy, "unknown interface type: %d\n", type); - return -EINVAL; + wiphy_err(wiphy, "%s: unknown iftype: %d\n", + dev->name, dev->ieee80211_ptr->iftype); + return -EOPNOTSUPP; } + dev->ieee80211_ptr->iftype = type; + priv->bss_mode = type; mwifiex_deauthenticate(priv, NULL); priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM; @@ -804,6 +896,90 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy, return 0; } +/* cfg80211 operation handler for stop ap. + * Function stops BSS running at uAP interface. + */ +static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +{ + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (mwifiex_del_mgmt_ies(priv)) + wiphy_err(wiphy, "Failed to delete mgmt IEs!\n"); + + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + return -1; + } + + return 0; +} + +/* cfg80211 operation handler for start_ap. + * Function sets beacon period, DTIM period, SSID and security into + * AP config structure. + * AP is configured with these settings and BSS is started. + */ +static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, + struct net_device *dev, + struct cfg80211_ap_settings *params) +{ + struct mwifiex_uap_bss_param *bss_cfg; + struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) + return -1; + if (mwifiex_set_mgmt_ies(priv, params)) + return -1; + + bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + mwifiex_set_sys_config_invalid_data(bss_cfg); + + if (params->beacon_interval) + bss_cfg->beacon_period = params->beacon_interval; + if (params->dtim_period) + bss_cfg->dtim_period = params->dtim_period; + + if (params->ssid && params->ssid_len) { + memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len); + bss_cfg->ssid.ssid_len = params->ssid_len; + } + + if (mwifiex_set_secure_params(priv, bss_cfg, params)) { + kfree(bss_cfg); + wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); + return -1; + } + + if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to stop the BSS\n"); + kfree(bss_cfg); + return -1; + } + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg)) { + wiphy_err(wiphy, "Failed to set the SSID\n"); + kfree(bss_cfg); + return -1; + } + + kfree(bss_cfg); + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START, + HostCmd_ACT_GEN_SET, 0, NULL)) { + wiphy_err(wiphy, "Failed to start the BSS\n"); + return -1; + } + + return 0; +} + /* * CFG802.11 operation handler for disconnection request. * @@ -923,7 +1099,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, priv->wep_key_curr_index = 0; priv->sec_info.encryption_mode = 0; priv->sec_info.is_authtype_auto = 0; - ret = mwifiex_set_encode(priv, NULL, 0, 0, 1); + ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1); if (mode == NL80211_IFTYPE_ADHOC) { /* "privacy" is set only for ad-hoc mode */ @@ -971,7 +1147,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, " with key len %d\n", sme->key_len); priv->wep_key_curr_index = sme->key_idx; ret = mwifiex_set_encode(priv, sme->key, sme->key_len, - sme->key_idx, 0); + sme->key_idx, NULL, 0); } } done: @@ -1050,6 +1226,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev, goto done; } + if (priv->bss_mode == NL80211_IFTYPE_AP) { + wiphy_err(wiphy, "skip association request for AP interface\n"); + goto done; + } + wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n", (char *) sme->ssid, sme->bssid); @@ -1283,15 +1464,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, u32 *flags, struct vif_params *params) { - struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy); - struct mwifiex_adapter *adapter; + struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); + struct mwifiex_private *priv; struct net_device *dev; void *mdev_priv; + struct wireless_dev *wdev; - if (!priv) - return NULL; - - adapter = priv->adapter; if (!adapter) return NULL; @@ -1299,12 +1477,21 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, case NL80211_IFTYPE_UNSPECIFIED: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; if (priv->bss_mode) { - wiphy_err(wiphy, "cannot create multiple" - " station/adhoc interfaces\n"); + wiphy_err(wiphy, + "cannot create multiple sta/adhoc ifaces\n"); return NULL; } + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) + return NULL; + + wdev->wiphy = wiphy; + priv->wdev = wdev; + wdev->iftype = NL80211_IFTYPE_STATION; + if (type == NL80211_IFTYPE_UNSPECIFIED) priv->bss_mode = NL80211_IFTYPE_STATION; else @@ -1312,11 +1499,36 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, priv->bss_type = MWIFIEX_BSS_TYPE_STA; priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; - priv->bss_priority = 0; + priv->bss_priority = MWIFIEX_BSS_ROLE_STA; priv->bss_role = MWIFIEX_BSS_ROLE_STA; priv->bss_num = 0; break; + case NL80211_IFTYPE_AP: + priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP]; + + if (priv->bss_mode) { + wiphy_err(wiphy, "Can't create multiple AP interfaces"); + return NULL; + } + + wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); + if (!wdev) + return NULL; + + priv->wdev = wdev; + wdev->wiphy = wiphy; + wdev->iftype = NL80211_IFTYPE_AP; + + priv->bss_type = MWIFIEX_BSS_TYPE_UAP; + priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II; + priv->bss_priority = MWIFIEX_BSS_ROLE_UAP; + priv->bss_role = MWIFIEX_BSS_ROLE_UAP; + priv->bss_started = 0; + priv->bss_num = 0; + priv->bss_mode = type; + + break; default: wiphy_err(wiphy, "type not supported\n"); return NULL; @@ -1329,6 +1541,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, goto error; } + mwifiex_init_priv_params(priv, dev); + priv->netdev = dev; + + mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv); + + if (adapter->config_bands & BAND_A) + mwifiex_setup_ht_caps( + &wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv); + dev_net_set(dev, wiphy_net(wiphy)); dev->ieee80211_ptr = priv->wdev; dev->ieee80211_ptr->iftype = priv->bss_mode; @@ -1343,9 +1564,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, mdev_priv = netdev_priv(dev); *((unsigned long *) mdev_priv) = (unsigned long) priv; - priv->netdev = dev; - mwifiex_init_priv_params(priv, dev); - SET_NETDEV_DEV(dev, adapter->dev); /* Register network device */ @@ -1417,7 +1635,6 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .get_station = mwifiex_cfg80211_get_station, .dump_station = mwifiex_cfg80211_dump_station, .set_wiphy_params = mwifiex_cfg80211_set_wiphy_params, - .set_channel = mwifiex_cfg80211_set_channel, .join_ibss = mwifiex_cfg80211_join_ibss, .leave_ibss = mwifiex_cfg80211_leave_ibss, .add_key = mwifiex_cfg80211_add_key, @@ -1426,6 +1643,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { .set_power_mgmt = mwifiex_cfg80211_set_power_mgmt, .set_tx_power = mwifiex_cfg80211_set_tx_power, .set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask, + .start_ap = mwifiex_cfg80211_start_ap, + .stop_ap = mwifiex_cfg80211_stop_ap, .set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config, }; @@ -1436,82 +1655,67 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = { * default parameters and handler function pointers, and finally * registers the device. */ -int mwifiex_register_cfg80211(struct mwifiex_private *priv) + +int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) { int ret; void *wdev_priv; - struct wireless_dev *wdev; - struct ieee80211_sta_ht_cap *ht_info; + struct wiphy *wiphy; + struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA]; u8 *country_code; - wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL); - if (!wdev) { - dev_err(priv->adapter->dev, "%s: allocating wireless device\n", - __func__); - return -ENOMEM; - } - wdev->wiphy = - wiphy_new(&mwifiex_cfg80211_ops, - sizeof(struct mwifiex_private *)); - if (!wdev->wiphy) { - kfree(wdev); + /* create a new wiphy for use with cfg80211 */ + wiphy = wiphy_new(&mwifiex_cfg80211_ops, + sizeof(struct mwifiex_adapter *)); + if (!wiphy) { + dev_err(adapter->dev, "%s: creating new wiphy\n", __func__); return -ENOMEM; } - wdev->iftype = NL80211_IFTYPE_STATION; - wdev->wiphy->max_scan_ssids = 10; - wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; - wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - - wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; - ht_info = &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap; - mwifiex_setup_ht_caps(ht_info, priv); - - if (priv->adapter->config_bands & BAND_A) { - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; - ht_info = &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap; - mwifiex_setup_ht_caps(ht_info, priv); - } else { - wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; - } + wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH; + wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN; + wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); + + wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz; + if (adapter->config_bands & BAND_A) + wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz; + else + wiphy->bands[IEEE80211_BAND_5GHZ] = NULL; + + wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta; + wiphy->n_iface_combinations = 1; /* Initialize cipher suits */ - wdev->wiphy->cipher_suites = mwifiex_cipher_suites; - wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); + wiphy->cipher_suites = mwifiex_cipher_suites; + wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites); - memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN); - wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN); + wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM; + wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY; /* Reserve space for mwifiex specific private data for BSS */ - wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); - - wdev->wiphy->reg_notifier = mwifiex_reg_notifier; + wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); - /* Set struct mwifiex_private pointer in wiphy_priv */ - wdev_priv = wiphy_priv(wdev->wiphy); + wiphy->reg_notifier = mwifiex_reg_notifier; - *(unsigned long *) wdev_priv = (unsigned long) priv; + /* Set struct mwifiex_adapter pointer in wiphy_priv */ + wdev_priv = wiphy_priv(wiphy); + *(unsigned long *)wdev_priv = (unsigned long)adapter; - set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev); + set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev); - ret = wiphy_register(wdev->wiphy); + ret = wiphy_register(wiphy); if (ret < 0) { - dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n", - __func__); - wiphy_free(wdev->wiphy); - kfree(wdev); + dev_err(adapter->dev, + "%s: wiphy_register failed: %d\n", __func__, ret); + wiphy_free(wiphy); return ret; - } else { - dev_dbg(priv->adapter->dev, - "info: successfully registered wiphy device\n"); } - country_code = mwifiex_11d_code_2_region(priv->adapter->region_code); - if (country_code && regulatory_hint(wdev->wiphy, country_code)) - dev_err(priv->adapter->dev, - "%s: regulatory_hint failed\n", __func__); - - priv->wdev = wdev; + if (country_code && regulatory_hint(wiphy, country_code)) + dev_err(adapter->dev, "regulatory_hint() failed\n"); + adapter->wiphy = wiphy; return ret; } diff --git a/drivers/net/wireless/mwifiex/cfg80211.h b/drivers/net/wireless/mwifiex/cfg80211.h index 76c76c60438..c5848934f11 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.h +++ b/drivers/net/wireless/mwifiex/cfg80211.h @@ -24,6 +24,6 @@ #include "main.h" -int mwifiex_register_cfg80211(struct mwifiex_private *); +int mwifiex_register_cfg80211(struct mwifiex_adapter *); #endif diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c index 1710beffb93..51e023ec1de 100644 --- a/drivers/net/wireless/mwifiex/cmdevt.c +++ b/drivers/net/wireless/mwifiex/cmdevt.c @@ -440,6 +440,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter) do_gettimeofday(&tstamp); dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n", tstamp.tv_sec, tstamp.tv_usec, eventcause); + } else { + /* Handle PS_SLEEP/AWAKE events on STA */ + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA); + if (!priv) + priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY); } ret = mwifiex_process_sta_event(priv); @@ -540,8 +545,20 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no, /* Prepare command */ if (cmd_no) { - ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, - cmd_oid, data_buf, cmd_ptr); + switch (cmd_no) { + case HostCmd_CMD_UAP_SYS_CONFIG: + case HostCmd_CMD_UAP_BSS_START: + case HostCmd_CMD_UAP_BSS_STOP: + ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action, + cmd_oid, data_buf, + cmd_ptr); + break; + default: + ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action, + cmd_oid, data_buf, + cmd_ptr); + break; + } } else { ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf); cmd_node->cmd_flag |= CMD_F_HOSTCMD; diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index d04aba4131d..f918f66e5e2 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -28,7 +28,7 @@ #include <linux/ieee80211.h> -#define MWIFIEX_MAX_BSS_NUM (1) +#define MWIFIEX_MAX_BSS_NUM (2) #define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd) * + 4 byte alignment @@ -55,11 +55,17 @@ #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) #define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) +#define MAX_BEACON_PERIOD (4000) +#define MIN_BEACON_PERIOD (50) +#define MAX_DTIM_PERIOD (100) +#define MIN_DTIM_PERIOD (1) + #define MWIFIEX_RTS_MIN_VALUE (0) #define MWIFIEX_RTS_MAX_VALUE (2347) #define MWIFIEX_FRAG_MIN_VALUE (256) #define MWIFIEX_FRAG_MAX_VALUE (2346) +#define MWIFIEX_RETRY_LIMIT 14 #define MWIFIEX_SDIO_BLOCK_SIZE 256 #define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0) @@ -92,6 +98,11 @@ struct mwifiex_fw_image { u32 fw_len; }; +struct mwifiex_802_11_ssid { + u32 ssid_len; + u8 ssid[IEEE80211_MAX_SSID_LEN]; +}; + struct mwifiex_wait_queue { wait_queue_head_t wait; int status; diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 5f6adeb9b95..9f674bbebe6 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -93,6 +93,20 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF))) +#define UAP_BSS_PARAMS_I 0 +#define UAP_CUSTOM_IE_I 1 +#define MWIFIEX_AUTO_IDX_MASK 0xffff +#define MWIFIEX_DELETE_MASK 0x0000 +#define MGMT_MASK_ASSOC_REQ 0x01 +#define MGMT_MASK_REASSOC_REQ 0x04 +#define MGMT_MASK_ASSOC_RESP 0x02 +#define MGMT_MASK_REASSOC_RESP 0x08 +#define MGMT_MASK_PROBE_REQ 0x10 +#define MGMT_MASK_PROBE_RESP 0x20 +#define MGMT_MASK_BEACON 0x100 + +#define TLV_TYPE_UAP_SSID 0x0000 + #define PROPRIETARY_TLV_BASE_ID 0x0100 #define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0) #define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1) @@ -104,14 +118,26 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19) #define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22) #define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31) +#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32) #define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42) +#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44) +#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45) +#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51) +#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60) +#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64) +#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65) +#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70) #define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82) #define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83) #define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84) +#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93) #define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94) +#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104) #define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105) #define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113) #define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114) +#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145) +#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146) #define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048 @@ -209,6 +235,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_RSSI_INFO 0x00a4 #define HostCmd_CMD_FUNC_INIT 0x00a9 #define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa +#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0 +#define HostCmd_CMD_UAP_BSS_START 0x00b1 +#define HostCmd_CMD_UAP_BSS_STOP 0x00b2 #define HostCmd_CMD_11N_CFG 0x00cd #define HostCmd_CMD_11N_ADDBA_REQ 0x00ce #define HostCmd_CMD_11N_ADDBA_RSP 0x00cf @@ -223,6 +252,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_SET_BSS_MODE 0x00f7 #define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa +#define PROTOCOL_NO_SECURITY 0x01 +#define PROTOCOL_STATIC_WEP 0x02 +#define PROTOCOL_WPA 0x08 +#define PROTOCOL_WPA2 0x20 +#define PROTOCOL_WPA2_MIXED 0x28 +#define PROTOCOL_EAP 0x40 +#define KEY_MGMT_NONE 0x04 +#define KEY_MGMT_PSK 0x02 +#define KEY_MGMT_EAP 0x01 +#define CIPHER_TKIP 0x04 +#define CIPHER_AES_CCMP 0x08 +#define VALID_CIPHER_BITMAP 0x0c + enum ENH_PS_MODES { EN_PS = 1, DIS_PS = 2, @@ -313,15 +355,20 @@ enum ENH_PS_MODES { #define EVENT_DATA_SNR_HIGH 0x00000027 #define EVENT_LINK_QUALITY 0x00000028 #define EVENT_PORT_RELEASE 0x0000002b +#define EVENT_UAP_STA_DEAUTH 0x0000002c +#define EVENT_UAP_STA_ASSOC 0x0000002d +#define EVENT_UAP_BSS_START 0x0000002e #define EVENT_PRE_BEACON_LOST 0x00000031 #define EVENT_ADDBA 0x00000033 #define EVENT_DELBA 0x00000034 #define EVENT_BA_STREAM_TIEMOUT 0x00000037 #define EVENT_AMSDU_AGGR_CTRL 0x00000042 +#define EVENT_UAP_BSS_IDLE 0x00000043 +#define EVENT_UAP_BSS_ACTIVE 0x00000044 #define EVENT_WEP_ICV_ERR 0x00000046 #define EVENT_HS_ACT_REQ 0x00000047 #define EVENT_BW_CHANGE 0x00000048 - +#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c #define EVENT_HOSTWAKE_STAIE 0x0000004d #define EVENT_ID_MASK 0xffff @@ -1103,6 +1150,101 @@ struct host_cmd_ds_802_11_eeprom_access { u8 value; } __packed; +struct host_cmd_tlv { + __le16 type; + __le16 len; +} __packed; + +struct mwifiex_assoc_event { + u8 sta_addr[ETH_ALEN]; + __le16 type; + __le16 len; + __le16 frame_control; + __le16 cap_info; + __le16 listen_interval; + u8 data[0]; +} __packed; + +struct host_cmd_ds_sys_config { + __le16 action; + u8 tlv[0]; +}; + +struct host_cmd_tlv_akmp { + struct host_cmd_tlv tlv; + __le16 key_mgmt; + __le16 key_mgmt_operation; +} __packed; + +struct host_cmd_tlv_pwk_cipher { + struct host_cmd_tlv tlv; + __le16 proto; + u8 cipher; + u8 reserved; +} __packed; + +struct host_cmd_tlv_gwk_cipher { + struct host_cmd_tlv tlv; + u8 cipher; + u8 reserved; +} __packed; + +struct host_cmd_tlv_passphrase { + struct host_cmd_tlv tlv; + u8 passphrase[0]; +} __packed; + +struct host_cmd_tlv_auth_type { + struct host_cmd_tlv tlv; + u8 auth_type; +} __packed; + +struct host_cmd_tlv_encrypt_protocol { + struct host_cmd_tlv tlv; + __le16 proto; +} __packed; + +struct host_cmd_tlv_ssid { + struct host_cmd_tlv tlv; + u8 ssid[0]; +} __packed; + +struct host_cmd_tlv_beacon_period { + struct host_cmd_tlv tlv; + __le16 period; +} __packed; + +struct host_cmd_tlv_dtim_period { + struct host_cmd_tlv tlv; + u8 period; +} __packed; + +struct host_cmd_tlv_frag_threshold { + struct host_cmd_tlv tlv; + __le16 frag_thr; +} __packed; + +struct host_cmd_tlv_rts_threshold { + struct host_cmd_tlv tlv; + __le16 rts_thr; +} __packed; + +struct host_cmd_tlv_retry_limit { + struct host_cmd_tlv tlv; + u8 limit; +} __packed; + +struct host_cmd_tlv_mac_addr { + struct host_cmd_tlv tlv; + u8 mac_addr[ETH_ALEN]; +} __packed; + +struct host_cmd_tlv_channel_band { + struct host_cmd_tlv tlv; + u8 band_config; + u8 channel; +} __packed; + struct host_cmd_ds_802_11_rf_channel { __le16 action; __le16 current_channel; @@ -1167,6 +1309,20 @@ struct host_cmd_ds_802_11_subsc_evt { __le16 events; } __packed; +struct mwifiex_ie { + __le16 ie_index; + __le16 mgmt_subtype_mask; + __le16 ie_length; + u8 ie_buffer[IEEE_MAX_IE_SIZE]; +} __packed; + +#define MAX_MGMT_IE_INDEX 16 +struct mwifiex_ie_list { + __le16 type; + __le16 len; + struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX]; +} __packed; + struct host_cmd_ds_command { __le16 command; __le16 size; @@ -1217,6 +1373,7 @@ struct host_cmd_ds_command { struct host_cmd_ds_pcie_details pcie_host_spec; struct host_cmd_ds_802_11_eeprom_access eeprom; struct host_cmd_ds_802_11_subsc_evt subsc_evt; + struct host_cmd_ds_sys_config uap_sys_config; } params; } __packed; diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c new file mode 100644 index 00000000000..ceb82cd749c --- /dev/null +++ b/drivers/net/wireless/mwifiex/ie.c @@ -0,0 +1,396 @@ +/* + * Marvell Wireless LAN device driver: management IE handling- setting and + * deleting IE. + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" + +/* This function checks if current IE index is used by any on other interface. + * Return: -1: yes, current IE index is used by someone else. + * 0: no, current IE index is NOT used by other interface. + */ +static int +mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx) +{ + int i; + struct mwifiex_adapter *adapter = priv->adapter; + struct mwifiex_ie *ie; + + for (i = 0; i < adapter->priv_num; i++) { + if (adapter->priv[i] != priv) { + ie = &adapter->priv[i]->mgmt_ie[idx]; + if (ie->mgmt_subtype_mask && ie->ie_length) + return -1; + } + } + + return 0; +} + +/* Get unused IE index. This index will be used for setting new IE */ +static int +mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask, + struct mwifiex_ie *ie, u16 *index) +{ + u16 mask, len, i; + + 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); + + if (mask == MWIFIEX_AUTO_IDX_MASK) + continue; + + if (mask == subtype_mask) { + if (len > IEEE_MAX_IE_SIZE) + continue; + + *index = i; + return 0; + } + + if (!priv->mgmt_ie[i].ie_length) { + if (mwifiex_ie_index_used_by_other_intf(priv, i)) + continue; + + *index = i; + return 0; + } + } + + return -1; +} + +/* This function prepares IE data buffer for command to be sent to FW */ +static int +mwifiex_update_autoindex_ies(struct mwifiex_private *priv, + struct mwifiex_ie_list *ie_list) +{ + u16 travel_len, index, mask; + s16 input_len; + struct mwifiex_ie *ie; + u8 *tmp; + + input_len = le16_to_cpu(ie_list->len); + travel_len = sizeof(struct host_cmd_tlv); + + ie_list->len = 0; + + while (input_len > 0) { + ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len); + input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; + travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE; + + index = le16_to_cpu(ie->ie_index); + mask = le16_to_cpu(ie->mgmt_subtype_mask); + + if (index == MWIFIEX_AUTO_IDX_MASK) { + /* automatic addition */ + if (mwifiex_ie_get_autoidx(priv, mask, ie, &index)) + return -1; + if (index == MWIFIEX_AUTO_IDX_MASK) + 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_index = cpu_to_le16(index); + priv->mgmt_ie[index].mgmt_subtype_mask = + cpu_to_le16(mask); + + ie->ie_index = cpu_to_le16(index); + ie->ie_length = priv->mgmt_ie[index].ie_length; + memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer, + le16_to_cpu(priv->mgmt_ie[index].ie_length)); + } else { + if (mask != MWIFIEX_DELETE_MASK) + return -1; + /* + * Check if this index is being used on any + * other interface. + */ + if (mwifiex_ie_index_used_by_other_intf(priv, index)) + return -1; + + ie->ie_length = 0; + memcpy(&priv->mgmt_ie[index], ie, + sizeof(struct mwifiex_ie)); + } + + le16_add_cpu(&ie_list->len, + le16_to_cpu(priv->mgmt_ie[index].ie_length) + + MWIFIEX_IE_HDR_SIZE); + } + + if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) + return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_CUSTOM_IE_I, ie_list); + + return 0; +} + +/* Copy individual custom IEs for beacon, probe response and assoc response + * and prepare single structure for IE setting. + * This function also updates allocated IE indices from driver. + */ +static int +mwifiex_update_uap_custom_ie(struct mwifiex_private *priv, + struct mwifiex_ie *beacon_ie, u16 *beacon_idx, + struct mwifiex_ie *pr_ie, u16 *probe_idx, + struct mwifiex_ie *ar_ie, u16 *assoc_idx) +{ + struct mwifiex_ie_list *ap_custom_ie; + u8 *pos; + u16 len; + int ret; + + ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!ap_custom_ie) + return -ENOMEM; + + ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); + pos = (u8 *)ap_custom_ie->ie_list; + + if (beacon_ie) { + len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(beacon_ie->ie_length); + memcpy(pos, beacon_ie, len); + pos += len; + le16_add_cpu(&ap_custom_ie->len, len); + } + if (pr_ie) { + len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(pr_ie->ie_length); + memcpy(pos, pr_ie, len); + pos += len; + le16_add_cpu(&ap_custom_ie->len, len); + } + if (ar_ie) { + len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(ar_ie->ie_length); + memcpy(pos, ar_ie, len); + pos += len; + le16_add_cpu(&ap_custom_ie->len, len); + } + + ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie); + + pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index); + if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) { + /* save beacon ie index after auto-indexing */ + *beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index); + len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(beacon_ie->ie_length); + pos += len; + } + if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) { + /* save probe resp ie index after auto-indexing */ + *probe_idx = *((u16 *)pos); + len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE + + le16_to_cpu(pr_ie->ie_length); + pos += len; + } + if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) + /* save assoc resp ie index after auto-indexing */ + *assoc_idx = *((u16 *)pos); + + 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 mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; + struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL; + struct ieee_types_header *ie = NULL; + u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK; + u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK; + u16 mask; + int ret = 0; + + if (params->beacon.tail && params->beacon.tail_len) { + ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail, + params->beacon.tail_len); + if (ie) { + rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!rsn_ie) + return -ENOMEM; + + rsn_ie->ie_index = cpu_to_le16(rsn_idx); + mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP | + MGMT_MASK_ASSOC_RESP; + rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask); + rsn_ie->ie_length = cpu_to_le16(ie->len + 2); + memcpy(rsn_ie->ie_buffer, ie, ie->len + 2); + + if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx, + NULL, NULL, + NULL, NULL)) { + ret = -1; + goto done; + } + + 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; + } + + 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(rsn_ie); + + return ret; +} + +/* This function removes management IE set */ +int mwifiex_del_mgmt_ies(struct mwifiex_private *priv) +{ + struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL; + struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL; + int ret = 0; + + if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) { + rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!rsn_ie) + return -ENOMEM; + + rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx); + rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + rsn_ie->ie_length = 0; + if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx, + NULL, &priv->proberesp_idx, + NULL, &priv->assocresp_idx)) { + ret = -1; + goto done; + } + + priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; + } + + if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) { + beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!beacon_ie) { + ret = -ENOMEM; + goto done; + } + beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx); + beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + beacon_ie->ie_length = 0; + } + if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) { + pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!pr_ie) { + ret = -ENOMEM; + goto done; + } + pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx); + pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + pr_ie->ie_length = 0; + } + if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) { + ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL); + if (!ar_ie) { + ret = -ENOMEM; + goto done; + } + ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx); + ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK); + ar_ie->ie_length = 0; + } + + if (beacon_ie || pr_ie || ar_ie) + ret = mwifiex_update_uap_custom_ie(priv, + beacon_ie, &priv->beacon_idx, + pr_ie, &priv->proberesp_idx, + ar_ie, &priv->assocresp_idx); + +done: + kfree(beacon_ie); + kfree(pr_ie); + kfree(ar_ie); + kfree(rsn_ie); + + return ret; +} diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index d440c3eb640..c1cb004db91 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -279,6 +279,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter)); adapter->arp_filter_size = 0; adapter->channel_type = NL80211_CHAN_HT20; + adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX; } /* diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h index f0f95524e96..e6be6ee7595 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -62,6 +62,36 @@ enum { BAND_AN = 16, }; +#define MWIFIEX_WPA_PASSHPHRASE_LEN 64 +struct wpa_param { + u8 pairwise_cipher_wpa; + u8 pairwise_cipher_wpa2; + u8 group_cipher; + u32 length; + u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN]; +}; + +#define KEY_MGMT_ON_HOST 0x03 +#define MWIFIEX_AUTH_MODE_AUTO 0xFF +#define BAND_CONFIG_MANUAL 0x00 +struct mwifiex_uap_bss_param { + u8 channel; + u8 band_cfg; + u16 rts_threshold; + u16 frag_threshold; + u8 retry_limit; + struct mwifiex_802_11_ssid ssid; + u8 bcast_ssid_ctl; + u8 radio_ctl; + u8 dtim_period; + u16 beacon_period; + u16 auth_mode; + u16 protocol; + u16 key_mgmt; + u16 key_mgmt_operation; + struct wpa_param wpa_cfg; +}; + enum { ADHOC_IDLE, ADHOC_STARTED, @@ -269,6 +299,8 @@ struct mwifiex_ds_read_eeprom { #define IEEE_MAX_IE_SIZE 256 +#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE) + struct mwifiex_ds_misc_gen_ie { u32 type; u32 len; diff --git a/drivers/net/wireless/mwifiex/join.c b/drivers/net/wireless/mwifiex/join.c index 8a390982463..d6b4fb04011 100644 --- a/drivers/net/wireless/mwifiex/join.c +++ b/drivers/net/wireless/mwifiex/join.c @@ -1374,22 +1374,28 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac) * * In case of infra made, it sends deauthentication request, and * in case of ad-hoc mode, a stop network request is sent to the firmware. + * In AP mode, a command to stop bss is sent to firmware. */ int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac) { - int ret = 0; + if (!priv->media_connected) + return 0; - if (priv->media_connected) { - if (priv->bss_mode == NL80211_IFTYPE_STATION) { - ret = mwifiex_deauthenticate_infra(priv, mac); - } else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { - ret = mwifiex_send_cmd_sync(priv, - HostCmd_CMD_802_11_AD_HOC_STOP, - HostCmd_ACT_GEN_SET, 0, NULL); - } + switch (priv->bss_mode) { + case NL80211_IFTYPE_STATION: + return mwifiex_deauthenticate_infra(priv, mac); + case NL80211_IFTYPE_ADHOC: + return mwifiex_send_cmd_sync(priv, + HostCmd_CMD_802_11_AD_HOC_STOP, + HostCmd_ACT_GEN_SET, 0, NULL); + case NL80211_IFTYPE_AP: + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP, + HostCmd_ACT_GEN_SET, 0, NULL); + default: + break; } - return ret; + return 0; } EXPORT_SYMBOL_GPL(mwifiex_deauthenticate); diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index be0f0e583f7..3192855c31c 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -64,17 +64,17 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops, adapter->priv_num = 0; - /* Allocate memory for private structure */ - adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); - if (!adapter->priv[0]) { - dev_err(adapter->dev, - "%s: failed to alloc priv[0]\n", __func__); - goto error; - } - - adapter->priv_num++; + for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) { + /* Allocate memory for private structure */ + adapter->priv[i] = + kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL); + if (!adapter->priv[i]) + goto error; - adapter->priv[0]->adapter = adapter; + adapter->priv[i]->adapter = adapter; + adapter->priv[i]->bss_priority = i; + adapter->priv_num++; + } mwifiex_init_lock_list(adapter); init_timer(&adapter->cmd_timer); @@ -349,19 +349,26 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) if (adapter->hw_status != MWIFIEX_HW_STATUS_READY) goto done; - priv = adapter->priv[0]; - if (mwifiex_register_cfg80211(priv) != 0) { + priv = adapter->priv[MWIFIEX_BSS_ROLE_STA]; + if (mwifiex_register_cfg80211(adapter)) { dev_err(adapter->dev, "cannot register with cfg80211\n"); goto err_init_fw; } rtnl_lock(); /* Create station interface by default */ - if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d", + if (!mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d", NL80211_IFTYPE_STATION, NULL, NULL)) { dev_err(adapter->dev, "cannot create default STA interface\n"); goto err_add_intf; } + + /* Create AP interface by default */ + if (!mwifiex_add_virtual_intf(adapter->wiphy, "uap%d", + NL80211_IFTYPE_AP, NULL, NULL)) { + dev_err(adapter->dev, "cannot create default AP interface\n"); + goto err_add_intf; + } rtnl_unlock(); mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1); @@ -369,7 +376,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); @@ -633,6 +640,12 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv, priv->current_key_index = 0; priv->media_connected = false; memset(&priv->nick_name, 0, sizeof(priv->nick_name)); + memset(priv->mgmt_ie, 0, + sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX); + priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK; + priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK; + priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK; + priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK; priv->num_tx_timeout = 0; memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN); } @@ -830,19 +843,21 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) rtnl_lock(); if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(priv->wdev->wiphy, - priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); rtnl_unlock(); } priv = adapter->priv[0]; - if (!priv) + if (!priv || !priv->wdev) goto exit_remove; - if (priv->wdev) { - wiphy_unregister(priv->wdev->wiphy); - wiphy_free(priv->wdev->wiphy); - kfree(priv->wdev); + wiphy_unregister(priv->wdev->wiphy); + wiphy_free(priv->wdev->wiphy); + + for (i = 0; i < adapter->priv_num; i++) { + priv = adapter->priv[i]; + if (priv) + kfree(priv->wdev); } mwifiex_terminate_workqueue(adapter); diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 324ad390cac..bd3b0bf94b9 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -116,6 +116,7 @@ enum { #define MAX_FREQUENCY_BAND_BG 2484 #define MWIFIEX_EVENT_HEADER_LEN 4 +#define MWIFIEX_UAP_EVENT_EXTRA_HEADER 2 #define MWIFIEX_TYPE_LEN 4 #define MWIFIEX_USB_TYPE_CMD 0xF00DFACE @@ -370,6 +371,7 @@ struct mwifiex_private { u8 bss_role; u8 bss_priority; u8 bss_num; + u8 bss_started; u8 frame_type; u8 curr_addr[ETH_ALEN]; u8 media_connected; @@ -470,12 +472,16 @@ struct mwifiex_private { struct cfg80211_scan_request *scan_request; struct mwifiex_user_scan_cfg *user_scan_cfg; u8 cfg_bssid[6]; - u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; struct wps wps; u8 scan_block; s32 cqm_rssi_thold; u32 cqm_rssi_hyst; u8 subsc_evt_rssi_state; + struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX]; + u16 beacon_idx; + u16 proberesp_idx; + u16 assocresp_idx; + u16 rsn_idx; }; enum mwifiex_ba_status { @@ -571,6 +577,7 @@ struct mwifiex_adapter { char fw_name[32]; int winner; struct device *dev; + struct wiphy *wiphy; bool surprise_removed; u32 fw_release_number; u16 init_wait_q_woken; @@ -677,6 +684,8 @@ struct mwifiex_adapter { struct cmd_ctrl_node *cmd_queued; spinlock_t queue_lock; /* lock for tx queues */ struct completion fw_load; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; + u16 max_mgmt_ie_index; }; int mwifiex_init_lock_list(struct mwifiex_adapter *adapter); @@ -760,6 +769,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter, int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no, u16 cmd_action, u32 cmd_oid, void *data_buf, void *cmd_buf); +int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, + u16 cmd_action, u32 cmd_oid, + void *data_buf, void *cmd_buf); int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no, struct host_cmd_ds_command *resp); int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *, @@ -820,6 +832,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv, int is_command_pending(struct mwifiex_adapter *adapter); void mwifiex_init_priv_params(struct mwifiex_private *priv, struct net_device *dev); +int mwifiex_set_secure_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_config, + struct cfg80211_ap_settings *params); /* * This function checks if the queuing is RA based or not. @@ -933,7 +948,8 @@ int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel); int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, - int key_len, u8 key_index, int disable); + int key_len, u8 key_index, const u8 *mac_addr, + int disable); int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len); @@ -969,6 +985,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, int mwifiex_main_process(struct mwifiex_adapter *); +int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel); int mwifiex_bss_set_channel(struct mwifiex_private *, struct mwifiex_chan_freq_power *cfp); int mwifiex_get_bss_info(struct mwifiex_private *, @@ -986,6 +1003,11 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, u32 *flags, struct vif_params *params); 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); +int mwifiex_del_mgmt_ies(struct mwifiex_private *priv); u8 *mwifiex_11d_code_2_region(u8 code); #ifdef CONFIG_DEBUG_FS diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 87ed2a1f6cd..40e025da6bc 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -498,7 +498,8 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, { struct host_cmd_ds_802_11_key_material *key_material = &cmd->params.key_material; - u16 key_param_len = 0; + struct host_cmd_tlv_mac_addr *tlv_mac; + u16 key_param_len = 0, cmd_size; int ret = 0; const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; @@ -614,11 +615,26 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv, cpu_to_le16((u16) enc_key->key_len + KEYPARAMSET_FIXED_LEN); - key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN) + key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN) + sizeof(struct mwifiex_ie_types_header); cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN + key_param_len); + + if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) { + tlv_mac = (void *)((u8 *)&key_material->key_param_set + + key_param_len); + tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR); + tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN); + memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN); + cmd_size = key_param_len + S_DS_GEN + + sizeof(key_material->action) + + sizeof(struct host_cmd_tlv_mac_addr); + } else { + cmd_size = key_param_len + S_DS_GEN + + sizeof(key_material->action); + } + cmd->size = cpu_to_le16(cmd_size); } return ret; @@ -1248,13 +1264,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - /* Enable IEEE PS by default */ - priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_PS_MODE_ENH, - EN_AUTO_PS, BITMAP_STA_PS, NULL); - if (ret) - return -1; + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + /* Enable IEEE PS by default */ + priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP; + ret = mwifiex_send_cmd_async( + priv, HostCmd_CMD_802_11_PS_MODE_ENH, + EN_AUTO_PS, BITMAP_STA_PS, NULL); + if (ret) + return -1; + } } /* get tx rate */ @@ -1270,12 +1288,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - /* set ibss coalescing_status */ - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, - HostCmd_ACT_GEN_SET, 0, &enable); - if (ret) - return -1; + if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { + /* set ibss coalescing_status */ + ret = mwifiex_send_cmd_async( + priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS, + HostCmd_ACT_GEN_SET, 0, &enable); + if (ret) + return -1; + } memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl)); amsdu_aggr_ctrl.enable = true; @@ -1293,7 +1313,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) if (ret) return -1; - if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) { + if (first_sta && priv->adapter->iface_type != MWIFIEX_USB && + priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { /* Enable auto deep sleep */ auto_ds.auto_ds = DEEP_SLEEP_ON; auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME; @@ -1305,12 +1326,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta) return -1; } - /* Send cmd to FW to enable/disable 11D function */ - state_11d = ENABLE_11D; - ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, - HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d); - if (ret) - dev_err(priv->adapter->dev, "11D: failed to enable 11D\n"); + if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) { + /* Send cmd to FW to enable/disable 11D function */ + state_11d = ENABLE_11D; + ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB, + HostCmd_ACT_GEN_SET, DOT11D_I, + &state_11d); + if (ret) + dev_err(priv->adapter->dev, + "11D: failed to enable 11D\n"); + } /* Send cmd to FW to configure 11n specific configuration * (Short GI, Channel BW, Green field support etc.) for transmit diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 3aa54243dea..a79ed9bd969 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -944,6 +944,14 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_802_11_SUBSCRIBE_EVENT: ret = mwifiex_ret_subsc_evt(priv, resp, data_buf); break; + case HostCmd_CMD_UAP_SYS_CONFIG: + break; + case HostCmd_CMD_UAP_BSS_START: + priv->bss_started = 1; + break; + case HostCmd_CMD_UAP_BSS_STOP: + priv->bss_started = 0; + break; default: dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n", resp->command); diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c index f6bbb9307f8..4ace5a3dcd2 100644 --- a/drivers/net/wireless/mwifiex/sta_event.c +++ b/drivers/net/wireless/mwifiex/sta_event.c @@ -184,8 +184,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv) int mwifiex_process_sta_event(struct mwifiex_private *priv) { struct mwifiex_adapter *adapter = priv->adapter; - int ret = 0; + int len, ret = 0; u32 eventcause = adapter->event_cause; + struct station_info sinfo; + struct mwifiex_assoc_event *event; switch (eventcause) { case EVENT_DUMMY_HOST_WAKEUP_SIGNAL: @@ -402,6 +404,53 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv) case EVENT_HOSTWAKE_STAIE: dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause); break; + + case EVENT_UAP_STA_ASSOC: + skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER); + memset(&sinfo, 0, sizeof(sinfo)); + event = (struct mwifiex_assoc_event *)adapter->event_skb->data; + if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) { + len = -1; + + if (ieee80211_is_assoc_req(event->frame_control)) + len = 0; + else if (ieee80211_is_reassoc_req(event->frame_control)) + /* There will be ETH_ALEN bytes of + * current_ap_addr before the re-assoc ies. + */ + len = ETH_ALEN; + + if (len != -1) { + sinfo.filled = STATION_INFO_ASSOC_REQ_IES; + sinfo.assoc_req_ies = (u8 *)&event->data[len]; + len = (u8 *)sinfo.assoc_req_ies - + (u8 *)&event->frame_control; + sinfo.assoc_req_ies_len = + le16_to_cpu(event->len) - (u16)len; + } + } + cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo, + GFP_KERNEL); + break; + case EVENT_UAP_STA_DEAUTH: + skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER); + cfg80211_del_sta(priv->netdev, adapter->event_skb->data, + GFP_KERNEL); + break; + case EVENT_UAP_BSS_IDLE: + priv->media_connected = false; + break; + case EVENT_UAP_BSS_ACTIVE: + priv->media_connected = true; + break; + case EVENT_UAP_BSS_START: + dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); + memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN); + break; + case EVENT_UAP_MIC_COUNTERMEASURES: + /* For future development */ + dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause); + break; default: dev_dbg(adapter->dev, "event: unknown event id: %#x\n", eventcause); diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index 58970e0f7d1..106c449477b 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -462,7 +462,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv, info->bss_chan = bss_desc->channel; - memcpy(info->country_code, priv->country_code, + memcpy(info->country_code, adapter->country_code, IEEE80211_COUNTRY_STRING_LEN); info->media_connected = priv->media_connected; @@ -1219,7 +1219,8 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version, * with requisite parameters and calls the IOCTL handler. */ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, - int key_len, u8 key_index, int disable) + int key_len, u8 key_index, + const u8 *mac_addr, int disable) { struct mwifiex_ds_encrypt_key encrypt_key; @@ -1229,8 +1230,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, encrypt_key.key_index = key_index; if (key_len) memcpy(encrypt_key.key_material, key, key_len); + if (mac_addr) + memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); } else { encrypt_key.key_disable = true; + if (mac_addr) + memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN); } return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key); diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c new file mode 100644 index 00000000000..76dfbc42a73 --- /dev/null +++ b/drivers/net/wireless/mwifiex/uap_cmd.c @@ -0,0 +1,432 @@ +/* + * Marvell Wireless LAN device driver: AP specific command handling + * + * Copyright (C) 2012, Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available by writing to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the + * worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +#include "main.h" + +/* This function parses security related parameters from cfg80211_ap_settings + * and sets into FW understandable bss_config structure. + */ +int mwifiex_set_secure_params(struct mwifiex_private *priv, + struct mwifiex_uap_bss_param *bss_config, + struct cfg80211_ap_settings *params) { + int i; + + switch (params->auth_type) { + case NL80211_AUTHTYPE_OPEN_SYSTEM: + bss_config->auth_mode = WLAN_AUTH_OPEN; + break; + case NL80211_AUTHTYPE_SHARED_KEY: + bss_config->auth_mode = WLAN_AUTH_SHARED_KEY; + break; + case NL80211_AUTHTYPE_NETWORK_EAP: + bss_config->auth_mode = WLAN_AUTH_LEAP; + break; + default: + bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO; + break; + } + + bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST; + + for (i = 0; i < params->crypto.n_akm_suites; i++) { + switch (params->crypto.akm_suites[i]) { + case WLAN_AKM_SUITE_8021X: + if (params->crypto.wpa_versions & + NL80211_WPA_VERSION_1) { + bss_config->protocol = PROTOCOL_WPA; + bss_config->key_mgmt = KEY_MGMT_EAP; + } + if (params->crypto.wpa_versions & + NL80211_WPA_VERSION_2) { + bss_config->protocol = PROTOCOL_WPA2; + bss_config->key_mgmt = KEY_MGMT_EAP; + } + break; + case WLAN_AKM_SUITE_PSK: + if (params->crypto.wpa_versions & + NL80211_WPA_VERSION_1) { + bss_config->protocol = PROTOCOL_WPA; + bss_config->key_mgmt = KEY_MGMT_PSK; + } + if (params->crypto.wpa_versions & + NL80211_WPA_VERSION_2) { + bss_config->protocol = PROTOCOL_WPA2; + bss_config->key_mgmt = KEY_MGMT_PSK; + } + break; + default: + break; + } + } + for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) { + switch (params->crypto.ciphers_pairwise[i]) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + break; + case WLAN_CIPHER_SUITE_TKIP: + bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + bss_config->wpa_cfg.pairwise_cipher_wpa2 = + CIPHER_AES_CCMP; + default: + break; + } + } + + switch (params->crypto.cipher_group) { + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + break; + case WLAN_CIPHER_SUITE_TKIP: + bss_config->wpa_cfg.group_cipher = CIPHER_TKIP; + break; + case WLAN_CIPHER_SUITE_CCMP: + bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP; + break; + default: + break; + } + + return 0; +} + +/* This function initializes some of mwifiex_uap_bss_param variables. + * This helps FW in ignoring invalid values. These values may or may not + * be get updated to valid ones at later stage. + */ +void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config) +{ + config->bcast_ssid_ctl = 0x7F; + config->radio_ctl = 0x7F; + config->dtim_period = 0x7F; + config->beacon_period = 0x7FFF; + config->auth_mode = 0x7F; + config->rts_threshold = 0x7FFF; + config->frag_threshold = 0x7FFF; + config->retry_limit = 0x7F; +} + +/* This function parses BSS related parameters from structure + * and prepares TLVs. These TLVs are appended to command buffer. +*/ +static int +mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size) +{ + struct host_cmd_tlv_dtim_period *dtim_period; + struct host_cmd_tlv_beacon_period *beacon_period; + struct host_cmd_tlv_ssid *ssid; + struct host_cmd_tlv_channel_band *chan_band; + struct host_cmd_tlv_frag_threshold *frag_threshold; + struct host_cmd_tlv_rts_threshold *rts_threshold; + struct host_cmd_tlv_retry_limit *retry_limit; + struct host_cmd_tlv_pwk_cipher *pwk_cipher; + struct host_cmd_tlv_gwk_cipher *gwk_cipher; + struct host_cmd_tlv_encrypt_protocol *encrypt_protocol; + struct host_cmd_tlv_auth_type *auth_type; + struct host_cmd_tlv_passphrase *passphrase; + struct host_cmd_tlv_akmp *tlv_akmp; + struct mwifiex_uap_bss_param *bss_cfg = cmd_buf; + u16 cmd_size = *param_size; + + if (bss_cfg->ssid.ssid_len) { + ssid = (struct host_cmd_tlv_ssid *)tlv; + ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID); + ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len); + memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len); + cmd_size += sizeof(struct host_cmd_tlv) + + bss_cfg->ssid.ssid_len; + tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len; + } + if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) { + chan_band = (struct host_cmd_tlv_channel_band *)tlv; + chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST); + chan_band->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) - + sizeof(struct host_cmd_tlv)); + chan_band->band_config = bss_cfg->band_cfg; + chan_band->channel = bss_cfg->channel; + cmd_size += sizeof(struct host_cmd_tlv_channel_band); + tlv += sizeof(struct host_cmd_tlv_channel_band); + } + if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD && + bss_cfg->beacon_period <= MAX_BEACON_PERIOD) { + beacon_period = (struct host_cmd_tlv_beacon_period *)tlv; + beacon_period->tlv.type = + cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD); + beacon_period->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) - + sizeof(struct host_cmd_tlv)); + beacon_period->period = cpu_to_le16(bss_cfg->beacon_period); + cmd_size += sizeof(struct host_cmd_tlv_beacon_period); + tlv += sizeof(struct host_cmd_tlv_beacon_period); + } + if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD && + bss_cfg->dtim_period <= MAX_DTIM_PERIOD) { + dtim_period = (struct host_cmd_tlv_dtim_period *)tlv; + dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD); + dtim_period->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) - + sizeof(struct host_cmd_tlv)); + dtim_period->period = bss_cfg->dtim_period; + cmd_size += sizeof(struct host_cmd_tlv_dtim_period); + tlv += sizeof(struct host_cmd_tlv_dtim_period); + } + if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) { + rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv; + rts_threshold->tlv.type = + cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD); + rts_threshold->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) - + sizeof(struct host_cmd_tlv)); + rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold); + cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); + tlv += sizeof(struct host_cmd_tlv_frag_threshold); + } + if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) && + (bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) { + frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv; + frag_threshold->tlv.type = + cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD); + frag_threshold->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) - + sizeof(struct host_cmd_tlv)); + frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold); + cmd_size += sizeof(struct host_cmd_tlv_frag_threshold); + tlv += sizeof(struct host_cmd_tlv_frag_threshold); + } + if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) { + retry_limit = (struct host_cmd_tlv_retry_limit *)tlv; + retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT); + retry_limit->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) - + sizeof(struct host_cmd_tlv)); + retry_limit->limit = (u8)bss_cfg->retry_limit; + cmd_size += sizeof(struct host_cmd_tlv_retry_limit); + tlv += sizeof(struct host_cmd_tlv_retry_limit); + } + if ((bss_cfg->protocol & PROTOCOL_WPA) || + (bss_cfg->protocol & PROTOCOL_WPA2) || + (bss_cfg->protocol & PROTOCOL_EAP)) { + tlv_akmp = (struct host_cmd_tlv_akmp *)tlv; + tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP); + tlv_akmp->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) - + sizeof(struct host_cmd_tlv)); + tlv_akmp->key_mgmt_operation = + cpu_to_le16(bss_cfg->key_mgmt_operation); + tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt); + cmd_size += sizeof(struct host_cmd_tlv_akmp); + tlv += sizeof(struct host_cmd_tlv_akmp); + + if (bss_cfg->wpa_cfg.pairwise_cipher_wpa & + VALID_CIPHER_BITMAP) { + pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; + pwk_cipher->tlv.type = + cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->tlv.len = cpu_to_le16( + sizeof(struct host_cmd_tlv_pwk_cipher) - + sizeof(struct host_cmd_tlv)); + pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA); + pwk_cipher->cipher = + bss_cfg->wpa_cfg.pairwise_cipher_wpa; + cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); + tlv += sizeof(struct host_cmd_tlv_pwk_cipher); + } + if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 & + VALID_CIPHER_BITMAP) { + pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv; + pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER); + pwk_cipher->tlv.len = cpu_to_le16( + sizeof(struct host_cmd_tlv_pwk_cipher) - + sizeof(struct host_cmd_tlv)); + pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2); + pwk_cipher->cipher = + bss_cfg->wpa_cfg.pairwise_cipher_wpa2; + cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher); + tlv += sizeof(struct host_cmd_tlv_pwk_cipher); + } + if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) { + gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv; + gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER); + gwk_cipher->tlv.len = cpu_to_le16( + sizeof(struct host_cmd_tlv_gwk_cipher) - + sizeof(struct host_cmd_tlv)); + gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher; + cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher); + tlv += sizeof(struct host_cmd_tlv_gwk_cipher); + } + if (bss_cfg->wpa_cfg.length) { + passphrase = (struct host_cmd_tlv_passphrase *)tlv; + passphrase->tlv.type = + cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE); + passphrase->tlv.len = + cpu_to_le16(bss_cfg->wpa_cfg.length); + memcpy(passphrase->passphrase, + bss_cfg->wpa_cfg.passphrase, + bss_cfg->wpa_cfg.length); + cmd_size += sizeof(struct host_cmd_tlv) + + bss_cfg->wpa_cfg.length; + tlv += sizeof(struct host_cmd_tlv) + + bss_cfg->wpa_cfg.length; + } + } + if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) || + (bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) { + auth_type = (struct host_cmd_tlv_auth_type *)tlv; + auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE); + auth_type->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) - + sizeof(struct host_cmd_tlv)); + auth_type->auth_type = (u8)bss_cfg->auth_mode; + cmd_size += sizeof(struct host_cmd_tlv_auth_type); + tlv += sizeof(struct host_cmd_tlv_auth_type); + } + if (bss_cfg->protocol) { + encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv; + encrypt_protocol->tlv.type = + cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL); + encrypt_protocol->tlv.len = + cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol) + - sizeof(struct host_cmd_tlv)); + encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol); + cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol); + tlv += sizeof(struct host_cmd_tlv_encrypt_protocol); + } + + *param_size = cmd_size; + + return 0; +} + +/* This function parses custom IEs from IE list and prepares command buffer */ +static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size) +{ + struct mwifiex_ie_list *ap_ie = cmd_buf; + struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv; + + if (!ap_ie || !ap_ie->len || !ap_ie->ie_list) + return -1; + + *ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv); + + tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE); + tlv_ie->len = ap_ie->len; + tlv += sizeof(struct host_cmd_tlv); + + memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len)); + + return 0; +} + +/* Parse AP config structure and prepare TLV based command structure + * to be sent to FW for uAP configuration + */ +static int +mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action, + u32 type, void *cmd_buf) +{ + u8 *tlv; + u16 cmd_size, param_size, ie_size; + struct host_cmd_ds_sys_config *sys_cfg; + + cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG); + cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN); + sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config; + sys_cfg->action = cpu_to_le16(cmd_action); + tlv = sys_cfg->tlv; + + switch (type) { + case UAP_BSS_PARAMS_I: + param_size = cmd_size; + if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, ¶m_size)) + return -1; + cmd->size = cpu_to_le16(param_size); + break; + case UAP_CUSTOM_IE_I: + ie_size = cmd_size; + if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size)) + return -1; + cmd->size = cpu_to_le16(ie_size); + break; + default: + return -1; + } + + return 0; +} + +/* This function prepares the AP specific commands before sending them + * to the firmware. + * This is a generic function which calls specific command preparation + * routines based upon the command number. + */ +int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no, + u16 cmd_action, u32 type, + void *data_buf, void *cmd_buf) +{ + struct host_cmd_ds_command *cmd = cmd_buf; + + switch (cmd_no) { + case HostCmd_CMD_UAP_SYS_CONFIG: + if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf)) + return -1; + break; + case HostCmd_CMD_UAP_BSS_START: + case HostCmd_CMD_UAP_BSS_STOP: + cmd->command = cpu_to_le16(cmd_no); + cmd->size = cpu_to_le16(S_DS_GEN); + break; + default: + dev_err(priv->adapter->dev, + "PREP_CMD: unknown cmd %#x\n", cmd_no); + return -1; + } + + return 0; +} + +/* This function sets the RF channel for AP. + * + * This function populates channel information in AP config structure + * and sends command to configure channel information in AP. + */ +int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel) +{ + struct mwifiex_uap_bss_param *bss_cfg; + struct wiphy *wiphy = priv->wdev->wiphy; + + bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL); + if (!bss_cfg) + return -ENOMEM; + + bss_cfg->band_cfg = BAND_CONFIG_MANUAL; + bss_cfg->channel = channel; + + if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG, + HostCmd_ACT_GEN_SET, + UAP_BSS_PARAMS_I, bss_cfg)) { + wiphy_err(wiphy, "Failed to set the uAP channel\n"); + kfree(bss_cfg); + return -1; + } + + kfree(bss_cfg); + return 0; +} diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c index 429a1dee2d2..f3fc6551585 100644 --- a/drivers/net/wireless/mwifiex/wmm.c +++ b/drivers/net/wireless/mwifiex/wmm.c @@ -885,6 +885,10 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter, tid_ptr = &(priv_tmp)->wmm. tid_tbl_ptr[tos_to_tid[i]]; + /* For non-STA ra_list_curr may be NULL */ + if (!tid_ptr->ra_list_curr) + continue; + spin_lock_irqsave(&tid_ptr->tid_tbl_lock, flags); is_list_empty = diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index c5404eb82b2..2e9e6af2136 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -505,9 +505,6 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev, static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev); -static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev, - struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); - static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params); @@ -549,7 +546,6 @@ static const struct cfg80211_ops rndis_config_ops = { .disconnect = rndis_disconnect, .join_ibss = rndis_join_ibss, .leave_ibss = rndis_leave_ibss, - .set_channel = rndis_set_channel, .add_key = rndis_add_key, .del_key = rndis_del_key, .set_default_key = rndis_set_default_key, @@ -2398,16 +2394,6 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev) return deauthenticate(usbdev); } -static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev, - struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) -{ - struct rndis_wlan_private *priv = wiphy_priv(wiphy); - struct usbnet *usbdev = priv->usbdev; - - return set_channel(usbdev, - ieee80211_frequency_to_channel(chan->center_freq)); -} - static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev, u8 key_index, bool pairwise, const u8 *mac_addr, struct key_params *params) diff --git a/drivers/net/wireless/rt2x00/rt2800pci.c b/drivers/net/wireless/rt2x00/rt2800pci.c index 931331d9521..cad25bfebd7 100644 --- a/drivers/net/wireless/rt2x00/rt2800pci.c +++ b/drivers/net/wireless/rt2x00/rt2800pci.c @@ -1192,6 +1192,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = { { PCI_DEVICE(0x1814, 0x5390) }, { PCI_DEVICE(0x1814, 0x5392) }, { PCI_DEVICE(0x1814, 0x539a) }, + { PCI_DEVICE(0x1814, 0x539b) }, { PCI_DEVICE(0x1814, 0x539f) }, #endif { 0, } diff --git a/drivers/net/wireless/ti/wl12xx/Kconfig b/drivers/net/wireless/ti/wl12xx/Kconfig index 5b92329122c..c2183594655 100644 --- a/drivers/net/wireless/ti/wl12xx/Kconfig +++ b/drivers/net/wireless/ti/wl12xx/Kconfig @@ -1,5 +1,6 @@ config WL12XX tristate "TI wl12xx support" + depends on MAC80211 select WLCORE ---help--- This module adds support for wireless adapters based on TI wl1271, diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index 9d04c38938b..54156b0b5c2 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig @@ -1,6 +1,6 @@ config WLCORE tristate "TI wlcore support" - depends on WL_TI && GENERIC_HARDIRQS + depends on WL_TI && GENERIC_HARDIRQS && MAC80211 depends on INET select FW_LOADER ---help--- diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c index 5912541a925..509aa881d79 100644 --- a/drivers/net/wireless/ti/wlcore/acx.c +++ b/drivers/net/wireless/ti/wlcore/acx.c @@ -1714,3 +1714,83 @@ out: return ret; } + +/* Set the global behaviour of RX filters - On/Off + default action */ +int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, + enum rx_filter_action action) +{ + struct acx_default_rx_filter *acx; + int ret; + + wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d", + enable, action); + + acx = kzalloc(sizeof(*acx), GFP_KERNEL); + if (!acx) + return -ENOMEM; + + acx->enable = enable; + acx->default_action = action; + + ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx, + sizeof(*acx)); + if (ret < 0) { + wl1271_warning("acx default rx filter enable failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} + +/* Configure or disable a specific RX filter pattern */ +int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, + struct wl12xx_rx_filter *filter) +{ + struct acx_rx_filter_cfg *acx; + int fields_size = 0; + int acx_size; + int ret; + + WARN_ON(enable && !filter); + WARN_ON(index >= WL1271_MAX_RX_FILTERS); + + wl1271_debug(DEBUG_ACX, + "acx set rx filter idx: %d enable: %d filter: %p", + index, enable, filter); + + if (enable) { + fields_size = wl1271_rx_filter_get_fields_size(filter); + + wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d", + filter->action, filter->num_fields, fields_size); + } + + acx_size = ALIGN(sizeof(*acx) + fields_size, 4); + acx = kzalloc(acx_size, GFP_KERNEL); + + if (!acx) + return -ENOMEM; + + acx->enable = enable; + acx->index = index; + + if (enable) { + acx->num_fields = filter->num_fields; + acx->action = filter->action; + wl1271_rx_filter_flatten_fields(filter, acx->fields); + } + + wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size); + + ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size); + if (ret < 0) { + wl1271_warning("setting rx filter failed: %d", ret); + goto out; + } + +out: + kfree(acx); + return ret; +} diff --git a/drivers/net/wireless/ti/wlcore/acx.h b/drivers/net/wireless/ti/wlcore/acx.h index b2f88831b7a..8106b2ebfe6 100644 --- a/drivers/net/wireless/ti/wlcore/acx.h +++ b/drivers/net/wireless/ti/wlcore/acx.h @@ -1147,6 +1147,32 @@ struct wl12xx_acx_config_hangover { u8 padding[2]; } __packed; + +struct acx_default_rx_filter { + struct acx_header header; + u8 enable; + + /* action of type FILTER_XXX */ + u8 default_action; + + u8 pad[2]; +} __packed; + + +struct acx_rx_filter_cfg { + struct acx_header header; + + u8 enable; + + /* 0 - WL1271_MAX_RX_FILTERS-1 */ + u8 index; + + u8 action; + + u8 num_fields; + u8 fields[0]; +} __packed; + enum { ACX_WAKE_UP_CONDITIONS = 0x0000, ACX_MEM_CFG = 0x0001, @@ -1304,5 +1330,9 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr); int wl1271_acx_fm_coex(struct wl1271 *wl); int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl); int wl12xx_acx_config_hangover(struct wl1271 *wl); +int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable, + enum rx_filter_action action); +int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable, + struct wl12xx_rx_filter *filter); #endif /* __WL1271_ACX_H__ */ diff --git a/drivers/net/wireless/ti/wlcore/boot.c b/drivers/net/wireless/ti/wlcore/boot.c index 3a2207db540..9b98230f84c 100644 --- a/drivers/net/wireless/ti/wlcore/boot.c +++ b/drivers/net/wireless/ti/wlcore/boot.c @@ -72,7 +72,7 @@ static int wlcore_boot_fw_version(struct wl1271 *wl) struct wl1271_static_data *static_data; int ret; - static_data = kmalloc(sizeof(*static_data), GFP_DMA); + static_data = kmalloc(sizeof(*static_data), GFP_KERNEL | GFP_DMA); if (!static_data) { wl1271_error("Couldn't allocate memory for static data!"); return -ENOMEM; @@ -413,6 +413,7 @@ int wlcore_boot_run_firmware(struct wl1271 *wl) /* unmask required mbox events */ wl->event_mask = BSS_LOSE_EVENT_ID | + REGAINED_BSS_EVENT_ID | SCAN_COMPLETE_EVENT_ID | ROLE_STOP_COMPLETE_EVENT_ID | RSSI_SNR_TRIGGER_0_EVENT_ID | diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index 5c4716c6f04..5b128a97144 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -123,7 +123,9 @@ static int wl1271_cmd_wait_for_event_or_timeout(struct wl1271 *wl, u32 mask) unsigned long timeout; int ret = 0; - events_vector = kmalloc(sizeof(*events_vector), GFP_DMA); + events_vector = kmalloc(sizeof(*events_vector), GFP_KERNEL | GFP_DMA); + if (!events_vector) + return -ENOMEM; timeout = jiffies + msecs_to_jiffies(WL1271_EVENT_TIMEOUT); @@ -1034,7 +1036,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) skb_reserve(skb, sizeof(*hdr) + WL1271_EXTRA_SPACE_MAX); tmpl = (struct wl12xx_arp_rsp_template *)skb_put(skb, sizeof(*tmpl)); - memset(tmpl, 0, sizeof(tmpl)); + memset(tmpl, 0, sizeof(*tmpl)); /* llc layer */ memcpy(tmpl->llc_hdr, rfc1042_header, sizeof(rfc1042_header)); @@ -1083,7 +1085,7 @@ int wl1271_cmd_build_arp_rsp(struct wl1271 *wl, struct wl12xx_vif *wlvif) /* mac80211 header */ hdr = (struct ieee80211_hdr_3addr *)skb_push(skb, sizeof(*hdr)); - memset(hdr, 0, sizeof(hdr)); + memset(hdr, 0, sizeof(*hdr)); fc = IEEE80211_FTYPE_DATA | IEEE80211_FCTL_TODS; if (wlvif->sta.qos) fc |= IEEE80211_STYPE_QOS_DATA; diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c index 292632ddf89..28e2a633c3b 100644 --- a/drivers/net/wireless/ti/wlcore/event.c +++ b/drivers/net/wireless/ti/wlcore/event.c @@ -103,7 +103,6 @@ static int wl1271_event_process(struct wl1271 *wl) struct ieee80211_vif *vif; struct wl12xx_vif *wlvif; u32 vector; - bool beacon_loss = false; bool disconnect_sta = false; unsigned long sta_bitmap = 0; @@ -141,20 +140,23 @@ static int wl1271_event_process(struct wl1271 *wl) mbox->soft_gemini_sense_info); /* - * The BSS_LOSE_EVENT_ID is only needed while psm (and hence beacon - * filtering) is enabled. Without PSM, the stack will receive all - * beacons and can detect beacon loss by itself. - * - * As there's possibility that the driver disables PSM before receiving - * BSS_LOSE_EVENT, beacon loss has to be reported to the stack. - * + * We are HW_MONITOR device. On beacon loss - queue + * connection loss work. Cancel it on REGAINED event. */ if (vector & BSS_LOSE_EVENT_ID) { /* TODO: check for multi-role */ + int delay = wl->conf.conn.synch_fail_thold * + wl->conf.conn.bss_lose_timeout; wl1271_info("Beacon loss detected."); + cancel_delayed_work_sync(&wl->connection_loss_work); + ieee80211_queue_delayed_work(wl->hw, &wl->connection_loss_work, + msecs_to_jiffies(delay)); + } - /* indicate to the stack, that beacons have been lost */ - beacon_loss = true; + if (vector & REGAINED_BSS_EVENT_ID) { + /* TODO: check for multi-role */ + wl1271_info("Beacon regained."); + cancel_delayed_work_sync(&wl->connection_loss_work); } if (vector & RSSI_SNR_TRIGGER_0_EVENT_ID) { @@ -257,13 +259,6 @@ static int wl1271_event_process(struct wl1271 *wl) rcu_read_unlock(); } } - - if (beacon_loss) - wl12xx_for_each_wlvif_sta(wl, wlvif) { - vif = wl12xx_wlvif_to_vif(wlvif); - ieee80211_connection_loss(vif); - } - return 0; } diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 2b0f987660c..acef93390d3 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1120,6 +1120,7 @@ int wl1271_plt_stop(struct wl1271 *wl) cancel_work_sync(&wl->recovery_work); cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); + cancel_delayed_work_sync(&wl->connection_loss_work); mutex_lock(&wl->mutex); wl1271_power_off(wl); @@ -1261,8 +1262,270 @@ static struct sk_buff *wl12xx_alloc_dummy_packet(struct wl1271 *wl) #ifdef CONFIG_PM +static int +wl1271_validate_wowlan_pattern(struct cfg80211_wowlan_trig_pkt_pattern *p) +{ + int num_fields = 0, in_field = 0, fields_size = 0; + int i, pattern_len = 0; + + if (!p->mask) { + wl1271_warning("No mask in WoWLAN pattern"); + return -EINVAL; + } + + /* + * The pattern is broken up into segments of bytes at different offsets + * that need to be checked by the FW filter. Each segment is called + * a field in the FW API. We verify that the total number of fields + * required for this pattern won't exceed FW limits (8) + * as well as the total fields buffer won't exceed the FW limit. + * Note that if there's a pattern which crosses Ethernet/IP header + * boundary a new field is required. + */ + for (i = 0; i < p->pattern_len; i++) { + if (test_bit(i, (unsigned long *)p->mask)) { + if (!in_field) { + in_field = 1; + pattern_len = 1; + } else { + if (i == WL1271_RX_FILTER_ETH_HEADER_SIZE) { + num_fields++; + fields_size += pattern_len + + RX_FILTER_FIELD_OVERHEAD; + pattern_len = 1; + } else + pattern_len++; + } + } else { + if (in_field) { + in_field = 0; + fields_size += pattern_len + + RX_FILTER_FIELD_OVERHEAD; + num_fields++; + } + } + } + + if (in_field) { + fields_size += pattern_len + RX_FILTER_FIELD_OVERHEAD; + num_fields++; + } + + if (num_fields > WL1271_RX_FILTER_MAX_FIELDS) { + wl1271_warning("RX Filter too complex. Too many segments"); + return -EINVAL; + } + + if (fields_size > WL1271_RX_FILTER_MAX_FIELDS_SIZE) { + wl1271_warning("RX filter pattern is too big"); + return -E2BIG; + } + + return 0; +} + +struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void) +{ + return kzalloc(sizeof(struct wl12xx_rx_filter), GFP_KERNEL); +} + +void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter) +{ + int i; + + if (filter == NULL) + return; + + for (i = 0; i < filter->num_fields; i++) + kfree(filter->fields[i].pattern); + + kfree(filter); +} + +int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, + u16 offset, u8 flags, + u8 *pattern, u8 len) +{ + struct wl12xx_rx_filter_field *field; + + if (filter->num_fields == WL1271_RX_FILTER_MAX_FIELDS) { + wl1271_warning("Max fields per RX filter. can't alloc another"); + return -EINVAL; + } + + field = &filter->fields[filter->num_fields]; + + field->pattern = kzalloc(len, GFP_KERNEL); + if (!field->pattern) { + wl1271_warning("Failed to allocate RX filter pattern"); + return -ENOMEM; + } + + filter->num_fields++; + + field->offset = cpu_to_le16(offset); + field->flags = flags; + field->len = len; + memcpy(field->pattern, pattern, len); + + return 0; +} + +int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter) +{ + int i, fields_size = 0; + + for (i = 0; i < filter->num_fields; i++) + fields_size += filter->fields[i].len + + sizeof(struct wl12xx_rx_filter_field) - + sizeof(u8 *); + + return fields_size; +} + +void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter, + u8 *buf) +{ + int i; + struct wl12xx_rx_filter_field *field; + + for (i = 0; i < filter->num_fields; i++) { + field = (struct wl12xx_rx_filter_field *)buf; + + field->offset = filter->fields[i].offset; + field->flags = filter->fields[i].flags; + field->len = filter->fields[i].len; + + memcpy(&field->pattern, filter->fields[i].pattern, field->len); + buf += sizeof(struct wl12xx_rx_filter_field) - + sizeof(u8 *) + field->len; + } +} + +/* + * Allocates an RX filter returned through f + * which needs to be freed using rx_filter_free() + */ +static int wl1271_convert_wowlan_pattern_to_rx_filter( + struct cfg80211_wowlan_trig_pkt_pattern *p, + struct wl12xx_rx_filter **f) +{ + int i, j, ret = 0; + struct wl12xx_rx_filter *filter; + u16 offset; + u8 flags, len; + + filter = wl1271_rx_filter_alloc(); + if (!filter) { + wl1271_warning("Failed to alloc rx filter"); + ret = -ENOMEM; + goto err; + } + + i = 0; + while (i < p->pattern_len) { + if (!test_bit(i, (unsigned long *)p->mask)) { + i++; + continue; + } + + for (j = i; j < p->pattern_len; j++) { + if (!test_bit(j, (unsigned long *)p->mask)) + break; + + if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE && + j >= WL1271_RX_FILTER_ETH_HEADER_SIZE) + break; + } + + if (i < WL1271_RX_FILTER_ETH_HEADER_SIZE) { + offset = i; + flags = WL1271_RX_FILTER_FLAG_ETHERNET_HEADER; + } else { + offset = i - WL1271_RX_FILTER_ETH_HEADER_SIZE; + flags = WL1271_RX_FILTER_FLAG_IP_HEADER; + } + + len = j - i; + + ret = wl1271_rx_filter_alloc_field(filter, + offset, + flags, + &p->pattern[i], len); + if (ret) + goto err; + + i = j; + } + + filter->action = FILTER_SIGNAL; + + *f = filter; + return 0; + +err: + wl1271_rx_filter_free(filter); + *f = NULL; + + return ret; +} + +static int wl1271_configure_wowlan(struct wl1271 *wl, + struct cfg80211_wowlan *wow) +{ + int i, ret; + + if (!wow || wow->any || !wow->n_patterns) { + wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); + wl1271_rx_filter_clear_all(wl); + return 0; + } + + if (WARN_ON(wow->n_patterns > WL1271_MAX_RX_FILTERS)) + return -EINVAL; + + /* Validate all incoming patterns before clearing current FW state */ + for (i = 0; i < wow->n_patterns; i++) { + ret = wl1271_validate_wowlan_pattern(&wow->patterns[i]); + if (ret) { + wl1271_warning("Bad wowlan pattern %d", i); + return ret; + } + } + + wl1271_acx_default_rx_filter_enable(wl, 0, FILTER_SIGNAL); + wl1271_rx_filter_clear_all(wl); + + /* Translate WoWLAN patterns into filters */ + for (i = 0; i < wow->n_patterns; i++) { + struct cfg80211_wowlan_trig_pkt_pattern *p; + struct wl12xx_rx_filter *filter = NULL; + + p = &wow->patterns[i]; + + ret = wl1271_convert_wowlan_pattern_to_rx_filter(p, &filter); + if (ret) { + wl1271_warning("Failed to create an RX filter from " + "wowlan pattern %d", i); + goto out; + } + + ret = wl1271_rx_filter_enable(wl, i, 1, filter); + + wl1271_rx_filter_free(filter); + if (ret) + goto out; + } + + ret = wl1271_acx_default_rx_filter_enable(wl, 1, FILTER_DROP); + +out: + return ret; +} + static int wl1271_configure_suspend_sta(struct wl1271 *wl, - struct wl12xx_vif *wlvif) + struct wl12xx_vif *wlvif, + struct cfg80211_wowlan *wow) { int ret = 0; @@ -1273,6 +1536,7 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (ret < 0) goto out; + wl1271_configure_wowlan(wl, wow); ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.suspend_wake_up_event, wl->conf.conn.suspend_listen_interval); @@ -1308,10 +1572,11 @@ out: } static int wl1271_configure_suspend(struct wl1271 *wl, - struct wl12xx_vif *wlvif) + struct wl12xx_vif *wlvif, + struct cfg80211_wowlan *wow) { if (wlvif->bss_type == BSS_TYPE_STA_BSS) - return wl1271_configure_suspend_sta(wl, wlvif); + return wl1271_configure_suspend_sta(wl, wlvif, wow); if (wlvif->bss_type == BSS_TYPE_AP_BSS) return wl1271_configure_suspend_ap(wl, wlvif); return 0; @@ -1332,6 +1597,8 @@ static void wl1271_configure_resume(struct wl1271 *wl, return; if (is_sta) { + wl1271_configure_wowlan(wl, NULL); + ret = wl1271_acx_wake_up_conditions(wl, wlvif, wl->conf.conn.wake_up_event, wl->conf.conn.listen_interval); @@ -1355,15 +1622,16 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw, int ret; wl1271_debug(DEBUG_MAC80211, "mac80211 suspend wow=%d", !!wow); - WARN_ON(!wow || !wow->any); + WARN_ON(!wow); wl1271_tx_flush(wl); mutex_lock(&wl->mutex); wl->wow_enabled = true; wl12xx_for_each_wlvif(wl, wlvif) { - ret = wl1271_configure_suspend(wl, wlvif); + ret = wl1271_configure_suspend(wl, wlvif, wow); if (ret < 0) { + mutex_unlock(&wl->mutex); wl1271_warning("couldn't prepare device to suspend"); return ret; } @@ -1487,6 +1755,7 @@ static void wl1271_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&wl->tx_work); cancel_delayed_work_sync(&wl->elp_work); cancel_delayed_work_sync(&wl->tx_watchdog_work); + cancel_delayed_work_sync(&wl->connection_loss_work); /* let's notify MAC80211 about the remaining pending TX frames */ wl12xx_tx_reset(wl, true); @@ -3439,6 +3708,9 @@ sta_not_found: do_join = true; set_assoc = true; + /* Cancel connection_loss_work */ + cancel_delayed_work_sync(&wl->connection_loss_work); + /* * use basic rates from AP, and determine lowest rate * to use with control frames. @@ -4549,6 +4821,34 @@ static struct bin_attribute fwlog_attr = { .read = wl1271_sysfs_read_fwlog, }; +static void wl1271_connection_loss_work(struct work_struct *work) +{ + struct delayed_work *dwork; + struct wl1271 *wl; + struct ieee80211_vif *vif; + struct wl12xx_vif *wlvif; + + dwork = container_of(work, struct delayed_work, work); + wl = container_of(dwork, struct wl1271, connection_loss_work); + + wl1271_info("Connection loss work."); + + mutex_lock(&wl->mutex); + + if (unlikely(wl->state == WL1271_STATE_OFF)) + goto out; + + /* Call mac80211 connection loss */ + wl12xx_for_each_wlvif_sta(wl, wlvif) { + if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) + goto out; + vif = wl12xx_wlvif_to_vif(wlvif); + ieee80211_connection_loss(vif); + } +out: + mutex_unlock(&wl->mutex); +} + static void wl12xx_derive_mac_addresses(struct wl1271 *wl, u32 oui, u32 nic, int n) { @@ -4804,6 +5104,8 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) INIT_WORK(&wl->recovery_work, wl1271_recovery_work); INIT_DELAYED_WORK(&wl->scan_complete_work, wl1271_scan_complete_work); INIT_DELAYED_WORK(&wl->tx_watchdog_work, wl12xx_tx_watchdog_work); + INIT_DELAYED_WORK(&wl->connection_loss_work, + wl1271_connection_loss_work); wl->freezable_wq = create_freezable_workqueue("wl12xx_wq"); if (!wl->freezable_wq) { @@ -4861,7 +5163,7 @@ struct ieee80211_hw *wlcore_alloc_hw(size_t priv_size) goto err_dummy_packet; } - wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_DMA); + wl->mbox = kmalloc(sizeof(*wl->mbox), GFP_KERNEL | GFP_DMA); if (!wl->mbox) { ret = -ENOMEM; goto err_fwlog; @@ -5003,9 +5305,14 @@ int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev) if (!ret) { wl->irq_wake_enabled = true; device_init_wakeup(wl->dev, 1); - if (pdata->pwr_in_suspend) + if (pdata->pwr_in_suspend) { wl->hw->wiphy->wowlan.flags = WIPHY_WOWLAN_ANY; - + wl->hw->wiphy->wowlan.n_patterns = + WL1271_MAX_RX_FILTERS; + wl->hw->wiphy->wowlan.pattern_min_len = 1; + wl->hw->wiphy->wowlan.pattern_max_len = + WL1271_RX_FILTER_MAX_PATTERN_SIZE; + } } disable_irq(wl->irq); diff --git a/drivers/net/wireless/ti/wlcore/rx.c b/drivers/net/wireless/ti/wlcore/rx.c index 89bd9385e90..1f1d9488dfb 100644 --- a/drivers/net/wireless/ti/wlcore/rx.c +++ b/drivers/net/wireless/ti/wlcore/rx.c @@ -278,3 +278,39 @@ void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status) wl12xx_rearm_rx_streaming(wl, active_hlids); } + +int wl1271_rx_filter_enable(struct wl1271 *wl, + int index, bool enable, + struct wl12xx_rx_filter *filter) +{ + int ret; + + if (wl->rx_filter_enabled[index] == enable) { + wl1271_warning("Request to enable an already " + "enabled rx filter %d", index); + return 0; + } + + ret = wl1271_acx_set_rx_filter(wl, index, enable, filter); + + if (ret) { + wl1271_error("Failed to %s rx data filter %d (err=%d)", + enable ? "enable" : "disable", index, ret); + return ret; + } + + wl->rx_filter_enabled[index] = enable; + + return 0; +} + +void wl1271_rx_filter_clear_all(struct wl1271 *wl) +{ + int i; + + for (i = 0; i < WL1271_MAX_RX_FILTERS; i++) { + if (!wl->rx_filter_enabled[i]) + continue; + wl1271_rx_filter_enable(wl, i, 0, NULL); + } +} diff --git a/drivers/net/wireless/ti/wlcore/rx.h b/drivers/net/wireless/ti/wlcore/rx.h index 6e129e2a854..e9a162a864c 100644 --- a/drivers/net/wireless/ti/wlcore/rx.h +++ b/drivers/net/wireless/ti/wlcore/rx.h @@ -138,5 +138,9 @@ struct wl1271_rx_descriptor { void wl12xx_rx(struct wl1271 *wl, struct wl_fw_status *status); u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band); +int wl1271_rx_filter_enable(struct wl1271 *wl, + int index, bool enable, + struct wl12xx_rx_filter *filter); +void wl1271_rx_filter_clear_all(struct wl1271 *wl); #endif diff --git a/drivers/net/wireless/ti/wlcore/wl12xx.h b/drivers/net/wireless/ti/wlcore/wl12xx.h index a9b220c43e5..f12bdf74518 100644 --- a/drivers/net/wireless/ti/wlcore/wl12xx.h +++ b/drivers/net/wireless/ti/wlcore/wl12xx.h @@ -279,6 +279,39 @@ struct wl1271_link { u8 ba_bitmap; }; +#define WL1271_MAX_RX_FILTERS 5 +#define WL1271_RX_FILTER_MAX_FIELDS 8 + +#define WL1271_RX_FILTER_ETH_HEADER_SIZE 14 +#define WL1271_RX_FILTER_MAX_FIELDS_SIZE 95 +#define RX_FILTER_FIELD_OVERHEAD \ + (sizeof(struct wl12xx_rx_filter_field) - sizeof(u8 *)) +#define WL1271_RX_FILTER_MAX_PATTERN_SIZE \ + (WL1271_RX_FILTER_MAX_FIELDS_SIZE - RX_FILTER_FIELD_OVERHEAD) + +#define WL1271_RX_FILTER_FLAG_MASK BIT(0) +#define WL1271_RX_FILTER_FLAG_IP_HEADER 0 +#define WL1271_RX_FILTER_FLAG_ETHERNET_HEADER BIT(1) + +enum rx_filter_action { + FILTER_DROP = 0, + FILTER_SIGNAL = 1, + FILTER_FW_HANDLE = 2 +}; + +struct wl12xx_rx_filter_field { + __le16 offset; + u8 len; + u8 flags; + u8 *pattern; +} __packed; + +struct wl12xx_rx_filter { + u8 action; + int num_fields; + struct wl12xx_rx_filter_field fields[WL1271_RX_FILTER_MAX_FIELDS]; +}; + struct wl1271_station { u8 hlid; }; @@ -439,6 +472,14 @@ int wl1271_plt_stop(struct wl1271 *wl); int wl1271_recalc_rx_streaming(struct wl1271 *wl, struct wl12xx_vif *wlvif); void wl12xx_queue_recovery_work(struct wl1271 *wl); size_t wl12xx_copy_fwlog(struct wl1271 *wl, u8 *memblock, size_t maxlen); +int wl1271_rx_filter_alloc_field(struct wl12xx_rx_filter *filter, + u16 offset, u8 flags, + u8 *pattern, u8 len); +void wl1271_rx_filter_free(struct wl12xx_rx_filter *filter); +struct wl12xx_rx_filter *wl1271_rx_filter_alloc(void); +int wl1271_rx_filter_get_fields_size(struct wl12xx_rx_filter *filter); +void wl1271_rx_filter_flatten_fields(struct wl12xx_rx_filter *filter, + u8 *buf); #define JOIN_TIMEOUT 5000 /* 5000 milliseconds to join */ diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 39f9fadfebd..0b3f0b586f4 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -243,6 +243,9 @@ struct wl1271 { struct wl1271_scan scan; struct delayed_work scan_complete_work; + /* Connection loss work */ + struct delayed_work connection_loss_work; + bool sched_scanning; /* The current band */ @@ -349,6 +352,9 @@ struct wl1271 { /* size of the private FW status data */ size_t fw_status_priv_len; + + /* RX Data filter rule state - enabled/disabled */ + bool rx_filter_enabled[WL1271_MAX_RX_FILTERS]; }; int __devinit wlcore_probe(struct wl1271 *wl, struct platform_device *pdev); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 0ebbb1906c3..2027afe405f 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -1962,9 +1962,6 @@ static int __init netif_init(void) if (!xen_domain()) return -ENODEV; - if (xen_initial_domain()) - return 0; - if (xen_hvm_domain() && !xen_platform_pci_unplug) return -ENODEV; @@ -1977,9 +1974,6 @@ module_init(netif_init); static void __exit netif_exit(void) { - if (xen_initial_domain()) - return; - xenbus_unregister_driver(&netfront_driver); } module_exit(netif_exit); diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig index 5af959274d4..3b20b73ee64 100644 --- a/drivers/nfc/Kconfig +++ b/drivers/nfc/Kconfig @@ -17,6 +17,19 @@ config PN544_NFC To compile this driver as a module, choose m here. The module will be called pn544. +config PN544_HCI_NFC + tristate "HCI PN544 NFC driver" + depends on I2C && NFC_SHDLC + select CRC_CCITT + default n + ---help--- + NXP PN544 i2c driver. + This is a driver based on the SHDLC and HCI NFC kernel layers and + will thus not work with NXP libnfc library. + + To compile this driver as a module, choose m here. The module will + be called pn544_hci. + config NFC_PN533 tristate "NXP PN533 USB driver" depends on USB diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile index ab99e8572f0..473e44cef61 100644 --- a/drivers/nfc/Makefile +++ b/drivers/nfc/Makefile @@ -3,6 +3,7 @@ # obj-$(CONFIG_PN544_NFC) += pn544.o +obj-$(CONFIG_PN544_HCI_NFC) += pn544_hci.o obj-$(CONFIG_NFC_PN533) += pn533.o obj-$(CONFIG_NFC_WILINK) += nfcwilink.o diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c index e6ec16d92e6..19110f0eb15 100644 --- a/drivers/nfc/pn533.c +++ b/drivers/nfc/pn533.c @@ -394,9 +394,6 @@ static void pn533_wq_cmd_complete(struct work_struct *work) struct pn533_frame *in_frame; int rc; - if (dev == NULL) - return; - in_frame = dev->wq_in_frame; if (dev->wq_in_error) @@ -1194,8 +1191,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev) return rc; } -static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) +static int pn533_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); int rc; @@ -1243,7 +1240,8 @@ static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, return 0; } -static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void pn533_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); u8 tg; @@ -1351,7 +1349,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg, return 0; } -static int pn533_dep_link_up(struct nfc_dev *nfc_dev, int target_idx, +static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target, u8 comm_mode, u8* gb, size_t gb_len) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); @@ -1552,10 +1550,9 @@ error: return 0; } -static int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, - struct sk_buff *skb, - data_exchange_cb_t cb, - void *cb_context) +static int pn533_data_exchange(struct nfc_dev *nfc_dev, + struct nfc_target *target, struct sk_buff *skb, + data_exchange_cb_t cb, void *cb_context) { struct pn533 *dev = nfc_get_drvdata(nfc_dev); struct pn533_frame *out_frame, *in_frame; diff --git a/drivers/nfc/pn544_hci.c b/drivers/nfc/pn544_hci.c new file mode 100644 index 00000000000..46f4a9f9f5e --- /dev/null +++ b/drivers/nfc/pn544_hci.c @@ -0,0 +1,947 @@ +/* + * HCI based Driver for NXP PN544 NFC Chip + * + * Copyright (C) 2012 Intel Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions 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., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/crc-ccitt.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/miscdevice.h> +#include <linux/interrupt.h> +#include <linux/gpio.h> +#include <linux/i2c.h> + +#include <linux/nfc.h> +#include <net/nfc/hci.h> +#include <net/nfc/shdlc.h> + +#include <linux/nfc/pn544.h> + +#define DRIVER_DESC "HCI NFC driver for PN544" + +#define PN544_HCI_DRIVER_NAME "pn544_hci" + +/* Timing restrictions (ms) */ +#define PN544_HCI_RESETVEN_TIME 30 + +static struct i2c_device_id pn544_hci_id_table[] = { + {"pn544", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pn544_hci_id_table); + +#define HCI_MODE 0 +#define FW_MODE 1 + +/* framing in HCI mode */ +#define PN544_HCI_LLC_LEN 1 +#define PN544_HCI_LLC_CRC 2 +#define PN544_HCI_LLC_LEN_CRC (PN544_HCI_LLC_LEN + PN544_HCI_LLC_CRC) +#define PN544_HCI_LLC_MIN_SIZE (1 + PN544_HCI_LLC_LEN_CRC) +#define PN544_HCI_LLC_MAX_PAYLOAD 29 +#define PN544_HCI_LLC_MAX_SIZE (PN544_HCI_LLC_LEN_CRC + 1 + \ + PN544_HCI_LLC_MAX_PAYLOAD) + +enum pn544_state { + PN544_ST_COLD, + PN544_ST_FW_READY, + PN544_ST_READY, +}; + +#define FULL_VERSION_LEN 11 + +/* Proprietary commands */ +#define PN544_WRITE 0x3f + +/* Proprietary gates, events, commands and registers */ + +/* NFC_HCI_RF_READER_A_GATE additional registers and commands */ +#define PN544_RF_READER_A_AUTO_ACTIVATION 0x10 +#define PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION 0x12 +#define PN544_MIFARE_CMD 0x21 + +/* Commands that apply to all RF readers */ +#define PN544_RF_READER_CMD_PRESENCE_CHECK 0x30 +#define PN544_RF_READER_CMD_ACTIVATE_NEXT 0x32 + +/* NFC_HCI_ID_MGMT_GATE additional registers */ +#define PN544_ID_MGMT_FULL_VERSION_SW 0x10 + +#define PN544_RF_READER_ISO15693_GATE 0x12 + +#define PN544_RF_READER_F_GATE 0x14 +#define PN544_FELICA_ID 0x04 +#define PN544_FELICA_RAW 0x20 + +#define PN544_RF_READER_JEWEL_GATE 0x15 +#define PN544_JEWEL_RAW_CMD 0x23 + +#define PN544_RF_READER_NFCIP1_INITIATOR_GATE 0x30 +#define PN544_RF_READER_NFCIP1_TARGET_GATE 0x31 + +#define PN544_SYS_MGMT_GATE 0x90 +#define PN544_SYS_MGMT_INFO_NOTIFICATION 0x02 + +#define PN544_POLLING_LOOP_MGMT_GATE 0x94 +#define PN544_PL_RDPHASES 0x06 +#define PN544_PL_EMULATION 0x07 +#define PN544_PL_NFCT_DEACTIVATED 0x09 + +#define PN544_SWP_MGMT_GATE 0xA0 + +#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 +}; + +/* Largest headroom needed for outgoing custom commands */ +#define PN544_CMDS_HEADROOM 2 + +struct pn544_hci_info { + struct i2c_client *i2c_dev; + struct nfc_shdlc *shdlc; + + enum pn544_state state; + + struct mutex info_lock; + + unsigned int gpio_en; + unsigned int gpio_irq; + unsigned int gpio_fw; + unsigned int en_polarity; + + int hard_fault; /* + * < 0 if hardware error occured (e.g. i2c err) + * and prevents normal operation. + */ +}; + +static void pn544_hci_platform_init(struct pn544_hci_info *info) +{ + int polarity, retry, ret; + char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 }; + int count = sizeof(rset_cmd); + + pr_info(DRIVER_DESC ": %s\n", __func__); + dev_info(&info->i2c_dev->dev, "Detecting nfc_en polarity\n"); + + /* Disable fw download */ + gpio_set_value(info->gpio_fw, 0); + + for (polarity = 0; polarity < 2; polarity++) { + info->en_polarity = polarity; + retry = 3; + while (retry--) { + /* power off */ + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + /* power on */ + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + /* send reset */ + dev_dbg(&info->i2c_dev->dev, "Sending reset cmd\n"); + ret = i2c_master_send(info->i2c_dev, rset_cmd, count); + if (ret == count) { + dev_info(&info->i2c_dev->dev, + "nfc_en polarity : active %s\n", + (polarity == 0 ? "low" : "high")); + goto out; + } + } + } + + dev_err(&info->i2c_dev->dev, + "Could not detect nfc_en polarity, fallback to active high\n"); + +out: + gpio_set_value(info->gpio_en, !info->en_polarity); +} + +static int pn544_hci_enable(struct pn544_hci_info *info, int mode) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + return 0; +} + +static void pn544_hci_disable(struct pn544_hci_info *info) +{ + pr_info(DRIVER_DESC ": %s\n", __func__); + + gpio_set_value(info->gpio_fw, 0); + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, info->en_polarity); + usleep_range(10000, 15000); + + gpio_set_value(info->gpio_en, !info->en_polarity); + usleep_range(10000, 15000); +} + +static int pn544_hci_i2c_write(struct i2c_client *client, u8 *buf, int len) +{ + int r; + + usleep_range(3000, 6000); + + r = i2c_master_send(client, buf, len); + + if (r == -EREMOTEIO) { /* Retry, chip was in standby */ + usleep_range(6000, 10000); + r = i2c_master_send(client, buf, len); + } + + if (r >= 0 && r != len) + r = -EREMOTEIO; + + return r; +} + +static int check_crc(u8 *buf, int buflen) +{ + u8 len; + u16 crc; + + len = buf[0] + 1; + crc = crc_ccitt(0xffff, buf, len - 2); + crc = ~crc; + + if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) { + pr_err(PN544_HCI_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n", + crc, buf[len - 1], buf[len - 2]); + + pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__); + print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE, + 16, 2, buf, buflen, false); + return -EPERM; + } + return 0; +} + +/* + * Reads an shdlc frame and returns it in a newly allocated sk_buff. Guarantees + * that i2c bus will be flushed and that next read will start on a new frame. + * returned skb contains only LLC header and payload. + * returns: + * -EREMOTEIO : i2c read error (fatal) + * -EBADMSG : frame was incorrect and discarded + * -ENOMEM : cannot allocate skb, frame dropped + */ +static int pn544_hci_i2c_read(struct i2c_client *client, struct sk_buff **skb) +{ + int r; + u8 len; + u8 tmp[PN544_HCI_LLC_MAX_SIZE - 1]; + + r = i2c_master_recv(client, &len, 1); + if (r != 1) { + dev_err(&client->dev, "cannot read len byte\n"); + return -EREMOTEIO; + } + + if ((len < (PN544_HCI_LLC_MIN_SIZE - 1)) || + (len > (PN544_HCI_LLC_MAX_SIZE - 1))) { + dev_err(&client->dev, "invalid len byte\n"); + r = -EBADMSG; + goto flush; + } + + *skb = alloc_skb(1 + len, GFP_KERNEL); + if (*skb == NULL) { + r = -ENOMEM; + goto flush; + } + + *skb_put(*skb, 1) = len; + + r = i2c_master_recv(client, skb_put(*skb, len), len); + if (r != len) { + kfree_skb(*skb); + return -EREMOTEIO; + } + + r = check_crc((*skb)->data, (*skb)->len); + if (r != 0) { + kfree_skb(*skb); + r = -EBADMSG; + goto flush; + } + + skb_pull(*skb, 1); + skb_trim(*skb, (*skb)->len - 2); + + usleep_range(3000, 6000); + + return 0; + +flush: + if (i2c_master_recv(client, tmp, sizeof(tmp)) < 0) + r = -EREMOTEIO; + + usleep_range(3000, 6000); + + return r; +} + +/* + * Reads an shdlc frame from the chip. This is not as straightforward as it + * seems. There are cases where we could loose the frame start synchronization. + * The frame format is len-data-crc, and corruption can occur anywhere while + * transiting on i2c bus, such that we could read an invalid len. + * In order to recover synchronization with the next frame, we must be sure + * to read the real amount of data without using the len byte. We do this by + * assuming the following: + * - the chip will always present only one single complete frame on the bus + * before triggering the interrupt + * - the chip will not present a new frame until we have completely read + * the previous one (or until we have handled the interrupt). + * The tricky case is when we read a corrupted len that is less than the real + * len. We must detect this here in order to determine that we need to flush + * the bus. This is the reason why we check the crc here. + */ +static irqreturn_t pn544_hci_irq_thread_fn(int irq, void *dev_id) +{ + struct pn544_hci_info *info = dev_id; + struct i2c_client *client = info->i2c_dev; + struct sk_buff *skb = NULL; + int r; + + BUG_ON(!info); + BUG_ON(irq != info->i2c_dev->irq); + + dev_dbg(&client->dev, "IRQ\n"); + + if (info->hard_fault != 0) + return IRQ_HANDLED; + + r = pn544_hci_i2c_read(client, &skb); + if (r == -EREMOTEIO) { + info->hard_fault = r; + + nfc_shdlc_recv_frame(info->shdlc, NULL); + + return IRQ_HANDLED; + } else if ((r == -ENOMEM) || (r == -EBADMSG)) { + return IRQ_HANDLED; + } + + nfc_shdlc_recv_frame(info->shdlc, skb); + + return IRQ_HANDLED; +} + +static int pn544_hci_open(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + int r = 0; + + mutex_lock(&info->info_lock); + + if (info->state != PN544_ST_COLD) { + r = -EBUSY; + goto out; + } + + r = pn544_hci_enable(info, HCI_MODE); + +out: + mutex_unlock(&info->info_lock); + return r; +} + +static void pn544_hci_close(struct nfc_shdlc *shdlc) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + + mutex_lock(&info->info_lock); + + if (info->state == PN544_ST_COLD) + goto out; + + pn544_hci_disable(info); + +out: + mutex_unlock(&info->info_lock); +} + +static int pn544_hci_ready(struct nfc_shdlc *shdlc) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *skb; + static struct hw_config { + u8 adr[2]; + u8 value; + } hw_config[] = { + {{0x9f, 0x9a}, 0x00}, + + {{0x98, 0x10}, 0xbc}, + + {{0x9e, 0x71}, 0x00}, + + {{0x98, 0x09}, 0x00}, + + {{0x9e, 0xb4}, 0x00}, + + {{0x9e, 0xd9}, 0xff}, + {{0x9e, 0xda}, 0xff}, + {{0x9e, 0xdb}, 0x23}, + {{0x9e, 0xdc}, 0x21}, + {{0x9e, 0xdd}, 0x22}, + {{0x9e, 0xde}, 0x24}, + + {{0x9c, 0x01}, 0x08}, + + {{0x9e, 0xaa}, 0x01}, + + {{0x9b, 0xd1}, 0x0d}, + {{0x9b, 0xd2}, 0x24}, + {{0x9b, 0xd3}, 0x0a}, + {{0x9b, 0xd4}, 0x22}, + {{0x9b, 0xd5}, 0x08}, + {{0x9b, 0xd6}, 0x1e}, + {{0x9b, 0xdd}, 0x1c}, + + {{0x9b, 0x84}, 0x13}, + {{0x99, 0x81}, 0x7f}, + {{0x99, 0x31}, 0x70}, + + {{0x98, 0x00}, 0x3f}, + + {{0x9f, 0x09}, 0x00}, + + {{0x9f, 0x0a}, 0x05}, + + {{0x9e, 0xd1}, 0xa1}, + {{0x99, 0x23}, 0x00}, + + {{0x9e, 0x74}, 0x80}, + + {{0x9f, 0x28}, 0x10}, + + {{0x9f, 0x35}, 0x14}, + + {{0x9f, 0x36}, 0x60}, + + {{0x9c, 0x31}, 0x00}, + + {{0x9c, 0x32}, 0xc8}, + + {{0x9c, 0x19}, 0x40}, + + {{0x9c, 0x1a}, 0x40}, + + {{0x9c, 0x0c}, 0x00}, + + {{0x9c, 0x0d}, 0x00}, + + {{0x9c, 0x12}, 0x00}, + + {{0x9c, 0x13}, 0x00}, + + {{0x98, 0xa2}, 0x0e}, + + {{0x98, 0x93}, 0x40}, + + {{0x98, 0x7d}, 0x02}, + {{0x98, 0x7e}, 0x00}, + {{0x9f, 0xc8}, 0x01}, + }; + struct hw_config *p = hw_config; + int count = ARRAY_SIZE(hw_config); + struct sk_buff *res_skb; + u8 param[4]; + int r; + + param[0] = 0; + while (count--) { + param[1] = p->adr[0]; + param[2] = p->adr[1]; + param[3] = p->value; + + r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_WRITE, + param, 4, &res_skb); + if (r < 0) + return r; + + if (res_skb->len != 1) { + kfree_skb(res_skb); + return -EPROTO; + } + + if (res_skb->data[0] != p->value) { + kfree_skb(res_skb); + return -EIO; + } + + kfree_skb(res_skb); + + p++; + } + + param[0] = NFC_HCI_UICC_HOST_ID; + r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, + NFC_HCI_ADMIN_WHITELIST, param, 1); + if (r < 0) + return r; + + param[0] = 0x3d; + r = nfc_hci_set_param(hdev, PN544_SYS_MGMT_GATE, + PN544_SYS_MGMT_INFO_NOTIFICATION, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_AUTO_ACTIVATION, param, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + param[0] = 0x1; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, param, 1); + if (r < 0) + return r; + + param[0] = 0x0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, param, 1); + if (r < 0) + return r; + + r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE, + PN544_ID_MGMT_FULL_VERSION_SW, &skb); + if (r < 0) + return r; + + if (skb->len != FULL_VERSION_LEN) { + kfree_skb(skb); + return -EINVAL; + } + + print_hex_dump(KERN_DEBUG, "FULL VERSION SOFTWARE INFO: ", + DUMP_PREFIX_NONE, 16, 1, + skb->data, FULL_VERSION_LEN, false); + + kfree_skb(skb); + + return 0; +} + +static int pn544_hci_xmit(struct nfc_shdlc *shdlc, struct sk_buff *skb) +{ + struct pn544_hci_info *info = nfc_shdlc_get_clientdata(shdlc); + struct i2c_client *client = info->i2c_dev; + + if (info->hard_fault != 0) + return info->hard_fault; + + return pn544_hci_i2c_write(client, skb->data, skb->len); +} + +static int pn544_hci_start_poll(struct nfc_shdlc *shdlc, u32 protocols) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + u8 phases = 0; + int r; + u8 duration[2]; + u8 activated; + + pr_info(DRIVER_DESC ": %s protocols = %d\n", __func__, protocols); + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + if (r < 0) + return r; + + duration[0] = 0x18; + duration[1] = 0x6a; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_EMULATION, duration, 2); + if (r < 0) + return r; + + activated = 0; + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_NFCT_DEACTIVATED, &activated, 1); + if (r < 0) + return r; + + if (protocols & (NFC_PROTO_ISO14443_MASK | NFC_PROTO_MIFARE_MASK | + NFC_PROTO_JEWEL_MASK)) + phases |= 1; /* Type A */ + if (protocols & NFC_PROTO_FELICA_MASK) { + phases |= (1 << 2); /* Type F 212 */ + phases |= (1 << 3); /* Type F 424 */ + } + + phases |= (1 << 5); /* NFC active */ + + r = nfc_hci_set_param(hdev, PN544_POLLING_LOOP_MGMT_GATE, + PN544_PL_RDPHASES, &phases, 1); + if (r < 0) + return r; + + r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_READER_REQUESTED, NULL, 0); + if (r < 0) + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); + + return r; +} + +static int pn544_hci_target_from_gate(struct nfc_shdlc *shdlc, u8 gate, + struct nfc_target *target) +{ + switch (gate) { + case PN544_RF_READER_F_GATE: + target->supported_protocols = NFC_PROTO_FELICA_MASK; + break; + case PN544_RF_READER_JEWEL_GATE: + target->supported_protocols = NFC_PROTO_JEWEL_MASK; + target->sens_res = 0x0c00; + break; + default: + return -EPROTO; + } + + return 0; +} + +static int pn544_hci_complete_target_discovered(struct nfc_shdlc *shdlc, + u8 gate, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + struct sk_buff *uid_skb; + int r = 0; + + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + if (target->nfcid1_len != 4 && target->nfcid1_len != 7 && + target->nfcid1_len != 10) + return -EPROTO; + + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + target->nfcid1, target->nfcid1_len, NULL); + } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) { + r = nfc_hci_get_param(hdev, PN544_RF_READER_F_GATE, + PN544_FELICA_ID, &uid_skb); + if (r < 0) + return r; + + if (uid_skb->len != 8) { + kfree_skb(uid_skb); + return -EPROTO; + } + + r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE, + PN544_RF_READER_CMD_ACTIVATE_NEXT, + uid_skb->data, uid_skb->len, NULL); + kfree_skb(uid_skb); + } else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) { + /* + * TODO: maybe other ISO 14443 require some kind of continue + * activation, but for now we've seen only this one below. + */ + if (target->sens_res == 0x4403) /* Type 4 Mifare DESFire */ + r = nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE, + PN544_RF_READER_A_CMD_CONTINUE_ACTIVATION, + NULL, 0, NULL); + } + + return r; +} + +#define MIFARE_CMD_AUTH_KEY_A 0x60 +#define MIFARE_CMD_AUTH_KEY_B 0x61 +#define MIFARE_CMD_HEADER 2 +#define MIFARE_UID_LEN 4 +#define MIFARE_KEY_LEN 6 +#define MIFARE_CMD_LEN 12 +/* + * Returns: + * <= 0: driver handled the data exchange + * 1: driver doesn't especially handle, please do standard processing + */ +static int pn544_hci_data_exchange(struct nfc_shdlc *shdlc, + struct nfc_target *target, + struct sk_buff *skb, + struct sk_buff **res_skb) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + int r; + + pr_info(DRIVER_DESC ": %s for gate=%d\n", __func__, + target->hci_reader_gate); + + switch (target->hci_reader_gate) { + case NFC_HCI_RF_READER_A_GATE: + if (target->supported_protocols & NFC_PROTO_MIFARE_MASK) { + /* + * It seems that pn544 is inverting key and UID for + * MIFARE authentication commands. + */ + if (skb->len == MIFARE_CMD_LEN && + (skb->data[0] == MIFARE_CMD_AUTH_KEY_A || + skb->data[0] == MIFARE_CMD_AUTH_KEY_B)) { + u8 uid[MIFARE_UID_LEN]; + u8 *data = skb->data + MIFARE_CMD_HEADER; + + memcpy(uid, data + MIFARE_KEY_LEN, + MIFARE_UID_LEN); + memmove(data + MIFARE_UID_LEN, data, + MIFARE_KEY_LEN); + memcpy(data, uid, MIFARE_UID_LEN); + } + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_MIFARE_CMD, + skb->data, skb->len, res_skb); + } else + return 1; + case PN544_RF_READER_F_GATE: + *skb_push(skb, 1) = 0; + *skb_push(skb, 1) = 0; + + r = nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_FELICA_RAW, + skb->data, skb->len, res_skb); + if (r == 0) + skb_pull(*res_skb, 1); + return r; + case PN544_RF_READER_JEWEL_GATE: + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_JEWEL_RAW_CMD, + skb->data, skb->len, res_skb); + default: + return 1; + } +} + +static int pn544_hci_check_presence(struct nfc_shdlc *shdlc, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_shdlc_get_hci_dev(shdlc); + + return nfc_hci_send_cmd(hdev, target->hci_reader_gate, + PN544_RF_READER_CMD_PRESENCE_CHECK, + NULL, 0, NULL); +} + +static struct nfc_shdlc_ops pn544_shdlc_ops = { + .open = pn544_hci_open, + .close = pn544_hci_close, + .hci_ready = pn544_hci_ready, + .xmit = pn544_hci_xmit, + .start_poll = pn544_hci_start_poll, + .target_from_gate = pn544_hci_target_from_gate, + .complete_target_discovered = pn544_hci_complete_target_discovered, + .data_exchange = pn544_hci_data_exchange, + .check_presence = pn544_hci_check_presence, +}; + +static int __devinit pn544_hci_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct pn544_hci_info *info; + struct pn544_nfc_platform_data *pdata; + int r = 0; + u32 protocols; + struct nfc_hci_init_data init_data; + + dev_dbg(&client->dev, "%s\n", __func__); + dev_dbg(&client->dev, "IRQ: %d\n", client->irq); + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "Need I2C_FUNC_I2C\n"); + return -ENODEV; + } + + info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL); + if (!info) { + dev_err(&client->dev, + "Cannot allocate memory for pn544_hci_info.\n"); + r = -ENOMEM; + goto err_info_alloc; + } + + info->i2c_dev = client; + info->state = PN544_ST_COLD; + mutex_init(&info->info_lock); + i2c_set_clientdata(client, info); + + pdata = client->dev.platform_data; + if (pdata == NULL) { + dev_err(&client->dev, "No platform data\n"); + r = -EINVAL; + goto err_pdata; + } + + if (pdata->request_resources == NULL) { + dev_err(&client->dev, "request_resources() missing\n"); + r = -EINVAL; + goto err_pdata; + } + + r = pdata->request_resources(client); + if (r) { + dev_err(&client->dev, "Cannot get platform resources\n"); + goto err_pdata; + } + + info->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); + info->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); + info->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); + + pn544_hci_platform_init(info); + + r = request_threaded_irq(client->irq, NULL, pn544_hci_irq_thread_fn, + IRQF_TRIGGER_RISING, PN544_HCI_DRIVER_NAME, + info); + if (r < 0) { + dev_err(&client->dev, "Unable to register IRQ handler\n"); + goto err_rti; + } + + init_data.gate_count = ARRAY_SIZE(pn544_custom_gates); + + memcpy(init_data.gates, pn544_custom_gates, + ARRAY_SIZE(pn544_custom_gates)); + + /* + * TODO: Session id must include the driver name + some bus addr + * persistent info to discriminate 2 identical chips + */ + strcpy(init_data.session_id, "ID544HCI"); + + protocols = NFC_PROTO_JEWEL_MASK | + NFC_PROTO_MIFARE_MASK | + NFC_PROTO_FELICA_MASK | + NFC_PROTO_ISO14443_MASK | + NFC_PROTO_NFC_DEP_MASK; + + info->shdlc = nfc_shdlc_allocate(&pn544_shdlc_ops, + &init_data, protocols, + PN544_CMDS_HEADROOM, 0, + PN544_HCI_LLC_MAX_PAYLOAD, + dev_name(&client->dev)); + if (!info->shdlc) { + dev_err(&client->dev, "Cannot allocate nfc shdlc.\n"); + r = -ENOMEM; + goto err_allocshdlc; + } + + nfc_shdlc_set_clientdata(info->shdlc, info); + + return 0; + +err_allocshdlc: + free_irq(client->irq, info); + +err_rti: + if (pdata->free_resources != NULL) + pdata->free_resources(); + +err_pdata: + kfree(info); + +err_info_alloc: + return r; +} + +static __devexit int pn544_hci_remove(struct i2c_client *client) +{ + struct pn544_hci_info *info = i2c_get_clientdata(client); + struct pn544_nfc_platform_data *pdata = client->dev.platform_data; + + dev_dbg(&client->dev, "%s\n", __func__); + + nfc_shdlc_free(info->shdlc); + + if (info->state != PN544_ST_COLD) { + if (pdata->disable) + pdata->disable(); + } + + free_irq(client->irq, info); + if (pdata->free_resources) + pdata->free_resources(); + + kfree(info); + + return 0; +} + +static struct i2c_driver pn544_hci_driver = { + .driver = { + .name = PN544_HCI_DRIVER_NAME, + }, + .probe = pn544_hci_probe, + .id_table = pn544_hci_id_table, + .remove = __devexit_p(pn544_hci_remove), +}; + +static int __init pn544_hci_init(void) +{ + int r; + + pr_debug(DRIVER_DESC ": %s\n", __func__); + + r = i2c_add_driver(&pn544_hci_driver); + if (r) { + pr_err(PN544_HCI_DRIVER_NAME ": driver registration failed\n"); + return r; + } + + return 0; +} + +static void __exit pn544_hci_exit(void) +{ + i2c_del_driver(&pn544_hci_driver); +} + +module_init(pn544_hci_init); +module_exit(pn544_hci_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(DRIVER_DESC); diff --git a/drivers/ssb/b43_pci_bridge.c b/drivers/ssb/b43_pci_bridge.c index bad7ba517a1..f551e537614 100644 --- a/drivers/ssb/b43_pci_bridge.c +++ b/drivers/ssb/b43_pci_bridge.c @@ -29,6 +29,8 @@ static const struct pci_device_id b43_pci_bridge_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4319) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4320) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4321) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4322) }, + { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43222) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4325) }, { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4328) }, diff --git a/drivers/ssb/pci.c b/drivers/ssb/pci.c index ed4124469a3..e9d94968f39 100644 --- a/drivers/ssb/pci.c +++ b/drivers/ssb/pci.c @@ -178,6 +178,18 @@ err_pci: #define SPEX(_outvar, _offset, _mask, _shift) \ SPEX16(_outvar, _offset, _mask, _shift) +#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \ + do { \ + SPEX(_field[0], _offset + 0, _mask, _shift); \ + SPEX(_field[1], _offset + 2, _mask, _shift); \ + SPEX(_field[2], _offset + 4, _mask, _shift); \ + SPEX(_field[3], _offset + 6, _mask, _shift); \ + SPEX(_field[4], _offset + 8, _mask, _shift); \ + SPEX(_field[5], _offset + 10, _mask, _shift); \ + SPEX(_field[6], _offset + 12, _mask, _shift); \ + SPEX(_field[7], _offset + 14, _mask, _shift); \ + } while (0) + static inline u8 ssb_crc8(u8 crc, u8 data) { @@ -360,8 +372,9 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(et0mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET0M, 14); SPEX(et1mdcport, SSB_SPROM1_ETHPHY, SSB_SPROM1_ETHPHY_ET1M, 15); SPEX(board_rev, SSB_SPROM1_BINF, SSB_SPROM1_BINF_BREV, 0); - SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, - SSB_SPROM1_BINF_CCODE_SHIFT); + if (out->revision == 1) + SPEX(country_code, SSB_SPROM1_BINF, SSB_SPROM1_BINF_CCODE, + SSB_SPROM1_BINF_CCODE_SHIFT); SPEX(ant_available_a, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTA, SSB_SPROM1_BINF_ANTA_SHIFT); SPEX(ant_available_bg, SSB_SPROM1_BINF, SSB_SPROM1_BINF_ANTBG, @@ -387,6 +400,8 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in) SPEX(boardflags_lo, SSB_SPROM1_BFLLO, 0xFFFF, 0); if (out->revision >= 2) SPEX(boardflags_hi, SSB_SPROM2_BFLHI, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM1_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM1_CCODE, 0x00ff, 0); /* Extract the antenna gain values. */ out->antenna_gain.a0 = r123_extract_antgain(out->revision, in, @@ -455,14 +470,17 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in) SPEX(et0phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET0A, 0); SPEX(et1phyaddr, SSB_SPROM4_ETHPHY, SSB_SPROM4_ETHPHY_ET1A, SSB_SPROM4_ETHPHY_ET1A_SHIFT); + SPEX(board_rev, SSB_SPROM4_BOARDREV, 0xFFFF, 0); if (out->revision == 4) { - SPEX(country_code, SSB_SPROM4_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM4_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM4_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM4_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM4_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM4_BFL2LO, 0xFFFF, 0); SPEX(boardflags2_hi, SSB_SPROM4_BFL2HI, 0xFFFF, 0); } else { - SPEX(country_code, SSB_SPROM5_CCODE, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM5_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM5_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM5_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM5_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM5_BFL2LO, 0xFFFF, 0); @@ -525,7 +543,9 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) v = in[SPOFF(SSB_SPROM8_IL0MAC) + i]; *(((__be16 *)out->il0mac) + i) = cpu_to_be16(v); } - SPEX(country_code, SSB_SPROM8_CCODE, 0xFFFF, 0); + SPEX(board_rev, SSB_SPROM8_BOARDREV, 0xFFFF, 0); + SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8); + SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0); SPEX(boardflags_lo, SSB_SPROM8_BFLLO, 0xFFFF, 0); SPEX(boardflags_hi, SSB_SPROM8_BFLHI, 0xFFFF, 0); SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, 0xFFFF, 0); @@ -655,6 +675,63 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in) SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT, SSB_SROM8_FEM_ANTSWLUT_SHIFT); + SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON, + SSB_SPROM8_LEDDC_ON_SHIFT); + SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF, + SSB_SPROM8_LEDDC_OFF_SHIFT); + + SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN, + SSB_SPROM8_TXRXC_TXCHAIN_SHIFT); + SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN, + SSB_SPROM8_TXRXC_RXCHAIN_SHIFT); + SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH, + SSB_SPROM8_TXRXC_SWITCH_SHIFT); + + SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0); + + SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0); + SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0); + + SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP, + SSB_SPROM8_RAWTS_RAWTEMP_SHIFT); + SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER, + SSB_SPROM8_RAWTS_MEASPOWER_SHIFT); + SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE, + SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT); + SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX, + SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT); + SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION, + SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT); + SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR, + SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT); + SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP, + SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT); + SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL, + SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT); + + SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0); + SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0); + SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0); + SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0); + + SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH, + SSB_SPROM8_THERMAL_TRESH_SHIFT); + SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET, + SSB_SPROM8_THERMAL_OFFSET_SHIFT); + SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_PHYCAL, + SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT); + SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD, + SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT); + SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA, + SSB_SPROM8_TEMPDELTA_HYSTERESIS, + SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT); sprom_extract_r458(out, in); /* TODO - get remaining rev 8 stuff needed */ @@ -784,7 +861,6 @@ static void ssb_pci_get_boardinfo(struct ssb_bus *bus, { bi->vendor = bus->host_pci->subsystem_vendor; bi->type = bus->host_pci->subsystem_device; - bi->rev = bus->host_pci->revision; } int ssb_pci_get_invariants(struct ssb_bus *bus, |