diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 11:54:29 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-05-24 11:54:29 -0700 |
commit | 28f3d717618156c0dcd2f497d791b578a7931d87 (patch) | |
tree | 37b11581b51929b5473541e53bd242b3e1a9f666 | |
parent | 654443e20dfc0617231f28a07c96a979ee1a0239 (diff) | |
parent | 1ca7ee30630e1022dbcf1b51be20580815ffab73 (diff) | |
download | lwn-28f3d717618156c0dcd2f497d791b578a7931d87.tar.gz lwn-28f3d717618156c0dcd2f497d791b578a7931d87.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Pull more networking updates from David Miller:
"Ok, everything from here on out will be bug fixes."
1) One final sync of wireless and bluetooth stuff from John Linville.
These changes have all been in his tree for more than a week, and
therefore have had the necessary -next exposure. John was just away
on a trip and didn't have a change to send the pull request until a
day or two ago.
2) Put back some defines in user exposed header file areas that were
removed during the tokenring purge. From Stephen Hemminger and Paul
Gortmaker.
3) A bug fix for UDP hash table allocation got lost in the pile due to
one of those "you got it.. no I've got it.." situations. :-)
From Tim Bird.
4) SKB coalescing in TCP needs to have stricter checks, otherwise we'll
try to coalesce overlapping frags and crash. Fix from Eric Dumazet.
5) RCU routing table lookups can race with free_fib_info(), causing
crashes when we deref the device pointers in the route. Fix by
releasing the net device in the RCU callback. From Yanmin Zhang.
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (293 commits)
tcp: take care of overlaps in tcp_try_coalesce()
ipv4: fix the rcu race between free_fib_info and ip_route_output_slow
mm: add a low limit to alloc_large_system_hash
ipx: restore token ring define to include/linux/ipx.h
if: restore token ring ARP type to header
xen: do not disable netfront in dom0
phy/micrel: Fix ID of KSZ9021
mISDN: Add X-Tensions USB ISDN TA XC-525
gianfar:don't add FCB length to hard_header_len
Bluetooth: Report proper error number in disconnection
Bluetooth: Create flags for bt_sk()
Bluetooth: report the right security level in getsockopt
Bluetooth: Lock the L2CAP channel when sending
Bluetooth: Restore locking semantics when looking up L2CAP channels
Bluetooth: Fix a redundant and problematic incoming MTU check
Bluetooth: Add support for Foxconn/Hon Hai AR5BBU22 0489:E03C
Bluetooth: Fix EIR data generation for mgmt_device_found
Bluetooth: Fix Inquiry with RSSI event mask
Bluetooth: improve readability of l2cap_seq_list code
Bluetooth: Fix skb length calculation
...
189 files changed, 6665 insertions, 5539 deletions
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index c59f6e59fc1e..50d82ae09e2a 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -541,6 +541,18 @@ Who: Kees Cook <keescook@chromium.org> ---------------------------- +What: Removing the pn544 raw driver. +When: 3.6 +Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c + is being replaced by pn544_hci.c which is accessible through the netlink + and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to + work properly with the latest Android stacks. + Having 2 drivers for the same hardware is confusing and as such we + should only keep the one following the kernel NFC APIs. +Who: Samuel Ortiz <sameo@linux.intel.com> + +---------------------------- + What: setitimer accepts user NULL pointer (value) When: 3.6 Why: setitimer is not returning -EFAULT if user pointer is NULL. This diff --git a/Documentation/nfc/nfc-hci.txt b/Documentation/nfc/nfc-hci.txt index 216b7254fcc3..320f9336c781 100644 --- a/Documentation/nfc/nfc-hci.txt +++ b/Documentation/nfc/nfc-hci.txt @@ -22,9 +22,9 @@ response to arrive. HCI events can also be received from the host controller. They will be handled and a translation will be forwarded to NFC Core as needed. HCI uses 2 execution contexts: -- one if for executing commands : nfc_hci_msg_tx_work(). Only one command +- one for executing commands : nfc_hci_msg_tx_work(). Only one command can be executing at any given moment. -- one if for dispatching received events and responses : nfc_hci_msg_rx_work() +- one for dispatching received events and commands : nfc_hci_msg_rx_work(). HCI Session initialization: --------------------------- @@ -52,18 +52,42 @@ entry points: struct nfc_hci_ops { int (*open)(struct nfc_hci_dev *hdev); void (*close)(struct nfc_hci_dev *hdev); + int (*hci_ready) (struct nfc_hci_dev *hdev); int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols); int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate, struct nfc_target *target); + int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate, + struct nfc_target *target); + int (*data_exchange) (struct nfc_hci_dev *hdev, + struct nfc_target *target, + struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_hci_dev *hdev, + struct nfc_target *target); }; -open() and close() shall turn the hardware on and off. xmit() shall simply -write a frame to the chip. start_poll() is an optional entrypoint that shall -set the hardware in polling mode. This must be implemented only if the hardware -uses proprietary gates or a mechanism slightly different from the HCI standard. -target_from_gate() is another optional entrypoint to return the protocols +- open() and close() shall turn the hardware on and off. +- hci_ready() is an optional entry point that is called right after the hci +session has been set up. The driver can use it to do additional initialization +that must be performed using HCI commands. +- xmit() shall simply write a frame to the chip. +- start_poll() is an optional entrypoint that shall set the hardware in polling +mode. This must be implemented only if the hardware uses proprietary gates or a +mechanism slightly different from the HCI standard. +- target_from_gate() is an optional entrypoint to return the nfc protocols corresponding to a proprietary gate. +- complete_target_discovered() is an optional entry point to let the driver +perform additional proprietary processing necessary to auto activate the +discovered target. +- data_exchange() must be implemented by the driver if proprietary HCI commands +are required to send data to the tag. Some tag types will require custom +commands, others can be written to using the standard HCI commands. The driver +can check the tag type and either do proprietary processing, or return 1 to ask +for standard processing. +- check_presence() is an optional entry point that will be called regularly +by the core to check that an activated tag is still in the field. If this is +not implemented, the core will not be able to push tag_lost events to the user +space On the rx path, the driver is responsible to push incoming HCP frames to HCI using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling @@ -99,7 +123,8 @@ fast, cannot sleep. stores incoming frames into an shdlc rx queue handles shdlc rx & tx queues. Dispatches HCI cmd responses. - HCI Tx Cmd worker (MSGTXWQ) -Serialize execution of HCI commands. Complete execution in case of resp timeout. +Serializes execution of HCI commands. Completes execution in case of response +timeout. - HCI Rx worker (MSGRXWQ) Dispatches incoming HCI commands or events. @@ -133,11 +158,11 @@ able to complete the command with a timeout error if no response arrive. SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function handles shdlc framing in and out. It uses the driver xmit to send frames and receives incoming frames in an skb queue filled from the driver IRQ handler. -SHDLC I(nformation) frames payload are HCP fragments. They are agregated to +SHDLC I(nformation) frames payload are HCP fragments. They are aggregated to form complete HCI frames, which can be a response, command, or event. HCI Responses are dispatched immediately from this context to unblock -waiting command execution. Reponse processing involves invoking the completion +waiting command execution. Response processing involves invoking the completion callback that was provided by nfc_hci_msg_tx_work() when it sent the command. The completion callback will then wake the syscall context. diff --git a/arch/mips/bcm47xx/setup.c b/arch/mips/bcm47xx/setup.c index 19780aa91708..95bf4d7bac21 100644 --- a/arch/mips/bcm47xx/setup.c +++ b/arch/mips/bcm47xx/setup.c @@ -90,6 +90,7 @@ static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out) char prefix[10]; if (bus->bustype == SSB_BUSTYPE_PCI) { + memset(out, 0, sizeof(struct ssb_sprom)); snprintf(prefix, sizeof(prefix), "pci/%u/%u/", bus->host_pci->bus->number + 1, PCI_SLOT(bus->host_pci->devfn)); @@ -109,15 +110,9 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus, /* Fill boardinfo structure */ memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo)); - if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0) - iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0); - else - iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM; - if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0) - iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0); - if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0) - iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0); + bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL); + memset(&iv->sprom, 0, sizeof(struct ssb_sprom)); bcm47xx_fill_sprom(&iv->sprom, NULL); if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0) @@ -166,12 +161,14 @@ static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out) switch (bus->hosttype) { case BCMA_HOSTTYPE_PCI: + memset(out, 0, sizeof(struct ssb_sprom)); snprintf(prefix, sizeof(prefix), "pci/%u/%u/", bus->host_pci->bus->number + 1, PCI_SLOT(bus->host_pci->devfn)); bcm47xx_fill_sprom(out, prefix); return 0; case BCMA_HOSTTYPE_SOC: + memset(out, 0, sizeof(struct ssb_sprom)); bcm47xx_fill_sprom_ethernet(out, NULL); core = bcma_find_core(bus, BCMA_CORE_80211); if (core) { @@ -197,6 +194,8 @@ static void __init bcm47xx_register_bcma(void) err = bcma_host_soc_register(&bcm47xx_bus.bcma); if (err) panic("Failed to initialize BCMA bus (err %d)", err); + + bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL); } #endif diff --git a/arch/mips/bcm47xx/sprom.c b/arch/mips/bcm47xx/sprom.c index 5c8dcd2a8a93..d3a889745e20 100644 --- a/arch/mips/bcm47xx/sprom.c +++ b/arch/mips/bcm47xx/sprom.c @@ -165,6 +165,8 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom, const char *prefix) { nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0); + if (!sprom->board_rev) + nvram_read_u16(NULL, NULL, "boardrev", &sprom->board_rev, 0); nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0); nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff); nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff); @@ -555,8 +557,6 @@ void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix) void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) { - memset(sprom, 0, sizeof(struct ssb_sprom)); - bcm47xx_fill_sprom_ethernet(sprom, prefix); nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0); @@ -618,3 +618,27 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix) bcm47xx_fill_sprom_r1(sprom, prefix); } } + +#ifdef CONFIG_BCM47XX_SSB +void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0); + if (!boardinfo->vendor) + boardinfo->vendor = SSB_BOARDVENDOR_BCM; + + nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); +} +#endif + +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix) +{ + nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0); + if (!boardinfo->vendor) + boardinfo->vendor = SSB_BOARDVENDOR_BCM; + + nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0); +} +#endif diff --git a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h index 5ecaf47b34d2..26fdaf40b930 100644 --- a/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h +++ b/arch/mips/include/asm/mach-bcm47xx/bcm47xx.h @@ -47,4 +47,13 @@ extern enum bcm47xx_bus_type bcm47xx_bus_type; void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix); void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix); +#ifdef CONFIG_BCM47XX_SSB +void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo, + const char *prefix); +#endif +#ifdef CONFIG_BCM47XX_BCMA +void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo, + const char *prefix); +#endif + #endif /* __ASM_BCM47XX_H */ diff --git a/drivers/bcma/core.c b/drivers/bcma/core.c index 893f6e0c759f..bc6e89212ad3 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 4d38ae179b48..9a96f14c8f47 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 d2097a11c3c7..b9a86edfec39 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 e3928d68802b..6c05cf470f96 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 3bea7fe25b20..5ed0718fc660 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 3e2a6002aae6..c7f93359acb0 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 2812b152d6e9..ad591bd240ec 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 90bda50dc446..94f2d65131c4 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 d1209adc882d..681ca9d18e12 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 27b74b0d547b..a853244e7fd7 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 461c68bc4dd7..c9463af8e564 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 98a8c05d4f23..e564579a6115 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 158bfe507da7..3f72595a6017 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 cb1231b08f78..4157311d569d 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 1adb0245b9dd..0741aded9eb0 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 28a65d3a03d0..b869a358ce43 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 c5def436417f..5ea8cbb79f43 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 9d67964a51dd..4d9c6f142698 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 1b76aff78508..15cfe30e54fd 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 065e61516d7a..2798624d3a9d 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 b277b3446882..f9626c723693 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 29ef50ea07d5..7eb0515f458a 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 4d818f96c415..e5524470529c 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 44ea7a742101..05b95405f7b5 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 82f2f5cb475b..67206aedea6c 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 44a795f14da9..3740c3d6ab88 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 7c8a9977faf5..ee8ec2394c2c 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 d3d2ab5c1689..9076bec3a2ba 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 a0387a027db0..9fdd70fcaf5b 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 3cac293a2849..ffbb180f91e1 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 458bedf0b0ae..74de3539c2c8 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 030758d087d6..a43b30d723a4 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 f84477c5ebb1..abe05ec85d50 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 828b9bbc456d..b620c557c2a6 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 424692df239d..565fdbdd6915 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 b5f1b91002bb..777cd74921d7 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 617afc8211b2..5a39b226b2e3 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 1be214b815fb..cd9c9bc186d9 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 950334197f40..995c7d0c212a 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 fcbafcd603cc..896177690394 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 4add7da24681..e2480d196276 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 dd07d33a927c..82f51dbd0d66 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 149ee67beb2e..1dbf2be478c8 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 1534efc21631..f8e1f1c84d08 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 7010eaf71f99..29bf78d264e0 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 c2eb2d0af386..e227c4c68ef9 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 c93ea35bceec..6d8b7213643a 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 f84c6f781692..d9f04a683bdb 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 a47ce25cb9a2..55e12c327911 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 0efe88e25a9a..eb77ac3cfb6b 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 aa15558f75c8..50f92a0b7c41 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 b4d92792c502..19db4052c44c 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 7fad6dc19258..000000000000 --- 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 9fc3ead540a8..000000000000 --- 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 f1ca12625860..000000000000 --- 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 6b6d31cf9569..000000000000 --- 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 0fce56235f38..abfd78822fb8 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 812b6e38526e..13b261517cce 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 5926854f62e2..a0de5db0cd64 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 9168c459b185..2c5b66b75970 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 f0038ad7d7bf..aa5d67f8d874 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 b96f4b9d74bd..000000000000 --- 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 f2a58f262c99..000000000000 --- 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 d8f528eb180c..ed1d1aa71d2d 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 01dc44267317..e55ec6c8a920 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 74fbee627306..0a3aa7c83003 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 f2e9f298a947..3366e2e2f00f 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 8d7637083fcf..ec36e2b020b6 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 83a6930f3658..9af6a239b384 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 d33cc9cc7d3f..ab2f4d7500a4 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 8352265dbc4b..544ddf17f5bd 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 a8437a6bc18e..031d8e21f82f 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 03c0c6b1372c..fb787df01666 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 5c1a46bf1e11..3f66ebb0a630 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 c78ea873a63a..87671446e24b 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 76c76c60438b..c5848934f111 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 1710beffb93a..51e023ec1de4 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 d04aba4131dc..f918f66e5e27 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 5f6adeb9b950..9f674bbebe65 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 000000000000..ceb82cd749cc --- /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 d440c3eb640b..c1cb004db913 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 f0f95524e96b..e6be6ee75951 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 8a390982463e..d6b4fb04011f 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 be0f0e583f75..3192855c31c0 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 324ad390cacd..bd3b0bf94b9e 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 87ed2a1f6cd9..40e025da6bc2 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 3aa54243dea9..a79ed9bd9695 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 f6bbb9307f86..4ace5a3dcd23 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 58970e0f7d13..106c449477b2 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 000000000000..76dfbc42a732 --- /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 429a1dee2d26..f3fc65515857 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 c5404eb82b2f..2e9e6af21362 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 931331d95217..cad25bfebd7a 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 5b92329122c4..c2183594655a 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 9d04c38938bc..54156b0b5c2d 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 5912541a925e..509aa881d790 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 b2f88831b7a9..8106b2ebfe60 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 3a2207db5405..9b98230f84ce 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 5c4716c6f040..5b128a971449 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 292632ddf890..28e2a633c3be 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 2b0f987660c6..acef93390d3d 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 89bd9385e90b..1f1d9488dfb6 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 6e129e2a8546..e9a162a864ca 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 a9b220c43e54..f12bdf745180 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 39f9fadfebd9..0b3f0b586f4b 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 0ebbb1906c30..2027afe405fe 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 5af959274d4e..3b20b73ee649 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 ab99e8572f02..473e44cef612 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 e6ec16d92e65..19110f0eb15f 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 000000000000..46f4a9f9f5e4 --- /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 bad7ba517a1c..f551e5376147 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 ed4124469a3a..e9d94968f394 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, diff --git a/fs/dcache.c b/fs/dcache.c index 8c1ab8fb5012..4435d8b32904 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3093,6 +3093,7 @@ static void __init dcache_init_early(void) HASH_EARLY, &d_hash_shift, &d_hash_mask, + 0, 0); for (loop = 0; loop < (1U << d_hash_shift); loop++) @@ -3123,6 +3124,7 @@ static void __init dcache_init(void) 0, &d_hash_shift, &d_hash_mask, + 0, 0); for (loop = 0; loop < (1U << d_hash_shift); loop++) diff --git a/fs/inode.c b/fs/inode.c index deb72f6c2b4f..da93f7d160d4 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -1647,6 +1647,7 @@ void __init inode_init_early(void) HASH_EARLY, &i_hash_shift, &i_hash_mask, + 0, 0); for (loop = 0; loop < (1U << i_hash_shift); loop++) @@ -1677,6 +1678,7 @@ void __init inode_init(void) 0, &i_hash_shift, &i_hash_mask, + 0, 0); for (loop = 0; loop < (1U << i_hash_shift); loop++) diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 74af192ef7ae..4cd59b95858f 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -270,6 +270,7 @@ header-y += netfilter_ipv4.h header-y += netfilter_ipv6.h header-y += netlink.h header-y += netrom.h +header-y += nfc.h header-y += nfs.h header-y += nfs2.h header-y += nfs3.h diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 98bb2901d7b7..8deaf6d050c3 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -26,6 +26,11 @@ struct bcma_chipinfo { u8 pkg; }; +struct bcma_boardinfo { + u16 vendor; + u16 type; +}; + enum bcma_clkmode { BCMA_CLKMODE_FAST, BCMA_CLKMODE_DYNAMIC, @@ -199,6 +204,8 @@ struct bcma_bus { struct bcma_chipinfo chipinfo; + struct bcma_boardinfo boardinfo; + struct bcma_device *mapped_core; struct list_head cores; u8 nr_cores; diff --git a/include/linux/bcma/bcma_driver_pci.h b/include/linux/bcma/bcma_driver_pci.h index 46c71e27d31f..41da581e1612 100644 --- a/include/linux/bcma/bcma_driver_pci.h +++ b/include/linux/bcma/bcma_driver_pci.h @@ -87,6 +87,13 @@ struct pci_dev; #define BCMA_CORE_PCI_PCICFG2 0x0600 /* PCI config space 2 (rev >= 8) */ #define BCMA_CORE_PCI_PCICFG3 0x0700 /* PCI config space 3 (rev >= 8) */ #define BCMA_CORE_PCI_SPROM(wordoffset) (0x0800 + ((wordoffset) * 2)) /* SPROM shadow area (72 bytes) */ +#define BCMA_CORE_PCI_SPROM_PI_OFFSET 0 /* first word */ +#define BCMA_CORE_PCI_SPROM_PI_MASK 0xf000 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_PI_SHIFT 12 /* bit 15:12 */ +#define BCMA_CORE_PCI_SPROM_MISC_CONFIG 5 /* word 5 */ +#define BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */ +#define BCMA_CORE_PCI_SPROM_CLKREQ_ENB 0x0800 /* bit 11 */ /* SBtoPCIx */ #define BCMA_CORE_PCI_SBTOPCI_MEM 0x00000000 @@ -133,6 +140,7 @@ struct pci_dev; #define BCMA_CORE_PCI_DLLP_LRREG 0x120 /* Link Replay */ #define BCMA_CORE_PCI_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ #define BCMA_CORE_PCI_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ +#define BCMA_CORE_PCI_ASPMTIMER_EXTEND 0x01000000 /* > rev7: enable extend ASPM timer */ #define BCMA_CORE_PCI_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ #define BCMA_CORE_PCI_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ #define BCMA_CORE_PCI_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ @@ -201,12 +209,15 @@ struct bcma_drv_pci { }; /* Register access */ +#define pcicore_read16(pc, offset) bcma_read16((pc)->core, offset) #define pcicore_read32(pc, offset) bcma_read32((pc)->core, offset) +#define pcicore_write16(pc, offset, val) bcma_write16((pc)->core, offset, val) #define pcicore_write32(pc, offset, val) bcma_write32((pc)->core, offset, val) extern void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc); extern int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core, bool enable); +extern void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend); extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev); extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev); diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h index 66d3e954eb6c..1a0cd270bb7a 100644 --- a/include/linux/bootmem.h +++ b/include/linux/bootmem.h @@ -154,7 +154,8 @@ extern void *alloc_large_system_hash(const char *tablename, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, - unsigned long limit); + unsigned long low_limit, + unsigned long high_limit); #define HASH_EARLY 0x00000001 /* Allocating during early boot? */ #define HASH_SMALL 0x00000002 /* sub-page allocation allowed, min diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 26cb3c2c5c71..f0e69c6e8208 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -82,7 +82,7 @@ #define ARPHRD_FCPL 786 /* Fibrechannel public loop */ #define ARPHRD_FCFABRIC 787 /* Fibrechannel fabric */ /* 787->799 reserved for fibrechannel media types */ -/* 800 used to be used for token ring */ +#define ARPHRD_IEEE802_TR 800 /* Magic type ident for TR */ #define ARPHRD_IEEE80211 801 /* IEEE 802.11 */ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ diff --git a/include/linux/ipx.h b/include/linux/ipx.h index 8f0243982eb6..3d48014cdd71 100644 --- a/include/linux/ipx.h +++ b/include/linux/ipx.h @@ -38,7 +38,7 @@ struct ipx_interface_definition { #define IPX_FRAME_8022 2 #define IPX_FRAME_ETHERII 3 #define IPX_FRAME_8023 4 -/* obsolete token ring was 5 */ +#define IPX_FRAME_TR_8022 5 /* obsolete */ unsigned char ipx_special; #define IPX_SPECIAL_NONE 0 #define IPX_PRIMARY 1 diff --git a/include/linux/micrel_phy.h b/include/linux/micrel_phy.h index dd8da342a991..61f0905bdc48 100644 --- a/include/linux/micrel_phy.h +++ b/include/linux/micrel_phy.h @@ -3,7 +3,7 @@ #define MICREL_PHY_ID_MASK 0x00fffff0 -#define PHY_ID_KSZ9021 0x00221611 +#define PHY_ID_KSZ9021 0x00221610 #define PHY_ID_KS8737 0x00221720 #define PHY_ID_KS8041 0x00221510 #define PHY_ID_KS8051 0x00221550 diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h index 7ab8521f2347..9890bbaf4328 100644 --- a/include/linux/nfc/pn544.h +++ b/include/linux/nfc/pn544.h @@ -84,6 +84,12 @@ struct pn544_fw_packet { }; #ifdef __KERNEL__ +enum { + NFC_GPIO_ENABLE, + NFC_GPIO_FW_RESET, + NFC_GPIO_IRQ +}; + /* board config */ struct pn544_nfc_platform_data { int (*request_resources) (struct i2c_client *client); @@ -91,6 +97,7 @@ struct pn544_nfc_platform_data { void (*enable) (int fw); int (*test) (void); void (*disable) (void); + int (*get_gpio)(int type); }; #endif /* __KERNEL__ */ diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 2540e86d99ab..a6959f72745e 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -1594,6 +1594,8 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +#define NL80211_STA_FLAG_MAX_OLD_API NL80211_STA_FLAG_TDLS_PEER + /** * struct nl80211_sta_flag_update - station flags mask/set * @mask: mask of station flags to set @@ -1994,9 +1996,9 @@ enum nl80211_reg_rule_flags { * enum nl80211_dfs_regions - regulatory DFS regions * * @NL80211_DFS_UNSET: Country has no DFS master region specified - * @NL80211_DFS_FCC_: Country follows DFS master rules from FCC - * @NL80211_DFS_FCC_: Country follows DFS master rules from ETSI - * @NL80211_DFS_JP_: Country follows DFS master rules from JP/MKK/Telec + * @NL80211_DFS_FCC: Country follows DFS master rules from FCC + * @NL80211_DFS_ETSI: Country follows DFS master rules from ETSI + * @NL80211_DFS_JP: Country follows DFS master rules from JP/MKK/Telec */ enum nl80211_dfs_regions { NL80211_DFS_UNSET = 0, diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index d27683180025..bc14bd738ade 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h @@ -188,7 +188,6 @@ struct ssb_sprom { struct ssb_boardinfo { u16 vendor; u16 type; - u8 rev; }; diff --git a/include/linux/ssb/ssb_regs.h b/include/linux/ssb/ssb_regs.h index 40b1ef8595ee..a0525019e1d1 100644 --- a/include/linux/ssb/ssb_regs.h +++ b/include/linux/ssb/ssb_regs.h @@ -228,6 +228,7 @@ #define SSB_SPROM1_AGAIN_BG_SHIFT 0 #define SSB_SPROM1_AGAIN_A 0xFF00 /* A-PHY */ #define SSB_SPROM1_AGAIN_A_SHIFT 8 +#define SSB_SPROM1_CCODE 0x0076 /* SPROM Revision 2 (inherits from rev 1) */ #define SSB_SPROM2_BFLHI 0x0038 /* Boardflags (high 16 bits) */ @@ -267,6 +268,7 @@ #define SSB_SPROM3_OFDMGPO 0x107A /* G-PHY OFDM Power Offset (4 bytes, BigEndian) */ /* SPROM Revision 4 */ +#define SSB_SPROM4_BOARDREV 0x0042 /* Board revision */ #define SSB_SPROM4_BFLLO 0x0044 /* Boardflags (low 16 bits) */ #define SSB_SPROM4_BFLHI 0x0046 /* Board Flags Hi */ #define SSB_SPROM4_BFL2LO 0x0048 /* Board flags 2 (low 16 bits) */ @@ -389,6 +391,11 @@ #define SSB_SPROM8_GPIOB_P2 0x00FF /* Pin 2 */ #define SSB_SPROM8_GPIOB_P3 0xFF00 /* Pin 3 */ #define SSB_SPROM8_GPIOB_P3_SHIFT 8 +#define SSB_SPROM8_LEDDC 0x009A +#define SSB_SPROM8_LEDDC_ON 0xFF00 /* oncount */ +#define SSB_SPROM8_LEDDC_ON_SHIFT 8 +#define SSB_SPROM8_LEDDC_OFF 0x00FF /* offcount */ +#define SSB_SPROM8_LEDDC_OFF_SHIFT 0 #define SSB_SPROM8_ANTAVAIL 0x009C /* Antenna available bitfields*/ #define SSB_SPROM8_ANTAVAIL_A 0xFF00 /* A-PHY bitfield */ #define SSB_SPROM8_ANTAVAIL_A_SHIFT 8 @@ -404,6 +411,13 @@ #define SSB_SPROM8_AGAIN2_SHIFT 0 #define SSB_SPROM8_AGAIN3 0xFF00 /* Antenna 3 */ #define SSB_SPROM8_AGAIN3_SHIFT 8 +#define SSB_SPROM8_TXRXC 0x00A2 +#define SSB_SPROM8_TXRXC_TXCHAIN 0x000f +#define SSB_SPROM8_TXRXC_TXCHAIN_SHIFT 0 +#define SSB_SPROM8_TXRXC_RXCHAIN 0x00f0 +#define SSB_SPROM8_TXRXC_RXCHAIN_SHIFT 4 +#define SSB_SPROM8_TXRXC_SWITCH 0xff00 +#define SSB_SPROM8_TXRXC_SWITCH_SHIFT 8 #define SSB_SPROM8_RSSIPARM2G 0x00A4 /* RSSI params for 2GHz */ #define SSB_SPROM8_RSSISMF2G 0x000F #define SSB_SPROM8_RSSISMC2G 0x00F0 @@ -430,6 +444,7 @@ #define SSB_SPROM8_TRI5GH_SHIFT 8 #define SSB_SPROM8_RXPO 0x00AC /* RX power offsets */ #define SSB_SPROM8_RXPO2G 0x00FF /* 2GHz RX power offset */ +#define SSB_SPROM8_RXPO2G_SHIFT 0 #define SSB_SPROM8_RXPO5G 0xFF00 /* 5GHz RX power offset */ #define SSB_SPROM8_RXPO5G_SHIFT 8 #define SSB_SPROM8_FEM2G 0x00AE @@ -445,10 +460,38 @@ #define SSB_SROM8_FEM_ANTSWLUT 0xF800 #define SSB_SROM8_FEM_ANTSWLUT_SHIFT 11 #define SSB_SPROM8_THERMAL 0x00B2 -#define SSB_SPROM8_MPWR_RAWTS 0x00B4 -#define SSB_SPROM8_TS_SLP_OPT_CORRX 0x00B6 -#define SSB_SPROM8_FOC_HWIQ_IQSWP 0x00B8 -#define SSB_SPROM8_PHYCAL_TEMPDELTA 0x00BA +#define SSB_SPROM8_THERMAL_OFFSET 0x00ff +#define SSB_SPROM8_THERMAL_OFFSET_SHIFT 0 +#define SSB_SPROM8_THERMAL_TRESH 0xff00 +#define SSB_SPROM8_THERMAL_TRESH_SHIFT 8 +/* Temp sense related entries */ +#define SSB_SPROM8_RAWTS 0x00B4 +#define SSB_SPROM8_RAWTS_RAWTEMP 0x01ff +#define SSB_SPROM8_RAWTS_RAWTEMP_SHIFT 0 +#define SSB_SPROM8_RAWTS_MEASPOWER 0xfe00 +#define SSB_SPROM8_RAWTS_MEASPOWER_SHIFT 9 +#define SSB_SPROM8_OPT_CORRX 0x00B6 +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE 0x00ff +#define SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT 0 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX 0xfc00 +#define SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT 10 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION 0x0300 +#define SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT 8 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */ +#define SSB_SPROM8_HWIQ_IQSWP 0x00B8 +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR 0x000f +#define SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT 0 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP 0x0010 +#define SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL 0x0020 +#define SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT 5 +#define SSB_SPROM8_TEMPDELTA 0x00BA +#define SSB_SPROM8_TEMPDELTA_PHYCAL 0x00ff +#define SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT 0 +#define SSB_SPROM8_TEMPDELTA_PERIOD 0x0f00 +#define SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT 8 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS 0xf000 +#define SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT 12 /* There are 4 blocks with power info sharing the same layout */ #define SSB_SROM8_PWR_INFO_CORE0 0x00C0 @@ -513,6 +556,16 @@ #define SSB_SPROM8_OFDM5GLPO 0x014A /* 5.2GHz OFDM power offset */ #define SSB_SPROM8_OFDM5GHPO 0x014E /* 5.8GHz OFDM power offset */ +#define SSB_SPROM8_2G_MCSPO 0x0152 +#define SSB_SPROM8_5G_MCSPO 0x0162 +#define SSB_SPROM8_5GL_MCSPO 0x0172 +#define SSB_SPROM8_5GH_MCSPO 0x0182 + +#define SSB_SPROM8_CDDPO 0x0192 +#define SSB_SPROM8_STBCPO 0x0194 +#define SSB_SPROM8_BW40PO 0x0196 +#define SSB_SPROM8_BWDUPPO 0x0198 + /* Values for boardflags_lo read from SPROM */ #define SSB_BFL_BTCOEXIST 0x0001 /* implements Bluetooth coexistance */ #define SSB_BFL_PACTRL 0x0002 /* GPIO 9 controlling the PA */ diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index a65910bda381..961669b648fd 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -163,6 +163,11 @@ typedef struct { __u8 b[6]; } __packed bdaddr_t; +/* BD Address type */ +#define BDADDR_BREDR 0x00 +#define BDADDR_LE_PUBLIC 0x01 +#define BDADDR_LE_RANDOM 0x02 + #define BDADDR_ANY (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}}) #define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}}) @@ -178,7 +183,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) void baswap(bdaddr_t *dst, bdaddr_t *src); char *batostr(bdaddr_t *ba); -bdaddr_t *strtoba(char *str); /* Common socket structures and functions */ @@ -190,8 +194,12 @@ struct bt_sock { bdaddr_t dst; struct list_head accept_q; struct sock *parent; - u32 defer_setup; - bool suspended; + unsigned long flags; +}; + +enum { + BT_SK_DEFER_SETUP, + BT_SK_SUSPEND, }; struct bt_sock_list { @@ -216,14 +224,24 @@ void bt_accept_unlink(struct sock *sk); struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock); /* Skb helpers */ +struct l2cap_ctrl { + unsigned int sframe : 1, + poll : 1, + final : 1, + fcs : 1, + sar : 2, + super : 2; + __u16 reqseq; + __u16 txseq; + __u8 retries; +}; + struct bt_skb_cb { __u8 pkt_type; __u8 incoming; __u16 expect; - __u16 tx_seq; - __u8 retries; - __u8 sar; __u8 force_active; + struct l2cap_ctrl control; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) @@ -243,12 +261,10 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk, { struct sk_buff *skb; - release_sock(sk); if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) { skb_reserve(skb, BT_SKB_RESERVE); bt_cb(skb)->incoming = 0; } - lock_sock(sk); if (!skb && *err) return NULL; diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index d47e523c9d83..66a7b579e31c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -102,6 +102,7 @@ enum { HCI_DISCOVERABLE, HCI_LINK_SECURITY, HCI_PENDING_CLASS, + HCI_PERIODIC_INQ, }; /* HCI ioctl defines */ @@ -324,6 +325,8 @@ struct hci_cp_inquiry { #define HCI_OP_INQUIRY_CANCEL 0x0402 +#define HCI_OP_PERIODIC_INQ 0x0403 + #define HCI_OP_EXIT_PERIODIC_INQ 0x0404 #define HCI_OP_CREATE_CONN 0x0405 @@ -717,6 +720,10 @@ struct hci_rp_read_local_oob_data { } __packed; #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 +struct hci_rp_read_inq_rsp_tx_power { + __u8 status; + __s8 tx_power; +} __packed; #define HCI_OP_READ_FLOW_CONTROL_MODE 0x0c66 struct hci_rp_read_flow_control_mode { @@ -1431,6 +1438,5 @@ struct hci_inquiry_req { #define IREQ_CACHE_FLUSH 0x0001 extern bool enable_hs; -extern bool enable_le; #endif /* __HCI_H */ diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index db1c5df45224..9fc7728f94e4 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -155,9 +155,14 @@ struct hci_dev { __u16 hci_rev; __u8 lmp_ver; __u16 manufacturer; - __le16 lmp_subver; + __u16 lmp_subver; __u16 voice_setting; __u8 io_capability; + __s8 inq_tx_power; + __u16 devid_source; + __u16 devid_vendor; + __u16 devid_product; + __u16 devid_version; __u16 pkt_type; __u16 esco_type; @@ -250,9 +255,6 @@ struct hci_dev { struct list_head remote_oob_data; - struct list_head adv_entries; - struct delayed_work adv_work; - struct hci_dev_stats stat; struct sk_buff_head driver_init; @@ -263,7 +265,6 @@ struct hci_dev { struct dentry *debugfs; - struct device *parent; struct device dev; struct rfkill *rfkill; @@ -571,7 +572,7 @@ int hci_chan_del(struct hci_chan *chan); void hci_chan_list_flush(struct hci_conn *conn); struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, - __u8 sec_level, __u8 auth_type); + __u8 dst_type, __u8 sec_level, __u8 auth_type); int hci_conn_check_link_mode(struct hci_conn *conn); int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); @@ -673,8 +674,8 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]); int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 ediv, - u8 rand[8]); + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, + __le16 ediv, u8 rand[8]); struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type); int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr); @@ -688,14 +689,6 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, u8 *randomizer); int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); -#define ADV_CLEAR_TIMEOUT (3*60*HZ) /* Three minutes */ -int hci_adv_entries_clear(struct hci_dev *hdev); -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev); - -void hci_del_off_timer(struct hci_dev *hdev); - void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct sk_buff *skb); @@ -709,7 +702,7 @@ void hci_conn_init_sysfs(struct hci_conn *conn); void hci_conn_add_sysfs(struct hci_conn *conn); void hci_conn_del_sysfs(struct hci_conn *conn); -#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) +#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev)) /* ----- LMP capabilities ----- */ #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) @@ -933,6 +926,23 @@ static inline bool eir_has_data_type(u8 *data, size_t data_len, u8 type) return false; } +static inline size_t eir_get_length(u8 *eir, size_t eir_len) +{ + size_t parsed = 0; + + while (parsed < eir_len) { + u8 field_len = eir[0]; + + if (field_len == 0) + return parsed; + + parsed += field_len + 1; + eir += field_len + 1; + } + + return eir_len; +} + static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, u8 data_len) { @@ -961,17 +971,12 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); void hci_sock_dev_event(struct hci_dev *hdev, int event); /* Management interface */ -#define MGMT_ADDR_BREDR 0x00 -#define MGMT_ADDR_LE_PUBLIC 0x01 -#define MGMT_ADDR_LE_RANDOM 0x02 -#define MGMT_ADDR_INVALID 0xff - -#define DISCOV_TYPE_BREDR (BIT(MGMT_ADDR_BREDR)) -#define DISCOV_TYPE_LE (BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) -#define DISCOV_TYPE_INTERLEAVED (BIT(MGMT_ADDR_BREDR) | \ - BIT(MGMT_ADDR_LE_PUBLIC) | \ - BIT(MGMT_ADDR_LE_RANDOM)) +#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR)) +#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) +#define DISCOV_TYPE_INTERLEAVED (BIT(BDADDR_BREDR) | \ + BIT(BDADDR_LE_PUBLIC) | \ + BIT(BDADDR_LE_RANDOM)) int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len); int mgmt_index_added(struct hci_dev *hdev); @@ -1067,12 +1072,12 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, u16 latency, u16 to_multiplier); void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], __u8 ltk[16]); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]); -void hci_le_ltk_neg_reply(struct hci_conn *conn); - int hci_do_inquiry(struct hci_dev *hdev, u8 length); int hci_cancel_inquiry(struct hci_dev *hdev); int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, int timeout); +int hci_cancel_le_scan(struct hci_dev *hdev); + +u8 bdaddr_to_le(u8 bdaddr_type); #endif /* __HCI_CORE_H */ diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9b242c6bf55b..1c7d1cd5e679 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -44,6 +44,7 @@ #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF +#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */ #define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100) #define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000) @@ -57,6 +58,7 @@ struct sockaddr_l2 { __le16 l2_psm; bdaddr_t l2_bdaddr; __le16 l2_cid; + __u8 l2_bdaddr_type; }; /* L2CAP socket options */ @@ -139,6 +141,8 @@ struct l2cap_conninfo { #define L2CAP_CTRL_TXSEQ_SHIFT 1 #define L2CAP_CTRL_SUPER_SHIFT 2 +#define L2CAP_CTRL_POLL_SHIFT 4 +#define L2CAP_CTRL_FINAL_SHIFT 7 #define L2CAP_CTRL_REQSEQ_SHIFT 8 #define L2CAP_CTRL_SAR_SHIFT 14 @@ -152,9 +156,11 @@ struct l2cap_conninfo { #define L2CAP_EXT_CTRL_FINAL 0x00000002 #define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */ +#define L2CAP_EXT_CTRL_FINAL_SHIFT 1 #define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2 #define L2CAP_EXT_CTRL_SAR_SHIFT 16 #define L2CAP_EXT_CTRL_SUPER_SHIFT 16 +#define L2CAP_EXT_CTRL_POLL_SHIFT 18 #define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18 /* L2CAP Supervisory Function */ @@ -186,6 +192,8 @@ struct l2cap_hdr { #define L2CAP_FCS_SIZE 2 #define L2CAP_SDULEN_SIZE 2 #define L2CAP_PSMLEN_SIZE 2 +#define L2CAP_ENH_CTRL_SIZE 2 +#define L2CAP_EXT_CTRL_SIZE 4 struct l2cap_cmd_hdr { __u8 code; @@ -401,6 +409,16 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ +struct l2cap_seq_list { + __u16 head; + __u16 tail; + __u16 mask; + __u16 *list; +}; + +#define L2CAP_SEQ_LIST_CLEAR 0xFFFF +#define L2CAP_SEQ_LIST_TAIL 0x8000 + struct srej_list { __u16 tx_seq; struct list_head list; @@ -446,6 +464,9 @@ struct l2cap_chan { __u16 monitor_timeout; __u16 mps; + __u8 tx_state; + __u8 rx_state; + unsigned long conf_state; unsigned long conn_state; unsigned long flags; @@ -456,9 +477,11 @@ struct l2cap_chan { __u16 buffer_seq; __u16 buffer_seq_srej; __u16 srej_save_reqseq; + __u16 last_acked_seq; __u16 frames_sent; __u16 unacked_frames; __u8 retry_count; + __u16 srej_queue_next; __u8 num_acked; __u16 sdu_len; struct sk_buff *sdu; @@ -490,6 +513,8 @@ struct l2cap_chan { struct sk_buff *tx_send_head; struct sk_buff_head tx_q; struct sk_buff_head srej_q; + struct l2cap_seq_list srej_list; + struct l2cap_seq_list retrans_list; struct list_head srej_l; struct list_head list; @@ -508,8 +533,7 @@ struct l2cap_ops { void (*close) (void *data); void (*state_change) (void *data, int state); struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, - unsigned long len, int nb, int *err); - + unsigned long len, int nb); }; struct l2cap_conn { @@ -600,6 +624,44 @@ enum { FLAG_EFS_ENABLE, }; +enum { + L2CAP_TX_STATE_XMIT, + L2CAP_TX_STATE_WAIT_F, +}; + +enum { + L2CAP_RX_STATE_RECV, + L2CAP_RX_STATE_SREJ_SENT, +}; + +enum { + L2CAP_TXSEQ_EXPECTED, + L2CAP_TXSEQ_EXPECTED_SREJ, + L2CAP_TXSEQ_UNEXPECTED, + L2CAP_TXSEQ_UNEXPECTED_SREJ, + L2CAP_TXSEQ_DUPLICATE, + L2CAP_TXSEQ_DUPLICATE_SREJ, + L2CAP_TXSEQ_INVALID, + L2CAP_TXSEQ_INVALID_IGNORE, +}; + +enum { + L2CAP_EV_DATA_REQUEST, + L2CAP_EV_LOCAL_BUSY_DETECTED, + L2CAP_EV_LOCAL_BUSY_CLEAR, + L2CAP_EV_RECV_REQSEQ_AND_FBIT, + L2CAP_EV_RECV_FBIT, + L2CAP_EV_RETRANS_TO, + L2CAP_EV_MONITOR_TO, + L2CAP_EV_EXPLICIT_POLL, + L2CAP_EV_RECV_IFRAME, + L2CAP_EV_RECV_RR, + L2CAP_EV_RECV_REJ, + L2CAP_EV_RECV_RNR, + L2CAP_EV_RECV_SREJ, + L2CAP_EV_RECV_FRAME, +}; + static inline void l2cap_chan_hold(struct l2cap_chan *c) { atomic_inc(&c->refcnt); @@ -622,21 +684,26 @@ static inline void l2cap_chan_unlock(struct l2cap_chan *chan) } static inline void l2cap_set_timer(struct l2cap_chan *chan, - struct delayed_work *work, long timeout) + struct delayed_work *work, long timeout) { BT_DBG("chan %p state %s timeout %ld", chan, - state_to_string(chan->state), timeout); + state_to_string(chan->state), timeout); + /* If delayed work cancelled do not hold(chan) + since it is already done with previous set_timer */ if (!cancel_delayed_work(work)) l2cap_chan_hold(chan); + schedule_delayed_work(work, timeout); } static inline bool l2cap_clear_timer(struct l2cap_chan *chan, - struct delayed_work *work) + struct delayed_work *work) { bool ret; + /* put(chan) if delayed work cancelled otherwise it + is done in delayed work function */ ret = cancel_delayed_work(work); if (ret) l2cap_chan_put(chan); @@ -658,13 +725,10 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan, static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2) { - int offset; - - offset = (seq1 - seq2) % (chan->tx_win_max + 1); - if (offset < 0) - offset += (chan->tx_win_max + 1); - - return offset; + if (seq1 >= seq2) + return seq1 - seq2; + else + return chan->tx_win_max + 1 - seq2 + seq1; } static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq) @@ -852,14 +916,15 @@ int __l2cap_wait_ack(struct sock *sk); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); -struct l2cap_chan *l2cap_chan_create(struct sock *sk); +struct l2cap_chan *l2cap_chan_create(void); void l2cap_chan_close(struct l2cap_chan *chan, int reason); void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, - bdaddr_t *dst); + bdaddr_t *dst, u8 dst_type); int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority); void l2cap_chan_busy(struct l2cap_chan *chan, int busy); int l2cap_chan_check_security(struct l2cap_chan *chan); +void l2cap_chan_set_defaults(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index ebfd91fc20f8..23fd0546fccb 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -341,6 +341,15 @@ struct mgmt_cp_unblock_device { } __packed; #define MGMT_UNBLOCK_DEVICE_SIZE MGMT_ADDR_INFO_SIZE +#define MGMT_OP_SET_DEVICE_ID 0x0028 +struct mgmt_cp_set_device_id { + __le16 source; + __le16 vendor; + __le16 product; + __le16 version; +} __packed; +#define MGMT_SET_DEVICE_ID_SIZE 8 + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h index 7b3acdd29134..ca356a734920 100644 --- a/include/net/bluetooth/smp.h +++ b/include/net/bluetooth/smp.h @@ -77,7 +77,7 @@ struct smp_cmd_encrypt_info { #define SMP_CMD_MASTER_IDENT 0x07 struct smp_cmd_master_ident { - __u16 ediv; + __le16 ediv; __u8 rand[8]; } __packed; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index adb2320bccdf..0289d4ce7070 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -3365,9 +3365,9 @@ void cfg80211_report_obss_beacon(struct wiphy *wiphy, * @chan: main channel * @channel_type: HT mode */ -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type); +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); /* * cfg80211_ch_switch_notify - update wdev channel and notify userspace diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 4d6e6c6818d0..1937c7d98304 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -667,6 +667,9 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) * @RX_FLAG_SHORT_GI: Short guard interval was used * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present. * Valid only for data frames (mainly A-MPDU) + * @RX_FLAG_HT_GF: This frame was received in a HT-greenfield transmission, if + * the driver fills this value it should add %IEEE80211_RADIOTAP_MCS_HAVE_FMT + * to hw.radiotap_mcs_details to advertise that fact */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -681,6 +684,7 @@ enum mac80211_rx_flags { RX_FLAG_40MHZ = 1<<10, RX_FLAG_SHORT_GI = 1<<11, RX_FLAG_NO_SIGNAL_VAL = 1<<12, + RX_FLAG_HT_GF = 1<<13, }; /** @@ -939,7 +943,7 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif) * CCMP key if it requires CCMP encryption of management frames (MFP) to * be done in software. * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver - * for a CCMP key if space should be prepared for the IV, but the IV + * if space should be prepared for the IV, but the IV * itself should not be generated. Do not set together with * @IEEE80211_KEY_FLAG_GENERATE_IV on the same key. */ @@ -1288,6 +1292,11 @@ enum ieee80211_hw_flags { * * @offchannel_tx_hw_queue: HW queue ID to use for offchannel TX * (if %IEEE80211_HW_QUEUE_CONTROL is set) + * + * @radiotap_mcs_details: lists which MCS information can the HW + * reports, by default it is set to _MCS, _GI and _BW but doesn't + * include _FMT. Use %IEEE80211_RADIOTAP_MCS_HAVE_* values, only + * adding _BW is supported today. */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -1309,6 +1318,7 @@ struct ieee80211_hw { u8 max_rx_aggregation_subframes; u8 max_tx_aggregation_subframes; u8 offchannel_tx_hw_queue; + u8 radiotap_mcs_details; }; /** diff --git a/include/net/nfc/hci.h b/include/net/nfc/hci.h index aca65a5a9d0d..4467c9460857 100644 --- a/include/net/nfc/hci.h +++ b/include/net/nfc/hci.h @@ -39,6 +39,8 @@ struct nfc_hci_ops { int (*data_exchange) (struct nfc_hci_dev *hdev, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_hci_dev *hdev, + struct nfc_target *target); }; #define NFC_HCI_MAX_CUSTOM_GATES 15 @@ -82,10 +84,6 @@ struct nfc_hci_dev { u8 gate2pipe[NFC_HCI_MAX_GATES]; - bool poll_started; - struct nfc_target *targets; - int target_count; - u8 sw_romlib; u8 sw_patch; u8 sw_flashlib_major; diff --git a/include/net/nfc/nfc.h b/include/net/nfc/nfc.h index 9a2505a5b8de..b7ca4a2a1d72 100644 --- a/include/net/nfc/nfc.h +++ b/include/net/nfc/nfc.h @@ -48,26 +48,28 @@ struct nfc_dev; typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb, int err); +struct nfc_target; + struct nfc_ops { int (*dev_up)(struct nfc_dev *dev); int (*dev_down)(struct nfc_dev *dev); int (*start_poll)(struct nfc_dev *dev, u32 protocols); void (*stop_poll)(struct nfc_dev *dev); - int (*dep_link_up)(struct nfc_dev *dev, int target_idx, u8 comm_mode, - u8 *gb, size_t gb_len); + int (*dep_link_up)(struct nfc_dev *dev, struct nfc_target *target, + u8 comm_mode, u8 *gb, size_t gb_len); int (*dep_link_down)(struct nfc_dev *dev); - int (*activate_target)(struct nfc_dev *dev, u32 target_idx, + int (*activate_target)(struct nfc_dev *dev, struct nfc_target *target, u32 protocol); - void (*deactivate_target)(struct nfc_dev *dev, u32 target_idx); - int (*data_exchange)(struct nfc_dev *dev, u32 target_idx, + void (*deactivate_target)(struct nfc_dev *dev, + struct nfc_target *target); + int (*data_exchange)(struct nfc_dev *dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context); - int (*check_presence)(struct nfc_dev *dev, u32 target_idx); + int (*check_presence)(struct nfc_dev *dev, struct nfc_target *target); }; #define NFC_TARGET_IDX_ANY -1 #define NFC_MAX_GT_LEN 48 -#define NFC_TARGET_IDX_NONE 0xffffffff struct nfc_target { u32 idx; @@ -95,11 +97,10 @@ struct nfc_dev { struct nfc_target *targets; int n_targets; int targets_generation; - spinlock_t targets_lock; struct device dev; bool dev_up; bool polling; - u32 activated_target_idx; + struct nfc_target *active_target; bool dep_link_up; u32 dep_rf_mode; struct nfc_genl_data genl_data; diff --git a/include/net/nfc/shdlc.h b/include/net/nfc/shdlc.h index 1071987d0408..ab06afd462da 100644 --- a/include/net/nfc/shdlc.h +++ b/include/net/nfc/shdlc.h @@ -35,6 +35,8 @@ struct nfc_shdlc_ops { int (*data_exchange) (struct nfc_shdlc *shdlc, struct nfc_target *target, struct sk_buff *skb, struct sk_buff **res_skb); + int (*check_presence)(struct nfc_shdlc *shdlc, + struct nfc_target *target); }; enum shdlc_state { diff --git a/kernel/pid.c b/kernel/pid.c index 9f08dfabaf13..e86b291ad834 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -547,7 +547,8 @@ void __init pidhash_init(void) pid_hash = alloc_large_system_hash("PID", sizeof(*pid_hash), 0, 18, HASH_EARLY | HASH_SMALL, - &pidhash_shift, NULL, 4096); + &pidhash_shift, NULL, + 0, 4096); pidhash_size = 1U << pidhash_shift; for (i = 0; i < pidhash_size; i++) diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 9f389e50ed18..1851df600438 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -5242,9 +5242,10 @@ void *__init alloc_large_system_hash(const char *tablename, int flags, unsigned int *_hash_shift, unsigned int *_hash_mask, - unsigned long limit) + unsigned long low_limit, + unsigned long high_limit) { - unsigned long long max = limit; + unsigned long long max = high_limit; unsigned long log2qty, size; void *table = NULL; @@ -5282,6 +5283,8 @@ void *__init alloc_large_system_hash(const char *tablename, } max = min(max, 0x80000000ULL); + if (numentries < low_limit) + numentries = low_limit; if (numentries > max) numentries = max; diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 6fb68a9743af..46e7f86acfc9 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -210,7 +210,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock) } if (sk->sk_state == BT_CONNECTED || !newsock || - bt_sk(parent)->defer_setup) { + test_bit(BT_DEFER_SETUP, &bt_sk(parent)->flags)) { bt_accept_unlink(sk); if (newsock) sock_graft(sk, newsock); @@ -410,8 +410,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent) list_for_each_safe(p, n, &bt_sk(parent)->accept_q) { sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); if (sk->sk_state == BT_CONNECTED || - (bt_sk(parent)->defer_setup && - sk->sk_state == BT_CONNECT2)) + (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags) && + sk->sk_state == BT_CONNECT2)) return POLLIN | POLLRDNORM; } @@ -450,7 +450,7 @@ unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wa sk->sk_state == BT_CONFIG) return mask; - if (!bt_sk(sk)->suspended && sock_writeable(sk)) + if (!test_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags) && sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 88884d1d95fd..031d7d656754 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -340,7 +340,7 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) } /* Strip 802.1p header */ - if (ntohs(s->eh.h_proto) == 0x8100) { + if (ntohs(s->eh.h_proto) == ETH_P_8021Q) { if (!skb_pull(skb, 4)) goto badframe; s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2)); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5238b6b3ea6a..3f18a6ed9731 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -223,36 +223,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], } EXPORT_SYMBOL(hci_le_start_enc); -void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - memcpy(cp.ltk, ltk, sizeof(ltk)); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp); -} -EXPORT_SYMBOL(hci_le_ltk_reply); - -void hci_le_ltk_neg_reply(struct hci_conn *conn) -{ - struct hci_dev *hdev = conn->hdev; - struct hci_cp_le_ltk_neg_reply cp; - - BT_DBG("%p", conn); - - memset(&cp, 0, sizeof(cp)); - - cp.handle = cpu_to_le16(conn->handle); - - hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp); -} - /* Device _must_ be locked */ void hci_sco_setup(struct hci_conn *conn, __u8 status) { @@ -513,7 +483,8 @@ EXPORT_SYMBOL(hci_get_route); /* Create SCO, ACL or LE connection. * Device _must_ be locked */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) +struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, + __u8 dst_type, __u8 sec_level, __u8 auth_type) { struct hci_conn *acl; struct hci_conn *sco; @@ -522,23 +493,18 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 BT_DBG("%s dst %s", hdev->name, batostr(dst)); if (type == LE_LINK) { - struct adv_entry *entry; - le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); - if (le) - return ERR_PTR(-EBUSY); - - entry = hci_find_adv_entry(hdev, dst); - if (!entry) - return ERR_PTR(-EHOSTUNREACH); + if (!le) { + le = hci_conn_add(hdev, LE_LINK, dst); + if (!le) + return ERR_PTR(-ENOMEM); - le = hci_conn_add(hdev, LE_LINK, dst); - if (!le) - return ERR_PTR(-ENOMEM); - - le->dst_type = entry->bdaddr_type; + le->dst_type = bdaddr_to_le(dst_type); + hci_le_connect(le); + } - hci_le_connect(le); + le->pending_sec_level = sec_level; + le->auth_type = auth_type; hci_conn_hold(le); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index d6dc44cd15b0..411ace8e647b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -83,6 +83,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) */ if (test_bit(HCI_INIT, &hdev->flags) && hdev->init_last_cmd != cmd) { struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + u16 opcode = __le16_to_cpu(sent->opcode); struct sk_buff *skb; /* Some CSR based controllers generate a spontaneous @@ -92,7 +93,7 @@ void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) * command. */ - if (cmd != HCI_OP_RESET || sent->opcode == HCI_OP_RESET) + if (cmd != HCI_OP_RESET || opcode == HCI_OP_RESET) return; skb = skb_clone(hdev->sent_cmd, GFP_ATOMIC); @@ -251,6 +252,9 @@ static void amp_init(struct hci_dev *hdev) /* Read Local Version */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); + + /* Read Local AMP Info */ + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL); } static void hci_init_req(struct hci_dev *hdev, unsigned long opt) @@ -384,7 +388,6 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state) case DISCOVERY_STOPPED: if (hdev->discovery.state != DISCOVERY_STARTING) mgmt_discovering(hdev, 0); - hdev->discovery.type = 0; break; case DISCOVERY_STARTING: break; @@ -1089,32 +1092,6 @@ static const struct rfkill_ops hci_rfkill_ops = { .set_block = hci_rfkill_set_block, }; -/* Alloc HCI device */ -struct hci_dev *hci_alloc_dev(void) -{ - struct hci_dev *hdev; - - hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); - if (!hdev) - return NULL; - - hci_init_sysfs(hdev); - skb_queue_head_init(&hdev->driver_init); - - return hdev; -} -EXPORT_SYMBOL(hci_alloc_dev); - -/* Free HCI device */ -void hci_free_dev(struct hci_dev *hdev) -{ - skb_queue_purge(&hdev->driver_init); - - /* will free via device release */ - put_device(&hdev->dev); -} -EXPORT_SYMBOL(hci_free_dev); - static void hci_power_on(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, power_on); @@ -1336,7 +1313,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, } int hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type, u8 type, - int new_key, u8 authenticated, u8 tk[16], u8 enc_size, u16 + int new_key, u8 authenticated, u8 tk[16], u8 enc_size, __le16 ediv, u8 rand[8]) { struct smp_ltk *key, *old_key; @@ -1544,75 +1521,6 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) return mgmt_device_unblocked(hdev, bdaddr, type); } -static void hci_clear_adv_cache(struct work_struct *work) -{ - struct hci_dev *hdev = container_of(work, struct hci_dev, - adv_work.work); - - hci_dev_lock(hdev); - - hci_adv_entries_clear(hdev); - - hci_dev_unlock(hdev); -} - -int hci_adv_entries_clear(struct hci_dev *hdev) -{ - struct adv_entry *entry, *tmp; - - list_for_each_entry_safe(entry, tmp, &hdev->adv_entries, list) { - list_del(&entry->list); - kfree(entry); - } - - BT_DBG("%s adv cache cleared", hdev->name); - - return 0; -} - -struct adv_entry *hci_find_adv_entry(struct hci_dev *hdev, bdaddr_t *bdaddr) -{ - struct adv_entry *entry; - - list_for_each_entry(entry, &hdev->adv_entries, list) - if (bacmp(bdaddr, &entry->bdaddr) == 0) - return entry; - - return NULL; -} - -static inline int is_connectable_adv(u8 evt_type) -{ - if (evt_type == ADV_IND || evt_type == ADV_DIRECT_IND) - return 1; - - return 0; -} - -int hci_add_adv_entry(struct hci_dev *hdev, - struct hci_ev_le_advertising_info *ev) { struct adv_entry *entry; if (!is_connectable_adv(ev->evt_type)) - return -EINVAL; - - /* Only new entries should be added to adv_entries. So, if - * bdaddr was found, don't add it. */ - if (hci_find_adv_entry(hdev, &ev->bdaddr)) - return 0; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return -ENOMEM; - - bacpy(&entry->bdaddr, &ev->bdaddr); - entry->bdaddr_type = ev->bdaddr_type; - - list_add(&entry->list, &hdev->adv_entries); - - BT_DBG("%s adv entry added: address %s type %u", hdev->name, - batostr(&entry->bdaddr), entry->bdaddr_type); - - return 0; -} - static void le_scan_param_req(struct hci_dev *hdev, unsigned long opt) { struct le_scan_params *param = (struct le_scan_params *) opt; @@ -1670,6 +1578,24 @@ static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval, return 0; } +int hci_cancel_le_scan(struct hci_dev *hdev) +{ + BT_DBG("%s", hdev->name); + + if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags)) + return -EALREADY; + + if (cancel_delayed_work(&hdev->le_scan_disable)) { + struct hci_cp_le_set_scan_enable cp; + + /* Send HCI command to disable LE Scan */ + memset(&cp, 0, sizeof(cp)); + hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp); + } + + return 0; +} + static void le_scan_disable_work(struct work_struct *work) { struct hci_dev *hdev = container_of(work, struct hci_dev, @@ -1714,95 +1640,103 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window, return 0; } -/* Register HCI device */ -int hci_register_dev(struct hci_dev *hdev) +/* Alloc HCI device */ +struct hci_dev *hci_alloc_dev(void) { - struct list_head *head = &hci_dev_list, *p; - int i, id, error; - - BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - - if (!hdev->open || !hdev->close) - return -EINVAL; - - /* Do not allow HCI_AMP devices to register at index 0, - * so the index can be used as the AMP controller ID. - */ - id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; - - write_lock(&hci_dev_list_lock); - - /* Find first available device id */ - list_for_each(p, &hci_dev_list) { - if (list_entry(p, struct hci_dev, list)->id != id) - break; - head = p; id++; - } - - sprintf(hdev->name, "hci%d", id); - hdev->id = id; - list_add_tail(&hdev->list, head); + struct hci_dev *hdev; - mutex_init(&hdev->lock); + hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL); + if (!hdev) + return NULL; - hdev->flags = 0; - hdev->dev_flags = 0; hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); hdev->esco_type = (ESCO_HV1); hdev->link_mode = (HCI_LM_ACCEPT); hdev->io_capability = 0x03; /* No Input No Output */ - hdev->idle_timeout = 0; hdev->sniff_max_interval = 800; hdev->sniff_min_interval = 80; + mutex_init(&hdev->lock); + mutex_init(&hdev->req_lock); + + INIT_LIST_HEAD(&hdev->mgmt_pending); + INIT_LIST_HEAD(&hdev->blacklist); + INIT_LIST_HEAD(&hdev->uuids); + INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->long_term_keys); + INIT_LIST_HEAD(&hdev->remote_oob_data); + INIT_WORK(&hdev->rx_work, hci_rx_work); INIT_WORK(&hdev->cmd_work, hci_cmd_work); INIT_WORK(&hdev->tx_work, hci_tx_work); + INIT_WORK(&hdev->power_on, hci_power_on); + INIT_WORK(&hdev->le_scan, le_scan_work); + INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); + INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); + INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); + skb_queue_head_init(&hdev->driver_init); skb_queue_head_init(&hdev->rx_q); skb_queue_head_init(&hdev->cmd_q); skb_queue_head_init(&hdev->raw_q); - setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); - - for (i = 0; i < NUM_REASSEMBLY; i++) - hdev->reassembly[i] = NULL; - init_waitqueue_head(&hdev->req_wait_q); - mutex_init(&hdev->req_lock); - discovery_init(hdev); + setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); + hci_init_sysfs(hdev); + discovery_init(hdev); hci_conn_hash_init(hdev); - INIT_LIST_HEAD(&hdev->mgmt_pending); - - INIT_LIST_HEAD(&hdev->blacklist); + return hdev; +} +EXPORT_SYMBOL(hci_alloc_dev); - INIT_LIST_HEAD(&hdev->uuids); +/* Free HCI device */ +void hci_free_dev(struct hci_dev *hdev) +{ + skb_queue_purge(&hdev->driver_init); - INIT_LIST_HEAD(&hdev->link_keys); - INIT_LIST_HEAD(&hdev->long_term_keys); + /* will free via device release */ + put_device(&hdev->dev); +} +EXPORT_SYMBOL(hci_free_dev); - INIT_LIST_HEAD(&hdev->remote_oob_data); +/* Register HCI device */ +int hci_register_dev(struct hci_dev *hdev) +{ + struct list_head *head, *p; + int id, error; - INIT_LIST_HEAD(&hdev->adv_entries); + if (!hdev->open || !hdev->close) + return -EINVAL; - INIT_DELAYED_WORK(&hdev->adv_work, hci_clear_adv_cache); - INIT_WORK(&hdev->power_on, hci_power_on); - INIT_DELAYED_WORK(&hdev->power_off, hci_power_off); + write_lock(&hci_dev_list_lock); - INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off); + /* Do not allow HCI_AMP devices to register at index 0, + * so the index can be used as the AMP controller ID. + */ + id = (hdev->dev_type == HCI_BREDR) ? 0 : 1; + head = &hci_dev_list; - memset(&hdev->stat, 0, sizeof(struct hci_dev_stats)); + /* Find first available device id */ + list_for_each(p, &hci_dev_list) { + int nid = list_entry(p, struct hci_dev, list)->id; + if (nid > id) + break; + if (nid == id) + id++; + head = p; + } - atomic_set(&hdev->promisc, 0); + sprintf(hdev->name, "hci%d", id); + hdev->id = id; - INIT_WORK(&hdev->le_scan, le_scan_work); + BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work); + list_add(&hdev->list, head); write_unlock(&hci_dev_list_lock); @@ -1884,8 +1818,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_del_sysfs(hdev); - cancel_delayed_work_sync(&hdev->adv_work); - destroy_workqueue(hdev->workqueue); hci_dev_lock(hdev); @@ -1894,7 +1826,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_link_keys_clear(hdev); hci_smp_ltks_clear(hdev); hci_remote_oob_data_clear(hdev); - hci_adv_entries_clear(hdev); hci_dev_unlock(hdev); hci_dev_put(hdev); @@ -2231,6 +2162,12 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, struct hci_dev *hdev = conn->hdev; struct sk_buff *list; + skb->len = skb_headlen(skb); + skb->data_len = 0; + + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; + hci_add_acl_hdr(skb, conn->handle, flags); + list = skb_shinfo(skb)->frag_list; if (!list) { /* Non fragmented */ @@ -2274,8 +2211,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags); skb->dev = (void *) hdev; - bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; - hci_add_acl_hdr(skb, conn->handle, flags); hci_queue_acl(conn, &chan->data_q, skb, flags); @@ -2313,7 +2248,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_conn *conn = NULL, *c; - int num = 0, min = ~0; + unsigned int num = 0, min = ~0; /* We don't have to lock device here. Connections are always * added and removed with TX task disabled. */ @@ -2394,7 +2329,7 @@ static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, { struct hci_conn_hash *h = &hdev->conn_hash; struct hci_chan *chan = NULL; - int num = 0, min = ~0, cur_prio = 0; + unsigned int num = 0, min = ~0, cur_prio = 0; struct hci_conn *conn; int cnt, q, conn_num = 0; @@ -2945,7 +2880,19 @@ int hci_cancel_inquiry(struct hci_dev *hdev) BT_DBG("%s", hdev->name); if (!test_bit(HCI_INQUIRY, &hdev->flags)) - return -EPERM; + return -EALREADY; return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); } + +u8 bdaddr_to_le(u8 bdaddr_type) +{ + switch (bdaddr_type) { + case BDADDR_LE_PUBLIC: + return ADDR_LE_DEV_PUBLIC; + + default: + /* Fallback to LE Random address type */ + return ADDR_LE_DEV_RANDOM; + } +} diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1266f78fa8e3..4eefb7f65cf6 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -69,6 +69,18 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) hci_conn_check_pending(hdev); } +static void hci_cc_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) +{ + __u8 status = *((__u8 *) skb->data); + + BT_DBG("%s status 0x%x", hdev->name, status); + + if (status) + return; + + set_bit(HCI_PERIODIC_INQ, &hdev->dev_flags); +} + static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); @@ -78,6 +90,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; + clear_bit(HCI_PERIODIC_INQ, &hdev->dev_flags); + hci_conn_check_pending(hdev); } @@ -192,7 +206,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) hci_req_complete(hdev, HCI_OP_RESET, status); /* Reset all non-persistent flags */ - hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS)); + hdev->dev_flags &= ~(BIT(HCI_LE_SCAN) | BIT(HCI_PENDING_CLASS) | + BIT(HCI_PERIODIC_INQ)); hdev->discovery.state = DISCOVERY_STOPPED; } @@ -505,7 +520,7 @@ static void hci_setup_event_mask(struct hci_dev *hdev) events[5] |= 0x10; /* Synchronous Connection Changed */ if (hdev->features[3] & LMP_RSSI_INQ) - events[4] |= 0x04; /* Inquiry Result with RSSI */ + events[4] |= 0x02; /* Inquiry Result with RSSI */ if (hdev->features[5] & LMP_SNIFF_SUBR) events[5] |= 0x20; /* Sniff Subrating */ @@ -615,6 +630,7 @@ done: static void hci_setup_link_policy(struct hci_dev *hdev) { + struct hci_cp_write_def_link_policy cp; u16 link_policy = 0; if (hdev->features[0] & LMP_RSWITCH) @@ -626,9 +642,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev) if (hdev->features[1] & LMP_PARK) link_policy |= HCI_LP_PARK; - link_policy = cpu_to_le16(link_policy); - hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(link_policy), - &link_policy); + cp.policy = cpu_to_le16(link_policy); + hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp); } static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) @@ -710,7 +725,7 @@ static void hci_set_le_support(struct hci_dev *hdev) memset(&cp, 0, sizeof(cp)); - if (enable_le && test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { + if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) { cp.le = 1; cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR); } @@ -887,11 +902,14 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, struct sk_buff *skb) { - __u8 status = *((__u8 *) skb->data); + struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + if (!rp->status) + hdev->inq_tx_power = rp->tx_power; - hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status); + hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, rp->status); } static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb) @@ -1082,23 +1100,23 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, set_bit(HCI_LE_SCAN, &hdev->dev_flags); - cancel_delayed_work_sync(&hdev->adv_work); - hci_dev_lock(hdev); - hci_adv_entries_clear(hdev); hci_discovery_set_state(hdev, DISCOVERY_FINDING); hci_dev_unlock(hdev); break; case LE_SCANNING_DISABLED: - if (status) + if (status) { + hci_dev_lock(hdev); + mgmt_stop_discovery_failed(hdev, status); + hci_dev_unlock(hdev); return; + } clear_bit(HCI_LE_SCAN, &hdev->dev_flags); - schedule_delayed_work(&hdev->adv_work, ADV_CLEAR_TIMEOUT); - - if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED) { + if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && + hdev->discovery.state == DISCOVERY_FINDING) { mgmt_interleaved_discovery(hdev); } else { hci_dev_lock(hdev); @@ -1625,6 +1643,8 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) if (status) { if (conn && conn->state == BT_CONNECT) { conn->state = BT_CLOSED; + mgmt_connect_failed(hdev, &cp->peer_addr, conn->type, + conn->dst_type, status); hci_proto_connect_cfm(conn, status); hci_conn_del(conn); } @@ -1699,6 +1719,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { @@ -2040,7 +2063,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags); if (ev->status && conn->state == BT_CONNECTED) { - hci_acl_disconn(conn, 0x13); + hci_acl_disconn(conn, HCI_ERROR_AUTH_FAILURE); hci_conn_put(conn); goto unlock; } @@ -2154,6 +2177,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_inquiry_cancel(hdev, skb); break; + case HCI_OP_PERIODIC_INQ: + hci_cc_periodic_inq(hdev, skb); + break; + case HCI_OP_EXIT_PERIODIC_INQ: hci_cc_exit_periodic_inq(hdev, skb); break; @@ -2806,6 +2833,9 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) { @@ -2971,12 +3001,16 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct struct inquiry_data data; struct extended_inquiry_info *info = (void *) (skb->data + 1); int num_rsp = *((__u8 *) skb->data); + size_t eir_len; BT_DBG("%s num_rsp %d", hdev->name, num_rsp); if (!num_rsp) return; + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) + return; + hci_dev_lock(hdev); for (; num_rsp; num_rsp--, info++) { @@ -3000,9 +3034,10 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct name_known = hci_inquiry_cache_update(hdev, &data, name_known, &ssp); + eir_len = eir_get_length(info->data, sizeof(info->data)); mgmt_device_found(hdev, &info->bdaddr, ACL_LINK, 0x00, info->dev_class, info->rssi, !name_known, - ssp, info->data, sizeof(info->data)); + ssp, info->data, eir_len); } hci_dev_unlock(hdev); @@ -3322,8 +3357,6 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev, while (num_reports--) { struct hci_ev_le_advertising_info *ev = ptr; - hci_add_adv_entry(hdev, ev); - rssi = ev->data[ev->length]; mgmt_device_found(hdev, &ev->bdaddr, LE_LINK, ev->bdaddr_type, NULL, rssi, 0, 1, ev->data, ev->length); @@ -3343,7 +3376,7 @@ static inline void hci_le_ltk_request_evt(struct hci_dev *hdev, struct hci_conn *conn; struct smp_ltk *ltk; - BT_DBG("%s handle %d", hdev->name, cpu_to_le16(ev->handle)); + BT_DBG("%s handle %d", hdev->name, __le16_to_cpu(ev->handle)); hci_dev_lock(hdev); diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index bc154298979a..937f3187eafa 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -444,8 +444,8 @@ static const struct file_operations blacklist_fops = { static void print_bt_uuid(struct seq_file *f, u8 *uuid) { - u32 data0, data4; - u16 data1, data2, data3, data5; + __be32 data0, data4; + __be16 data1, data2, data3, data5; memcpy(&data0, &uuid[0], 4); memcpy(&data1, &uuid[4], 2); @@ -533,7 +533,6 @@ int hci_add_sysfs(struct hci_dev *hdev) BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); - dev->parent = hdev->parent; dev_set_name(dev, "%s", hdev->name); err = device_add(dev); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6f9c25b633a6..24f144b72a96 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -4,6 +4,7 @@ Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org> Copyright (C) 2010 Google Inc. Copyright (C) 2011 ProFUSION Embedded Systems + Copyright (c) 2012 Code Aurora Forum. All rights reserved. Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com> @@ -70,7 +71,7 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static void l2cap_send_disconn_req(struct l2cap_conn *conn, - struct l2cap_chan *chan, int err); + struct l2cap_chan *chan, int err); /* ---- L2CAP channels ---- */ @@ -97,13 +98,15 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 } /* Find channel with given SCID. - * Returns locked socket */ + * Returns locked channel. */ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; mutex_lock(&conn->chan_lock); c = __l2cap_get_chan_by_scid(conn, cid); + if (c) + l2cap_chan_lock(c); mutex_unlock(&conn->chan_lock); return c; @@ -120,17 +123,6 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 return NULL; } -static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) -{ - struct l2cap_chan *c; - - mutex_lock(&conn->chan_lock); - c = __l2cap_get_chan_by_ident(conn, ident); - mutex_unlock(&conn->chan_lock); - - return c; -} - static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) { struct l2cap_chan *c; @@ -232,6 +224,124 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err) release_sock(sk); } +/* ---- L2CAP sequence number lists ---- */ + +/* For ERTM, ordered lists of sequence numbers must be tracked for + * SREJ requests that are received and for frames that are to be + * retransmitted. These seq_list functions implement a singly-linked + * list in an array, where membership in the list can also be checked + * in constant time. Items can also be added to the tail of the list + * and removed from the head in constant time, without further memory + * allocs or frees. + */ + +static int l2cap_seq_list_init(struct l2cap_seq_list *seq_list, u16 size) +{ + size_t alloc_size, i; + + /* Allocated size is a power of 2 to map sequence numbers + * (which may be up to 14 bits) in to a smaller array that is + * sized for the negotiated ERTM transmit windows. + */ + alloc_size = roundup_pow_of_two(size); + + seq_list->list = kmalloc(sizeof(u16) * alloc_size, GFP_KERNEL); + if (!seq_list->list) + return -ENOMEM; + + seq_list->mask = alloc_size - 1; + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + for (i = 0; i < alloc_size; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + return 0; +} + +static inline void l2cap_seq_list_free(struct l2cap_seq_list *seq_list) +{ + kfree(seq_list->list); +} + +static inline bool l2cap_seq_list_contains(struct l2cap_seq_list *seq_list, + u16 seq) +{ + /* Constant-time check for list membership */ + return seq_list->list[seq & seq_list->mask] != L2CAP_SEQ_LIST_CLEAR; +} + +static u16 l2cap_seq_list_remove(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) { + /* In case someone tries to pop the head of an empty list */ + return L2CAP_SEQ_LIST_CLEAR; + } else if (seq_list->head == seq) { + /* Head can be removed in constant time */ + seq_list->head = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + + if (seq_list->head == L2CAP_SEQ_LIST_TAIL) { + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; + } + } else { + /* Walk the list to find the sequence number */ + u16 prev = seq_list->head; + while (seq_list->list[prev & mask] != seq) { + prev = seq_list->list[prev & mask]; + if (prev == L2CAP_SEQ_LIST_TAIL) + return L2CAP_SEQ_LIST_CLEAR; + } + + /* Unlink the number from the list and clear it */ + seq_list->list[prev & mask] = seq_list->list[seq & mask]; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_CLEAR; + if (seq_list->tail == seq) + seq_list->tail = prev; + } + return seq; +} + +static inline u16 l2cap_seq_list_pop(struct l2cap_seq_list *seq_list) +{ + /* Remove the head in constant time */ + return l2cap_seq_list_remove(seq_list, seq_list->head); +} + +static void l2cap_seq_list_clear(struct l2cap_seq_list *seq_list) +{ + u16 i; + + if (seq_list->head == L2CAP_SEQ_LIST_CLEAR) + return; + + for (i = 0; i <= seq_list->mask; i++) + seq_list->list[i] = L2CAP_SEQ_LIST_CLEAR; + + seq_list->head = L2CAP_SEQ_LIST_CLEAR; + seq_list->tail = L2CAP_SEQ_LIST_CLEAR; +} + +static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq) +{ + u16 mask = seq_list->mask; + + /* All appends happen in constant time */ + + if (seq_list->list[seq & mask] != L2CAP_SEQ_LIST_CLEAR) + return; + + if (seq_list->tail == L2CAP_SEQ_LIST_CLEAR) + seq_list->head = seq; + else + seq_list->list[seq_list->tail & mask] = seq; + + seq_list->tail = seq; + seq_list->list[seq & mask] = L2CAP_SEQ_LIST_TAIL; +} + static void l2cap_chan_timeout(struct work_struct *work) { struct l2cap_chan *chan = container_of(work, struct l2cap_chan, @@ -262,7 +372,7 @@ static void l2cap_chan_timeout(struct work_struct *work) l2cap_chan_put(chan); } -struct l2cap_chan *l2cap_chan_create(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(void) { struct l2cap_chan *chan; @@ -272,8 +382,6 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) mutex_init(&chan->lock); - chan->sk = sk; - write_lock(&chan_list_lock); list_add(&chan->global_l, &chan_list); write_unlock(&chan_list_lock); @@ -284,7 +392,7 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk) atomic_set(&chan->refcnt, 1); - BT_DBG("sk %p chan %p", sk, chan); + BT_DBG("chan %p", chan); return chan; } @@ -298,10 +406,21 @@ void l2cap_chan_destroy(struct l2cap_chan *chan) l2cap_chan_put(chan); } -void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +void l2cap_chan_set_defaults(struct l2cap_chan *chan) +{ + chan->fcs = L2CAP_FCS_CRC16; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->sec_level = BT_SECURITY_LOW; + + set_bit(FLAG_FORCE_ACTIVE, &chan->flags); +} + +static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, - chan->psm, chan->dcid); + __le16_to_cpu(chan->psm), chan->dcid); conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM; @@ -347,7 +466,7 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) list_add(&chan->list, &conn->chan_l); } -void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) +static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { mutex_lock(&conn->chan_lock); __l2cap_chan_add(conn, chan); @@ -405,6 +524,8 @@ static void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); + l2cap_seq_list_free(&chan->srej_list); + l2cap_seq_list_free(&chan->retrans_list); list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); @@ -453,7 +574,6 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) case BT_CONFIG: if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && conn->hcon->type == ACL_LINK) { - __clear_chan_timer(chan); __set_chan_timer(chan, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, chan, reason); } else @@ -466,7 +586,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason) struct l2cap_conn_rsp rsp; __u16 result; - if (bt_sk(sk)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) result = L2CAP_CR_SEC_BLOCK; else result = L2CAP_CR_BAD_PSM; @@ -599,6 +719,117 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) hci_send_acl(chan->conn->hchan, skb, flags); } +static void __unpack_enhanced_control(u16 enh, struct l2cap_ctrl *control) +{ + control->reqseq = (enh & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT; + control->final = (enh & L2CAP_CTRL_FINAL) >> L2CAP_CTRL_FINAL_SHIFT; + + if (enh & L2CAP_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (enh & L2CAP_CTRL_POLL) >> L2CAP_CTRL_POLL_SHIFT; + control->super = (enh & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (enh & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT; + control->txseq = (enh & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static void __unpack_extended_control(u32 ext, struct l2cap_ctrl *control) +{ + control->reqseq = (ext & L2CAP_EXT_CTRL_REQSEQ) >> L2CAP_EXT_CTRL_REQSEQ_SHIFT; + control->final = (ext & L2CAP_EXT_CTRL_FINAL) >> L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (ext & L2CAP_EXT_CTRL_FRAME_TYPE) { + /* S-Frame */ + control->sframe = 1; + control->poll = (ext & L2CAP_EXT_CTRL_POLL) >> L2CAP_EXT_CTRL_POLL_SHIFT; + control->super = (ext & L2CAP_EXT_CTRL_SUPERVISE) >> L2CAP_EXT_CTRL_SUPER_SHIFT; + + control->sar = 0; + control->txseq = 0; + } else { + /* I-Frame */ + control->sframe = 0; + control->sar = (ext & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT; + control->txseq = (ext & L2CAP_EXT_CTRL_TXSEQ) >> L2CAP_EXT_CTRL_TXSEQ_SHIFT; + + control->poll = 0; + control->super = 0; + } +} + +static inline void __unpack_control(struct l2cap_chan *chan, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + __unpack_extended_control(get_unaligned_le32(skb->data), + &bt_cb(skb)->control); + } else { + __unpack_enhanced_control(get_unaligned_le16(skb->data), + &bt_cb(skb)->control); + } +} + +static u32 __pack_extended_control(struct l2cap_ctrl *control) +{ + u32 packed; + + packed = control->reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_EXT_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_EXT_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_EXT_CTRL_SUPER_SHIFT; + packed |= L2CAP_EXT_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_EXT_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static u16 __pack_enhanced_control(struct l2cap_ctrl *control) +{ + u16 packed; + + packed = control->reqseq << L2CAP_CTRL_REQSEQ_SHIFT; + packed |= control->final << L2CAP_CTRL_FINAL_SHIFT; + + if (control->sframe) { + packed |= control->poll << L2CAP_CTRL_POLL_SHIFT; + packed |= control->super << L2CAP_CTRL_SUPER_SHIFT; + packed |= L2CAP_CTRL_FRAME_TYPE; + } else { + packed |= control->sar << L2CAP_CTRL_SAR_SHIFT; + packed |= control->txseq << L2CAP_CTRL_TXSEQ_SHIFT; + } + + return packed; +} + +static inline void __pack_control(struct l2cap_chan *chan, + struct l2cap_ctrl *control, + struct sk_buff *skb) +{ + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) { + put_unaligned_le32(__pack_extended_control(control), + skb->data + L2CAP_HDR_SIZE); + } else { + put_unaligned_le16(__pack_enhanced_control(control), + skb->data + L2CAP_HDR_SIZE); + } +} + static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control) { struct sk_buff *skb; @@ -681,10 +912,38 @@ static void l2cap_send_conn_req(struct l2cap_chan *chan) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); } +static void l2cap_chan_ready(struct l2cap_chan *chan) +{ + struct sock *sk = chan->sk; + struct sock *parent; + + lock_sock(sk); + + parent = bt_sk(sk)->parent; + + BT_DBG("sk %p, parent %p", sk, parent); + + chan->conf_state = 0; + __clear_chan_timer(chan); + + __l2cap_state_change(chan, BT_CONNECTED); + sk->sk_state_change(sk); + + if (parent) + parent->sk_data_ready(parent, 0); + + release_sock(sk); +} + static void l2cap_do_start(struct l2cap_chan *chan) { struct l2cap_conn *conn = chan->conn; + if (conn->hcon->type == LE_LINK) { + l2cap_chan_ready(chan); + return; + } + if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; @@ -791,7 +1050,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (l2cap_chan_check_security(chan)) { lock_sock(sk); - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND); @@ -830,10 +1090,12 @@ static void l2cap_conn_start(struct l2cap_conn *conn) mutex_unlock(&conn->chan_lock); } -/* Find socket with cid and source bdaddr. +/* Find socket with cid and source/destination bdaddr. * Returns closest match, locked. */ -static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_scid(int state, u16 cid, + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -846,14 +1108,22 @@ static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdadd continue; if (c->scid == cid) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -872,7 +1142,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) /* Check if we have socket listening on cid */ pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, - conn->src); + conn->src, conn->dst); if (!pchan) return; @@ -910,29 +1180,6 @@ clean: release_sock(parent); } -static void l2cap_chan_ready(struct l2cap_chan *chan) -{ - struct sock *sk = chan->sk; - struct sock *parent; - - lock_sock(sk); - - parent = bt_sk(sk)->parent; - - BT_DBG("sk %p, parent %p", sk, parent); - - chan->conf_state = 0; - __clear_chan_timer(chan); - - __l2cap_state_change(chan, BT_CONNECTED); - sk->sk_state_change(sk); - - if (parent) - parent->sk_data_ready(parent, 0); - - release_sock(sk); -} - static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan *chan; @@ -1016,6 +1263,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) /* Kill channels */ list_for_each_entry_safe(chan, l, &conn->chan_l, list) { + l2cap_chan_hold(chan); l2cap_chan_lock(chan); l2cap_chan_del(chan, err); @@ -1023,6 +1271,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); } mutex_unlock(&conn->chan_lock); @@ -1100,10 +1349,12 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) /* ---- Socket interface ---- */ -/* Find socket with psm and source bdaddr. +/* Find socket with psm and source / destination bdaddr. * Returns closest match. */ -static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, + bdaddr_t *src, + bdaddr_t *dst) { struct l2cap_chan *c, *c1 = NULL; @@ -1116,14 +1367,22 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr continue; if (c->psm == psm) { + int src_match, dst_match; + int src_any, dst_any; + /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) { + src_match = !bacmp(&bt_sk(sk)->src, src); + dst_match = !bacmp(&bt_sk(sk)->dst, dst); + if (src_match && dst_match) { read_unlock(&chan_list_lock); return c; } /* Closest match */ - if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) + src_any = !bacmp(&bt_sk(sk)->src, BDADDR_ANY); + dst_any = !bacmp(&bt_sk(sk)->dst, BDADDR_ANY); + if ((src_match && dst_any) || (src_any && dst_match) || + (src_any && dst_any)) c1 = c; } } @@ -1133,7 +1392,8 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr return c1; } -int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst) +int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, + bdaddr_t *dst, u8 dst_type) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; @@ -1143,8 +1403,8 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d __u8 auth_type; int err; - BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - chan->psm); + BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst), + dst_type, __le16_to_cpu(chan->psm)); hdev = hci_get_route(dst, src); if (!hdev) @@ -1218,11 +1478,11 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d auth_type = l2cap_get_auth_type(chan); if (chan->dcid == L2CAP_CID_LE_DATA) - hcon = hci_connect(hdev, LE_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, LE_LINK, dst, dst_type, + chan->sec_level, auth_type); else - hcon = hci_connect(hdev, ACL_LINK, dst, - chan->sec_level, auth_type); + hcon = hci_connect(hdev, ACL_LINK, dst, dst_type, + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); @@ -1236,6 +1496,18 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *d goto done; } + if (hcon->type == LE_LINK) { + err = 0; + + if (!list_empty(&conn->chan_l)) { + err = -EBUSY; + hci_conn_put(hcon); + } + + if (err) + goto done; + } + /* Update source addr of the socket */ bacpy(src, conn->src); @@ -1346,7 +1618,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { - if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) + if (bt_cb(skb)->control.txseq == chan->expected_ack_seq) break; skb = skb_dequeue(&chan->tx_q); @@ -1368,6 +1640,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan) while ((skb = skb_dequeue(&chan->tx_q))) { control = __get_control(chan, skb->data + L2CAP_HDR_SIZE); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, skb->data + L2CAP_HDR_SIZE); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -1393,21 +1666,21 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq) if (!skb) return; - while (bt_cb(skb)->tx_seq != tx_seq) { + while (bt_cb(skb)->control.txseq != tx_seq) { if (skb_queue_is_last(&chan->tx_q, skb)) return; skb = skb_queue_next(&chan->tx_q, skb); } - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1440,17 +1713,20 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->state != BT_CONNECTED) return -ENOTCONN; + if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state)) + return 0; + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { - if (chan->remote_max_tx && - bt_cb(skb)->retries == chan->remote_max_tx) { + if (bt_cb(skb)->control.retries == chan->remote_max_tx && + chan->remote_max_tx) { l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } tx_skb = skb_clone(skb, GFP_ATOMIC); - bt_cb(skb)->retries++; + bt_cb(skb)->control.retries++; control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE); control &= __get_sar_mask(chan); @@ -1460,6 +1736,7 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) control |= __set_reqseq(chan, chan->buffer_seq); control |= __set_txseq(chan, chan->next_tx_seq); + control |= __set_ctrl_sar(chan, bt_cb(skb)->control.sar); __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1474,11 +1751,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) __set_retrans_timer(chan); - bt_cb(skb)->tx_seq = chan->next_tx_seq; + bt_cb(skb)->control.txseq = chan->next_tx_seq; chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); - if (bt_cb(skb)->retries == 1) { + if (bt_cb(skb)->control.retries == 1) { chan->unacked_frames++; if (!nsent++) @@ -1554,7 +1831,7 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, { struct l2cap_conn *conn = chan->conn; struct sk_buff **frag; - int err, sent = 0; + int sent = 0; if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) return -EFAULT; @@ -1565,14 +1842,17 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, /* Continuation fragments (no L2CAP header) */ frag = &skb_shinfo(skb)->frag_list; while (len) { + struct sk_buff *tmp; + count = min_t(unsigned int, conn->mtu, len); - *frag = chan->ops->alloc_skb(chan, count, - msg->msg_flags & MSG_DONTWAIT, - &err); + tmp = chan->ops->alloc_skb(chan, count, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(tmp)) + return PTR_ERR(tmp); + + *frag = tmp; - if (!*frag) - return err; if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count)) return -EFAULT; @@ -1581,6 +1861,9 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, sent += count; len -= count; + skb->len += (*frag)->len; + skb->data_len += (*frag)->len; + frag = &(*frag)->next; } @@ -1601,18 +1884,17 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(chan->psm, skb_put(skb, 2)); + lh->len = cpu_to_le16(len + L2CAP_PSMLEN_SIZE); + put_unaligned(chan->psm, skb_put(skb, L2CAP_PSMLEN_SIZE)); err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1628,25 +1910,24 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; - int err, count, hlen = L2CAP_HDR_SIZE; + int err, count; struct l2cap_hdr *lh; BT_DBG("chan %p len %d", chan, (int)len); - count = min_t(unsigned int, (conn->mtu - hlen), len); + count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); - skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + skb = chan->ops->alloc_skb(chan, count + L2CAP_HDR_SIZE, + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; skb->priority = priority; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); - lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); + lh->len = cpu_to_le16(len); err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1658,7 +1939,7 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, - u32 control, u16 sdulen) + u16 sdulen) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; @@ -1684,17 +1965,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, count = min_t(unsigned int, (conn->mtu - hlen), len); skb = chan->ops->alloc_skb(chan, count + hlen, - msg->msg_flags & MSG_DONTWAIT, &err); - - if (!skb) - return ERR_PTR(err); + msg->msg_flags & MSG_DONTWAIT); + if (IS_ERR(skb)) + return skb; /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - __put_control(chan, control, skb_put(skb, __ctrl_size(chan))); + __put_control(chan, 0, skb_put(skb, __ctrl_size(chan))); if (sdulen) put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE)); @@ -1708,61 +1988,82 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE)); - bt_cb(skb)->retries = 0; + bt_cb(skb)->control.retries = 0; return skb; } -static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) +static int l2cap_segment_sdu(struct l2cap_chan *chan, + struct sk_buff_head *seg_queue, + struct msghdr *msg, size_t len) { struct sk_buff *skb; - struct sk_buff_head sar_queue; - u32 control; - size_t size = 0; + u16 sdu_len; + size_t pdu_len; + int err = 0; + u8 sar; - skb_queue_head_init(&sar_queue); - control = __set_ctrl_sar(chan, L2CAP_SAR_START); - skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); - if (IS_ERR(skb)) - return PTR_ERR(skb); + BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); - __skb_queue_tail(&sar_queue, skb); - len -= chan->remote_mps; - size += chan->remote_mps; + /* It is critical that ERTM PDUs fit in a single HCI fragment, + * so fragmented skbs are not used. The HCI layer's handling + * of fragmented skbs is not compatible with ERTM's queueing. + */ - while (len > 0) { - size_t buflen; + /* PDU size is derived from the HCI MTU */ + pdu_len = chan->conn->mtu; - if (len > chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE); - buflen = chan->remote_mps; - } else { - control = __set_ctrl_sar(chan, L2CAP_SAR_END); - buflen = len; - } + pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD); + + /* Adjust for largest possible L2CAP overhead. */ + pdu_len -= L2CAP_EXT_HDR_SIZE + L2CAP_FCS_SIZE; + + /* Remote device may have requested smaller PDUs */ + pdu_len = min_t(size_t, pdu_len, chan->remote_mps); + + if (len <= pdu_len) { + sar = L2CAP_SAR_UNSEGMENTED; + sdu_len = 0; + pdu_len = len; + } else { + sar = L2CAP_SAR_START; + sdu_len = len; + pdu_len -= L2CAP_SDULEN_SIZE; + } + + while (len > 0) { + skb = l2cap_create_iframe_pdu(chan, msg, pdu_len, sdu_len); - skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { - skb_queue_purge(&sar_queue); + __skb_queue_purge(seg_queue); return PTR_ERR(skb); } - __skb_queue_tail(&sar_queue, skb); - len -= buflen; - size += buflen; + bt_cb(skb)->control.sar = sar; + __skb_queue_tail(seg_queue, skb); + + len -= pdu_len; + if (sdu_len) { + sdu_len = 0; + pdu_len += L2CAP_SDULEN_SIZE; + } + + if (len <= pdu_len) { + sar = L2CAP_SAR_END; + pdu_len = len; + } else { + sar = L2CAP_SAR_CONTINUE; + } } - skb_queue_splice_tail(&sar_queue, &chan->tx_q); - if (chan->tx_send_head == NULL) - chan->tx_send_head = sar_queue.next; - return size; + return err; } int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u32 priority) { struct sk_buff *skb; - u32 control; int err; + struct sk_buff_head seg_queue; /* Connectionless channel */ if (chan->chan_type == L2CAP_CHAN_CONN_LESS) { @@ -1791,42 +2092,47 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len, case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: - /* Entire SDU fits into one PDU */ - if (len <= chan->remote_mps) { - control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED); - skb = l2cap_create_iframe_pdu(chan, msg, len, control, - 0); - if (IS_ERR(skb)) - return PTR_ERR(skb); + /* Check outgoing MTU */ + if (len > chan->omtu) { + err = -EMSGSIZE; + break; + } - __skb_queue_tail(&chan->tx_q, skb); + __skb_queue_head_init(&seg_queue); - if (chan->tx_send_head == NULL) - chan->tx_send_head = skb; + /* Do segmentation before calling in to the state machine, + * since it's possible to block while waiting for memory + * allocation. + */ + err = l2cap_segment_sdu(chan, &seg_queue, msg, len); - } else { - /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(chan, msg, len); - if (err < 0) - return err; + /* The channel could have been closed while segmenting, + * check that it is still connected. + */ + if (chan->state != BT_CONNECTED) { + __skb_queue_purge(&seg_queue); + err = -ENOTCONN; } - if (chan->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(chan); - err = len; + if (err) break; - } - if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) && - test_bit(CONN_WAIT_F, &chan->conn_state)) { - err = len; - break; - } + if (chan->mode == L2CAP_MODE_ERTM && chan->tx_send_head == NULL) + chan->tx_send_head = seg_queue.next; + skb_queue_splice_tail_init(&seg_queue, &chan->tx_q); + + if (chan->mode == L2CAP_MODE_ERTM) + err = l2cap_ertm_send(chan); + else + l2cap_streaming_send(chan); - err = l2cap_ertm_send(chan); if (err >= 0) err = len; + /* If the skbs were not queued for sending, they'll still be in + * seg_queue and need to be purged. + */ + __skb_queue_purge(&seg_queue); break; default: @@ -2040,13 +2346,29 @@ static void l2cap_ack_timeout(struct work_struct *work) l2cap_chan_put(chan); } -static inline void l2cap_ertm_init(struct l2cap_chan *chan) +static inline int l2cap_ertm_init(struct l2cap_chan *chan) { + int err; + + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; chan->expected_ack_seq = 0; chan->unacked_frames = 0; chan->buffer_seq = 0; chan->num_acked = 0; chan->frames_sent = 0; + chan->last_acked_seq = 0; + chan->sdu = NULL; + chan->sdu_last_frag = NULL; + chan->sdu_len = 0; + + skb_queue_head_init(&chan->tx_q); + + if (chan->mode != L2CAP_MODE_ERTM) + return 0; + + chan->rx_state = L2CAP_RX_STATE_RECV; + chan->tx_state = L2CAP_TX_STATE_XMIT; INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout); INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout); @@ -2055,6 +2377,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); INIT_LIST_HEAD(&chan->srej_l); + err = l2cap_seq_list_init(&chan->srej_list, chan->tx_win); + if (err < 0) + return err; + + return l2cap_seq_list_init(&chan->retrans_list, chan->remote_tx_win); } static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) @@ -2378,9 +2705,9 @@ done: chan->remote_mps = size; rfc.retrans_timeout = - le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); rfc.monitor_timeout = - le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); + __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); set_bit(CONF_MODE_DONE, &chan->conf_state); @@ -2644,10 +2971,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_DBG("psm 0x%2.2x scid 0x%4.4x", __le16_to_cpu(psm), scid); /* Check if we have socket listening on psm */ - pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src, conn->dst); if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; @@ -2706,7 +3033,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_chan_check_security(chan)) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) { __l2cap_state_change(chan, BT_CONNECT2); result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHOR_PEND; @@ -2848,7 +3175,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u16 dcid, flags; u8 rsp[64]; struct l2cap_chan *chan; - int len; + int len, err = 0; dcid = __le16_to_cpu(req->dcid); flags = __le16_to_cpu(req->flags); @@ -2859,8 +3186,6 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!chan) return -ENOENT; - l2cap_chan_lock(chan); - if (chan->state != BT_CONFIG && chan->state != BT_CONNECT2) { struct l2cap_cmd_rej_cid rej; @@ -2915,13 +3240,15 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) + err = l2cap_ertm_init(chan); + + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); - l2cap_chan_ready(chan); goto unlock; } @@ -2949,7 +3276,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr unlock: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -2957,21 +3284,20 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; struct l2cap_chan *chan; - int len = cmd->len - sizeof(*rsp); + int len = le16_to_cpu(cmd->len) - sizeof(*rsp); + int err = 0; scid = __le16_to_cpu(rsp->scid); flags = __le16_to_cpu(rsp->flags); result = __le16_to_cpu(rsp->result); - BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", - scid, flags, result); + BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x len %d", scid, flags, + result, len); chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; - l2cap_chan_lock(chan); - switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(chan, rsp->data, len); @@ -3045,18 +3371,19 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr set_default_fcs(chan); l2cap_state_change(chan, BT_CONNECTED); - chan->next_tx_seq = 0; - chan->expected_tx_seq = 0; - skb_queue_head_init(&chan->tx_q); - if (chan->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(chan); + if (chan->mode == L2CAP_MODE_ERTM || + chan->mode == L2CAP_MODE_STREAMING) + err = l2cap_ertm_init(chan); - l2cap_chan_ready(chan); + if (err < 0) + l2cap_send_disconn_req(chan->conn, chan, -err); + else + l2cap_chan_ready(chan); } done: l2cap_chan_unlock(chan); - return 0; + return err; } static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) @@ -3092,11 +3419,13 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk->sk_shutdown = SHUTDOWN_MASK; release_sock(sk); + l2cap_chan_hold(chan); l2cap_chan_del(chan, ECONNRESET); l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); @@ -3124,11 +3453,13 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd l2cap_chan_lock(chan); + l2cap_chan_hold(chan); l2cap_chan_del(chan, 0); l2cap_chan_unlock(chan); chan->ops->close(chan->data); + l2cap_chan_put(chan); mutex_unlock(&conn->chan_lock); @@ -3265,8 +3596,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, /* Placeholder: Always reject */ rsp.dcid = 0; rsp.scid = cpu_to_le16(scid); - rsp.result = L2CAP_CR_NO_MEM; - rsp.status = L2CAP_CS_NO_INFO; + rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM); + rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP, sizeof(rsp), &rsp); @@ -3665,19 +3996,19 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; next_skb = skb_peek(&chan->srej_q); tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq); while (next_skb) { - if (bt_cb(next_skb)->tx_seq == tx_seq) + if (bt_cb(next_skb)->control.txseq == tx_seq) return -EINVAL; next_tx_seq_offset = __seq_offset(chan, - bt_cb(next_skb)->tx_seq, chan->buffer_seq); + bt_cb(next_skb)->control.txseq, chan->buffer_seq); if (next_tx_seq_offset > tx_seq_offset) { __skb_queue_before(&chan->srej_q, next_skb, skb); @@ -3800,6 +4131,7 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan) BT_DBG("chan %p, Enter local busy", chan); set_bit(CONN_LOCAL_BUSY, &chan->conn_state); + l2cap_seq_list_clear(&chan->srej_list); __set_ack_timer(chan); } @@ -3848,11 +4180,11 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq) !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) { int err; - if (bt_cb(skb)->tx_seq != tx_seq) + if (bt_cb(skb)->control.txseq != tx_seq) break; skb = skb_dequeue(&chan->srej_q); - control = __set_ctrl_sar(chan, bt_cb(skb)->sar); + control = __set_ctrl_sar(chan, bt_cb(skb)->control.sar); err = l2cap_reassemble_sdu(chan, skb, control); if (err < 0) { @@ -3892,6 +4224,7 @@ static int l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq) while (tx_seq != chan->expected_tx_seq) { control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ); control |= __set_reqseq(chan, chan->expected_tx_seq); + l2cap_seq_list_append(&chan->srej_list, chan->expected_tx_seq); l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); @@ -4022,8 +4355,8 @@ expected: chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq); if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) { - bt_cb(skb)->tx_seq = tx_seq; - bt_cb(skb)->sar = sar; + bt_cb(skb)->control.txseq = tx_seq; + bt_cb(skb)->control.sar = sar; __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -4220,6 +4553,8 @@ static int l2cap_ertm_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb) u16 req_seq; int len, next_tx_seq_offset, req_seq_offset; + __unpack_control(chan, skb); + control = __get_control(chan, skb->data); skb_pull(skb, __ctrl_size(chan)); len = skb->len; @@ -4295,8 +4630,6 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk return 0; } - l2cap_chan_lock(chan); - BT_DBG("chan %p, len %d", chan, skb->len); if (chan->state != BT_CONNECTED) @@ -4375,7 +4708,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str { struct l2cap_chan *chan; - chan = l2cap_global_chan_by_psm(0, psm, conn->src); + chan = l2cap_global_chan_by_psm(0, psm, conn->src, conn->dst); if (!chan) goto drop; @@ -4396,11 +4729,12 @@ drop: return 0; } -static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) +static inline int l2cap_att_channel(struct l2cap_conn *conn, u16 cid, + struct sk_buff *skb) { struct l2cap_chan *chan; - chan = l2cap_global_chan_by_scid(0, cid, conn->src); + chan = l2cap_global_chan_by_scid(0, cid, conn->src, conn->dst); if (!chan) goto drop; @@ -4445,7 +4779,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) break; case L2CAP_CID_CONN_LESS: - psm = get_unaligned_le16(skb->data); + psm = get_unaligned((__le16 *) skb->data); skb_pull(skb, 2); l2cap_conless_channel(conn, psm, skb); break; @@ -4540,7 +4874,6 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) if (encrypt == 0x00) { if (chan->sec_level == BT_SECURITY_MEDIUM) { - __clear_chan_timer(chan); __set_chan_timer(chan, L2CAP_ENC_TIMEOUT); } else if (chan->sec_level == BT_SECURITY_HIGH) l2cap_chan_close(chan, ECONNREFUSED); @@ -4561,7 +4894,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) BT_DBG("conn %p", conn); if (hcon->type == LE_LINK) { - smp_distribute_keys(conn, 0); + if (!status && encrypt) + smp_distribute_keys(conn, 0); cancel_delayed_work(&conn->security_timer); } @@ -4591,7 +4925,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) chan->state == BT_CONFIG)) { struct sock *sk = chan->sk; - bt_sk(sk)->suspended = false; + clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); sk->sk_state_change(sk); l2cap_check_encryption(chan, encrypt); @@ -4603,7 +4937,6 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status) { l2cap_send_conn_req(chan); } else { - __clear_chan_timer(chan); __set_chan_timer(chan, L2CAP_DISC_TIMEOUT); } } else if (chan->state == BT_CONNECT2) { @@ -4614,7 +4947,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) lock_sock(sk); if (!status) { - if (bt_sk(sk)->defer_setup) { + if (test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { struct sock *parent = bt_sk(sk)->parent; res = L2CAP_CR_PEND; stat = L2CAP_CS_AUTHOR_PEND; @@ -4664,8 +4998,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; - struct l2cap_chan *chan; - u16 cid; int len; if (conn->rx_len) { @@ -4685,7 +5017,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) hdr = (struct l2cap_hdr *) skb->data; len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE; - cid = __le16_to_cpu(hdr->cid); if (len == skb->len) { /* Complete frame received */ @@ -4702,23 +5033,6 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags) goto drop; } - chan = l2cap_get_chan_by_scid(conn, cid); - - if (chan && chan->sk) { - struct sock *sk = chan->sk; - lock_sock(sk); - - if (chan->imtu < len - L2CAP_HDR_SIZE) { - BT_ERR("Frame exceeding recv MTU (len %d, " - "MTU %d)", len, - chan->imtu); - release_sock(sk); - l2cap_conn_unreliable(conn, ECOMM); - goto drop; - } - release_sock(sk); - } - /* Allocate skb for the complete frame (with header) */ conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); if (!conn->rx_skb) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 04e7c172d49c..3bb1611b9d48 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -124,7 +124,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al return -EINVAL; err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid), - &la.l2_bdaddr); + &la.l2_bdaddr, la.l2_bdaddr_type); if (err) return err; @@ -148,12 +148,16 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) lock_sock(sk); - if ((sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM) - || sk->sk_state != BT_BOUND) { + if (sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { + err = -EINVAL; + goto done; + } + switch (chan->mode) { case L2CAP_MODE_BASIC: break; @@ -320,8 +324,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us case L2CAP_CONNINFO: if (sk->sk_state != BT_CONNECTED && - !(sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup)) { + !(sk->sk_state == BT_CONNECT2 && + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags))) { err = -ENOTCONN; break; } @@ -375,7 +379,10 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch } memset(&sec, 0, sizeof(sec)); - sec.level = chan->sec_level; + if (chan->conn) + sec.level = chan->conn->hcon->sec_level; + else + sec.level = chan->sec_level; if (sk->sk_state == BT_CONNECTED) sec.key_size = chan->conn->hcon->enc_key_size; @@ -392,7 +399,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -594,10 +602,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch /* or for ACL link */ } else if ((sk->sk_state == BT_CONNECT2 && - bt_sk(sk)->defer_setup) || + test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) || sk->sk_state == BT_CONNECTED) { if (!l2cap_chan_check_security(chan)) - bt_sk(sk)->suspended = true; + set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags); else sk->sk_state_change(sk); } else { @@ -616,7 +624,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); break; case BT_FLUSHABLE: @@ -716,16 +727,13 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - lock_sock(sk); - - if (sk->sk_state != BT_CONNECTED) { - release_sock(sk); + if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - } + l2cap_chan_lock(chan); err = l2cap_chan_send(chan, msg, len, sk->sk_priority); + l2cap_chan_unlock(chan); - release_sock(sk); return err; } @@ -737,7 +745,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); - if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { + if (sk->sk_state == BT_CONNECT2 && test_bit(BT_SK_DEFER_SETUP, + &bt_sk(sk)->flags)) { sk->sk_state = BT_CONFIG; pi->chan->state = BT_CONFIG; @@ -931,12 +940,19 @@ static void l2cap_sock_state_change_cb(void *data, int state) } static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan, - unsigned long len, int nb, - int *err) + unsigned long len, int nb) { - struct sock *sk = chan->sk; + struct sk_buff *skb; + int err; + + l2cap_chan_unlock(chan); + skb = bt_skb_send_alloc(chan->sk, len, nb, &err); + l2cap_chan_lock(chan); + + if (!skb) + return ERR_PTR(err); - return bt_skb_send_alloc(sk, len, nb, err); + return skb; } static struct l2cap_ops l2cap_chan_ops = { @@ -952,6 +968,7 @@ static void l2cap_sock_destruct(struct sock *sk) { BT_DBG("sk %p", sk); + l2cap_chan_put(l2cap_pi(sk)->chan); if (l2cap_pi(sk)->rx_busy_skb) { kfree_skb(l2cap_pi(sk)->rx_busy_skb); l2cap_pi(sk)->rx_busy_skb = NULL; @@ -972,7 +989,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) struct l2cap_chan *pchan = l2cap_pi(parent)->chan; sk->sk_type = parent->sk_type; - bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; + bt_sk(sk)->flags = bt_sk(parent)->flags; chan->chan_type = pchan->chan_type; chan->imtu = pchan->imtu; @@ -1010,13 +1027,8 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { chan->mode = L2CAP_MODE_BASIC; } - chan->max_tx = L2CAP_DEFAULT_MAX_TX; - chan->fcs = L2CAP_FCS_CRC16; - chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; - chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; - chan->sec_level = BT_SECURITY_LOW; - chan->flags = 0; - set_bit(FLAG_FORCE_ACTIVE, &chan->flags); + + l2cap_chan_set_defaults(chan); } /* Default config options */ @@ -1052,12 +1064,16 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p sk->sk_protocol = proto; sk->sk_state = BT_OPEN; - chan = l2cap_chan_create(sk); + chan = l2cap_chan_create(); if (!chan) { l2cap_sock_kill(sk); return NULL; } + l2cap_chan_hold(chan); + + chan->sk = sk; + l2cap_pi(sk)->chan = chan; return sk; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4bb03b111122..25d220776079 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -35,10 +35,9 @@ #include <net/bluetooth/smp.h> bool enable_hs; -bool enable_le; #define MGMT_VERSION 1 -#define MGMT_REVISION 0 +#define MGMT_REVISION 1 static const u16 mgmt_commands[] = { MGMT_OP_READ_INDEX_LIST, @@ -78,6 +77,7 @@ static const u16 mgmt_commands[] = { MGMT_OP_CONFIRM_NAME, MGMT_OP_BLOCK_DEVICE, MGMT_OP_UNBLOCK_DEVICE, + MGMT_OP_SET_DEVICE_ID, }; static const u16 mgmt_events[] = { @@ -224,7 +224,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) ev = (void *) skb_put(skb, sizeof(*ev)); ev->status = status; - put_unaligned_le16(cmd, &ev->opcode); + ev->opcode = cpu_to_le16(cmd); err = sock_queue_rcv_skb(sk, skb); if (err < 0) @@ -254,7 +254,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, hdr->len = cpu_to_le16(sizeof(*ev) + rp_len); ev = (void *) skb_put(skb, sizeof(*ev) + rp_len); - put_unaligned_le16(cmd, &ev->opcode); + ev->opcode = cpu_to_le16(cmd); ev->status = status; if (rp) @@ -275,7 +275,7 @@ static int read_version(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("sock %p", sk); rp.version = MGMT_VERSION; - put_unaligned_le16(MGMT_REVISION, &rp.revision); + rp.revision = __constant_cpu_to_le16(MGMT_REVISION); return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp, sizeof(rp)); @@ -285,9 +285,9 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { struct mgmt_rp_read_commands *rp; - u16 num_commands = ARRAY_SIZE(mgmt_commands); - u16 num_events = ARRAY_SIZE(mgmt_events); - u16 *opcode; + const u16 num_commands = ARRAY_SIZE(mgmt_commands); + const u16 num_events = ARRAY_SIZE(mgmt_events); + __le16 *opcode; size_t rp_size; int i, err; @@ -299,8 +299,8 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, if (!rp) return -ENOMEM; - put_unaligned_le16(num_commands, &rp->num_commands); - put_unaligned_le16(num_events, &rp->num_events); + rp->num_commands = __constant_cpu_to_le16(num_commands); + rp->num_events = __constant_cpu_to_le16(num_events); for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) put_unaligned_le16(mgmt_commands[i], opcode); @@ -341,14 +341,14 @@ static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data, return -ENOMEM; } - put_unaligned_le16(count, &rp->num_controllers); + rp->num_controllers = cpu_to_le16(count); i = 0; list_for_each_entry(d, &hci_dev_list, list) { if (test_bit(HCI_SETUP, &d->dev_flags)) continue; - put_unaligned_le16(d->id, &rp->index[i++]); + rp->index[i++] = cpu_to_le16(d->id); BT_DBG("Added hci%u", d->id); } @@ -383,10 +383,8 @@ static u32 get_supported_settings(struct hci_dev *hdev) if (enable_hs) settings |= MGMT_SETTING_HS; - if (enable_le) { - if (hdev->features[4] & LMP_LE) - settings |= MGMT_SETTING_LE; - } + if (hdev->features[4] & LMP_LE) + settings |= MGMT_SETTING_LE; return settings; } @@ -442,9 +440,7 @@ static u16 get_uuid16(u8 *uuid128) return 0; } - memcpy(&val, &uuid128[12], 4); - - val = le32_to_cpu(val); + val = get_unaligned_le32(&uuid128[12]); if (val > 0xffff) return 0; @@ -479,6 +475,28 @@ static void create_eir(struct hci_dev *hdev, u8 *data) ptr += (name_len + 2); } + if (hdev->inq_tx_power) { + ptr[0] = 2; + ptr[1] = EIR_TX_POWER; + ptr[2] = (u8) hdev->inq_tx_power; + + eir_len += 3; + ptr += 3; + } + + if (hdev->devid_source > 0) { + ptr[0] = 9; + ptr[1] = EIR_DEVICE_ID; + + put_unaligned_le16(hdev->devid_source, ptr + 2); + put_unaligned_le16(hdev->devid_vendor, ptr + 4); + put_unaligned_le16(hdev->devid_product, ptr + 6); + put_unaligned_le16(hdev->devid_version, ptr + 8); + + eir_len += 10; + ptr += 10; + } + memset(uuid16_list, 0, sizeof(uuid16_list)); /* Group all UUID16 types */ @@ -642,8 +660,7 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev, bacpy(&rp.bdaddr, &hdev->bdaddr); rp.version = hdev->hci_ver; - - put_unaligned_le16(hdev->manufacturer, &rp.manufacturer); + rp.manufacturer = cpu_to_le16(hdev->manufacturer); rp.supported_settings = cpu_to_le32(get_supported_settings(hdev)); rp.current_settings = cpu_to_le32(get_current_settings(hdev)); @@ -840,7 +857,7 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data, BT_DBG("request for %s", hdev->name); - timeout = get_unaligned_le16(&cp->timeout); + timeout = __le16_to_cpu(cp->timeout); if (!cp->val && timeout > 0) return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, MGMT_STATUS_INVALID_PARAMS); @@ -1122,8 +1139,8 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, - MGMT_STATUS_BUSY); + err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, + MGMT_STATUS_BUSY); goto failed; } @@ -1179,7 +1196,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) hci_dev_lock(hdev); - if (!enable_le || !(hdev->features[4] & LMP_LE)) { + if (!(hdev->features[4] & LMP_LE)) { err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE, MGMT_STATUS_NOT_SUPPORTED); goto unlock; @@ -1227,10 +1244,8 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp), &hci_cp); - if (err < 0) { + if (err < 0) mgmt_pending_remove(cmd); - goto unlock; - } unlock: hci_dev_unlock(hdev); @@ -1280,10 +1295,8 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) } cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto failed; - } failed: hci_dev_unlock(hdev); @@ -1368,10 +1381,8 @@ update_class: } cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto unlock; - } unlock: hci_dev_unlock(hdev); @@ -1422,10 +1433,8 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, } cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len); - if (!cmd) { + if (!cmd) err = -ENOMEM; - goto unlock; - } unlock: hci_dev_unlock(hdev); @@ -1439,7 +1448,7 @@ static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data, u16 key_count, expected_len; int i; - key_count = get_unaligned_le16(&cp->key_count); + key_count = __le16_to_cpu(cp->key_count); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_link_key_info); @@ -1512,7 +1521,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) err = hci_remove_link_key(hdev, &cp->addr.bdaddr); else err = hci_remove_ltk(hdev, &cp->addr.bdaddr); @@ -1524,7 +1533,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, } if (cp->disconnect) { - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else @@ -1548,7 +1557,7 @@ static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - put_unaligned_le16(conn->handle, &dc.handle); + dc.handle = cpu_to_le16(conn->handle); dc.reason = 0x13; /* Remote User Terminated Connection */ err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); if (err < 0) @@ -1584,7 +1593,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr); @@ -1601,7 +1610,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, goto failed; } - put_unaligned_le16(conn->handle, &dc.handle); + dc.handle = cpu_to_le16(conn->handle); dc.reason = 0x13; /* Remote User Terminated Connection */ err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); @@ -1613,22 +1622,22 @@ failed: return err; } -static u8 link_to_mgmt(u8 link_type, u8 addr_type) +static u8 link_to_bdaddr(u8 link_type, u8 addr_type) { switch (link_type) { case LE_LINK: switch (addr_type) { case ADDR_LE_DEV_PUBLIC: - return MGMT_ADDR_LE_PUBLIC; - case ADDR_LE_DEV_RANDOM: - return MGMT_ADDR_LE_RANDOM; + return BDADDR_LE_PUBLIC; + default: - return MGMT_ADDR_INVALID; + /* Fallback to LE Random address type */ + return BDADDR_LE_RANDOM; } - case ACL_LINK: - return MGMT_ADDR_BREDR; + default: - return MGMT_ADDR_INVALID; + /* Fallback to BR/EDR type */ + return BDADDR_BREDR; } } @@ -1669,13 +1678,13 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags)) continue; bacpy(&rp->addr[i].bdaddr, &c->dst); - rp->addr[i].type = link_to_mgmt(c->type, c->dst_type); - if (rp->addr[i].type == MGMT_ADDR_INVALID) + rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type); + if (c->type == SCO_LINK || c->type == ESCO_LINK) continue; i++; } - put_unaligned_le16(i, &rp->conn_count); + rp->conn_count = cpu_to_le16(i); /* Recalculate length in case of filtered SCO connections, etc */ rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); @@ -1836,7 +1845,7 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status) struct hci_conn *conn = cmd->user_data; bacpy(&rp.addr.bdaddr, &conn->dst); - rp.addr.type = link_to_mgmt(conn->type, conn->dst_type); + rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type); cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status, &rp, sizeof(rp)); @@ -1890,12 +1899,12 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, else auth_type = HCI_AT_DEDICATED_BONDING_MITM; - if (cp->addr.type == MGMT_ADDR_BREDR) - conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + if (cp->addr.type == BDADDR_BREDR) + conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); else - conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level, - auth_type); + conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, + cp->addr.type, sec_level, auth_type); memset(&rp, 0, sizeof(rp)); bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr); @@ -1923,7 +1932,7 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data, } /* For LE, just connecting isn't a proof that the pairing finished */ - if (cp->addr.type == MGMT_ADDR_BREDR) + if (cp->addr.type == BDADDR_BREDR) conn->connect_cfm_cb = pairing_complete_cb; conn->security_cfm_cb = pairing_complete_cb; @@ -2000,7 +2009,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_BREDR) + if (type == BDADDR_BREDR) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr); else conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr); @@ -2011,7 +2020,7 @@ static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev, goto done; } - if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) { + if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) { /* Continue with pairing via SMP */ err = smp_user_confirm_reply(conn, mgmt_op, passkey); @@ -2295,6 +2304,12 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, goto failed; } + if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) { + err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, + MGMT_STATUS_BUSY); + goto failed; + } + if (hdev->discovery.state != DISCOVERY_STOPPED) { err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, MGMT_STATUS_BUSY); @@ -2381,27 +2396,39 @@ static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data, goto unlock; } - if (hdev->discovery.state == DISCOVERY_FINDING) { - err = hci_cancel_inquiry(hdev); - if (err < 0) - mgmt_pending_remove(cmd); + switch (hdev->discovery.state) { + case DISCOVERY_FINDING: + if (test_bit(HCI_INQUIRY, &hdev->flags)) + err = hci_cancel_inquiry(hdev); else - hci_discovery_set_state(hdev, DISCOVERY_STOPPING); - goto unlock; - } + err = hci_cancel_le_scan(hdev); - e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING); - if (!e) { - mgmt_pending_remove(cmd); - err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0, - &mgmt_cp->type, sizeof(mgmt_cp->type)); - hci_discovery_set_state(hdev, DISCOVERY_STOPPED); - goto unlock; + break; + + case DISCOVERY_RESOLVING: + e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, + NAME_PENDING); + if (!e) { + mgmt_pending_remove(cmd); + err = cmd_complete(sk, hdev->id, + MGMT_OP_STOP_DISCOVERY, 0, + &mgmt_cp->type, + sizeof(mgmt_cp->type)); + hci_discovery_set_state(hdev, DISCOVERY_STOPPED); + goto unlock; + } + + bacpy(&cp.bdaddr, &e->data.bdaddr); + err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, + sizeof(cp), &cp); + + break; + + default: + BT_DBG("unknown discovery state %u", hdev->discovery.state); + err = -EFAULT; } - bacpy(&cp.bdaddr, &e->data.bdaddr); - err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp), - &cp); if (err < 0) mgmt_pending_remove(cmd); else @@ -2501,6 +2528,37 @@ static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data, return err; } +static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, + u16 len) +{ + struct mgmt_cp_set_device_id *cp = data; + int err; + __u16 source; + + BT_DBG("%s", hdev->name); + + source = __le16_to_cpu(cp->source); + + if (source > 0x0002) + return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, + MGMT_STATUS_INVALID_PARAMS); + + hci_dev_lock(hdev); + + hdev->devid_source = source; + hdev->devid_vendor = __le16_to_cpu(cp->vendor); + hdev->devid_product = __le16_to_cpu(cp->product); + hdev->devid_version = __le16_to_cpu(cp->version); + + err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0); + + update_eir(hdev); + + hci_dev_unlock(hdev); + + return err; +} + static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2565,7 +2623,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, u16 key_count, expected_len; int i; - key_count = get_unaligned_le16(&cp->key_count); + key_count = __le16_to_cpu(cp->key_count); expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_ltk_info); @@ -2591,7 +2649,8 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, else type = HCI_SMP_LTK_SLAVE; - hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type, + hci_add_ltk(hdev, &key->addr.bdaddr, + bdaddr_to_le(key->addr.type), type, 0, key->authenticated, key->val, key->enc_size, key->ediv, key->rand); } @@ -2601,7 +2660,7 @@ static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev, return 0; } -struct mgmt_handler { +static const struct mgmt_handler { int (*func) (struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len); bool var_len; @@ -2647,6 +2706,7 @@ struct mgmt_handler { { confirm_name, false, MGMT_CONFIRM_NAME_SIZE }, { block_device, false, MGMT_BLOCK_DEVICE_SIZE }, { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE }, + { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE }, }; @@ -2657,7 +2717,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) struct mgmt_hdr *hdr; u16 opcode, index, len; struct hci_dev *hdev = NULL; - struct mgmt_handler *handler; + const struct mgmt_handler *handler; int err; BT_DBG("got %zu bytes", msglen); @@ -2675,9 +2735,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) } hdr = buf; - opcode = get_unaligned_le16(&hdr->opcode); - index = get_unaligned_le16(&hdr->index); - len = get_unaligned_le16(&hdr->len); + opcode = __le16_to_cpu(hdr->opcode); + index = __le16_to_cpu(hdr->index); + len = __le16_to_cpu(hdr->len); if (len != msglen - sizeof(*hdr)) { err = -EINVAL; @@ -2884,7 +2944,8 @@ int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status) return 0; } -int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent) +int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, + bool persistent) { struct mgmt_ev_new_link_key ev; @@ -2892,7 +2953,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persisten ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = MGMT_ADDR_BREDR; + ev.key.addr.type = BDADDR_BREDR; ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; @@ -2908,7 +2969,7 @@ int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent) ev.store_hint = persistent; bacpy(&ev.key.addr.bdaddr, &key->bdaddr); - ev.key.addr.type = key->bdaddr_type; + ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type); ev.key.authenticated = key->authenticated; ev.key.enc_size = key->enc_size; ev.key.ediv = key->ediv; @@ -2932,7 +2993,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, u16 eir_len = 0; bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->flags = __cpu_to_le32(flags); @@ -2944,7 +3005,7 @@ int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf, sizeof(*ev) + eir_len, NULL); @@ -2995,13 +3056,13 @@ int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk); bacpy(&ev.bdaddr, bdaddr); - ev.type = link_to_mgmt(link_type, addr_type); + ev.type = link_to_bdaddr(link_type, addr_type); err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk); if (sk) - sock_put(sk); + sock_put(sk); mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp, hdev); @@ -3021,7 +3082,7 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.addr.type = link_to_bdaddr(link_type, addr_type); err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, mgmt_status(status), &rp, sizeof(rp)); @@ -3039,7 +3100,7 @@ int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, struct mgmt_ev_connect_failed ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL); @@ -3050,7 +3111,7 @@ int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure) struct mgmt_ev_pin_code_request ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = MGMT_ADDR_BREDR; + ev.addr.type = BDADDR_BREDR; ev.secure = secure; return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), @@ -3069,7 +3130,7 @@ int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, mgmt_status(status), &rp, sizeof(rp)); @@ -3091,7 +3152,7 @@ int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = MGMT_ADDR_BREDR; + rp.addr.type = BDADDR_BREDR; err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, mgmt_status(status), &rp, sizeof(rp)); @@ -3110,9 +3171,9 @@ int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s", hdev->name); bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.confirm_hint = confirm_hint; - put_unaligned_le32(value, &ev.value); + ev.value = value; return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev), NULL); @@ -3126,7 +3187,7 @@ int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr, BT_DBG("%s", hdev->name); bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev), NULL); @@ -3145,7 +3206,7 @@ static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr, return -ENOENT; bacpy(&rp.addr.bdaddr, bdaddr); - rp.addr.type = link_to_mgmt(link_type, addr_type); + rp.addr.type = link_to_bdaddr(link_type, addr_type); err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status), &rp, sizeof(rp)); @@ -3188,7 +3249,7 @@ int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, struct mgmt_ev_auth_failed ev; bacpy(&ev.addr.bdaddr, bdaddr); - ev.addr.type = link_to_mgmt(link_type, addr_type); + ev.addr.type = link_to_bdaddr(link_type, addr_type); ev.status = mgmt_status(status); return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL); @@ -3413,10 +3474,10 @@ int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (enable && test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags)) - err = new_settings(hdev, NULL); + err = new_settings(hdev, NULL); - mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, - cmd_status_rsp, &mgmt_err); + mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp, + &mgmt_err); return err; } @@ -3455,7 +3516,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->rssi = rssi; if (cfm_name) ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME; @@ -3469,7 +3530,7 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV, dev_class, 3); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); ev_size = sizeof(*ev) + eir_len; @@ -3488,13 +3549,13 @@ int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, memset(buf, 0, sizeof(buf)); bacpy(&ev->addr.bdaddr, bdaddr); - ev->addr.type = link_to_mgmt(link_type, addr_type); + ev->addr.type = link_to_bdaddr(link_type, addr_type); ev->rssi = rssi; eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name, name_len); - put_unaligned_le16(eir_len, &ev->eir_len); + ev->eir_len = cpu_to_le16(eir_len); return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL); @@ -3594,6 +3655,3 @@ int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) module_param(enable_hs, bool, 0644); MODULE_PARM_DESC(enable_hs, "Enable High Speed support"); - -module_param(enable_le, bool, 0644); -MODULE_PARM_DESC(enable_le, "Enable Low Energy support"); diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index a55a43e9f70e..e8707debb864 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -260,7 +260,8 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent) if (parent) { sk->sk_type = parent->sk_type; - pi->dlc->defer_setup = bt_sk(parent)->defer_setup; + pi->dlc->defer_setup = test_bit(BT_SK_DEFER_SETUP, + &bt_sk(parent)->flags); pi->sec_level = rfcomm_pi(parent)->sec_level; pi->role_switch = rfcomm_pi(parent)->role_switch; @@ -731,7 +732,11 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c break; } - bt_sk(sk)->defer_setup = opt; + if (opt) + set_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + else + clear_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags); + break; default: @@ -849,7 +854,8 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c break; } - if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval)) + if (put_user(test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags), + (u32 __user *) optval)) err = -EFAULT; break; @@ -972,7 +978,7 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc * done: bh_unlock_sock(parent); - if (bt_sk(parent)->defer_setup) + if (test_bit(BT_SK_DEFER_SETUP, &bt_sk(parent)->flags)) parent->sk_state_change(parent); return result; diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index f6ab12907963..cbdd313659a7 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -61,8 +61,6 @@ static struct bt_sock_list sco_sk_list = { static void __sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent); static void sco_chan_del(struct sock *sk, int err); -static int sco_conn_del(struct hci_conn *conn, int err); - static void sco_sock_close(struct sock *sk); static void sco_sock_kill(struct sock *sk); @@ -95,12 +93,12 @@ static void sco_sock_clear_timer(struct sock *sk) } /* ---- SCO connections ---- */ -static struct sco_conn *sco_conn_add(struct hci_conn *hcon, __u8 status) +static struct sco_conn *sco_conn_add(struct hci_conn *hcon) { struct hci_dev *hdev = hcon->hdev; struct sco_conn *conn = hcon->sco_data; - if (conn || status) + if (conn) return conn; conn = kzalloc(sizeof(struct sco_conn), GFP_ATOMIC); @@ -195,13 +193,14 @@ static int sco_connect(struct sock *sk) else type = SCO_LINK; - hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); + hcon = hci_connect(hdev, type, dst, BDADDR_BREDR, BT_SECURITY_LOW, + HCI_AT_NO_BONDING); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); goto done; } - conn = sco_conn_add(hcon, 0); + conn = sco_conn_add(hcon); if (!conn) { hci_conn_put(hcon); err = -ENOMEM; @@ -233,7 +232,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) { struct sco_conn *conn = sco_pi(sk)->conn; struct sk_buff *skb; - int err, count; + int err; /* Check outgoing MTU */ if (len > conn->mtu) @@ -241,20 +240,18 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len) BT_DBG("sk %p len %d", sk, len); - count = min_t(unsigned int, conn->mtu, len); - skb = bt_skb_send_alloc(sk, count, - msg->msg_flags & MSG_DONTWAIT, &err); + skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err); if (!skb) return err; - if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { + if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) { kfree_skb(skb); return -EFAULT; } hci_send_sco(conn->hcon, skb); - return count; + return len; } static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb) @@ -277,17 +274,20 @@ drop: } /* -------- Socket interface ---------- */ -static struct sock *__sco_get_sock_by_addr(bdaddr_t *ba) +static struct sock *__sco_get_sock_listen_by_addr(bdaddr_t *ba) { - struct sock *sk; struct hlist_node *node; + struct sock *sk; + + sk_for_each(sk, node, &sco_sk_list.head) { + if (sk->sk_state != BT_LISTEN) + continue; - sk_for_each(sk, node, &sco_sk_list.head) if (!bacmp(&bt_sk(sk)->src, ba)) - goto found; - sk = NULL; -found: - return sk; + return sk; + } + + return NULL; } /* Find socket listening on source bdaddr. @@ -466,7 +466,6 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le { struct sockaddr_sco *sa = (struct sockaddr_sco *) addr; struct sock *sk = sock->sk; - bdaddr_t *src = &sa->sco_bdaddr; int err = 0; BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); @@ -481,17 +480,14 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le goto done; } - write_lock(&sco_sk_list.lock); - - if (bacmp(src, BDADDR_ANY) && __sco_get_sock_by_addr(src)) { - err = -EADDRINUSE; - } else { - /* Save source address */ - bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); - sk->sk_state = BT_BOUND; + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; } - write_unlock(&sco_sk_list.lock); + bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); + + sk->sk_state = BT_BOUND; done: release_sock(sk); @@ -537,21 +533,38 @@ done: static int sco_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + bdaddr_t *src = &bt_sk(sk)->src; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); lock_sock(sk); - if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + if (sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } + if (sk->sk_type != SOCK_SEQPACKET) { + err = -EINVAL; + goto done; + } + + write_lock(&sco_sk_list.lock); + + if (__sco_get_sock_listen_by_addr(src)) { + err = -EADDRINUSE; + goto unlock; + } + sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; +unlock: + write_unlock(&sco_sk_list.lock); + done: release_sock(sk); return err; @@ -923,7 +936,7 @@ int sco_connect_cfm(struct hci_conn *hcon, __u8 status) if (!status) { struct sco_conn *conn; - conn = sco_conn_add(hcon, status); + conn = sco_conn_add(hcon); if (conn) sco_conn_ready(conn); } else diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c index deb119875fd9..6fc7c4708f3e 100644 --- a/net/bluetooth/smp.c +++ b/net/bluetooth/smp.c @@ -956,7 +956,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force) HCI_SMP_LTK_SLAVE, 1, authenticated, enc.ltk, smp->enc_key_size, ediv, ident.rand); - ident.ediv = cpu_to_le16(ediv); + ident.ediv = ediv; smp_send_cmd(conn, SMP_CMD_MASTER_IDENT, sizeof(ident), &ident); diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index a8bdf7405433..e5b7182fa099 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -145,6 +145,12 @@ static void free_fib_info_rcu(struct rcu_head *head) { struct fib_info *fi = container_of(head, struct fib_info, rcu); + change_nexthops(fi) { + if (nexthop_nh->nh_dev) + dev_put(nexthop_nh->nh_dev); + } endfor_nexthops(fi); + + release_net(fi->fib_net); if (fi->fib_metrics != (u32 *) dst_default_metrics) kfree(fi->fib_metrics); kfree(fi); @@ -156,13 +162,7 @@ void free_fib_info(struct fib_info *fi) pr_warn("Freeing alive fib_info %p\n", fi); return; } - change_nexthops(fi) { - if (nexthop_nh->nh_dev) - dev_put(nexthop_nh->nh_dev); - nexthop_nh->nh_dev = NULL; - } endfor_nexthops(fi); fib_info_cnt--; - release_net(fi->fib_net); call_rcu(&fi->rcu, free_fib_info_rcu); } diff --git a/net/ipv4/route.c b/net/ipv4/route.c index ffcb3b016843..98b30d08efe9 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -3452,6 +3452,7 @@ int __init ip_rt_init(void) 0, &rt_hash_log, &rt_hash_mask, + 0, rhash_entries ? 0 : 512 * 1024); memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket)); rt_hash_lock_init(); diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index bb485fcb077e..3ba605f60e4e 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3514,6 +3514,7 @@ void __init tcp_init(void) 0, NULL, &tcp_hashinfo.ehash_mask, + 0, thash_entries ? 0 : 512 * 1024); for (i = 0; i <= tcp_hashinfo.ehash_mask; i++) { INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i); @@ -3530,6 +3531,7 @@ void __init tcp_init(void) 0, &tcp_hashinfo.bhash_size, NULL, + 0, 64 * 1024); tcp_hashinfo.bhash_size = 1U << tcp_hashinfo.bhash_size; for (i = 0; i < tcp_hashinfo.bhash_size; i++) { diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index cfa2aa128342..b224eb8bce8b 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -4555,6 +4555,11 @@ static bool tcp_try_coalesce(struct sock *sk, if (tcp_hdr(from)->fin) return false; + + /* Its possible this segment overlaps with prior segment in queue */ + if (TCP_SKB_CB(from)->seq != TCP_SKB_CB(to)->end_seq) + return false; + if (!skb_try_coalesce(to, from, fragstolen, &delta)) return false; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 609397ee78fb..eaca73644e79 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2192,26 +2192,16 @@ void __init udp_table_init(struct udp_table *table, const char *name) { unsigned int i; - if (!CONFIG_BASE_SMALL) - table->hash = alloc_large_system_hash(name, - 2 * sizeof(struct udp_hslot), - uhash_entries, - 21, /* one slot per 2 MB */ - 0, - &table->log, - &table->mask, - 64 * 1024); - /* - * Make sure hash table has the minimum size - */ - if (CONFIG_BASE_SMALL || table->mask < UDP_HTABLE_SIZE_MIN - 1) { - table->hash = kmalloc(UDP_HTABLE_SIZE_MIN * - 2 * sizeof(struct udp_hslot), GFP_KERNEL); - if (!table->hash) - panic(name); - table->log = ilog2(UDP_HTABLE_SIZE_MIN); - table->mask = UDP_HTABLE_SIZE_MIN - 1; - } + table->hash = alloc_large_system_hash(name, + 2 * sizeof(struct udp_hslot), + uhash_entries, + 21, /* one slot per 2 MB */ + 0, + &table->log, + &table->mask, + UDP_HTABLE_SIZE_MIN, + 64 * 1024); + table->hash2 = table->hash + (table->mask + 1); for (i = 0; i <= table->mask; i++) { INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5b7053c58732..7cf07158805c 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -421,16 +421,22 @@ static void sta_tx_agg_session_timer_expired(unsigned long data) struct tid_ampdu_tx *tid_tx; unsigned long timeout; - tid_tx = rcu_dereference_protected_tid_tx(sta, *ptid); - if (!tid_tx) + rcu_read_lock(); + tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[*ptid]); + if (!tid_tx || test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { + rcu_read_unlock(); return; + } timeout = tid_tx->last_tx + TU_TO_JIFFIES(tid_tx->timeout); if (time_is_after_jiffies(timeout)) { mod_timer(&tid_tx->session_timer, timeout); + rcu_read_unlock(); return; } + rcu_read_unlock(); + #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "tx session timer expired on tid %d\n", (u16)*ptid); #endif diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index ea0122dbd2b3..7ed433c66d68 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -509,6 +509,7 @@ IEEE80211_IF_FILE(dot11MeshHWMPRannInterval, u.mesh.mshcfg.dot11MeshHWMPRannInterval, DEC); IEEE80211_IF_FILE(dot11MeshForwarding, u.mesh.mshcfg.dot11MeshForwarding, DEC); IEEE80211_IF_FILE(rssi_threshold, u.mesh.mshcfg.rssi_threshold, DEC); +IEEE80211_IF_FILE(ht_opmode, u.mesh.mshcfg.ht_opmode, DEC); #endif #define DEBUGFS_ADD_MODE(name, mode) \ @@ -608,6 +609,7 @@ static void add_mesh_config(struct ieee80211_sub_if_data *sdata) MESHPARAMS_ADD(dot11MeshHWMPRannInterval); MESHPARAMS_ADD(dot11MeshGateAnnouncementProtocol); MESHPARAMS_ADD(rssi_threshold); + MESHPARAMS_ADD(ht_opmode); #undef MESHPARAMS_ADD } #endif diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c index 3ad33a824624..33d9d0c3e3d0 100644 --- a/net/mac80211/ibss.c +++ b/net/mac80211/ibss.c @@ -163,6 +163,11 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, sizeof(struct ieee80211_ht_operation)); pos = ieee80211_ie_build_ht_cap(pos, &sband->ht_cap, sband->ht_cap.cap); + /* + * Note: According to 802.11n-2009 9.13.3.1, HT Protection + * field and RIFS Mode are reserved in IBSS mode, therefore + * keep them at 0 + */ pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap, chan, channel_type, 0); } diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 856237c5c1f8..d4c19a7773db 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -206,8 +206,10 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) for (i = 0; i < IEEE80211_NUM_ACS; i++) { if (local->hw.flags & IEEE80211_HW_QUEUE_CONTROL) sdata->vif.hw_queue[i] = IEEE80211_INVAL_HW_QUEUE; - else + else if (local->hw.queues >= IEEE80211_NUM_ACS) sdata->vif.hw_queue[i] = i; + else + sdata->vif.hw_queue[i] = 0; } sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } diff --git a/net/mac80211/main.c b/net/mac80211/main.c index b70f7f09da61..f5548e953259 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -596,6 +596,9 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, local->hw.offchannel_tx_hw_queue = IEEE80211_INVAL_HW_QUEUE; local->hw.conf.long_frame_max_tx_count = wiphy->retry_long; local->hw.conf.short_frame_max_tx_count = wiphy->retry_short; + local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS | + IEEE80211_RADIOTAP_MCS_HAVE_GI | + IEEE80211_RADIOTAP_MCS_HAVE_BW; local->user_power_level = -1; wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask; diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 0675a2fec6a6..2913113c5833 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -109,8 +109,10 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata, /* Disallow HT40+/- mismatch */ if (ie->ht_operation && - local->_oper_channel_type > NL80211_CHAN_HT20 && - sta_channel_type > NL80211_CHAN_HT20 && + (local->_oper_channel_type == NL80211_CHAN_HT40MINUS || + local->_oper_channel_type == NL80211_CHAN_HT40PLUS) && + (sta_channel_type == NL80211_CHAN_HT40MINUS || + sta_channel_type == NL80211_CHAN_HT40PLUS) && local->_oper_channel_type != sta_channel_type) goto mismatch; diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 27e0c2f06795..9b59658e8650 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -603,7 +603,10 @@ static void hwmp_preq_frame_process(struct ieee80211_sub_if_data *sdata, hopcount, ttl, cpu_to_le32(lifetime), cpu_to_le32(metric), cpu_to_le32(preq_id), sdata); - ifmsh->mshstats.fwded_mcast++; + if (!is_multicast_ether_addr(da)) + ifmsh->mshstats.fwded_unicast++; + else + ifmsh->mshstats.fwded_mcast++; ifmsh->mshstats.fwded_frames++; } } diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 8cc8461b48a0..60ef235c9d9b 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -105,15 +105,15 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, return sta; } -/** mesh_set_ht_prot_mode - set correct HT protection mode +/* + * mesh_set_ht_prot_mode - set correct HT protection mode * - * Section 9.23.3.5 of IEEE 80211s standard describes the protection rules for - * HT mesh STA in a MBSS. Three HT protection modes are supported for now, - * non-HT mixed mode, 20MHz-protection and no-protection mode. non-HT mixed - * mode is selected if any non-HT peers are present in our MBSS. - * 20MHz-protection mode is selected if all peers in our 20/40MHz MBSS support - * HT and atleast one HT20 peer is present. Otherwise no-protection mode is - * selected. + * Section 9.23.3.5 of IEEE 80211-2012 describes the protection rules for HT + * mesh STA in a MBSS. Three HT protection modes are supported for now, non-HT + * mixed mode, 20MHz-protection and no-protection mode. non-HT mixed mode is + * selected if any non-HT peers are present in our MBSS. 20MHz-protection mode + * is selected if all peers in our 20/40MHz MBSS support HT and atleast one + * HT20 peer is present. Otherwise no-protection mode is selected. */ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) { @@ -128,21 +128,22 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata) rcu_read_lock(); list_for_each_entry_rcu(sta, &local->sta_list, list) { - if (sdata == sta->sdata && - sta->plink_state == NL80211_PLINK_ESTAB) { - switch (sta->ch_type) { - case NL80211_CHAN_NO_HT: - mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - non_ht_sta = true; - goto out; - case NL80211_CHAN_HT20: - mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", - sdata->vif.addr, sta->sta.addr); - ht20_sta = true; - default: - break; - } + if (sdata != sta->sdata || + sta->plink_state != NL80211_PLINK_ESTAB) + continue; + + switch (sta->ch_type) { + case NL80211_CHAN_NO_HT: + mpl_dbg("mesh_plink %pM: nonHT sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + non_ht_sta = true; + goto out; + case NL80211_CHAN_HT20: + mpl_dbg("mesh_plink %pM: HT20 sta (%pM) is present", + sdata->vif.addr, sta->sta.addr); + ht20_sta = true; + default: + break; } } out: @@ -346,6 +347,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(sdata, addr); if (!sta) { + /* Userspace handles peer allocation when security is enabled */ + if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { + cfg80211_notify_new_peer_candidate(sdata->dev, addr, + elems->ie_start, + elems->total_len, + GFP_ATOMIC); + return NULL; + } + sta = mesh_plink_alloc(sdata, addr); if (!sta) return NULL; @@ -387,15 +397,6 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, { struct sta_info *sta; - /* Userspace handles peer allocation when security is enabled */ - if (sdata->u.mesh.security & IEEE80211_MESH_SEC_AUTHED) { - cfg80211_notify_new_peer_candidate(sdata->dev, hw_addr, - elems->ie_start, - elems->total_len, - GFP_KERNEL); - return; - } - rcu_read_lock(); sta = mesh_peer_init(sdata, hw_addr, elems); if (!sta) diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 8257a09eeed4..7bcecf73aafb 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -204,14 +204,14 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, if (status->flag & RX_FLAG_HT) { rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_MCS); - *pos++ = IEEE80211_RADIOTAP_MCS_HAVE_MCS | - IEEE80211_RADIOTAP_MCS_HAVE_GI | - IEEE80211_RADIOTAP_MCS_HAVE_BW; + *pos++ = local->hw.radiotap_mcs_details; *pos = 0; if (status->flag & RX_FLAG_SHORT_GI) *pos |= IEEE80211_RADIOTAP_MCS_SGI; if (status->flag & RX_FLAG_40MHZ) *pos |= IEEE80211_RADIOTAP_MCS_BW_40; + if (status->flag & RX_FLAG_HT_GF) + *pos |= IEEE80211_RADIOTAP_MCS_FMT_GF; pos++; *pos++ = status->rate_idx; } diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index 7aa31bbfaa3b..c04d401dae92 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -92,6 +92,7 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, int keylen, int keyidx) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); unsigned int hdrlen; u8 *newhdr; @@ -104,6 +105,13 @@ static u8 *ieee80211_wep_add_iv(struct ieee80211_local *local, hdrlen = ieee80211_hdrlen(hdr->frame_control); newhdr = skb_push(skb, WEP_IV_LEN); memmove(newhdr, newhdr + WEP_IV_LEN, hdrlen); + + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return newhdr + hdrlen; + + skb_set_network_header(skb, skb_network_offset(skb) + WEP_IV_LEN); ieee80211_wep_get_iv(local, keylen, keyidx, newhdr + hdrlen); return newhdr + hdrlen; } @@ -313,14 +321,15 @@ ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx) static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct ieee80211_key_conf *hw_key = info->control.hw_key; - if (!info->control.hw_key) { + if (!hw_key) { if (ieee80211_wep_encrypt(tx->local, skb, tx->key->conf.key, tx->key->conf.keylen, tx->key->conf.keyidx)) return -1; - } else if (info->control.hw_key->flags & - IEEE80211_KEY_FLAG_GENERATE_IV) { + } else if ((hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) || + (hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { if (!ieee80211_wep_add_iv(tx->local, skb, tx->key->conf.keylen, tx->key->conf.keyidx)) diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 0ae23c60968c..bdb53aba888e 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -183,7 +183,8 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) u8 *pos; if (info->control.hw_key && - !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) { + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) && + !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) { /* hwaccel - with no need for software-generated IV */ return 0; } @@ -202,8 +203,14 @@ static int tkip_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, TKIP_IV_LEN); memmove(pos, pos + TKIP_IV_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + TKIP_IV_LEN); pos += hdrlen; + /* the HW only needs room for the IV, but not the actual IV */ + if (info->control.hw_key && + (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) + return 0; + /* Increase IV for the frame */ spin_lock_irqsave(&key->u.tkip.txlock, flags); key->u.tkip.tx.iv16++; @@ -422,6 +429,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) pos = skb_push(skb, CCMP_HDR_LEN); memmove(pos, pos + CCMP_HDR_LEN, hdrlen); + skb_set_network_header(skb, skb_network_offset(skb) + CCMP_HDR_LEN); /* the HW only needs room for the IV, but not the actual IV */ if (info->control.hw_key && diff --git a/net/nfc/core.c b/net/nfc/core.c index 3192c3f589ee..9f6ce011d35d 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c @@ -97,7 +97,7 @@ int nfc_dev_down(struct nfc_dev *dev) goto error; } - if (dev->polling || dev->activated_target_idx != NFC_TARGET_IDX_NONE) { + if (dev->polling || dev->active_target) { rc = -EBUSY; goto error; } @@ -183,11 +183,27 @@ error: return rc; } +static struct nfc_target *nfc_find_target(struct nfc_dev *dev, u32 target_idx) +{ + int i; + + if (dev->n_targets == 0) + return NULL; + + for (i = 0; i < dev->n_targets ; i++) { + if (dev->targets[i].idx == target_idx) + return &dev->targets[i]; + } + + return NULL; +} + int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) { int rc = 0; u8 *gb; size_t gb_len; + struct nfc_target *target; pr_debug("dev_name=%s comm %d\n", dev_name(&dev->dev), comm_mode); @@ -212,9 +228,15 @@ int nfc_dep_link_up(struct nfc_dev *dev, int target_index, u8 comm_mode) goto error; } - rc = dev->ops->dep_link_up(dev, target_index, comm_mode, gb, gb_len); + target = nfc_find_target(dev, target_index); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->dep_link_up(dev, target, comm_mode, gb, gb_len); if (!rc) - dev->activated_target_idx = target_index; + dev->active_target = target; error: device_unlock(&dev->dev); @@ -250,7 +272,7 @@ int nfc_dep_link_down(struct nfc_dev *dev) rc = dev->ops->dep_link_down(dev); if (!rc) { dev->dep_link_up = false; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; nfc_llcp_mac_is_down(dev); nfc_genl_dep_link_down_event(dev); } @@ -282,6 +304,7 @@ EXPORT_SYMBOL(nfc_dep_link_is_up); int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) { int rc; + struct nfc_target *target; pr_debug("dev_name=%s target_idx=%u protocol=%u\n", dev_name(&dev->dev), target_idx, protocol); @@ -293,9 +316,20 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) goto error; } - rc = dev->ops->activate_target(dev, target_idx, protocol); + if (dev->active_target) { + rc = -EBUSY; + goto error; + } + + target = nfc_find_target(dev, target_idx); + if (target == NULL) { + rc = -ENOTCONN; + goto error; + } + + rc = dev->ops->activate_target(dev, target, protocol); if (!rc) { - dev->activated_target_idx = target_idx; + dev->active_target = target; if (dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -327,11 +361,21 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) goto error; } + if (dev->active_target == NULL) { + rc = -ENOTCONN; + goto error; + } + + if (dev->active_target->idx != target_idx) { + rc = -ENOTCONN; + goto error; + } + if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - dev->ops->deactivate_target(dev, target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->ops->deactivate_target(dev, dev->active_target); + dev->active_target = NULL; error: device_unlock(&dev->dev); @@ -365,13 +409,13 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, goto error; } - if (dev->activated_target_idx == NFC_TARGET_IDX_NONE) { + if (dev->active_target == NULL) { rc = -ENOTCONN; kfree_skb(skb); goto error; } - if (target_idx != dev->activated_target_idx) { + if (dev->active_target->idx != target_idx) { rc = -EADDRNOTAVAIL; kfree_skb(skb); goto error; @@ -380,7 +424,8 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, if (dev->ops->check_presence) del_timer_sync(&dev->check_pres_timer); - rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); + rc = dev->ops->data_exchange(dev, dev->active_target, skb, cb, + cb_context); if (!rc && dev->ops->check_presence) mod_timer(&dev->check_pres_timer, jiffies + @@ -456,6 +501,9 @@ EXPORT_SYMBOL(nfc_alloc_recv_skb); * The device driver must call this function when one or many nfc targets * are found. After calling this function, the device driver must stop * polling for targets. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. */ int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets, int n_targets) @@ -469,7 +517,7 @@ int nfc_targets_found(struct nfc_dev *dev, for (i = 0; i < n_targets; i++) targets[i].idx = dev->target_next_idx++; - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); dev->targets_generation++; @@ -479,12 +527,12 @@ int nfc_targets_found(struct nfc_dev *dev, if (!dev->targets) { dev->n_targets = 0; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -ENOMEM; } dev->n_targets = n_targets; - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_targets_found(dev); @@ -492,6 +540,18 @@ int nfc_targets_found(struct nfc_dev *dev, } EXPORT_SYMBOL(nfc_targets_found); +/** + * nfc_target_lost - inform that an activated target went out of field + * + * @dev: The nfc device that had the activated target in field + * @target_idx: the nfc index of the target + * + * The device driver must call this function when the activated target + * goes out of the field. + * IMPORTANT: this function must not be called from an atomic context. + * In addition, it must also not be called from a context that would prevent + * the NFC Core to call other nfc ops entry point concurrently. + */ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) { struct nfc_target *tg; @@ -499,7 +559,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) pr_debug("dev_name %s n_target %d\n", dev_name(&dev->dev), target_idx); - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); for (i = 0; i < dev->n_targets; i++) { tg = &dev->targets[i]; @@ -508,13 +568,13 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) } if (i == dev->n_targets) { - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); return -EINVAL; } dev->targets_generation++; dev->n_targets--; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + dev->active_target = NULL; if (dev->n_targets) { memcpy(&dev->targets[i], &dev->targets[i + 1], @@ -524,7 +584,7 @@ int nfc_target_lost(struct nfc_dev *dev, u32 target_idx) dev->targets = NULL; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); nfc_genl_target_lost(dev, target_idx); @@ -556,15 +616,16 @@ static void nfc_check_pres_work(struct work_struct *work) device_lock(&dev->dev); - if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && - timer_pending(&dev->check_pres_timer) == 0) { - rc = dev->ops->check_presence(dev, dev->activated_target_idx); + if (dev->active_target && timer_pending(&dev->check_pres_timer) == 0) { + rc = dev->ops->check_presence(dev, dev->active_target); if (!rc) { mod_timer(&dev->check_pres_timer, jiffies + msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); } else { - nfc_target_lost(dev, dev->activated_target_idx); - dev->activated_target_idx = NFC_TARGET_IDX_NONE; + u32 active_target_idx = dev->active_target->idx; + device_unlock(&dev->dev); + nfc_target_lost(dev, active_target_idx); + return; } } @@ -637,14 +698,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, dev->tx_headroom = tx_headroom; dev->tx_tailroom = tx_tailroom; - spin_lock_init(&dev->targets_lock); nfc_genl_data_init(&dev->genl_data); + /* first generation must not be 0 */ dev->targets_generation = 1; - dev->activated_target_idx = NFC_TARGET_IDX_NONE; - if (ops->check_presence) { char name[32]; init_timer(&dev->check_pres_timer); @@ -662,7 +721,6 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, } } - return dev; } EXPORT_SYMBOL(nfc_allocate_device); diff --git a/net/nfc/hci/Kconfig b/net/nfc/hci/Kconfig index 17213a6362b4..fd67f51d18e9 100644 --- a/net/nfc/hci/Kconfig +++ b/net/nfc/hci/Kconfig @@ -9,6 +9,7 @@ config NFC_HCI config NFC_SHDLC depends on NFC_HCI + select CRC_CCITT bool "SHDLC link layer for HCI based NFC drivers" default n ---help--- diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 86fd00d5a099..e1a640d2b588 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -235,13 +235,6 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) targets->hci_reader_gate = gate; r = nfc_targets_found(hdev->ndev, targets, 1); - if (r < 0) - goto exit; - - kfree(hdev->targets); - hdev->targets = targets; - targets = NULL; - hdev->target_count = 1; exit: kfree(targets); @@ -258,11 +251,6 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, switch (event) { case NFC_HCI_EVT_TARGET_DISCOVERED: - if (hdev->poll_started == false) { - r = -EPROTO; - goto exit; - } - if (skb->len < 1) { /* no status data? */ r = -EPROTO; goto exit; @@ -496,74 +484,42 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) static int hci_start_poll(struct nfc_dev *nfc_dev, u32 protocols) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - int r; if (hdev->ops->start_poll) - r = hdev->ops->start_poll(hdev, protocols); + return hdev->ops->start_poll(hdev, protocols); else - r = nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + return nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, NFC_HCI_EVT_READER_REQUESTED, NULL, 0); - if (r == 0) - hdev->poll_started = true; - - return r; } static void hci_stop_poll(struct nfc_dev *nfc_dev) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - if (hdev->poll_started) { - nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, - NFC_HCI_EVT_END_OPERATION, NULL, 0); - hdev->poll_started = false; - } -} - -static struct nfc_target *hci_find_target(struct nfc_hci_dev *hdev, - u32 target_idx) -{ - int i; - if (hdev->poll_started == false || hdev->targets == NULL) - return NULL; - - for (i = 0; i < hdev->target_count; i++) { - if (hdev->targets[i].idx == target_idx) - return &hdev->targets[i]; - } - - return NULL; + nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_EVT_END_OPERATION, NULL, 0); } -static int hci_activate_target(struct nfc_dev *nfc_dev, u32 target_idx, - u32 protocol) +static int hci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, u32 protocol) { - struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); - - if (hci_find_target(hdev, target_idx) == NULL) - return -ENOMEDIUM; - return 0; } -static void hci_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx) +static void hci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { } -static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, +static int hci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); int r; - struct nfc_target *target; struct sk_buff *res_skb = NULL; - pr_debug("target_idx=%d\n", target_idx); - - target = hci_find_target(hdev, target_idx); - if (target == NULL) - return -ENOMEDIUM; + pr_debug("target_idx=%d\n", target->idx); switch (target->hci_reader_gate) { case NFC_HCI_RF_READER_A_GATE: @@ -605,7 +561,18 @@ static int hci_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx, return 0; } -struct nfc_ops hci_nfc_ops = { +static int hci_check_presence(struct nfc_dev *nfc_dev, + struct nfc_target *target) +{ + struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev); + + if (hdev->ops->check_presence) + return hdev->ops->check_presence(hdev, target); + + return 0; +} + +static struct nfc_ops hci_nfc_ops = { .dev_up = hci_dev_up, .dev_down = hci_dev_down, .start_poll = hci_start_poll, @@ -613,6 +580,7 @@ struct nfc_ops hci_nfc_ops = { .activate_target = hci_activate_target, .deactivate_target = hci_deactivate_target, .data_exchange = hci_data_exchange, + .check_presence = hci_check_presence, }; struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, diff --git a/net/nfc/hci/shdlc.c b/net/nfc/hci/shdlc.c index 923bdf7c26d6..5665dc6d893a 100644 --- a/net/nfc/hci/shdlc.c +++ b/net/nfc/hci/shdlc.c @@ -816,6 +816,17 @@ static int nfc_shdlc_data_exchange(struct nfc_hci_dev *hdev, return -EPERM; } +static int nfc_shdlc_check_presence(struct nfc_hci_dev *hdev, + struct nfc_target *target) +{ + struct nfc_shdlc *shdlc = nfc_hci_get_clientdata(hdev); + + if (shdlc->ops->check_presence) + return shdlc->ops->check_presence(shdlc, target); + + return 0; +} + static struct nfc_hci_ops shdlc_ops = { .open = nfc_shdlc_open, .close = nfc_shdlc_close, @@ -825,6 +836,7 @@ static struct nfc_hci_ops shdlc_ops = { .target_from_gate = nfc_shdlc_target_from_gate, .complete_target_discovered = nfc_shdlc_complete_target_discovered, .data_exchange = nfc_shdlc_data_exchange, + .check_presence = nfc_shdlc_check_presence, }; struct nfc_shdlc *nfc_shdlc_allocate(struct nfc_shdlc_ops *ops, diff --git a/net/nfc/llcp/commands.c b/net/nfc/llcp/commands.c index 11a3b7d98dc5..bf8ae4f0b90c 100644 --- a/net/nfc/llcp/commands.c +++ b/net/nfc/llcp/commands.c @@ -488,7 +488,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len); - skb_queue_head(&sock->tx_queue, pdu); + skb_queue_tail(&sock->tx_queue, pdu); lock_sock(sk); @@ -502,7 +502,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock, kfree(msg_data); - return 0; + return len; } int nfc_llcp_send_rr(struct nfc_llcp_sock *sock) diff --git a/net/nfc/llcp/llcp.c b/net/nfc/llcp/llcp.c index 92988aa620dc..42994fac26d6 100644 --- a/net/nfc/llcp/llcp.c +++ b/net/nfc/llcp/llcp.c @@ -448,6 +448,8 @@ static struct nfc_llcp_sock *nfc_llcp_sock_get(struct nfc_llcp_local *local, { struct nfc_llcp_sock *sock, *llcp_sock, *n; + pr_debug("ssap dsap %d %d\n", ssap, dsap); + if (ssap == 0 && dsap == 0) return NULL; @@ -783,6 +785,7 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local, static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) { struct nfc_llcp_sock *llcp_sock; + struct sock *sk; u8 dsap, ssap; dsap = nfc_llcp_dsap(skb); @@ -801,10 +804,14 @@ static void nfc_llcp_recv_cc(struct nfc_llcp_local *local, struct sk_buff *skb) } llcp_sock->dsap = ssap; + sk = &llcp_sock->sk; nfc_llcp_parse_tlv(local, &skb->data[LLCP_HEADER_SIZE], skb->len - LLCP_HEADER_SIZE); + sk->sk_state = LLCP_CONNECTED; + sk->sk_state_change(sk); + nfc_llcp_sock_put(llcp_sock); } diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index c13e02ebdef9..3f339b19d140 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -27,6 +27,42 @@ #include "../nfc.h" #include "llcp.h" +static int sock_wait_state(struct sock *sk, int state, unsigned long timeo) +{ + DECLARE_WAITQUEUE(wait, current); + int err = 0; + + pr_debug("sk %p", sk); + + add_wait_queue(sk_sleep(sk), &wait); + set_current_state(TASK_INTERRUPTIBLE); + + while (sk->sk_state != state) { + if (!timeo) { + err = -EINPROGRESS; + break; + } + + if (signal_pending(current)) { + err = sock_intr_errno(timeo); + break; + } + + release_sock(sk); + timeo = schedule_timeout(timeo); + lock_sock(sk); + set_current_state(TASK_INTERRUPTIBLE); + + err = sock_error(sk); + if (err) + break; + } + + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk_sleep(sk), &wait); + return err; +} + static struct proto llcp_sock_proto = { .name = "NFC_LLCP", .owner = THIS_MODULE, @@ -304,11 +340,24 @@ static unsigned int llcp_sock_poll(struct file *file, struct socket *sock, mask |= POLLERR; if (!skb_queue_empty(&sk->sk_receive_queue)) - mask |= POLLIN; + mask |= POLLIN | POLLRDNORM; if (sk->sk_state == LLCP_CLOSED) mask |= POLLHUP; + if (sk->sk_shutdown & RCV_SHUTDOWN) + mask |= POLLRDHUP | POLLIN | POLLRDNORM; + + if (sk->sk_shutdown == SHUTDOWN_MASK) + mask |= POLLHUP; + + if (sock_writeable(sk)) + mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + else + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + + pr_debug("mask 0x%x\n", mask); + return mask; } @@ -462,9 +511,13 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr, if (ret) goto put_dev; - sk->sk_state = LLCP_CONNECTED; + ret = sock_wait_state(sk, LLCP_CONNECTED, + sock_sndtimeo(sk, flags & O_NONBLOCK)); + if (ret) + goto put_dev; release_sock(sk); + return 0; put_dev: diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 8737c2089fdd..d560e6f13072 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -436,16 +436,16 @@ static void nci_stop_poll(struct nfc_dev *nfc_dev) msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT)); } -static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, - __u32 protocol) +static int nci_activate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target, __u32 protocol) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); struct nci_rf_discover_select_param param; - struct nfc_target *target = NULL; + struct nfc_target *nci_target = NULL; int i; int rc = 0; - pr_debug("target_idx %d, protocol 0x%x\n", target_idx, protocol); + pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol); if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) && (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) { @@ -459,25 +459,25 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, } for (i = 0; i < ndev->n_targets; i++) { - if (ndev->targets[i].idx == target_idx) { - target = &ndev->targets[i]; + if (ndev->targets[i].idx == target->idx) { + nci_target = &ndev->targets[i]; break; } } - if (!target) { + if (!nci_target) { pr_err("unable to find the selected target\n"); return -EINVAL; } - if (!(target->supported_protocols & (1 << protocol))) { + if (!(nci_target->supported_protocols & (1 << protocol))) { pr_err("target does not support the requested protocol 0x%x\n", protocol); return -EINVAL; } if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) { - param.rf_discovery_id = target->logical_idx; + param.rf_discovery_id = nci_target->logical_idx; if (protocol == NFC_PROTO_JEWEL) param.rf_protocol = NCI_RF_PROTOCOL_T1T; @@ -501,11 +501,12 @@ static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx, return rc; } -static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) +static void nci_deactivate_target(struct nfc_dev *nfc_dev, + struct nfc_target *target) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); - pr_debug("target_idx %d\n", target_idx); + pr_debug("target_idx %d\n", target->idx); if (!ndev->target_active_prot) { pr_err("unable to deactivate target, no active target\n"); @@ -520,14 +521,14 @@ static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx) } } -static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx, +static int nci_data_exchange(struct nfc_dev *nfc_dev, struct nfc_target *target, struct sk_buff *skb, data_exchange_cb_t cb, void *cb_context) { struct nci_dev *ndev = nfc_get_drvdata(nfc_dev); int rc; - pr_debug("target_idx %d, len %d\n", target_idx, skb->len); + pr_debug("target_idx %d, len %d\n", target->idx, skb->len); if (!ndev->target_active_prot) { pr_err("unable to exchange data, no active target\n"); diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c index a0bc326308a5..76c48c5324f8 100644 --- a/net/nfc/nci/data.c +++ b/net/nfc/nci/data.c @@ -49,7 +49,7 @@ void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb, if (cb) { ndev->data_exchange_cb = NULL; - ndev->data_exchange_cb_context = 0; + ndev->data_exchange_cb_context = NULL; /* forward skb to nfc core */ cb(cb_context, skb, err); @@ -200,10 +200,10 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, pr_err("error adding room for accumulated rx data\n"); kfree_skb(skb); - skb = 0; + skb = NULL; kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; err = -ENOMEM; goto exit; @@ -216,7 +216,7 @@ static void nci_add_rx_data_frag(struct nci_dev *ndev, /* third, free old reassembly */ kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; } if (pbf == NCI_PBF_CONT) { diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c index 6a63e5eb483d..6b7fd26c68d9 100644 --- a/net/nfc/nci/lib.c +++ b/net/nfc/nci/lib.c @@ -31,6 +31,7 @@ #include <linux/errno.h> #include <net/nfc/nci.h> +#include <net/nfc/nci_core.h> /* NCI status codes to Unix errno mapping */ int nci_to_errno(__u8 code) diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c index 99e1632e6aac..cb2646179e5f 100644 --- a/net/nfc/nci/ntf.c +++ b/net/nfc/nci/ntf.c @@ -497,7 +497,7 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev, /* drop partial rx data packet */ if (ndev->rx_data_reassembly) { kfree_skb(ndev->rx_data_reassembly); - ndev->rx_data_reassembly = 0; + ndev->rx_data_reassembly = NULL; } /* complete the data exchange transaction, if exists */ diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f1829f6ae9c5..581d419083aa 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -33,7 +33,7 @@ static struct genl_multicast_group nfc_genl_event_mcgrp = { .name = NFC_GENL_MCAST_EVENT_NAME, }; -struct genl_family nfc_genl_family = { +static struct genl_family nfc_genl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = NFC_GENL_NAME, @@ -128,7 +128,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, cb->args[1] = (long) dev; } - spin_lock_bh(&dev->targets_lock); + device_lock(&dev->dev); cb->seq = dev->targets_generation; @@ -141,7 +141,7 @@ static int nfc_genl_dump_targets(struct sk_buff *skb, i++; } - spin_unlock_bh(&dev->targets_lock); + device_unlock(&dev->dev); cb->args[0] = i; diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h index 7d589a81942e..3dd4232ae664 100644 --- a/net/nfc/nfc.h +++ b/net/nfc/nfc.h @@ -84,7 +84,7 @@ static inline int nfc_llcp_set_remote_gb(struct nfc_dev *dev, return 0; } -static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, u8 *gb_len) +static inline u8 *nfc_llcp_general_bytes(struct nfc_dev *dev, size_t *gb_len) { *gb_len = 0; return NULL; diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 2fcfe0993ca2..884801ac4dd0 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -45,7 +45,7 @@ rdev_freq_to_chan(struct cfg80211_registered_device *rdev, return chan; } -int cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, +bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type) { diff --git a/net/wireless/core.c b/net/wireless/core.c index 39f2538a46fc..a87d43552974 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -664,7 +664,7 @@ void wiphy_unregister(struct wiphy *wiphy) mutex_lock(&rdev->devlist_mtx); __count = rdev->opencount; mutex_unlock(&rdev->devlist_mtx); - __count == 0;})); + __count == 0; })); mutex_lock(&rdev->devlist_mtx); BUG_ON(!list_empty(&rdev->netdev_list)); @@ -776,7 +776,7 @@ static struct device_type wiphy_type = { .name = "wlan", }; -static int cfg80211_netdev_notifier_call(struct notifier_block * nb, +static int cfg80211_netdev_notifier_call(struct notifier_block *nb, unsigned long state, void *ndev) { diff --git a/net/wireless/core.h b/net/wireless/core.h index 3ac2dd00d714..8523f3878677 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -445,8 +445,6 @@ int cfg80211_set_freq(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, int freq, enum nl80211_channel_type channel_type); -u16 cfg80211_calculate_bitrate(struct rate_info *rate); - int ieee80211_get_ratemask(struct ieee80211_supported_band *sband, const u8 *rates, unsigned int n_rates, u32 *mask); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index b67b1114e25a..206465dc0cab 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -1179,6 +1179,27 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev) wdev->iftype == NL80211_IFTYPE_P2P_GO; } +static bool nl80211_valid_channel_type(struct genl_info *info, + enum nl80211_channel_type *channel_type) +{ + enum nl80211_channel_type tmp; + + if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) + return false; + + tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (tmp != NL80211_CHAN_NO_HT && + tmp != NL80211_CHAN_HT20 && + tmp != NL80211_CHAN_HT40PLUS && + tmp != NL80211_CHAN_HT40MINUS) + return false; + + if (channel_type) + *channel_type = tmp; + + return true; +} + static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, struct wireless_dev *wdev, struct genl_info *info) @@ -1193,15 +1214,9 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev, if (!nl80211_can_set_dev_channel(wdev)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32(info->attrs[ - NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - return -EINVAL; - } + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && + !nl80211_valid_channel_type(info, &channel_type)) + return -EINVAL; freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); @@ -2410,10 +2425,16 @@ static int parse_station_flags(struct genl_info *info, return -EINVAL; } - for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) - if (flags[flag]) + for (flag = 1; flag <= NL80211_STA_FLAG_MAX; flag++) { + if (flags[flag]) { params->sta_flags_set |= (1<<flag); + /* no longer support new API additions in old API */ + if (flag > NL80211_STA_FLAG_MAX_OLD_API) + return -EINVAL; + } + } + return 0; } @@ -4912,12 +4933,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { enum nl80211_channel_type channel_type; - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40MINUS && - channel_type != NL80211_CHAN_HT40PLUS) + if (!nl80211_valid_channel_type(info, &channel_type)) return -EINVAL; if (channel_type != NL80211_CHAN_NO_HT && @@ -5485,15 +5501,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, !(rdev->wiphy.flags & WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL)) return -EOPNOTSUPP; - if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) - return -EINVAL; - } + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] && + !nl80211_valid_channel_type(info, &channel_type)) + return -EINVAL; freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); chan = rdev_freq_to_chan(rdev, freq, channel_type); @@ -5764,12 +5774,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { - channel_type = nla_get_u32( - info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]); - if (channel_type != NL80211_CHAN_NO_HT && - channel_type != NL80211_CHAN_HT20 && - channel_type != NL80211_CHAN_HT40PLUS && - channel_type != NL80211_CHAN_HT40MINUS) + if (!nl80211_valid_channel_type(info, &channel_type)) return -EINVAL; channel_type_valid = true; } diff --git a/net/wireless/util.c b/net/wireless/util.c index 1cd255892a43..55d99466babb 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -879,7 +879,7 @@ u16 cfg80211_calculate_bitrate(struct rate_info *rate) return rate->legacy; /* the formula below does only work for MCS values smaller than 32 */ - if (rate->mcs >= 32) + if (WARN_ON_ONCE(rate->mcs >= 32)) return 0; modulation = rate->mcs & 7; |