diff options
163 files changed, 5129 insertions, 2905 deletions
diff --git a/Documentation/DocBook/80211.tmpl b/Documentation/DocBook/80211.tmpl index f3e214f..42e7f03 100644 --- a/Documentation/DocBook/80211.tmpl +++ b/Documentation/DocBook/80211.tmpl @@ -404,7 +404,6 @@ !Finclude/net/mac80211.h ieee80211_get_tkip_p1k !Finclude/net/mac80211.h ieee80211_get_tkip_p1k_iv !Finclude/net/mac80211.h ieee80211_get_tkip_p2k -!Finclude/net/mac80211.h ieee80211_key_removed </chapter> <chapter id="powersave"> diff --git a/drivers/bcma/Kconfig b/drivers/bcma/Kconfig index fb7c80f..06b3207 100644 --- a/drivers/bcma/Kconfig +++ b/drivers/bcma/Kconfig @@ -46,6 +46,25 @@ config BCMA_DRIVER_MIPS If unsure, say N +config BCMA_SFLASH + bool + depends on BCMA_DRIVER_MIPS && BROKEN + default y + +config BCMA_NFLASH + bool + depends on BCMA_DRIVER_MIPS && BROKEN + default y + +config BCMA_DRIVER_GMAC_CMN + bool "BCMA Broadcom GBIT MAC COMMON core driver" + depends on BCMA + help + Driver for the Broadcom GBIT MAC COMMON core attached to Broadcom + specific Advanced Microcontroller Bus. + + If unsure, say N + config BCMA_DEBUG bool "BCMA debugging" depends on BCMA diff --git a/drivers/bcma/Makefile b/drivers/bcma/Makefile index 82de24e..8ad42d4 100644 --- a/drivers/bcma/Makefile +++ b/drivers/bcma/Makefile @@ -1,8 +1,11 @@ bcma-y += main.o scan.o core.o sprom.o bcma-y += driver_chipcommon.o driver_chipcommon_pmu.o +bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o +bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o bcma-y += driver_pci.o bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o +bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o bcma-$(CONFIG_BCMA_HOST_PCI) += host_pci.o bcma-$(CONFIG_BCMA_HOST_SOC) += host_soc.o obj-$(CONFIG_BCMA) += bcma.o diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h index f6589eb..3cf9cc9 100644 --- a/drivers/bcma/bcma_private.h +++ b/drivers/bcma/bcma_private.h @@ -51,6 +51,28 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc); u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc); u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc); +#ifdef CONFIG_BCMA_SFLASH +/* driver_chipcommon_sflash.c */ +int bcma_sflash_init(struct bcma_drv_cc *cc); +#else +static inline int bcma_sflash_init(struct bcma_drv_cc *cc) +{ + bcma_err(cc->core->bus, "Serial flash not supported\n"); + return 0; +} +#endif /* CONFIG_BCMA_SFLASH */ + +#ifdef CONFIG_BCMA_NFLASH +/* driver_chipcommon_nflash.c */ +int bcma_nflash_init(struct bcma_drv_cc *cc); +#else +static inline int bcma_nflash_init(struct bcma_drv_cc *cc) +{ + bcma_err(cc->core->bus, "NAND flash not supported\n"); + return 0; +} +#endif /* CONFIG_BCMA_NFLASH */ + #ifdef CONFIG_BCMA_HOST_PCI /* host_pci.c */ extern int __init bcma_host_pci_init(void); diff --git a/drivers/bcma/driver_chipcommon_nflash.c b/drivers/bcma/driver_chipcommon_nflash.c new file mode 100644 index 0000000..574d624 --- /dev/null +++ b/drivers/bcma/driver_chipcommon_nflash.c @@ -0,0 +1,19 @@ +/* + * Broadcom specific AMBA + * ChipCommon NAND flash interface + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_driver_chipcommon.h> +#include <linux/delay.h> + +#include "bcma_private.h" + +/* Initialize NAND flash access */ +int bcma_nflash_init(struct bcma_drv_cc *cc) +{ + bcma_err(cc->core->bus, "NAND flash support is broken\n"); + return 0; +} diff --git a/drivers/bcma/driver_chipcommon_sflash.c b/drivers/bcma/driver_chipcommon_sflash.c new file mode 100644 index 0000000..6e157a5 --- /dev/null +++ b/drivers/bcma/driver_chipcommon_sflash.c @@ -0,0 +1,19 @@ +/* + * Broadcom specific AMBA + * ChipCommon serial flash interface + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include <linux/bcma/bcma.h> +#include <linux/bcma/bcma_driver_chipcommon.h> +#include <linux/delay.h> + +#include "bcma_private.h" + +/* Initialize serial flash access */ +int bcma_sflash_init(struct bcma_drv_cc *cc) +{ + bcma_err(cc->core->bus, "Serial flash support is broken\n"); + return 0; +} diff --git a/drivers/bcma/driver_gmac_cmn.c b/drivers/bcma/driver_gmac_cmn.c new file mode 100644 index 0000000..834225f --- /dev/null +++ b/drivers/bcma/driver_gmac_cmn.c @@ -0,0 +1,14 @@ +/* + * Broadcom specific AMBA + * GBIT MAC COMMON Core + * + * Licensed under the GNU/GPL. See COPYING for details. + */ + +#include "bcma_private.h" +#include <linux/bcma/bcma.h> + +void __devinit bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) +{ + mutex_init(&gc->phy_mutex); +} diff --git a/drivers/bcma/driver_mips.c b/drivers/bcma/driver_mips.c index ef34ed2..b013b04 100644 --- a/drivers/bcma/driver_mips.c +++ b/drivers/bcma/driver_mips.c @@ -185,10 +185,11 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) { case BCMA_CC_FLASHT_STSER: case BCMA_CC_FLASHT_ATSER: - bcma_err(bus, "Serial flash not supported.\n"); + bcma_debug(bus, "Found serial flash\n"); + bcma_sflash_init(&bus->drv_cc); break; case BCMA_CC_FLASHT_PARA: - bcma_info(bus, "found parallel flash.\n"); + bcma_debug(bus, "Found parallel flash\n"); bus->drv_cc.pflash.window = 0x1c000000; bus->drv_cc.pflash.window_size = 0x02000000; @@ -199,7 +200,15 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore) bus->drv_cc.pflash.buswidth = 2; break; default: - bcma_err(bus, "flash not supported.\n"); + bcma_err(bus, "Flash type not supported\n"); + } + + if (bus->drv_cc.core->id.rev == 38 || + bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) { + if (bus->drv_cc.capabilities & BCMA_CC_CAP_NFLASH) { + bcma_debug(bus, "Found NAND flash\n"); + bcma_nflash_init(&bus->drv_cc); + } } } diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c index 7ff4bac..758af9c 100644 --- a/drivers/bcma/main.c +++ b/drivers/bcma/main.c @@ -61,6 +61,13 @@ static struct bus_type bcma_bus_type = { .dev_attrs = bcma_device_attrs, }; +static u16 bcma_cc_core_id(struct bcma_bus *bus) +{ + if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) + return BCMA_CORE_4706_CHIPCOMMON; + return BCMA_CORE_CHIPCOMMON; +} + struct bcma_device *bcma_find_core(struct bcma_bus *bus, u16 coreid) { struct bcma_device *core; @@ -91,10 +98,12 @@ static int bcma_register_cores(struct bcma_bus *bus) list_for_each_entry(core, &bus->cores, list) { /* We support that cores ourself */ switch (core->id.id) { + case BCMA_CORE_4706_CHIPCOMMON: case BCMA_CORE_CHIPCOMMON: case BCMA_CORE_PCI: case BCMA_CORE_PCIE: case BCMA_CORE_MIPS_74K: + case BCMA_CORE_4706_MAC_GBIT_COMMON: continue; } @@ -157,7 +166,7 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) } /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + core = bcma_find_core(bus, bcma_cc_core_id(bus)); if (core) { bus->drv_cc.core = core; bcma_core_chipcommon_init(&bus->drv_cc); @@ -177,6 +186,13 @@ int __devinit bcma_bus_register(struct bcma_bus *bus) bcma_core_pci_init(&bus->drv_pci); } + /* Init GBIT MAC COMMON core */ + core = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON); + if (core) { + bus->drv_gmac_cmn.core = core; + bcma_core_gmac_cmn_init(&bus->drv_gmac_cmn); + } + /* Try to get SPROM */ err = bcma_sprom_get(bus); if (err == -ENOENT) { @@ -208,7 +224,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, bcma_init_bus(bus); match.manuf = BCMA_MANUF_BCM; - match.id = BCMA_CORE_CHIPCOMMON; + match.id = bcma_cc_core_id(bus); match.class = BCMA_CL_SIM; match.rev = BCMA_ANY_REV; @@ -232,7 +248,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus, } /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); + core = bcma_find_core(bus, bcma_cc_core_id(bus)); if (core) { bus->drv_cc.core = core; bcma_core_chipcommon_init(&bus->drv_cc); @@ -271,8 +287,7 @@ int bcma_bus_resume(struct bcma_bus *bus) struct bcma_device *core; /* Init CC core */ - core = bcma_find_core(bus, BCMA_CORE_CHIPCOMMON); - if (core) { + if (bus->drv_cc.core) { bus->drv_cc.setup_done = false; bcma_core_chipcommon_init(&bus->drv_cc); } diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c index a0272bb..5672b13 100644 --- a/drivers/bcma/scan.c +++ b/drivers/bcma/scan.c @@ -21,6 +21,7 @@ struct bcma_device_id_name { }; static const struct bcma_device_id_name bcma_arm_device_names[] = { + { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" }, { BCMA_CORE_ARM_1176, "ARM 1176" }, { BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" }, { BCMA_CORE_ARM_CM3, "ARM CM3" }, @@ -33,7 +34,6 @@ static const struct bcma_device_id_name bcma_bcm_device_names[] = { { BCMA_CORE_4706_MAC_GBIT, "BCM4706 GBit MAC" }, { BCMA_CORE_AMEMC, "AMEMC (DDR)" }, { BCMA_CORE_ALTA, "ALTA (I2S)" }, - { BCMA_CORE_4706_MAC_GBIT_COMMON, "BCM4706 GBit MAC Common" }, { BCMA_CORE_INVALID, "Invalid" }, { BCMA_CORE_CHIPCOMMON, "ChipCommon" }, { BCMA_CORE_ILINE20, "ILine 20" }, @@ -295,11 +295,15 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr, /* check if component is a core at all */ if (wrappers[0] + wrappers[1] == 0) { - /* we could save addrl of the router - if (cid == BCMA_CORE_OOB_ROUTER) - */ - bcma_erom_skip_component(bus, eromptr); - return -ENXIO; + /* Some specific cores don't need wrappers */ + switch (core->id.id) { + case BCMA_CORE_4706_MAC_GBIT_COMMON: + /* Not used yet: case BCMA_CORE_OOB_ROUTER: */ + break; + default: + bcma_erom_skip_component(bus, eromptr); + return -ENXIO; + } } if (bcma_erom_is_bridge(bus, eromptr)) { @@ -487,7 +491,7 @@ int bcma_bus_scan(struct bcma_bus *bus) core->id.manuf, core->id.id, core->id.rev, core->id.class); - list_add(&core->list, &bus->cores); + list_add_tail(&core->list, &bus->cores); } if (bus->hosttype == BCMA_HOSTTYPE_SOC) @@ -542,7 +546,7 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus, core->id.manuf, core->id.id, core->id.rev, core->id.class); - list_add(&core->list, &bus->cores); + list_add_tail(&core->list, &bus->cores); err = 0; break; } diff --git a/drivers/bcma/scan.h b/drivers/bcma/scan.h index 113e6a6..30eb475 100644 --- a/drivers/bcma/scan.h +++ b/drivers/bcma/scan.h @@ -27,7 +27,7 @@ #define SCAN_CIB_NMW 0x0007C000 #define SCAN_CIB_NMW_SHIFT 14 #define SCAN_CIB_NSW 0x00F80000 -#define SCAN_CIB_NSW_SHIFT 17 +#define SCAN_CIB_NSW_SHIFT 19 #define SCAN_CIB_REV 0xFF000000 #define SCAN_CIB_REV_SHIFT 24 diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 5ccf142..e9f203e 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -81,6 +81,18 @@ config BT_HCIUART_LL Say Y here to compile support for HCILL protocol. +config BT_HCIUART_3WIRE + bool "Three-wire UART (H5) protocol support" + depends on BT_HCIUART + help + The HCI Three-wire UART Transport Layer makes it possible to + user the Bluetooth HCI over a serial port interface. The HCI + Three-wire UART Transport Layer assumes that the UART + communication may have bit errors, overrun errors or burst + errors and thereby making CTS/RTS lines unnecessary. + + Say Y here to compile support for Three-wire UART protocol. + config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index f4460f4..4afae20 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -28,4 +28,5 @@ hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o +hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o hci_uart-objs := $(hci_uart-y) diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 585c88e..66c3a67 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -621,7 +621,6 @@ static int bluecard_hci_flush(struct hci_dev *hdev) static int bluecard_hci_open(struct hci_dev *hdev) { bluecard_info_t *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) bluecard_hci_set_baud_rate(hdev, DEFAULT_BAUD_RATE); @@ -630,6 +629,8 @@ static int bluecard_hci_open(struct hci_dev *hdev) return 0; if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { + unsigned int iobase = info->p_dev->resource[0]->start; + /* Enable LED */ outb(0x08 | 0x20, iobase + 0x30); } @@ -641,7 +642,6 @@ static int bluecard_hci_open(struct hci_dev *hdev) static int bluecard_hci_close(struct hci_dev *hdev) { bluecard_info_t *info = hci_get_drvdata(hdev); - unsigned int iobase = info->p_dev->resource[0]->start; if (!test_and_clear_bit(HCI_RUNNING, &(hdev->flags))) return 0; @@ -649,6 +649,8 @@ static int bluecard_hci_close(struct hci_dev *hdev) bluecard_hci_flush(hdev); if (test_bit(CARD_HAS_PCCARD_ID, &(info->hw_state))) { + unsigned int iobase = info->p_dev->resource[0]->start; + /* Disable LED */ outb(0x00, iobase + 0x30); } diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index b2b0fbb..8925b6d 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -664,7 +664,7 @@ static int bt3c_check_config(struct pcmcia_device *p_dev, void *priv_data) { int *try = priv_data; - if (try == 0) + if (!try) p_dev->io_lines = 16; if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index dc304de..3a4343b 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -47,10 +47,11 @@ EXPORT_SYMBOL_GPL(btmrvl_interrupt); bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) { struct hci_event_hdr *hdr = (void *) skb->data; - struct hci_ev_cmd_complete *ec; - u16 opcode, ocf, ogf; if (hdr->evt == HCI_EV_CMD_COMPLETE) { + struct hci_ev_cmd_complete *ec; + u16 opcode, ocf, ogf; + ec = (void *) (skb->data + HCI_EVENT_HDR_SIZE); opcode = __le16_to_cpu(ec->opcode); ocf = hci_opcode_ocf(opcode); @@ -64,7 +65,8 @@ bool btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb) } if (ogf == OGF) { - BT_DBG("vendor event skipped: ogf 0x%4.4x", ogf); + BT_DBG("vendor event skipped: ogf 0x%4.4x ocf 0x%4.4x", + ogf, ocf); kfree_skb(skb); return false; } diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index cf7588ed..6a9e971 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -568,8 +568,9 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) if (type == HCI_EVENT_PKT) { if (btmrvl_check_evtpkt(priv, skb)) hci_recv_frame(skb); - } else + } else { hci_recv_frame(skb); + } hdev->stat.byte_rx += buf_len; break; diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c index 65b8d99..21e803a 100644 --- a/drivers/bluetooth/btuart_cs.c +++ b/drivers/bluetooth/btuart_cs.c @@ -593,7 +593,7 @@ static int btuart_check_config(struct pcmcia_device *p_dev, void *priv_data) { int *try = priv_data; - if (try == 0) + if (!try) p_dev->io_lines = 16; if ((p_dev->resource[0]->end != 8) || (p_dev->resource[0]->start == 0)) diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c index b1b37cc..97a7784 100644 --- a/drivers/bluetooth/dtl1_cs.c +++ b/drivers/bluetooth/dtl1_cs.c @@ -586,29 +586,31 @@ static int dtl1_confcheck(struct pcmcia_device *p_dev, void *priv_data) static int dtl1_config(struct pcmcia_device *link) { dtl1_info_t *info = link->priv; - int i; + int ret; /* Look for a generic full-sized window */ link->resource[0]->end = 8; - if (pcmcia_loop_config(link, dtl1_confcheck, NULL) < 0) + ret = pcmcia_loop_config(link, dtl1_confcheck, NULL); + if (ret) goto failed; - i = pcmcia_request_irq(link, dtl1_interrupt); - if (i != 0) + ret = pcmcia_request_irq(link, dtl1_interrupt); + if (ret) goto failed; - i = pcmcia_enable_device(link); - if (i != 0) + ret = pcmcia_enable_device(link); + if (ret) goto failed; - if (dtl1_open(info) != 0) + ret = dtl1_open(info); + if (ret) goto failed; return 0; failed: dtl1_detach(link); - return -ENODEV; + return ret; } static const struct pcmcia_device_id dtl1_ids[] = { diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c new file mode 100644 index 0000000..b6154d5 --- /dev/null +++ b/drivers/bluetooth/hci_h5.c @@ -0,0 +1,747 @@ +/* + * + * Bluetooth HCI Three-wire UART driver + * + * Copyright (C) 2012 Intel Corporation + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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/kernel.h> +#include <linux/errno.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" + +#define HCI_3WIRE_ACK_PKT 0 +#define HCI_3WIRE_LINK_PKT 15 + +/* Sliding window size */ +#define H5_TX_WIN_MAX 4 + +#define H5_ACK_TIMEOUT msecs_to_jiffies(250) +#define H5_SYNC_TIMEOUT msecs_to_jiffies(100) + +/* + * Maximum Three-wire packet: + * 4 byte header + max value for 12-bit length + 2 bytes for CRC + */ +#define H5_MAX_LEN (4 + 0xfff + 2) + +/* Convenience macros for reading Three-wire header values */ +#define H5_HDR_SEQ(hdr) ((hdr)[0] & 0x07) +#define H5_HDR_ACK(hdr) (((hdr)[0] >> 3) & 0x07) +#define H5_HDR_CRC(hdr) (((hdr)[0] >> 6) & 0x01) +#define H5_HDR_RELIABLE(hdr) (((hdr)[0] >> 7) & 0x01) +#define H5_HDR_PKT_TYPE(hdr) ((hdr)[1] & 0x0f) +#define H5_HDR_LEN(hdr) ((((hdr)[1] >> 4) & 0xff) + ((hdr)[2] << 4)) + +#define SLIP_DELIMITER 0xc0 +#define SLIP_ESC 0xdb +#define SLIP_ESC_DELIM 0xdc +#define SLIP_ESC_ESC 0xdd + +/* H5 state flags */ +enum { + H5_RX_ESC, /* SLIP escape mode */ + H5_TX_ACK_REQ, /* Pending ack to send */ +}; + +struct h5 { + struct sk_buff_head unack; /* Unack'ed packets queue */ + struct sk_buff_head rel; /* Reliable packets queue */ + struct sk_buff_head unrel; /* Unreliable packets queue */ + + unsigned long flags; + + struct sk_buff *rx_skb; /* Receive buffer */ + size_t rx_pending; /* Expecting more bytes */ + u8 rx_ack; /* Last ack number received */ + + int (*rx_func) (struct hci_uart *hu, u8 c); + + struct timer_list timer; /* Retransmission timer */ + + u8 tx_seq; /* Next seq number to send */ + u8 tx_ack; /* Next ack number to send */ + u8 tx_win; /* Sliding window size */ + + enum { + H5_UNINITIALIZED, + H5_INITIALIZED, + H5_ACTIVE, + } state; + + enum { + H5_AWAKE, + H5_SLEEPING, + H5_WAKING_UP, + } sleep; +}; + +static void h5_reset_rx(struct h5 *h5); + +static void h5_link_control(struct hci_uart *hu, const void *data, size_t len) +{ + struct h5 *h5 = hu->priv; + struct sk_buff *nskb; + + nskb = alloc_skb(3, GFP_ATOMIC); + if (!nskb) + return; + + bt_cb(nskb)->pkt_type = HCI_3WIRE_LINK_PKT; + + memcpy(skb_put(nskb, len), data, len); + + skb_queue_tail(&h5->unrel, nskb); +} + +static u8 h5_cfg_field(struct h5 *h5) +{ + u8 field = 0; + + /* Sliding window size (first 3 bits) */ + field |= (h5->tx_win & 7); + + return field; +} + +static void h5_timed_event(unsigned long arg) +{ + const unsigned char sync_req[] = { 0x01, 0x7e }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + struct hci_uart *hu = (struct hci_uart *) arg; + struct h5 *h5 = hu->priv; + struct sk_buff *skb; + unsigned long flags; + + BT_DBG("%s", hu->hdev->name); + + if (h5->state == H5_UNINITIALIZED) + h5_link_control(hu, sync_req, sizeof(sync_req)); + + if (h5->state == H5_INITIALIZED) { + conf_req[2] = h5_cfg_field(h5); + h5_link_control(hu, conf_req, sizeof(conf_req)); + } + + if (h5->state != H5_ACTIVE) { + mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + goto wakeup; + } + + if (h5->sleep != H5_AWAKE) { + h5->sleep = H5_SLEEPING; + goto wakeup; + } + + BT_DBG("hu %p retransmitting %u pkts", hu, h5->unack.qlen); + + spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); + + while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) { + h5->tx_seq = (h5->tx_seq - 1) & 0x07; + skb_queue_head(&h5->rel, skb); + } + + spin_unlock_irqrestore(&h5->unack.lock, flags); + +wakeup: + hci_uart_tx_wakeup(hu); +} + +static int h5_open(struct hci_uart *hu) +{ + struct h5 *h5; + const unsigned char sync[] = { 0x01, 0x7e }; + + BT_DBG("hu %p", hu); + + h5 = kzalloc(sizeof(*h5), GFP_KERNEL); + if (!h5) + return -ENOMEM; + + hu->priv = h5; + + skb_queue_head_init(&h5->unack); + skb_queue_head_init(&h5->rel); + skb_queue_head_init(&h5->unrel); + + h5_reset_rx(h5); + + init_timer(&h5->timer); + h5->timer.function = h5_timed_event; + h5->timer.data = (unsigned long) hu; + + h5->tx_win = H5_TX_WIN_MAX; + + set_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags); + + /* Send initial sync request */ + h5_link_control(hu, sync, sizeof(sync)); + mod_timer(&h5->timer, jiffies + H5_SYNC_TIMEOUT); + + return 0; +} + +static int h5_close(struct hci_uart *hu) +{ + struct h5 *h5 = hu->priv; + + skb_queue_purge(&h5->unack); + skb_queue_purge(&h5->rel); + skb_queue_purge(&h5->unrel); + + del_timer(&h5->timer); + + kfree(h5); + + return 0; +} + +static void h5_pkt_cull(struct h5 *h5) +{ + struct sk_buff *skb, *tmp; + unsigned long flags; + int i, to_remove; + u8 seq; + + spin_lock_irqsave(&h5->unack.lock, flags); + + to_remove = skb_queue_len(&h5->unack); + if (to_remove == 0) + goto unlock; + + seq = h5->tx_seq; + + while (to_remove > 0) { + if (h5->rx_ack == seq) + break; + + to_remove--; + seq = (seq - 1) % 8; + } + + if (seq != h5->rx_ack) + BT_ERR("Controller acked invalid packet"); + + i = 0; + skb_queue_walk_safe(&h5->unack, skb, tmp) { + if (i++ >= to_remove) + break; + + __skb_unlink(skb, &h5->unack); + kfree_skb(skb); + } + + if (skb_queue_empty(&h5->unack)) + del_timer(&h5->timer); + +unlock: + spin_unlock_irqrestore(&h5->unack.lock, flags); +} + +static void h5_handle_internal_rx(struct hci_uart *hu) +{ + struct h5 *h5 = hu->priv; + const unsigned char sync_req[] = { 0x01, 0x7e }; + const unsigned char sync_rsp[] = { 0x02, 0x7d }; + unsigned char conf_req[] = { 0x03, 0xfc, 0x01 }; + const unsigned char conf_rsp[] = { 0x04, 0x7b }; + const unsigned char wakeup_req[] = { 0x05, 0xfa }; + const unsigned char woken_req[] = { 0x06, 0xf9 }; + const unsigned char sleep_req[] = { 0x07, 0x78 }; + const unsigned char *hdr = h5->rx_skb->data; + const unsigned char *data = &h5->rx_skb->data[4]; + + BT_DBG("%s", hu->hdev->name); + + if (H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) + return; + + if (H5_HDR_LEN(hdr) < 2) + return; + + conf_req[2] = h5_cfg_field(h5); + + if (memcmp(data, sync_req, 2) == 0) { + h5_link_control(hu, sync_rsp, 2); + } else if (memcmp(data, sync_rsp, 2) == 0) { + h5->state = H5_INITIALIZED; + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_req, 2) == 0) { + h5_link_control(hu, conf_rsp, 2); + h5_link_control(hu, conf_req, 3); + } else if (memcmp(data, conf_rsp, 2) == 0) { + if (H5_HDR_LEN(hdr) > 2) + h5->tx_win = (data[2] & 7); + BT_DBG("Three-wire init complete. tx_win %u", h5->tx_win); + h5->state = H5_ACTIVE; + hci_uart_init_ready(hu); + return; + } else if (memcmp(data, sleep_req, 2) == 0) { + BT_DBG("Peer went to sleep"); + h5->sleep = H5_SLEEPING; + return; + } else if (memcmp(data, woken_req, 2) == 0) { + BT_DBG("Peer woke up"); + h5->sleep = H5_AWAKE; + } else if (memcmp(data, wakeup_req, 2) == 0) { + BT_DBG("Peer requested wakeup"); + h5_link_control(hu, woken_req, 2); + h5->sleep = H5_AWAKE; + } else { + BT_DBG("Link Control: 0x%02hhx 0x%02hhx", data[0], data[1]); + return; + } + + hci_uart_tx_wakeup(hu); +} + +static void h5_complete_rx_pkt(struct hci_uart *hu) +{ + struct h5 *h5 = hu->priv; + const unsigned char *hdr = h5->rx_skb->data; + + if (H5_HDR_RELIABLE(hdr)) { + h5->tx_ack = (h5->tx_ack + 1) % 8; + set_bit(H5_TX_ACK_REQ, &h5->flags); + hci_uart_tx_wakeup(hu); + } + + h5->rx_ack = H5_HDR_ACK(hdr); + + h5_pkt_cull(h5); + + switch (H5_HDR_PKT_TYPE(hdr)) { + case HCI_EVENT_PKT: + case HCI_ACLDATA_PKT: + case HCI_SCODATA_PKT: + bt_cb(h5->rx_skb)->pkt_type = H5_HDR_PKT_TYPE(hdr); + + /* Remove Three-wire header */ + skb_pull(h5->rx_skb, 4); + + hci_recv_frame(h5->rx_skb); + h5->rx_skb = NULL; + + break; + + default: + h5_handle_internal_rx(hu); + break; + } + + h5_reset_rx(h5); +} + +static int h5_rx_crc(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + h5_complete_rx_pkt(hu); + h5_reset_rx(h5); + + return 0; +} + +static int h5_rx_payload(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + const unsigned char *hdr = h5->rx_skb->data; + + if (H5_HDR_CRC(hdr)) { + h5->rx_func = h5_rx_crc; + h5->rx_pending = 2; + } else { + h5_complete_rx_pkt(hu); + h5_reset_rx(h5); + } + + return 0; +} + +static int h5_rx_3wire_hdr(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + const unsigned char *hdr = h5->rx_skb->data; + + BT_DBG("%s rx: seq %u ack %u crc %u rel %u type %u len %u", + hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr), + H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr), + H5_HDR_LEN(hdr)); + + if (((hdr[0] + hdr[1] + hdr[2] + hdr[3]) & 0xff) != 0xff) { + BT_ERR("Invalid header checksum"); + h5_reset_rx(h5); + return 0; + } + + if (H5_HDR_RELIABLE(hdr) && H5_HDR_SEQ(hdr) != h5->tx_ack) { + BT_ERR("Out-of-order packet arrived (%u != %u)", + H5_HDR_SEQ(hdr), h5->tx_ack); + h5_reset_rx(h5); + return 0; + } + + if (h5->state != H5_ACTIVE && + H5_HDR_PKT_TYPE(hdr) != HCI_3WIRE_LINK_PKT) { + BT_ERR("Non-link packet received in non-active state"); + h5_reset_rx(h5); + } + + h5->rx_func = h5_rx_payload; + h5->rx_pending = H5_HDR_LEN(hdr); + + return 0; +} + +static int h5_rx_pkt_start(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + if (c == SLIP_DELIMITER) + return 1; + + h5->rx_func = h5_rx_3wire_hdr; + h5->rx_pending = 4; + + h5->rx_skb = bt_skb_alloc(H5_MAX_LEN, GFP_ATOMIC); + if (!h5->rx_skb) { + BT_ERR("Can't allocate mem for new packet"); + h5_reset_rx(h5); + return -ENOMEM; + } + + h5->rx_skb->dev = (void *) hu->hdev; + + return 0; +} + +static int h5_rx_delimiter(struct hci_uart *hu, unsigned char c) +{ + struct h5 *h5 = hu->priv; + + if (c == SLIP_DELIMITER) + h5->rx_func = h5_rx_pkt_start; + + return 1; +} + +static void h5_unslip_one_byte(struct h5 *h5, unsigned char c) +{ + const u8 delim = SLIP_DELIMITER, esc = SLIP_ESC; + const u8 *byte = &c; + + if (!test_bit(H5_RX_ESC, &h5->flags) && c == SLIP_ESC) { + set_bit(H5_RX_ESC, &h5->flags); + return; + } + + if (test_and_clear_bit(H5_RX_ESC, &h5->flags)) { + switch (c) { + case SLIP_ESC_DELIM: + byte = &delim; + break; + case SLIP_ESC_ESC: + byte = &esc; + break; + default: + BT_ERR("Invalid esc byte 0x%02hhx", c); + h5_reset_rx(h5); + return; + } + } + + memcpy(skb_put(h5->rx_skb, 1), byte, 1); + h5->rx_pending--; + + BT_DBG("unsliped 0x%02hhx, rx_pending %zu", *byte, h5->rx_pending); +} + +static void h5_reset_rx(struct h5 *h5) +{ + if (h5->rx_skb) { + kfree_skb(h5->rx_skb); + h5->rx_skb = NULL; + } + + h5->rx_func = h5_rx_delimiter; + h5->rx_pending = 0; + clear_bit(H5_RX_ESC, &h5->flags); +} + +static int h5_recv(struct hci_uart *hu, void *data, int count) +{ + struct h5 *h5 = hu->priv; + unsigned char *ptr = data; + + BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending, + count); + + while (count > 0) { + int processed; + + if (h5->rx_pending > 0) { + if (*ptr == SLIP_DELIMITER) { + BT_ERR("Too short H5 packet"); + h5_reset_rx(h5); + continue; + } + + h5_unslip_one_byte(h5, *ptr); + + ptr++; count--; + continue; + } + + processed = h5->rx_func(hu, *ptr); + if (processed < 0) + return processed; + + ptr += processed; + count -= processed; + } + + return 0; +} + +static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + struct h5 *h5 = hu->priv; + + if (skb->len > 0xfff) { + BT_ERR("Packet too long (%u bytes)", skb->len); + kfree_skb(skb); + return 0; + } + + if (h5->state != H5_ACTIVE) { + BT_ERR("Ignoring HCI data in non-active state"); + kfree_skb(skb); + return 0; + } + + switch (bt_cb(skb)->pkt_type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + skb_queue_tail(&h5->rel, skb); + break; + + case HCI_SCODATA_PKT: + skb_queue_tail(&h5->unrel, skb); + break; + + default: + BT_ERR("Unknown packet type %u", bt_cb(skb)->pkt_type); + kfree_skb(skb); + break; + } + + return 0; +} + +static void h5_slip_delim(struct sk_buff *skb) +{ + const char delim = SLIP_DELIMITER; + + memcpy(skb_put(skb, 1), &delim, 1); +} + +static void h5_slip_one_byte(struct sk_buff *skb, u8 c) +{ + const char esc_delim[2] = { SLIP_ESC, SLIP_ESC_DELIM }; + const char esc_esc[2] = { SLIP_ESC, SLIP_ESC_ESC }; + + switch (c) { + case SLIP_DELIMITER: + memcpy(skb_put(skb, 2), &esc_delim, 2); + break; + case SLIP_ESC: + memcpy(skb_put(skb, 2), &esc_esc, 2); + break; + default: + memcpy(skb_put(skb, 1), &c, 1); + } +} + +static bool valid_packet_type(u8 type) +{ + switch (type) { + case HCI_ACLDATA_PKT: + case HCI_COMMAND_PKT: + case HCI_SCODATA_PKT: + case HCI_3WIRE_LINK_PKT: + case HCI_3WIRE_ACK_PKT: + return true; + default: + return false; + } +} + +static struct sk_buff *h5_prepare_pkt(struct hci_uart *hu, u8 pkt_type, + const u8 *data, size_t len) +{ + struct h5 *h5 = hu->priv; + struct sk_buff *nskb; + u8 hdr[4]; + int i; + + if (!valid_packet_type(pkt_type)) { + BT_ERR("Unknown packet type %u", pkt_type); + return NULL; + } + + /* + * Max len of packet: (original len + 4 (H5 hdr) + 2 (crc)) * 2 + * (because bytes 0xc0 and 0xdb are escaped, worst case is when + * the packet is all made of 0xc0 and 0xdb) + 2 (0xc0 + * delimiters at start and end). + */ + nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC); + if (!nskb) + return NULL; + + bt_cb(nskb)->pkt_type = pkt_type; + + h5_slip_delim(nskb); + + hdr[0] = h5->tx_ack << 3; + clear_bit(H5_TX_ACK_REQ, &h5->flags); + + /* Reliable packet? */ + if (pkt_type == HCI_ACLDATA_PKT || pkt_type == HCI_COMMAND_PKT) { + hdr[0] |= 1 << 7; + hdr[0] |= h5->tx_seq; + h5->tx_seq = (h5->tx_seq + 1) % 8; + } + + hdr[1] = pkt_type | ((len & 0x0f) << 4); + hdr[2] = len >> 4; + hdr[3] = ~((hdr[0] + hdr[1] + hdr[2]) & 0xff); + + BT_DBG("%s tx: seq %u ack %u crc %u rel %u type %u len %u", + hu->hdev->name, H5_HDR_SEQ(hdr), H5_HDR_ACK(hdr), + H5_HDR_CRC(hdr), H5_HDR_RELIABLE(hdr), H5_HDR_PKT_TYPE(hdr), + H5_HDR_LEN(hdr)); + + for (i = 0; i < 4; i++) + h5_slip_one_byte(nskb, hdr[i]); + + for (i = 0; i < len; i++) + h5_slip_one_byte(nskb, data[i]); + + h5_slip_delim(nskb); + + return nskb; +} + +static struct sk_buff *h5_dequeue(struct hci_uart *hu) +{ + struct h5 *h5 = hu->priv; + unsigned long flags; + struct sk_buff *skb, *nskb; + + if (h5->sleep != H5_AWAKE) { + const unsigned char wakeup_req[] = { 0x05, 0xfa }; + + if (h5->sleep == H5_WAKING_UP) + return NULL; + + h5->sleep = H5_WAKING_UP; + BT_DBG("Sending wakeup request"); + + mod_timer(&h5->timer, jiffies + HZ / 100); + return h5_prepare_pkt(hu, HCI_3WIRE_LINK_PKT, wakeup_req, 2); + } + + if ((skb = skb_dequeue(&h5->unrel)) != NULL) { + nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, + skb->data, skb->len); + if (nskb) { + kfree_skb(skb); + return nskb; + } + + skb_queue_head(&h5->unrel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } + + spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING); + + if (h5->unack.qlen >= h5->tx_win) + goto unlock; + + if ((skb = skb_dequeue(&h5->rel)) != NULL) { + nskb = h5_prepare_pkt(hu, bt_cb(skb)->pkt_type, + skb->data, skb->len); + if (nskb) { + __skb_queue_tail(&h5->unack, skb); + mod_timer(&h5->timer, jiffies + H5_ACK_TIMEOUT); + spin_unlock_irqrestore(&h5->unack.lock, flags); + return nskb; + } + + skb_queue_head(&h5->rel, skb); + BT_ERR("Could not dequeue pkt because alloc_skb failed"); + } + +unlock: + spin_unlock_irqrestore(&h5->unack.lock, flags); + + if (test_bit(H5_TX_ACK_REQ, &h5->flags)) + return h5_prepare_pkt(hu, HCI_3WIRE_ACK_PKT, NULL, 0); + + return NULL; +} + +static int h5_flush(struct hci_uart *hu) +{ + BT_DBG("hu %p", hu); + return 0; +} + +static struct hci_uart_proto h5p = { + .id = HCI_UART_3WIRE, + .open = h5_open, + .close = h5_close, + .recv = h5_recv, + .enqueue = h5_enqueue, + .dequeue = h5_dequeue, + .flush = h5_flush, +}; + +int __init h5_init(void) +{ + int err = hci_uart_register_proto(&h5p); + + if (!err) + BT_INFO("HCI Three-wire UART (H5) protocol initialized"); + else + BT_ERR("HCI Three-wire UART (H5) protocol init failed"); + + return err; +} + +int __exit h5_deinit(void) +{ + return hci_uart_unregister_proto(&h5p); +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 2f9b796..74e0966 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -156,6 +156,35 @@ restart: return 0; } +static void hci_uart_init_work(struct work_struct *work) +{ + struct hci_uart *hu = container_of(work, struct hci_uart, init_ready); + int err; + + if (!test_and_clear_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return; + + err = hci_register_dev(hu->hdev); + if (err < 0) { + BT_ERR("Can't register HCI device"); + hci_free_dev(hu->hdev); + hu->hdev = NULL; + hu->proto->close(hu); + } + + set_bit(HCI_UART_REGISTERED, &hu->flags); +} + +int hci_uart_init_ready(struct hci_uart *hu) +{ + if (!test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return -EALREADY; + + schedule_work(&hu->init_ready); + + return 0; +} + /* ------- Interface to HCI layer ------ */ /* Initialize device */ static int hci_uart_open(struct hci_dev *hdev) @@ -264,6 +293,8 @@ static int hci_uart_tty_open(struct tty_struct *tty) hu->tty = tty; tty->receive_room = 65536; + INIT_WORK(&hu->init_ready, hci_uart_init_work); + spin_lock_init(&hu->rx_lock); /* Flush any pending characters in the driver and line discipline. */ @@ -286,28 +317,30 @@ static int hci_uart_tty_open(struct tty_struct *tty) static void hci_uart_tty_close(struct tty_struct *tty) { struct hci_uart *hu = (void *)tty->disc_data; + struct hci_dev *hdev; BT_DBG("tty %p", tty); /* Detach from the tty */ tty->disc_data = NULL; - if (hu) { - struct hci_dev *hdev = hu->hdev; + if (!hu) + return; - if (hdev) - hci_uart_close(hdev); + hdev = hu->hdev; + if (hdev) + hci_uart_close(hdev); - if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { - if (hdev) { + if (test_and_clear_bit(HCI_UART_PROTO_SET, &hu->flags)) { + if (hdev) { + if (test_bit(HCI_UART_REGISTERED, &hu->flags)) hci_unregister_dev(hdev); - hci_free_dev(hdev); - } - hu->proto->close(hu); + hci_free_dev(hdev); } - - kfree(hu); + hu->proto->close(hu); } + + kfree(hu); } /* hci_uart_tty_wakeup() @@ -401,12 +434,17 @@ static int hci_uart_register_dev(struct hci_uart *hu) else hdev->dev_type = HCI_BREDR; + if (test_bit(HCI_UART_INIT_PENDING, &hu->hdev_flags)) + return 0; + if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); hci_free_dev(hdev); return -ENODEV; } + set_bit(HCI_UART_REGISTERED, &hu->flags); + return 0; } @@ -558,6 +596,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_ATH3K ath_init(); #endif +#ifdef CONFIG_BT_HCIUART_3WIRE + h5_init(); +#endif return 0; } @@ -578,6 +619,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_ATH3K ath_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_3WIRE + h5_deinit(); +#endif /* Release tty registration of line discipline */ if ((err = tty_unregister_ldisc(N_HCI))) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 6cf6ab22..fffa61f 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -47,6 +47,7 @@ #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 #define HCI_UART_CREATE_AMP 2 +#define HCI_UART_INIT_PENDING 3 struct hci_uart; @@ -66,6 +67,8 @@ struct hci_uart { unsigned long flags; unsigned long hdev_flags; + struct work_struct init_ready; + struct hci_uart_proto *proto; void *priv; @@ -76,6 +79,7 @@ struct hci_uart { /* HCI_UART proto flag bits */ #define HCI_UART_PROTO_SET 0 +#define HCI_UART_REGISTERED 1 /* TX states */ #define HCI_UART_SENDING 1 @@ -84,6 +88,7 @@ struct hci_uart { int hci_uart_register_proto(struct hci_uart_proto *p); int hci_uart_unregister_proto(struct hci_uart_proto *p); int hci_uart_tx_wakeup(struct hci_uart *hu); +int hci_uart_init_ready(struct hci_uart *hu); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); @@ -104,3 +109,8 @@ int ll_deinit(void); int ath_init(void); int ath_deinit(void); #endif + +#ifdef CONFIG_BT_HCIUART_3WIRE +int h5_init(void); +int h5_deinit(void); +#endif diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h index 420d69b..6169fbd 100644 --- a/drivers/net/wireless/ath/ath.h +++ b/drivers/net/wireless/ath/ath.h @@ -216,6 +216,7 @@ void ath_printk(const char *level, const struct ath_common *common, * used exclusively for WLAN-BT coexistence starting from * AR9462. * @ATH_DBG_DFS: radar datection + * @ATH_DBG_WOW: Wake on Wireless * @ATH_DBG_ANY: enable all debugging * * The debug level is used to control the amount and type of debugging output @@ -243,6 +244,7 @@ enum ATH_DEBUG { ATH_DBG_BSTUCK = 0x00008000, ATH_DBG_MCI = 0x00010000, ATH_DBG_DFS = 0x00020000, + ATH_DBG_WOW = 0x00040000, ATH_DBG_ANY = 0xffffffff }; diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c index 22b80af..260e7dc 100644 --- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c +++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c @@ -594,7 +594,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u16 queue, qi.tqi_aifs = params->aifs; qi.tqi_cw_min = params->cw_min; qi.tqi_cw_max = params->cw_max; - qi.tqi_burst_time = params->txop; + qi.tqi_burst_time = params->txop * 32; ATH5K_DBG(ah, ATH5K_DEBUG_ANY, "Configure tx [queue %d], " diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index aca1d26..86aeef4 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -966,11 +966,11 @@ static int ath6kl_set_probed_ssids(struct ath6kl *ar, return 0; } -static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, +static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { - struct ath6kl *ar = ath6kl_priv(ndev); - struct ath6kl_vif *vif = netdev_priv(ndev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(request->wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); s8 n_channels = 0; u16 *channels = NULL; int ret = 0; @@ -1487,14 +1487,14 @@ static int ath6kl_cfg80211_set_power_mgmt(struct wiphy *wiphy, return 0; } -static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +static struct wireless_dev *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ath6kl *ar = wiphy_priv(wiphy); - struct net_device *ndev; + struct wireless_dev *wdev; u8 if_idx, nw_type; if (ar->num_vif == ar->vif_max) { @@ -1507,20 +1507,20 @@ static struct net_device *ath6kl_cfg80211_add_iface(struct wiphy *wiphy, return ERR_PTR(-EINVAL); } - ndev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); - if (!ndev) + wdev = ath6kl_interface_add(ar, name, type, if_idx, nw_type); + if (!wdev) return ERR_PTR(-ENOMEM); ar->num_vif++; - return ndev; + return wdev; } static int ath6kl_cfg80211_del_iface(struct wiphy *wiphy, - struct net_device *ndev) + struct wireless_dev *wdev) { struct ath6kl *ar = wiphy_priv(wiphy); - struct ath6kl_vif *vif = netdev_priv(ndev); + struct ath6kl_vif *vif = netdev_priv(wdev->netdev); spin_lock_bh(&ar->list_lock); list_del(&vif->list); @@ -2975,14 +2975,14 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev, } static int ath6kl_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); u32 id; /* TODO: if already pending or ongoing remain-on-channel, @@ -2999,11 +2999,11 @@ static int ath6kl_remain_on_channel(struct wiphy *wiphy, } static int ath6kl_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); if (cookie != vif->last_roc_id) return -ENOENT; @@ -3134,15 +3134,15 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len) return false; } -static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct ath6kl *ar = ath6kl_priv(dev); - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); + struct ath6kl *ar = ath6kl_priv(vif->ndev); u32 id; const struct ieee80211_mgmt *mgmt; bool more_data, queued; @@ -3187,10 +3187,10 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } static void ath6kl_mgmt_frame_register(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg) { - struct ath6kl_vif *vif = netdev_priv(dev); + struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev); ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s: frame_type=0x%x reg=%d\n", __func__, frame_type, reg); @@ -3477,9 +3477,9 @@ void ath6kl_cfg80211_vif_cleanup(struct ath6kl_vif *vif) ar->num_vif--; } -struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, - enum nl80211_iftype type, u8 fw_vif_idx, - u8 nw_type) +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, + enum nl80211_iftype type, + u8 fw_vif_idx, u8 nw_type) { struct net_device *ndev; struct ath6kl_vif *vif; @@ -3533,7 +3533,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, list_add_tail(&vif->list, &ar->vif_list); spin_unlock_bh(&ar->list_lock); - return ndev; + return &vif->wdev; err: aggr_module_destroy(vif->aggr_cntxt); diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.h b/drivers/net/wireless/ath/ath6kl/cfg80211.h index b992046..56b1ebe 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.h +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.h @@ -25,9 +25,9 @@ enum ath6kl_cfg_suspend_mode { ATH6KL_CFG_SUSPEND_SCHED_SCAN, }; -struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name, - enum nl80211_iftype type, - u8 fw_vif_idx, u8 nw_type); +struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, char *name, + enum nl80211_iftype type, + u8 fw_vif_idx, u8 nw_type); void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq, enum wmi_phy_mode mode); void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted); diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index fdb3b1d..82c4dd2 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -56,7 +56,7 @@ EXPORT_SYMBOL(ath6kl_core_rx_complete); int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) { struct ath6kl_bmi_target_info targ_info; - struct net_device *ndev; + struct wireless_dev *wdev; int ret = 0, i; switch (htc_type) { @@ -187,12 +187,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) rtnl_lock(); /* Add an initial station interface */ - ndev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, + wdev = ath6kl_interface_add(ar, "wlan%d", NL80211_IFTYPE_STATION, 0, INFRA_NETWORK); rtnl_unlock(); - if (!ndev) { + if (!wdev) { ath6kl_err("Failed to instantiate a network device\n"); ret = -ENOMEM; wiphy_unregister(ar->wiphy); @@ -200,7 +200,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) } ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n", - __func__, ndev->name, ndev, ar); + __func__, wdev->netdev->name, wdev->netdev, ar); return ret; diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index d38a31d..cec49a3 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -589,6 +589,11 @@ struct ath6kl_vif { struct list_head mc_filter; }; +static inline struct ath6kl_vif *ath6kl_vif_from_wdev(struct wireless_dev *wdev) +{ + return container_of(wdev, struct ath6kl_vif, wdev); +} + #define WOW_LIST_ID 0 #define WOW_HOST_REQ_DELAY 500 /* ms */ diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index a6caa67..c30ab4b 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap, return -EINVAL; } id = vif->last_roc_id; - cfg80211_ready_on_channel(vif->ndev, id, chan, NL80211_CHAN_NO_HT, + cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, dur, GFP_ATOMIC); return 0; @@ -513,7 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi, else id = vif->last_roc_id; /* timeout on uncanceled r-o-c */ vif->last_cancel_roc_id = 0; - cfg80211_remain_on_channel_expired(vif->ndev, id, chan, + cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, NL80211_CHAN_NO_HT, GFP_ATOMIC); return 0; @@ -533,7 +533,7 @@ static int ath6kl_wmi_tx_status_event_rx(struct wmi *wmi, u8 *datap, int len, ath6kl_dbg(ATH6KL_DBG_WMI, "tx_status: id=%x ack_status=%u\n", id, ev->ack_status); if (wmi->last_mgmt_tx_frame) { - cfg80211_mgmt_tx_status(vif->ndev, id, + cfg80211_mgmt_tx_status(&vif->wdev, id, wmi->last_mgmt_tx_frame, wmi->last_mgmt_tx_frame_len, !!ev->ack_status, GFP_ATOMIC); @@ -568,7 +568,7 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len, dlen, freq, vif->probe_req_report); if (vif->probe_req_report || vif->nw_type == AP_NETWORK) - cfg80211_rx_mgmt(vif->ndev, freq, 0, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, GFP_ATOMIC); return 0; @@ -608,7 +608,7 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len, return -EINVAL; } ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq); - cfg80211_rx_mgmt(vif->ndev, freq, 0, + cfg80211_rx_mgmt(&vif->wdev, freq, 0, ev->data, dlen, GFP_ATOMIC); return 0; diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig index e507e78..c7aa664 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -64,7 +64,7 @@ config ATH9K_DEBUGFS config ATH9K_DFS_CERTIFIED bool "Atheros DFS support for certified platforms" - depends on ATH9K && EXPERT + depends on ATH9K && CFG80211_CERTIFICATION_ONUS default n ---help--- This option enables DFS support for initiating radiation on diff --git a/drivers/net/wireless/ath/ath9k/Makefile b/drivers/net/wireless/ath/ath9k/Makefile index 9c41232..2ad8f94 100644 --- a/drivers/net/wireless/ath/ath9k/Makefile +++ b/drivers/net/wireless/ath/ath9k/Makefile @@ -17,6 +17,7 @@ ath9k-$(CONFIG_ATH9K_DFS_CERTIFIED) += \ dfs.o \ dfs_pattern_detector.o \ dfs_pri_detector.o +ath9k-$(CONFIG_PM_SLEEP) += wow.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath/ath9k/ar9002_hw.c b/drivers/net/wireless/ath/ath9k/ar9002_hw.c index edf21ea..648da3e 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9002_hw.c @@ -26,101 +26,74 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) { if (AR_SREV_9271(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271, - ARRAY_SIZE(ar9271Modes_9271), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271, - ARRAY_SIZE(ar9271Common_9271), 2); - INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg, - ARRAY_SIZE(ar9271Modes_9271_ANI_reg), 5); + INIT_INI_ARRAY(&ah->iniModes, ar9271Modes_9271); + INIT_INI_ARRAY(&ah->iniCommon, ar9271Common_9271); + INIT_INI_ARRAY(&ah->iniModes_9271_ANI_reg, ar9271Modes_9271_ANI_reg); return; } if (ah->config.pcie_clock_req) INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280), 2); + ar9280PciePhy_clkreq_off_L1_9280); else INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + ar9280PciePhy_clkreq_always_on_L1_9280); +#ifdef CONFIG_PM_SLEEP + INIT_INI_ARRAY(&ah->iniPcieSerdesWow, + ar9280PciePhy_awow); +#endif if (AR_SREV_9287_11_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1, - ARRAY_SIZE(ar9287Modes_9287_1_1), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1, - ARRAY_SIZE(ar9287Common_9287_1_1), 2); + INIT_INI_ARRAY(&ah->iniModes, ar9287Modes_9287_1_1); + INIT_INI_ARRAY(&ah->iniCommon, ar9287Common_9287_1_1); } else if (AR_SREV_9285_12_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2, - ARRAY_SIZE(ar9285Modes_9285_1_2), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2, - ARRAY_SIZE(ar9285Common_9285_1_2), 2); + INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2); + INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2); } else if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); + INIT_INI_ARRAY(&ah->iniModes, ar9280Modes_9280_2); + INIT_INI_ARRAY(&ah->iniCommon, ar9280Common_9280_2); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + ar9280Modes_fast_clock_9280_2); } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9160); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9160); if (AR_SREV_9160_11(ah)) { INIT_INI_ARRAY(&ah->iniAddac, - ar5416Addac_9160_1_1, - ARRAY_SIZE(ar5416Addac_9160_1_1), 2); + ar5416Addac_9160_1_1); } else { - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9160); } } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes_9100); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common_9100); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6_9100); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac_9100); } else { - INIT_INI_ARRAY(&ah->iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 5); - INIT_INI_ARRAY(&ah->iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); + INIT_INI_ARRAY(&ah->iniModes, ar5416Modes); + INIT_INI_ARRAY(&ah->iniCommon, ar5416Common); + INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC); + INIT_INI_ARRAY(&ah->iniAddac, ar5416Addac); } if (!AR_SREV_9280_20_OR_LATER(ah)) { /* Common for AR5416, AR913x, AR9160 */ - INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - - INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ah->iniBB_RfGain, ar5416BB_RfGain); + + INIT_INI_ARRAY(&ah->iniBank0, ar5416Bank0); + INIT_INI_ARRAY(&ah->iniBank1, ar5416Bank1); + INIT_INI_ARRAY(&ah->iniBank2, ar5416Bank2); + INIT_INI_ARRAY(&ah->iniBank3, ar5416Bank3); + INIT_INI_ARRAY(&ah->iniBank7, ar5416Bank7); /* Common for AR5416, AR9160 */ if (!AR_SREV_9100(ah)) - INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ah->iniBank6, ar5416Bank6); /* Common for AR913x, AR9160 */ if (!AR_SREV_5416(ah)) - INIT_INI_ARRAY(&ah->iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ah->iniBank6TPC, + ar5416Bank6TPC_9100); } /* iniAddac needs to be modified for these chips */ @@ -143,13 +116,9 @@ static void ar9002_hw_init_mode_regs(struct ath_hw *ah) } if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniCckfirNormal, - ar9287Common_normal_cck_fir_coeff_9287_1_1, - ARRAY_SIZE(ar9287Common_normal_cck_fir_coeff_9287_1_1), - 2); + ar9287Common_normal_cck_fir_coeff_9287_1_1); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - ar9287Common_japan_2484_cck_fir_coeff_9287_1_1, - ARRAY_SIZE(ar9287Common_japan_2484_cck_fir_coeff_9287_1_1), - 2); + ar9287Common_japan_2484_cck_fir_coeff_9287_1_1); } } @@ -163,20 +132,16 @@ static void ar9280_20_hw_init_rxgain_ini(struct ath_hw *ah) if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_13db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 5); + ar9280Modes_backoff_13db_rxgain_9280_2); else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_backoff_23db_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 5); + ar9280Modes_backoff_23db_rxgain_9280_2); else INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5); + ar9280Modes_original_rxgain_9280_2); } else { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9280Modes_original_rxgain_9280_2, - ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 5); + ar9280Modes_original_rxgain_9280_2); } } @@ -186,16 +151,13 @@ static void ar9280_20_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) AR5416_EEP_MINOR_VER_19) { if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_high_power_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 5); + ar9280Modes_high_power_tx_gain_9280_2); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5); + ar9280Modes_original_tx_gain_9280_2); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9280Modes_original_tx_gain_9280_2, - ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 5); + ar9280Modes_original_tx_gain_9280_2); } } @@ -203,12 +165,10 @@ static void ar9271_hw_init_txgain_ini(struct ath_hw *ah, u32 txgain_type) { if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9271Modes_high_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_high_power_tx_gain_9271), 5); + ar9271Modes_high_power_tx_gain_9271); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9271Modes_normal_power_tx_gain_9271, - ARRAY_SIZE(ar9271Modes_normal_power_tx_gain_9271), 5); + ar9271Modes_normal_power_tx_gain_9271); } static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) @@ -217,8 +177,7 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) if (AR_SREV_9287_11_OR_LATER(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9287Modes_rx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_rx_gain_9287_1_1), 5); + ar9287Modes_rx_gain_9287_1_1); else if (AR_SREV_9280_20(ah)) ar9280_20_hw_init_rxgain_ini(ah); @@ -226,8 +185,7 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) ar9271_hw_init_txgain_ini(ah, txgain_type); } else if (AR_SREV_9287_11_OR_LATER(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9287Modes_tx_gain_9287_1_1, - ARRAY_SIZE(ar9287Modes_tx_gain_9287_1_1), 5); + ar9287Modes_tx_gain_9287_1_1); } else if (AR_SREV_9280_20(ah)) { ar9280_20_hw_init_txgain_ini(ah, txgain_type); } else if (AR_SREV_9285_12_OR_LATER(ah)) { @@ -235,26 +193,18 @@ static void ar9002_hw_init_mode_gain_regs(struct ath_hw *ah) if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) { if (AR_SREV_9285E_20(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_XE2_0_high_power, - ARRAY_SIZE( - ar9285Modes_XE2_0_high_power), 5); + ar9285Modes_XE2_0_high_power); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_high_power_tx_gain_9285_1_2, - ARRAY_SIZE( - ar9285Modes_high_power_tx_gain_9285_1_2), 5); + ar9285Modes_high_power_tx_gain_9285_1_2); } } else { if (AR_SREV_9285E_20(ah)) { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_XE2_0_normal_power, - ARRAY_SIZE( - ar9285Modes_XE2_0_normal_power), 5); + ar9285Modes_XE2_0_normal_power); } else { INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9285Modes_original_tx_gain_9285_1_2, - ARRAY_SIZE( - ar9285Modes_original_tx_gain_9285_1_2), 5); + ar9285Modes_original_tx_gain_9285_1_2); } } } diff --git a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h index 4d18c66..beb6162 100644 --- a/drivers/net/wireless/ath/ath9k/ar9002_initvals.h +++ b/drivers/net/wireless/ath/ath9k/ar9002_initvals.h @@ -925,6 +925,20 @@ static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { {0x00004044, 0x00000000}, }; +static const u32 ar9280PciePhy_awow[][2] = { + /* Addr allmodes */ + {0x00004040, 0x9248fd00}, + {0x00004040, 0x24924924}, + {0x00004040, 0xa8000019}, + {0x00004040, 0x13160820}, + {0x00004040, 0xe5980560}, + {0x00004040, 0xc01dcffd}, + {0x00004040, 0x1aaabe41}, + {0x00004040, 0xbe105554}, + {0x00004040, 0x00043007}, + {0x00004044, 0x00000000}, +}; + static const u32 ar9285Modes_9285_1_2[][5] = { /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */ {0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160}, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c index ab2bfcb..2588848 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c @@ -131,8 +131,9 @@ static const struct ar9300_eeprom ar9300_default = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -331,8 +332,9 @@ static const struct ar9300_eeprom ar9300_default = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -704,8 +706,9 @@ static const struct ar9300_eeprom ar9300_x113 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -904,8 +907,9 @@ static const struct ar9300_eeprom ar9300_x113 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -1278,8 +1282,9 @@ static const struct ar9300_eeprom ar9300_h112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -1478,8 +1483,9 @@ static const struct ar9300_eeprom ar9300_h112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -1852,8 +1858,9 @@ static const struct ar9300_eeprom ar9300_x112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80c080), .papdRateMaskHt40 = LE32(0x0080c080), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -2052,8 +2059,9 @@ static const struct ar9300_eeprom ar9300_x112 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -2425,8 +2433,9 @@ static const struct ar9300_eeprom ar9300_h116 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0c80C080), .papdRateMaskHt40 = LE32(0x0080C080), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext1 = { @@ -2625,8 +2634,9 @@ static const struct ar9300_eeprom ar9300_h116 = { .thresh62 = 28, .papdRateMaskHt20 = LE32(0x0cf0e0e0), .papdRateMaskHt40 = LE32(0x6cf0e0e0), + .xlna_bias_strength = 0, .futureModal = { - 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }, }, .base_ext2 = { @@ -2971,14 +2981,6 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, return (pBase->txrxMask >> 4) & 0xf; case EEP_RX_MASK: return pBase->txrxMask & 0xf; - case EEP_DRIVE_STRENGTH: -#define AR9300_EEP_BASE_DRIV_STRENGTH 0x1 - return pBase->miscConfiguration & AR9300_EEP_BASE_DRIV_STRENGTH; - case EEP_INTERNAL_REGULATOR: - /* Bit 4 is internal regulator flag */ - return (pBase->featureEnable & 0x10) >> 4; - case EEP_SWREG: - return le32_to_cpu(pBase->swreg); case EEP_PAPRD: return !!(pBase->featureEnable & BIT(5)); case EEP_CHAIN_MASK_REDUCE: @@ -2989,8 +2991,6 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah, return eep->modalHeader5G.antennaGain; case EEP_ANTENNA_GAIN_2G: return eep->modalHeader2G.antennaGain; - case EEP_QUICK_DROP: - return pBase->miscConfiguration & BIT(1); default: return 0; } @@ -3260,10 +3260,20 @@ static int ar9300_eeprom_restore_internal(struct ath_hw *ah, int it; u16 checksum, mchecksum; struct ath_common *common = ath9k_hw_common(ah); + struct ar9300_eeprom *eep; eeprom_read_op read; - if (ath9k_hw_use_flash(ah)) - return ar9300_eeprom_restore_flash(ah, mptr, mdata_size); + if (ath9k_hw_use_flash(ah)) { + u8 txrx; + + ar9300_eeprom_restore_flash(ah, mptr, mdata_size); + + /* check if eeprom contains valid data */ + eep = (struct ar9300_eeprom *) mptr; + txrx = eep->baseEepHeader.txrxMask; + if (txrx != 0 && txrx != 0xff) + return 0; + } word = kzalloc(2048, GFP_KERNEL); if (!word) @@ -3493,19 +3503,20 @@ static int ath9k_hw_ar9300_get_eeprom_rev(struct ath_hw *ah) return 0; } -static s32 ar9003_hw_xpa_bias_level_get(struct ath_hw *ah, bool is2ghz) +static struct ar9300_modal_eep_header *ar9003_modal_header(struct ath_hw *ah, + bool is2ghz) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; if (is2ghz) - return eep->modalHeader2G.xpaBiasLvl; + return &eep->modalHeader2G; else - return eep->modalHeader5G.xpaBiasLvl; + return &eep->modalHeader5G; } static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) { - int bias = ar9003_hw_xpa_bias_level_get(ah, is2ghz); + int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl; if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias); @@ -3521,57 +3532,26 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz) } } -static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is_2ghz) +static u16 ar9003_switch_com_spdt_get(struct ath_hw *ah, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - __le16 val; - - if (is_2ghz) - val = eep->modalHeader2G.switchcomspdt; - else - val = eep->modalHeader5G.switchcomspdt; - return le16_to_cpu(val); + return le16_to_cpu(ar9003_modal_header(ah, is2ghz)->switchcomspdt); } static u32 ar9003_hw_ant_ctrl_common_get(struct ath_hw *ah, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - __le32 val; - - if (is2ghz) - val = eep->modalHeader2G.antCtrlCommon; - else - val = eep->modalHeader5G.antCtrlCommon; - return le32_to_cpu(val); + return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon); } static u32 ar9003_hw_ant_ctrl_common_2_get(struct ath_hw *ah, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - __le32 val; - - if (is2ghz) - val = eep->modalHeader2G.antCtrlCommon2; - else - val = eep->modalHeader5G.antCtrlCommon2; - return le32_to_cpu(val); + return le32_to_cpu(ar9003_modal_header(ah, is2ghz)->antCtrlCommon2); } -static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, - int chain, +static u16 ar9003_hw_ant_ctrl_chain_get(struct ath_hw *ah, int chain, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - __le16 val = 0; - - if (chain >= 0 && chain < AR9300_MAX_CHAINS) { - if (is2ghz) - val = eep->modalHeader2G.antCtrlChain[chain]; - else - val = eep->modalHeader5G.antCtrlChain[chain]; - } - + __le16 val = ar9003_modal_header(ah, is2ghz)->antCtrlChain[chain]; return le16_to_cpu(val); } @@ -3681,11 +3661,12 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz) static void ar9003_hw_drive_strength_apply(struct ath_hw *ah) { + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader; int drive_strength; unsigned long reg; - drive_strength = ath9k_hw_ar9300_get_eeprom(ah, EEP_DRIVE_STRENGTH); - + drive_strength = pBase->miscConfiguration & BIT(0); if (!drive_strength) return; @@ -3815,11 +3796,11 @@ static bool is_pmu_set(struct ath_hw *ah, u32 pmu_reg, int pmu_set) void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) { - int internal_regulator = - ath9k_hw_ar9300_get_eeprom(ah, EEP_INTERNAL_REGULATOR); + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader; u32 reg_val; - if (internal_regulator) { + if (pBase->featureEnable & BIT(4)) { if (AR_SREV_9330(ah) || AR_SREV_9485(ah)) { int reg_pmu_set; @@ -3863,11 +3844,11 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah) if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set)) return; } else if (AR_SREV_9462(ah)) { - reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); + reg_val = le32_to_cpu(pBase->swreg); REG_WRITE(ah, AR_PHY_PMU1, reg_val); } else { /* Internal regulator is ON. Write swreg register. */ - reg_val = ath9k_hw_ar9300_get_eeprom(ah, EEP_SWREG); + reg_val = le32_to_cpu(pBase->swreg); REG_WRITE(ah, AR_RTC_REG_CONTROL1, REG_READ(ah, AR_RTC_REG_CONTROL1) & (~AR_RTC_REG_CONTROL1_SWREG_PROGRAM)); @@ -3909,6 +3890,9 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0]; + if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) + return; + if (eep->baseEepHeader.featureEnable & 0x40) { tuning_caps_param &= 0x7f; REG_RMW_FIELD(ah, AR_CH0_XTAL, AR_CH0_XTAL_CAPINDAC, @@ -3921,10 +3905,11 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah) static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq) { struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - int quick_drop = ath9k_hw_ar9300_get_eeprom(ah, EEP_QUICK_DROP); + struct ar9300_base_eep_hdr *pBase = &eep->baseEepHeader; + int quick_drop; s32 t[3], f[3] = {5180, 5500, 5785}; - if (!quick_drop) + if (!(pBase->miscConfiguration & BIT(1))) return; if (freq < 4000) @@ -3938,13 +3923,11 @@ static void ar9003_hw_quick_drop_apply(struct ath_hw *ah, u16 freq) REG_RMW_FIELD(ah, AR_PHY_AGC, AR_PHY_AGC_QUICK_DROP, quick_drop); } -static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, u16 freq) +static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; u32 value; - value = (freq < 4000) ? eep->modalHeader2G.txEndToXpaOff : - eep->modalHeader5G.txEndToXpaOff; + value = ar9003_modal_header(ah, is2ghz)->txEndToXpaOff; REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value); @@ -3952,19 +3935,63 @@ static void ar9003_hw_txend_to_xpa_off_apply(struct ath_hw *ah, u16 freq) AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value); } +static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + u8 xpa_ctl; + + if (!(eep->baseEepHeader.featureEnable & 0x80)) + return; + + if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah)) + return; + + xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn; + if (is2ghz) + REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, + AR_PHY_XPA_TIMING_CTL_FRAME_XPAB_ON, xpa_ctl); + else + REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL, + AR_PHY_XPA_TIMING_CTL_FRAME_XPAA_ON, xpa_ctl); +} + +static void ar9003_hw_xlna_bias_strength_apply(struct ath_hw *ah, bool is2ghz) +{ + struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; + u8 bias; + + if (!(eep->baseEepHeader.featureEnable & 0x40)) + return; + + if (!AR_SREV_9300(ah)) + return; + + bias = ar9003_modal_header(ah, is2ghz)->xlna_bias_strength; + REG_RMW_FIELD(ah, AR_PHY_65NM_CH0_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, + bias & 0x3); + bias >>= 2; + REG_RMW_FIELD(ah, AR_PHY_65NM_CH1_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, + bias & 0x3); + bias >>= 2; + REG_RMW_FIELD(ah, AR_PHY_65NM_CH2_RXTX4, AR_PHY_65NM_RXTX4_XLNA_BIAS, + bias & 0x3); +} + static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah, struct ath9k_channel *chan) { - ar9003_hw_xpa_bias_level_apply(ah, IS_CHAN_2GHZ(chan)); - ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan)); + bool is2ghz = IS_CHAN_2GHZ(chan); + ar9003_hw_xpa_timing_control_apply(ah, is2ghz); + ar9003_hw_xpa_bias_level_apply(ah, is2ghz); + ar9003_hw_ant_ctrl_apply(ah, is2ghz); ar9003_hw_drive_strength_apply(ah); + ar9003_hw_xlna_bias_strength_apply(ah, is2ghz); ar9003_hw_atten_apply(ah, chan); ar9003_hw_quick_drop_apply(ah, chan->channel); if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah)) ar9003_hw_internal_regulator_apply(ah); - if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah)) - ar9003_hw_apply_tuning_caps(ah); - ar9003_hw_txend_to_xpa_off_apply(ah, chan->channel); + ar9003_hw_apply_tuning_caps(ah); + ar9003_hw_txend_to_xpa_off_apply(ah, is2ghz); } static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah, @@ -5100,14 +5127,9 @@ s32 ar9003_hw_get_rx_gain_idx(struct ath_hw *ah) return (eep->baseEepHeader.txrxgain) & 0xf; /* bits 3:0 */ } -u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is_2ghz) +u8 *ar9003_get_spur_chan_ptr(struct ath_hw *ah, bool is2ghz) { - struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep; - - if (is_2ghz) - return eep->modalHeader2G.spurChans; - else - return eep->modalHeader5G.spurChans; + return ar9003_modal_header(ah, is2ghz)->spurChans; } unsigned int ar9003_get_paprd_scale_factor(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h index 8396d15..3a1ff55 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.h @@ -231,7 +231,8 @@ struct ar9300_modal_eep_header { __le32 papdRateMaskHt20; __le32 papdRateMaskHt40; __le16 switchcomspdt; - u8 futureModal[8]; + u8 xlna_bias_strength; + u8 futureModal[7]; } __packed; struct ar9300_cal_data_per_freq_op_loop { diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c index 41e88c6..1e8a4da 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c @@ -44,462 +44,310 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah) ar9462_2p0_baseband_core_txfir_coeff_japan_2484 if (AR_SREV_9330_11(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9331_1p1_mac_core, - ARRAY_SIZE(ar9331_1p1_mac_core), 2); + ar9331_1p1_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9331_1p1_mac_postamble, - ARRAY_SIZE(ar9331_1p1_mac_postamble), 5); + ar9331_1p1_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9331_1p1_baseband_core, - ARRAY_SIZE(ar9331_1p1_baseband_core), 2); + ar9331_1p1_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9331_1p1_baseband_postamble, - ARRAY_SIZE(ar9331_1p1_baseband_postamble), 5); + ar9331_1p1_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9331_1p1_radio_core, - ARRAY_SIZE(ar9331_1p1_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], NULL, 0, 0); + ar9331_1p1_radio_core); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9331_1p1_soc_preamble, - ARRAY_SIZE(ar9331_1p1_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9331_1p1_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9331_1p1_soc_postamble, - ARRAY_SIZE(ar9331_1p1_soc_postamble), 2); + ar9331_1p1_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p1, - ARRAY_SIZE(ar9331_common_rx_gain_1p1), 2); + ar9331_common_rx_gain_1p1); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1), - 5); + ar9331_modes_lowest_ob_db_tx_gain_1p1); /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, - ar9331_1p1_xtal_25M, - ARRAY_SIZE(ar9331_1p1_xtal_25M), 2); + ar9331_1p1_xtal_25M); else INIT_INI_ARRAY(&ah->iniAdditional, - ar9331_1p1_xtal_40M, - ARRAY_SIZE(ar9331_1p1_xtal_40M), 2); + ar9331_1p1_xtal_40M); } else if (AR_SREV_9330_12(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9331_1p2_mac_core, - ARRAY_SIZE(ar9331_1p2_mac_core), 2); + ar9331_1p2_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9331_1p2_mac_postamble, - ARRAY_SIZE(ar9331_1p2_mac_postamble), 5); + ar9331_1p2_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9331_1p2_baseband_core, - ARRAY_SIZE(ar9331_1p2_baseband_core), 2); + ar9331_1p2_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9331_1p2_baseband_postamble, - ARRAY_SIZE(ar9331_1p2_baseband_postamble), 5); + ar9331_1p2_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9331_1p2_radio_core, - ARRAY_SIZE(ar9331_1p2_radio_core), 2); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], NULL, 0, 0); + ar9331_1p2_radio_core); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9331_1p2_soc_preamble, - ARRAY_SIZE(ar9331_1p2_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9331_1p2_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9331_1p2_soc_postamble, - ARRAY_SIZE(ar9331_1p2_soc_postamble), 2); + ar9331_1p2_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p2, - ARRAY_SIZE(ar9331_common_rx_gain_1p2), 2); + ar9331_common_rx_gain_1p2); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2), - 5); + ar9331_modes_lowest_ob_db_tx_gain_1p2); /* additional clock settings */ if (ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, - ar9331_1p2_xtal_25M, - ARRAY_SIZE(ar9331_1p2_xtal_25M), 2); + ar9331_1p2_xtal_25M); else INIT_INI_ARRAY(&ah->iniAdditional, - ar9331_1p2_xtal_40M, - ARRAY_SIZE(ar9331_1p2_xtal_40M), 2); + ar9331_1p2_xtal_40M); } else if (AR_SREV_9340(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9340_1p0_mac_core, - ARRAY_SIZE(ar9340_1p0_mac_core), 2); + ar9340_1p0_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9340_1p0_mac_postamble, - ARRAY_SIZE(ar9340_1p0_mac_postamble), 5); + ar9340_1p0_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9340_1p0_baseband_core, - ARRAY_SIZE(ar9340_1p0_baseband_core), 2); + ar9340_1p0_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9340_1p0_baseband_postamble, - ARRAY_SIZE(ar9340_1p0_baseband_postamble), 5); + ar9340_1p0_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9340_1p0_radio_core, - ARRAY_SIZE(ar9340_1p0_radio_core), 2); + ar9340_1p0_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9340_1p0_radio_postamble, - ARRAY_SIZE(ar9340_1p0_radio_postamble), 5); + ar9340_1p0_radio_postamble); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9340_1p0_soc_preamble, - ARRAY_SIZE(ar9340_1p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9340_1p0_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9340_1p0_soc_postamble, - ARRAY_SIZE(ar9340_1p0_soc_postamble), 5); + ar9340_1p0_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9340Common_wo_xlna_rx_gain_table_1p0, - ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), - 5); + ar9340Common_wo_xlna_rx_gain_table_1p0); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_high_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_high_ob_db_tx_gain_table_1p0), - 5); + ar9340Modes_high_ob_db_tx_gain_table_1p0); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9340Modes_fast_clock_1p0, - ARRAY_SIZE(ar9340Modes_fast_clock_1p0), - 3); + ar9340Modes_fast_clock_1p0); if (!ah->is_clk_25mhz) INIT_INI_ARRAY(&ah->iniAdditional, - ar9340_1p0_radio_core_40M, - ARRAY_SIZE(ar9340_1p0_radio_core_40M), - 2); + ar9340_1p0_radio_core_40M); } else if (AR_SREV_9485_11(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9485_1_1_mac_core, - ARRAY_SIZE(ar9485_1_1_mac_core), 2); + ar9485_1_1_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9485_1_1_mac_postamble, - ARRAY_SIZE(ar9485_1_1_mac_postamble), 5); + ar9485_1_1_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1, - ARRAY_SIZE(ar9485_1_1), 2); + INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], ar9485_1_1); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9485_1_1_baseband_core, - ARRAY_SIZE(ar9485_1_1_baseband_core), 2); + ar9485_1_1_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9485_1_1_baseband_postamble, - ARRAY_SIZE(ar9485_1_1_baseband_postamble), 5); + ar9485_1_1_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9485_1_1_radio_core, - ARRAY_SIZE(ar9485_1_1_radio_core), 2); + ar9485_1_1_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9485_1_1_radio_postamble, - ARRAY_SIZE(ar9485_1_1_radio_postamble), 2); + ar9485_1_1_radio_postamble); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9485_1_1_soc_preamble, - ARRAY_SIZE(ar9485_1_1_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], NULL, 0, 0); + ar9485_1_1_soc_preamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_1, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), 2); + ar9485Common_wo_xlna_rx_gain_1_1); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485_modes_lowest_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), - 5); + ar9485_modes_lowest_ob_db_tx_gain_1_1); /* Load PCIE SERDES settings from INI */ /* Awake Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9485_1_1_pcie_phy_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), - 2); + ar9485_1_1_pcie_phy_clkreq_disable_L1); /* Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9485_1_1_pcie_phy_clkreq_disable_L1, - ARRAY_SIZE(ar9485_1_1_pcie_phy_clkreq_disable_L1), - 2); + ar9485_1_1_pcie_phy_clkreq_disable_L1); } else if (AR_SREV_9462_20(ah)) { - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core, - ARRAY_SIZE(ar9462_2p0_mac_core), 2); + INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], ar9462_2p0_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9462_2p0_mac_postamble, - ARRAY_SIZE(ar9462_2p0_mac_postamble), 5); + ar9462_2p0_mac_postamble); - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9462_2p0_baseband_core, - ARRAY_SIZE(ar9462_2p0_baseband_core), 2); + ar9462_2p0_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9462_2p0_baseband_postamble, - ARRAY_SIZE(ar9462_2p0_baseband_postamble), 5); + ar9462_2p0_baseband_postamble); - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9462_2p0_radio_core, - ARRAY_SIZE(ar9462_2p0_radio_core), 2); + ar9462_2p0_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9462_2p0_radio_postamble, - ARRAY_SIZE(ar9462_2p0_radio_postamble), 5); + ar9462_2p0_radio_postamble); INIT_INI_ARRAY(&ah->ini_radio_post_sys2ant, - ar9462_2p0_radio_postamble_sys2ant, - ARRAY_SIZE(ar9462_2p0_radio_postamble_sys2ant), - 5); + ar9462_2p0_radio_postamble_sys2ant); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9462_2p0_soc_preamble, - ARRAY_SIZE(ar9462_2p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9462_2p0_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9462_2p0_soc_postamble, - ARRAY_SIZE(ar9462_2p0_soc_postamble), 5); + ar9462_2p0_soc_postamble); INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), 2); + ar9462_common_rx_gain_table_2p0); /* Awake -> Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, - PCIE_PLL_ON_CREQ_DIS_L1_2P0, - ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0), - 2); + PCIE_PLL_ON_CREQ_DIS_L1_2P0); /* Sleep -> Awake Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - PCIE_PLL_ON_CREQ_DIS_L1_2P0, - ARRAY_SIZE(PCIE_PLL_ON_CREQ_DIS_L1_2P0), - 2); + PCIE_PLL_ON_CREQ_DIS_L1_2P0); /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9462_modes_fast_clock_2p0, - ARRAY_SIZE(ar9462_modes_fast_clock_2p0), 3); + ar9462_modes_fast_clock_2p0); INIT_INI_ARRAY(&ah->iniCckfirJapan2484, - AR9462_BB_CTX_COEFJ(2p0), - ARRAY_SIZE(AR9462_BB_CTX_COEFJ(2p0)), 2); + AR9462_BB_CTX_COEFJ(2p0)); - INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ, - ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2); + INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ); } else if (AR_SREV_9550(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar955x_1p0_mac_core, - ARRAY_SIZE(ar955x_1p0_mac_core), 2); + ar955x_1p0_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar955x_1p0_mac_postamble, - ARRAY_SIZE(ar955x_1p0_mac_postamble), 5); + ar955x_1p0_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar955x_1p0_baseband_core, - ARRAY_SIZE(ar955x_1p0_baseband_core), 2); + ar955x_1p0_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar955x_1p0_baseband_postamble, - ARRAY_SIZE(ar955x_1p0_baseband_postamble), 5); + ar955x_1p0_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar955x_1p0_radio_core, - ARRAY_SIZE(ar955x_1p0_radio_core), 2); + ar955x_1p0_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar955x_1p0_radio_postamble, - ARRAY_SIZE(ar955x_1p0_radio_postamble), 5); + ar955x_1p0_radio_postamble); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar955x_1p0_soc_preamble, - ARRAY_SIZE(ar955x_1p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar955x_1p0_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar955x_1p0_soc_postamble, - ARRAY_SIZE(ar955x_1p0_soc_postamble), 5); + ar955x_1p0_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar955x_1p0_common_wo_xlna_rx_gain_table, - ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), - 2); + ar955x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, - ar955x_1p0_common_wo_xlna_rx_gain_bounds, - ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), - 5); + ar955x_1p0_common_wo_xlna_rx_gain_bounds); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar955x_1p0_modes_xpa_tx_gain_table, - ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), - 9); + ar955x_1p0_modes_xpa_tx_gain_table); /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar955x_1p0_modes_fast_clock, - ARRAY_SIZE(ar955x_1p0_modes_fast_clock), 3); + ar955x_1p0_modes_fast_clock); } else if (AR_SREV_9580(ah)) { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9580_1p0_mac_core, - ARRAY_SIZE(ar9580_1p0_mac_core), 2); + ar9580_1p0_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9580_1p0_mac_postamble, - ARRAY_SIZE(ar9580_1p0_mac_postamble), 5); + ar9580_1p0_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9580_1p0_baseband_core, - ARRAY_SIZE(ar9580_1p0_baseband_core), 2); + ar9580_1p0_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9580_1p0_baseband_postamble, - ARRAY_SIZE(ar9580_1p0_baseband_postamble), 5); + ar9580_1p0_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9580_1p0_radio_core, - ARRAY_SIZE(ar9580_1p0_radio_core), 2); + ar9580_1p0_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9580_1p0_radio_postamble, - ARRAY_SIZE(ar9580_1p0_radio_postamble), 5); + ar9580_1p0_radio_postamble); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9580_1p0_soc_preamble, - ARRAY_SIZE(ar9580_1p0_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9580_1p0_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9580_1p0_soc_postamble, - ARRAY_SIZE(ar9580_1p0_soc_postamble), 5); + ar9580_1p0_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9580_1p0_rx_gain_table, - ARRAY_SIZE(ar9580_1p0_rx_gain_table), 2); + ar9580_1p0_rx_gain_table); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9580_1p0_low_ob_db_tx_gain_table, - ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), - 5); + ar9580_1p0_low_ob_db_tx_gain_table); INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9580_1p0_modes_fast_clock, - ARRAY_SIZE(ar9580_1p0_modes_fast_clock), - 3); + ar9580_1p0_modes_fast_clock); } else { /* mac */ - INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE], - ar9300_2p2_mac_core, - ARRAY_SIZE(ar9300_2p2_mac_core), 2); + ar9300_2p2_mac_core); INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST], - ar9300_2p2_mac_postamble, - ARRAY_SIZE(ar9300_2p2_mac_postamble), 5); + ar9300_2p2_mac_postamble); /* bb */ - INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE], - ar9300_2p2_baseband_core, - ARRAY_SIZE(ar9300_2p2_baseband_core), 2); + ar9300_2p2_baseband_core); INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST], - ar9300_2p2_baseband_postamble, - ARRAY_SIZE(ar9300_2p2_baseband_postamble), 5); + ar9300_2p2_baseband_postamble); /* radio */ - INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE], - ar9300_2p2_radio_core, - ARRAY_SIZE(ar9300_2p2_radio_core), 2); + ar9300_2p2_radio_core); INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST], - ar9300_2p2_radio_postamble, - ARRAY_SIZE(ar9300_2p2_radio_postamble), 5); + ar9300_2p2_radio_postamble); /* soc */ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE], - ar9300_2p2_soc_preamble, - ARRAY_SIZE(ar9300_2p2_soc_preamble), 2); - INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0); + ar9300_2p2_soc_preamble); INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST], - ar9300_2p2_soc_postamble, - ARRAY_SIZE(ar9300_2p2_soc_postamble), 5); + ar9300_2p2_soc_postamble); /* rx/tx gain */ INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), 2); + ar9300Common_rx_gain_table_2p2); INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), - 5); + ar9300Modes_lowest_ob_db_tx_gain_table_2p2); /* Load PCIE SERDES settings from INI */ /* Awake Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdes, - ar9300PciePhy_pll_on_clkreq_disable_L1_2p2, - ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2), - 2); + ar9300PciePhy_pll_on_clkreq_disable_L1_2p2); /* Sleep Setting */ INIT_INI_ARRAY(&ah->iniPcieSerdesLowPower, - ar9300PciePhy_pll_on_clkreq_disable_L1_2p2, - ARRAY_SIZE(ar9300PciePhy_pll_on_clkreq_disable_L1_2p2), - 2); + ar9300PciePhy_pll_on_clkreq_disable_L1_2p2); /* Fast clock modal settings */ INIT_INI_ARRAY(&ah->iniModesFastClock, - ar9300Modes_fast_clock_2p2, - ARRAY_SIZE(ar9300Modes_fast_clock_2p2), - 3); + ar9300Modes_fast_clock_2p2); } } @@ -507,156 +355,110 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p2), - 5); + ar9331_modes_lowest_ob_db_tx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_lowest_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_lowest_ob_db_tx_gain_1p1), - 5); + ar9331_modes_lowest_ob_db_tx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); + ar9340Modes_lowest_ob_db_tx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485_modes_lowest_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1), - 5); + ar9485_modes_lowest_ob_db_tx_gain_1_1); else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar955x_1p0_modes_xpa_tx_gain_table, - ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table), - 9); + ar955x_1p0_modes_xpa_tx_gain_table); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9580_1p0_lowest_ob_db_tx_gain_table, - ARRAY_SIZE(ar9580_1p0_lowest_ob_db_tx_gain_table), - 5); + ar9580_1p0_lowest_ob_db_tx_gain_table); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_low_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9462_modes_low_ob_db_tx_gain_table_2p0), - 5); + ar9462_modes_low_ob_db_tx_gain_table_2p0); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_lowest_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_lowest_ob_db_tx_gain_table_2p2), - 5); + ar9300Modes_lowest_ob_db_tx_gain_table_2p2); } static void ar9003_tx_gain_table_mode1(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p2), - 5); + ar9331_modes_high_ob_db_tx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_high_ob_db_tx_gain_1p1), - 5); + ar9331_modes_high_ob_db_tx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); + ar9340Modes_high_ob_db_tx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_high_ob_db_tx_gain_1_1), - 5); + ar9485Modes_high_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9580_1p0_high_ob_db_tx_gain_table, - ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table), - 5); + ar9580_1p0_high_ob_db_tx_gain_table); else if (AR_SREV_9550(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar955x_1p0_modes_no_xpa_tx_gain_table, - ARRAY_SIZE(ar955x_1p0_modes_no_xpa_tx_gain_table), - 9); + ar955x_1p0_modes_no_xpa_tx_gain_table); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9462_modes_high_ob_db_tx_gain_table_2p0, - ARRAY_SIZE(ar9462_modes_high_ob_db_tx_gain_table_2p0), - 5); + ar9462_modes_high_ob_db_tx_gain_table_2p0); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_high_ob_db_tx_gain_table_2p2), - 5); + ar9300Modes_high_ob_db_tx_gain_table_2p2); } static void ar9003_tx_gain_table_mode2(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_low_ob_db_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p2), - 5); + ar9331_modes_low_ob_db_tx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_low_ob_db_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_low_ob_db_tx_gain_1p1), - 5); + ar9331_modes_low_ob_db_tx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); + ar9340Modes_low_ob_db_tx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_low_ob_db_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_low_ob_db_tx_gain_1_1), - 5); + ar9485Modes_low_ob_db_tx_gain_1_1); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9580_1p0_low_ob_db_tx_gain_table, - ARRAY_SIZE(ar9580_1p0_low_ob_db_tx_gain_table), - 5); + ar9580_1p0_low_ob_db_tx_gain_table); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_low_ob_db_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_low_ob_db_tx_gain_table_2p2), - 5); + ar9300Modes_low_ob_db_tx_gain_table_2p2); } static void ar9003_tx_gain_table_mode3(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_power_tx_gain_1p2, - ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p2), - 5); + ar9331_modes_high_power_tx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9331_modes_high_power_tx_gain_1p1, - ARRAY_SIZE(ar9331_modes_high_power_tx_gain_1p1), - 5); + ar9331_modes_high_power_tx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9340Modes_lowest_ob_db_tx_gain_table_1p0, - ARRAY_SIZE(ar9340Modes_lowest_ob_db_tx_gain_table_1p0), - 5); + ar9340Modes_high_power_tx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9485Modes_high_power_tx_gain_1_1, - ARRAY_SIZE(ar9485Modes_high_power_tx_gain_1_1), - 5); + ar9485Modes_high_power_tx_gain_1_1); else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9580_1p0_high_power_tx_gain_table, - ARRAY_SIZE(ar9580_1p0_high_power_tx_gain_table), - 5); + ar9580_1p0_high_power_tx_gain_table); else INIT_INI_ARRAY(&ah->iniModesTxGain, - ar9300Modes_high_power_tx_gain_table_2p2, - ARRAY_SIZE(ar9300Modes_high_power_tx_gain_table_2p2), - 5); + ar9300Modes_high_power_tx_gain_table_2p2); +} + +static void ar9003_tx_gain_table_mode4(struct ath_hw *ah) +{ + if (AR_SREV_9340(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9340Modes_mixed_ob_db_tx_gain_table_1p0); + else if (AR_SREV_9580(ah)) + INIT_INI_ARRAY(&ah->iniModesTxGain, + ar9580_1p0_mixed_ob_db_tx_gain_table); } static void ar9003_tx_gain_table_apply(struct ath_hw *ah) @@ -675,6 +477,9 @@ static void ar9003_tx_gain_table_apply(struct ath_hw *ah) case 3: ar9003_tx_gain_table_mode3(ah); break; + case 4: + ar9003_tx_gain_table_mode4(ah); + break; } } @@ -682,104 +487,67 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p2, - ARRAY_SIZE(ar9331_common_rx_gain_1p2), - 2); + ar9331_common_rx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_rx_gain_1p1, - ARRAY_SIZE(ar9331_common_rx_gain_1p1), - 2); + ar9331_common_rx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9340Common_rx_gain_table_1p0, - ARRAY_SIZE(ar9340Common_rx_gain_table_1p0), - 2); + ar9340Common_rx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_1, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), - 2); + ar9485Common_wo_xlna_rx_gain_1_1); else if (AR_SREV_9550(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar955x_1p0_common_rx_gain_table, - ARRAY_SIZE(ar955x_1p0_common_rx_gain_table), - 2); + ar955x_1p0_common_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, - ar955x_1p0_common_rx_gain_bounds, - ARRAY_SIZE(ar955x_1p0_common_rx_gain_bounds), - 5); + ar955x_1p0_common_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9580_1p0_rx_gain_table, - ARRAY_SIZE(ar9580_1p0_rx_gain_table), - 2); + ar9580_1p0_rx_gain_table); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_rx_gain_table_2p0), - 2); + ar9462_common_rx_gain_table_2p0); else INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_rx_gain_table_2p2), - 2); + ar9300Common_rx_gain_table_2p2); } static void ar9003_rx_gain_table_mode1(struct ath_hw *ah) { if (AR_SREV_9330_12(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_wo_xlna_rx_gain_1p2, - ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p2), - 2); + ar9331_common_wo_xlna_rx_gain_1p2); else if (AR_SREV_9330_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9331_common_wo_xlna_rx_gain_1p1, - ARRAY_SIZE(ar9331_common_wo_xlna_rx_gain_1p1), - 2); + ar9331_common_wo_xlna_rx_gain_1p1); else if (AR_SREV_9340(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9340Common_wo_xlna_rx_gain_table_1p0, - ARRAY_SIZE(ar9340Common_wo_xlna_rx_gain_table_1p0), - 2); + ar9340Common_wo_xlna_rx_gain_table_1p0); else if (AR_SREV_9485_11(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9485Common_wo_xlna_rx_gain_1_1, - ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1), - 2); + ar9485Common_wo_xlna_rx_gain_1_1); else if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_wo_xlna_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0), - 2); + ar9462_common_wo_xlna_rx_gain_table_2p0); else if (AR_SREV_9550(ah)) { INIT_INI_ARRAY(&ah->iniModesRxGain, - ar955x_1p0_common_wo_xlna_rx_gain_table, - ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table), - 2); + ar955x_1p0_common_wo_xlna_rx_gain_table); INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds, - ar955x_1p0_common_wo_xlna_rx_gain_bounds, - ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds), - 5); + ar955x_1p0_common_wo_xlna_rx_gain_bounds); } else if (AR_SREV_9580(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9580_1p0_wo_xlna_rx_gain_table, - ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table), - 2); + ar9580_1p0_wo_xlna_rx_gain_table); else INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9300Common_wo_xlna_rx_gain_table_2p2, - ARRAY_SIZE(ar9300Common_wo_xlna_rx_gain_table_2p2), - 2); + ar9300Common_wo_xlna_rx_gain_table_2p2); } static void ar9003_rx_gain_table_mode2(struct ath_hw *ah) { if (AR_SREV_9462_20(ah)) INIT_INI_ARRAY(&ah->iniModesRxGain, - ar9462_common_mixed_rx_gain_table_2p0, - ARRAY_SIZE(ar9462_common_mixed_rx_gain_table_2p0), 2); + ar9462_common_mixed_rx_gain_table_2p0); } static void ar9003_rx_gain_table_apply(struct ath_hw *ah) diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c index d2346db..e476f9f 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c @@ -117,8 +117,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan) ah->is_clk_25mhz) { u32 chan_frac; - channelSel = (freq * 2) / 75; - chan_frac = (((freq * 2) % 75) * 0x20000) / 75; + channelSel = freq / 75; + chan_frac = ((freq % 75) * 0x20000) / 75; channelSel = (channelSel << 17) | chan_frac; } else { channelSel = CHANSEL_5G(freq); diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h index 751c83b..7bfbaf0 100644 --- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h +++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h @@ -633,6 +633,8 @@ #define AR_PHY_65NM_CH0_BIAS2 0x160c4 #define AR_PHY_65NM_CH0_BIAS4 0x160cc #define AR_PHY_65NM_CH0_RXTX4 0x1610c +#define AR_PHY_65NM_CH1_RXTX4 0x1650c +#define AR_PHY_65NM_CH2_RXTX4 0x1690c #define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \ ((AR_SREV_9462(ah) ? 0x1628c : 0x16280))) @@ -876,6 +878,9 @@ #define AR_PHY_65NM_CH0_RXTX4_THERM_ON 0x10000000 #define AR_PHY_65NM_CH0_RXTX4_THERM_ON_S 28 +#define AR_PHY_65NM_RXTX4_XLNA_BIAS 0xC0000000 +#define AR_PHY_65NM_RXTX4_XLNA_BIAS_S 30 + /* * Channel 1 Register Map */ diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h index 79840d6..b09285c 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -297,6 +297,8 @@ struct ath_tx { struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; struct ath_descdma txdma; struct ath_txq *txq_map[WME_NUM_AC]; + u32 txq_max_pending[WME_NUM_AC]; + u16 max_aggr_framelen[WME_NUM_AC][4][32]; }; struct ath_rx_edma { @@ -341,6 +343,7 @@ int ath_tx_init(struct ath_softc *sc, int nbufs); void ath_tx_cleanup(struct ath_softc *sc); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); +void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop); int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); @@ -360,7 +363,7 @@ void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc, struct ath_vif { int av_bslot; - bool is_bslot_active, primary_sta_vif; + bool primary_sta_vif; __le64 tsf_adjust; /* TSF adjustment for staggered beacons */ struct ath_buf *av_bcbuf; }; @@ -386,6 +389,7 @@ struct ath_beacon_config { u16 dtim_period; u16 bmiss_timeout; u8 dtim_count; + bool enable_beacon; }; struct ath_beacon { @@ -397,7 +401,6 @@ struct ath_beacon { u32 beaconq; u32 bmisscnt; - u32 ast_be_xmit; u32 bc_tstamp; struct ieee80211_vif *bslot[ATH_BCBUF]; int slottime; @@ -411,12 +414,14 @@ struct ath_beacon { bool tx_last; }; -void ath_beacon_tasklet(unsigned long data); -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); -int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); -void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); -int ath_beaconq_config(struct ath_softc *sc); -void ath_set_beacon(struct ath_softc *sc); +void ath9k_beacon_tasklet(unsigned long data); +bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, + u32 changed); +void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif); +void ath9k_set_beacon(struct ath_softc *sc); void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); /*******************/ @@ -442,9 +447,12 @@ void ath_rx_poll(unsigned long data); void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon); void ath_paprd_calibrate(struct work_struct *work); void ath_ani_calibrate(unsigned long data); -void ath_start_ani(struct ath_common *common); +void ath_start_ani(struct ath_softc *sc); +void ath_stop_ani(struct ath_softc *sc); +void ath_check_ani(struct ath_softc *sc); int ath_update_survey_stats(struct ath_softc *sc); void ath_update_survey_nf(struct ath_softc *sc, int channel); +void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type); /**********/ /* BTCOEX */ @@ -510,6 +518,12 @@ static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ +struct ath9k_wow_pattern { + u8 pattern_bytes[MAX_PATTERN_SIZE]; + u8 mask_bytes[MAX_PATTERN_SIZE]; + u32 pattern_len; +}; + /********************/ /* LED Control */ /********************/ @@ -613,7 +627,6 @@ enum sc_op_flags { SC_OP_INVALID, SC_OP_BEACONS, SC_OP_RXFLUSH, - SC_OP_TSF_RESET, SC_OP_ANI_RUN, SC_OP_PRIM_STA_VIF, SC_OP_HW_RESET, @@ -711,6 +724,13 @@ struct ath_softc { struct ath_ant_comb ant_comb; u8 ant_tx, ant_rx; struct dfs_pattern_detector *dfs_detector; + u32 wow_enabled; + +#ifdef CONFIG_PM_SLEEP + atomic_t wow_got_bmiss_intr; + atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */ + u32 wow_intr_before_sleep; +#endif }; void ath9k_tasklet(unsigned long data); diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 40775da..76f07d8 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c @@ -30,7 +30,7 @@ static void ath9k_reset_beacon_status(struct ath_softc *sc) * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max */ -int ath_beaconq_config(struct ath_softc *sc) +static void ath9k_beaconq_config(struct ath_softc *sc) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -38,6 +38,7 @@ int ath_beaconq_config(struct ath_softc *sc) struct ath_txq *txq; ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; @@ -56,12 +57,9 @@ int ath_beaconq_config(struct ath_softc *sc) } if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { - ath_err(common, - "Unable to update h/w beacon queue parameters\n"); - return 0; + ath_err(common, "Unable to update h/w beacon queue parameters\n"); } else { ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); - return 1; } } @@ -70,7 +68,7 @@ int ath_beaconq_config(struct ath_softc *sc) * up rate codes, and channel flags. Beacons are always sent out at the * lowest rate, and are not retried. */ -static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, +static void ath9k_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, struct ath_buf *bf, int rateidx) { struct sk_buff *skb = bf->bf_mpdu; @@ -81,8 +79,6 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, u8 chainmask = ah->txchainmask; u8 rate = 0; - ath9k_reset_beacon_status(sc); - sband = &sc->sbands[common->hw->conf.channel->band]; rate = sband->bitrates[rateidx].hw_value; if (vif->bss_conf.use_short_preamble) @@ -111,7 +107,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ieee80211_vif *vif, ath9k_hw_set_txdesc(ah, bf->bf_desc, &info); } -static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) +static void ath9k_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); @@ -128,28 +124,22 @@ static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) } } -static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) +static struct ath_buf *ath9k_beacon_generate(struct ieee80211_hw *hw, + struct ieee80211_vif *vif) { struct ath_softc *sc = hw->priv; struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_buf *bf; - struct ath_vif *avp; + struct ath_vif *avp = (void *)vif->drv_priv; struct sk_buff *skb; - struct ath_txq *cabq; + struct ath_txq *cabq = sc->beacon.cabq; struct ieee80211_tx_info *info; + struct ieee80211_mgmt *mgmt_hdr; int cabq_depth; - ath9k_reset_beacon_status(sc); - - avp = (void *)vif->drv_priv; - cabq = sc->beacon.cabq; - - if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active) + if (avp->av_bcbuf == NULL) return NULL; - /* Release the old beacon first */ - bf = avp->av_bcbuf; skb = bf->bf_mpdu; if (skb) { @@ -159,14 +149,14 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, bf->bf_buf_addr = 0; } - /* Get a new beacon from mac80211 */ - skb = ieee80211_beacon_get(hw, vif); - bf->bf_mpdu = skb; if (skb == NULL) return NULL; - ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = - avp->tsf_adjust; + + bf->bf_mpdu = skb; + + mgmt_hdr = (struct ieee80211_mgmt *)skb->data; + mgmt_hdr->u.beacon.timestamp = avp->tsf_adjust; info = IEEE80211_SKB_CB(skb); if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { @@ -212,61 +202,52 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, } } - ath_beacon_setup(sc, vif, bf, info->control.rates[0].idx); + ath9k_beacon_setup(sc, vif, bf, info->control.rates[0].idx); while (skb) { - ath_tx_cabq(hw, skb); + ath9k_tx_cabq(hw, skb); skb = ieee80211_get_buffered_bc(hw, vif); } return bf; } -int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) +void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ath_vif *avp; - struct ath_buf *bf; - struct sk_buff *skb; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - __le64 tstamp; - - avp = (void *)vif->drv_priv; - - /* Allocate a beacon descriptor if we haven't done so. */ - if (!avp->av_bcbuf) { - /* Allocate beacon state for hostap/ibss. We know - * a buffer is available. */ - avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, - struct ath_buf, list); - list_del(&avp->av_bcbuf->list); - - if (ath9k_uses_beacons(vif->type)) { - int slot; - /* - * Assign the vif to a beacon xmit slot. As - * above, this cannot fail to find one. - */ - avp->av_bslot = 0; - for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->beacon.bslot[slot] == NULL) { - avp->av_bslot = slot; - avp->is_bslot_active = false; - - /* NB: keep looking for a double slot */ - if (slot == 0 || !sc->beacon.bslot[slot-1]) - break; - } - BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); - sc->beacon.bslot[avp->av_bslot] = vif; - sc->nbcnvifs++; + struct ath_vif *avp = (void *)vif->drv_priv; + int slot; + + avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list); + list_del(&avp->av_bcbuf->list); + + for (slot = 0; slot < ATH_BCBUF; slot++) { + if (sc->beacon.bslot[slot] == NULL) { + avp->av_bslot = slot; + break; } } - /* release the previous beacon frame, if it already exists. */ - bf = avp->av_bcbuf; - if (bf->bf_mpdu != NULL) { - skb = bf->bf_mpdu; + sc->beacon.bslot[avp->av_bslot] = vif; + sc->nbcnvifs++; + + ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n", + avp->av_bslot); +} + +void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_vif *avp = (void *)vif->drv_priv; + struct ath_buf *bf = avp->av_bcbuf; + + ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n", + avp->av_bslot); + + tasklet_disable(&sc->bcon_tasklet); + + if (bf && bf->bf_mpdu) { + struct sk_buff *skb = bf->bf_mpdu; dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE); dev_kfree_skb_any(skb); @@ -274,99 +255,74 @@ int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) bf->bf_buf_addr = 0; } - /* NB: the beacon data buffer must be 32-bit aligned. */ - skb = ieee80211_beacon_get(sc->hw, vif); - if (skb == NULL) - return -ENOMEM; + avp->av_bcbuf = NULL; + sc->beacon.bslot[avp->av_bslot] = NULL; + sc->nbcnvifs--; + list_add_tail(&bf->list, &sc->beacon.bbuf); - tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); - /* Calculate a TSF adjustment factor required for staggered beacons. */ - if (avp->av_bslot > 0) { - u64 tsfadjust; - int intval; - - intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; + tasklet_enable(&sc->bcon_tasklet); +} - /* - * Calculate the TSF offset for this beacon slot, i.e., the - * number of usecs that need to be added to the timestamp field - * in Beacon and Probe Response frames. Beacon slot 0 is - * processed at the correct offset, so it does not require TSF - * adjustment. Other slots are adjusted to get the timestamp - * close to the TBTT for the BSS. - */ - tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; - avp->tsf_adjust = cpu_to_le64(tsfadjust); +static int ath9k_beacon_choose_slot(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + u16 intval; + u32 tsftu; + u64 tsf; + int slot; - ath_dbg(common, BEACON, - "stagger beacons, bslot %d intval %u tsfadjust %llu\n", - avp->av_bslot, intval, (unsigned long long)tsfadjust); + if (sc->sc_ah->opmode != NL80211_IFTYPE_AP) { + ath_dbg(common, BEACON, "slot 0, tsf: %llu\n", + ath9k_hw_gettsf64(sc->sc_ah)); + return 0; + } - ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = - avp->tsf_adjust; - } else - avp->tsf_adjust = cpu_to_le64(0); + intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; + tsf = ath9k_hw_gettsf64(sc->sc_ah); + tsf += TU_TO_USEC(sc->sc_ah->config.sw_beacon_response_time); + tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); + slot = (tsftu % (intval * ATH_BCBUF)) / intval; - bf->bf_mpdu = skb; - bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, - skb->len, DMA_TO_DEVICE); - if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - bf->bf_buf_addr = 0; - ath_err(common, "dma_mapping_error on beacon alloc\n"); - return -ENOMEM; - } - avp->is_bslot_active = true; + ath_dbg(common, BEACON, "slot: %d tsf: %llu tsftu: %u\n", + slot, tsf, tsftu / ATH_BCBUF); - return 0; + return slot; } -void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) +void ath9k_set_tsfadjust(struct ath_softc *sc, struct ieee80211_vif *vif) { - if (avp->av_bcbuf != NULL) { - struct ath_buf *bf; - - avp->is_bslot_active = false; - if (avp->av_bslot != -1) { - sc->beacon.bslot[avp->av_bslot] = NULL; - sc->nbcnvifs--; - avp->av_bslot = -1; - } + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + struct ath_vif *avp = (void *)vif->drv_priv; + u64 tsfadjust; - bf = avp->av_bcbuf; - if (bf->bf_mpdu != NULL) { - struct sk_buff *skb = bf->bf_mpdu; - dma_unmap_single(sc->dev, bf->bf_buf_addr, - skb->len, DMA_TO_DEVICE); - dev_kfree_skb_any(skb); - bf->bf_mpdu = NULL; - bf->bf_buf_addr = 0; - } - list_add_tail(&bf->list, &sc->beacon.bbuf); + if (avp->av_bslot == 0) + return; - avp->av_bcbuf = NULL; - } + tsfadjust = cur_conf->beacon_interval * avp->av_bslot / ATH_BCBUF; + avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); + + ath_dbg(common, CONFIG, "tsfadjust is: %llu for bslot: %d\n", + (unsigned long long)tsfadjust, avp->av_bslot); } -void ath_beacon_tasklet(unsigned long data) +void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath_buf *bf = NULL; struct ieee80211_vif *vif; bool edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA); int slot; - u32 bfaddr, bc = 0; - if (work_pending(&sc->hw_reset_work)) { + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) { ath_dbg(common, RESET, "reset work is pending, skip beaconing now\n"); return; } + /* * Check if the previous beacon has gone out. If * not don't try to post another, skip this period @@ -390,55 +346,25 @@ void ath_beacon_tasklet(unsigned long data) } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { ath_dbg(common, BSTUCK, "beacon is officially stuck\n"); sc->beacon.bmisscnt = 0; - set_bit(SC_OP_TSF_RESET, &sc->sc_flags); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_BEACON_STUCK); } return; } - /* - * Generate beacon frames. we are sending frames - * staggered so calculate the slot for this frame based - * on the tsf to safeguard against missing an swba. - */ - - - if (ah->opmode == NL80211_IFTYPE_AP) { - u16 intval; - u32 tsftu; - u64 tsf; - - intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; - tsf = ath9k_hw_gettsf64(ah); - tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); - tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); - slot = (tsftu % (intval * ATH_BCBUF)) / intval; - vif = sc->beacon.bslot[slot]; - - ath_dbg(common, BEACON, - "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", - slot, tsf, tsftu / ATH_BCBUF, intval, vif); - } else { - slot = 0; - vif = sc->beacon.bslot[slot]; - } + slot = ath9k_beacon_choose_slot(sc); + vif = sc->beacon.bslot[slot]; + if (!vif || !vif->bss_conf.enable_beacon) + return; - bfaddr = 0; - if (vif) { - bf = ath_beacon_generate(sc->hw, vif); - if (bf != NULL) { - bfaddr = bf->bf_daddr; - bc = 1; - } + bf = ath9k_beacon_generate(sc->hw, vif); + WARN_ON(!bf); - if (sc->beacon.bmisscnt != 0) { - ath_dbg(common, BSTUCK, - "resume beacon xmit after %u misses\n", - sc->beacon.bmisscnt); - sc->beacon.bmisscnt = 0; - } + if (sc->beacon.bmisscnt != 0) { + ath_dbg(common, BSTUCK, "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); + sc->beacon.bmisscnt = 0; } /* @@ -458,39 +384,40 @@ void ath_beacon_tasklet(unsigned long data) * set to ATH_BCBUF so this check is a noop. */ if (sc->beacon.updateslot == UPDATE) { - sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.updateslot = COMMIT; sc->beacon.slotupdate = slot; - } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { + } else if (sc->beacon.updateslot == COMMIT && + sc->beacon.slotupdate == slot) { ah->slottime = sc->beacon.slottime; ath9k_hw_init_global_settings(ah); sc->beacon.updateslot = OK; } - if (bfaddr != 0) { + + if (bf) { + ath9k_reset_beacon_status(sc); + + ath_dbg(common, BEACON, + "Transmitting beacon for slot: %d\n", slot); + /* NB: cabq traffic should already be queued and primed */ - ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); if (!edma) ath9k_hw_txstart(ah, sc->beacon.beaconq); - - sc->beacon.ast_be_xmit += bc; /* XXX per-vif? */ } } -static void ath9k_beacon_init(struct ath_softc *sc, - u32 next_beacon, - u32 beacon_period) +static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval) { - if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) { - ath9k_ps_wakeup(sc); - ath9k_hw_reset_tsf(sc->sc_ah); - } - - ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); + struct ath_hw *ah = sc->sc_ah; - if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) { - ath9k_ps_restore(sc); - clear_bit(SC_OP_TSF_RESET, &sc->sc_flags); - } + ath9k_hw_disable_interrupts(ah); + ath9k_hw_reset_tsf(ah); + ath9k_beaconq_config(sc); + ath9k_hw_beaconinit(ah, nexttbtt, intval); + sc->beacon.bmisscnt = 0; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); } /* @@ -498,32 +425,27 @@ static void ath9k_beacon_init(struct ath_softc *sc, * burst together. For the former arrange for the SWBA to be delivered for each * slot. Slots that are not occupied will generate nothing. */ -static void ath_beacon_config_ap(struct ath_softc *sc, - struct ath_beacon_config *conf) +static void ath9k_beacon_config_ap(struct ath_softc *sc, + struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); u32 nexttbtt, intval; /* NB: the beacon interval is kept internally in TU's */ intval = TU_TO_USEC(conf->beacon_interval); - intval /= ATH_BCBUF; /* for staggered beacons */ + intval /= ATH_BCBUF; nexttbtt = intval; - /* - * In AP mode we enable the beacon timers and SWBA interrupts to - * prepare beacon frames. - */ - ah->imask |= ATH9K_INT_SWBA; - ath_beaconq_config(sc); + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; - /* Set the computed AP beacon timers */ + ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n", + nexttbtt, intval, conf->beacon_interval); - ath9k_hw_disable_interrupts(ah); - set_bit(SC_OP_TSF_RESET, &sc->sc_flags); ath9k_beacon_init(sc, nexttbtt, intval); - sc->beacon.bmisscnt = 0; - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); } /* @@ -534,8 +456,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc, * we'll receive a BMISS interrupt when we stop seeing beacons from the AP * we've associated with. */ -static void ath_beacon_config_sta(struct ath_softc *sc, - struct ath_beacon_config *conf) +static void ath9k_beacon_config_sta(struct ath_softc *sc, + struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -547,7 +469,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc, int num_beacons, offset, dtim_dec_count, cfp_dec_count; /* No need to configure beacon if we are not associated */ - if (!common->curaid) { + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { ath_dbg(common, BEACON, "STA is not yet associated..skipping beacon config\n"); return; @@ -654,97 +576,65 @@ static void ath_beacon_config_sta(struct ath_softc *sc, ath9k_hw_enable_interrupts(ah); } -static void ath_beacon_config_adhoc(struct ath_softc *sc, - struct ath_beacon_config *conf) +static void ath9k_beacon_config_adhoc(struct ath_softc *sc, + struct ath_beacon_config *conf) { struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); - u32 tsf, intval, nexttbtt; + u32 intval, nexttbtt; ath9k_reset_beacon_status(sc); - if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) - ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp); intval = TU_TO_USEC(conf->beacon_interval); - tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval); - nexttbtt = tsf + intval; - - ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n", - nexttbtt, intval, conf->beacon_interval); - - /* - * In IBSS mode enable the beacon timers but only enable SWBA interrupts - * if we need to manually prepare beacon frames. Otherwise we use a - * self-linked tx descriptor and let the hardware deal with things. - */ - ah->imask |= ATH9K_INT_SWBA; + nexttbtt = intval; - ath_beaconq_config(sc); + if (conf->enable_beacon) + ah->imask |= ATH9K_INT_SWBA; + else + ah->imask &= ~ATH9K_INT_SWBA; - /* Set the computed ADHOC beacon timers */ + ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n", + nexttbtt, intval, conf->beacon_interval); - ath9k_hw_disable_interrupts(ah); ath9k_beacon_init(sc, nexttbtt, intval); - sc->beacon.bmisscnt = 0; - - ath9k_hw_set_interrupts(ah); - ath9k_hw_enable_interrupts(ah); } -static bool ath9k_allow_beacon_config(struct ath_softc *sc, - struct ieee80211_vif *vif) +bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) { - struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; - /* - * Can not have different beacon interval on multiple - * AP interface case - */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && - (sc->nbcnvifs > 1) && - (vif->type == NL80211_IFTYPE_AP) && - (cur_conf->beacon_interval != bss_conf->beacon_int)) { - ath_dbg(common, CONFIG, - "Changing beacon interval of multiple AP interfaces !\n"); - return false; - } - /* - * Can not configure station vif's beacon config - * while on AP opmode - */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && - (vif->type != NL80211_IFTYPE_AP)) { - ath_dbg(common, CONFIG, - "STA vif's beacon not allowed on AP mode\n"); - return false; + if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { + if ((vif->type != NL80211_IFTYPE_AP) || + (sc->nbcnvifs > 1)) { + ath_dbg(common, CONFIG, + "An AP interface is already present !\n"); + return false; + } } - /* - * Do not allow beacon config if HW was already configured - * with another STA vif - */ - if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && - (vif->type == NL80211_IFTYPE_STATION) && - test_bit(SC_OP_BEACONS, &sc->sc_flags) && - !avp->primary_sta_vif) { - ath_dbg(common, CONFIG, - "Beacon already configured for a station interface\n"); - return false; + + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { + if ((vif->type == NL80211_IFTYPE_STATION) && + test_bit(SC_OP_BEACONS, &sc->sc_flags) && + !avp->primary_sta_vif) { + ath_dbg(common, CONFIG, + "Beacon already configured for a station interface\n"); + return false; + } } + return true; } -void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_cache_beacon_config(struct ath_softc *sc, + struct ieee80211_bss_conf *bss_conf) { + struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - if (!ath9k_allow_beacon_config(sc, vif)) - return; + ath_dbg(common, BEACON, + "Caching beacon data for BSS: %pM\n", bss_conf->bssid); - /* Setup the beacon configuration parameters */ cur_conf->beacon_interval = bss_conf->beacon_int; cur_conf->dtim_period = bss_conf->dtim_period; cur_conf->listen_interval = 1; @@ -769,73 +659,62 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) if (cur_conf->dtim_period == 0) cur_conf->dtim_period = 1; - ath_set_beacon(sc); } -static bool ath_has_valid_bslot(struct ath_softc *sc) +void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif, + u32 changed) { - struct ath_vif *avp; - int slot; - bool found = false; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; - for (slot = 0; slot < ATH_BCBUF; slot++) { - if (sc->beacon.bslot[slot]) { - avp = (void *)sc->beacon.bslot[slot]->drv_priv; - if (avp->is_bslot_active) { - found = true; - break; + if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) { + ath9k_cache_beacon_config(sc, bss_conf); + ath9k_set_beacon(sc); + set_bit(SC_OP_BEACONS, &sc->sc_flags); + } else { + /* + * Take care of multiple interfaces when + * enabling/disabling SWBA. + */ + if (changed & BSS_CHANGED_BEACON_ENABLED) { + if (!bss_conf->enable_beacon && + (sc->nbcnvifs <= 1)) { + cur_conf->enable_beacon = false; + } else if (bss_conf->enable_beacon) { + cur_conf->enable_beacon = true; + ath9k_cache_beacon_config(sc, bss_conf); } } + + if (cur_conf->beacon_interval) { + ath9k_set_beacon(sc); + + if (cur_conf->enable_beacon) + set_bit(SC_OP_BEACONS, &sc->sc_flags); + else + clear_bit(SC_OP_BEACONS, &sc->sc_flags); + } } - return found; } - -void ath_set_beacon(struct ath_softc *sc) +void ath9k_set_beacon(struct ath_softc *sc) { struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; switch (sc->sc_ah->opmode) { case NL80211_IFTYPE_AP: - if (ath_has_valid_bslot(sc)) - ath_beacon_config_ap(sc, cur_conf); + ath9k_beacon_config_ap(sc, cur_conf); break; case NL80211_IFTYPE_ADHOC: case NL80211_IFTYPE_MESH_POINT: - ath_beacon_config_adhoc(sc, cur_conf); + ath9k_beacon_config_adhoc(sc, cur_conf); break; case NL80211_IFTYPE_STATION: - ath_beacon_config_sta(sc, cur_conf); + ath9k_beacon_config_sta(sc, cur_conf); break; default: ath_dbg(common, CONFIG, "Unsupported beaconing mode\n"); return; } - - set_bit(SC_OP_BEACONS, &sc->sc_flags); -} - -void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) -{ - struct ath_hw *ah = sc->sc_ah; - - if (!ath_has_valid_bslot(sc)) { - clear_bit(SC_OP_BEACONS, &sc->sc_flags); - return; - } - - ath9k_ps_wakeup(sc); - if (status) { - /* Re-enable beaconing */ - ah->imask |= ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah); - } else { - /* Disable SWBA interrupt */ - ah->imask &= ~ATH9K_INT_SWBA; - ath9k_hw_set_interrupts(ah); - tasklet_kill(&sc->bcon_tasklet); - ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); - } - ath9k_ps_restore(sc); } diff --git a/drivers/net/wireless/ath/ath9k/calib.h b/drivers/net/wireless/ath/ath9k/calib.h index 3b33996d..1060c19 100644 --- a/drivers/net/wireless/ath/ath9k/calib.h +++ b/drivers/net/wireless/ath/ath9k/calib.h @@ -30,10 +30,10 @@ struct ar5416IniArray { u32 ia_columns; }; -#define INIT_INI_ARRAY(iniarray, array, rows, columns) do { \ +#define INIT_INI_ARRAY(iniarray, array) do { \ (iniarray)->ia_array = (u32 *)(array); \ - (iniarray)->ia_rows = (rows); \ - (iniarray)->ia_columns = (columns); \ + (iniarray)->ia_rows = ARRAY_SIZE(array); \ + (iniarray)->ia_columns = ARRAY_SIZE(array[0]); \ } while (0) #define INI_RA(iniarray, row, column) \ diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c index 5c3192f..68b643c 100644 --- a/drivers/net/wireless/ath/ath9k/debug.c +++ b/drivers/net/wireless/ath/ath9k/debug.c @@ -206,10 +206,9 @@ static ssize_t write_file_disable_ani(struct file *file, if (disable_ani) { clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); - del_timer_sync(&common->ani.timer); + ath_stop_ani(sc); } else { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); - ath_start_ani(common); + ath_check_ani(sc); } return count; @@ -1556,6 +1555,14 @@ int ath9k_init_debug(struct ath_hw *ah) &fops_interrupt); debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_xmit); + debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + &sc->tx.txq_max_pending[WME_AC_BK]); + debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + &sc->tx.txq_max_pending[WME_AC_BE]); + debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + &sc->tx.txq_max_pending[WME_AC_VI]); + debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy, + &sc->tx.txq_max_pending[WME_AC_VO]); debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc, &fops_stations); debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc, diff --git a/drivers/net/wireless/ath/ath9k/debug.h b/drivers/net/wireless/ath/ath9k/debug.h index d0f851c..8b9d080 100644 --- a/drivers/net/wireless/ath/ath9k/debug.h +++ b/drivers/net/wireless/ath/ath9k/debug.h @@ -32,6 +32,19 @@ struct ath_buf; #define RESET_STAT_INC(sc, type) do { } while (0) #endif +enum ath_reset_type { + RESET_TYPE_BB_HANG, + RESET_TYPE_BB_WATCHDOG, + RESET_TYPE_FATAL_INT, + RESET_TYPE_TX_ERROR, + RESET_TYPE_TX_HANG, + RESET_TYPE_PLL_HANG, + RESET_TYPE_MAC_HANG, + RESET_TYPE_BEACON_STUCK, + RESET_TYPE_MCI, + __RESET_TYPE_MAX +}; + #ifdef CONFIG_ATH9K_DEBUGFS /** @@ -209,17 +222,6 @@ struct ath_rx_stats { u32 rx_frags; }; -enum ath_reset_type { - RESET_TYPE_BB_HANG, - RESET_TYPE_BB_WATCHDOG, - RESET_TYPE_FATAL_INT, - RESET_TYPE_TX_ERROR, - RESET_TYPE_TX_HANG, - RESET_TYPE_PLL_HANG, - RESET_TYPE_MAC_HANG, - __RESET_TYPE_MAX -}; - struct ath_stats { struct ath_interrupt_stats istats; struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES]; diff --git a/drivers/net/wireless/ath/ath9k/eeprom.h b/drivers/net/wireless/ath/ath9k/eeprom.h index 33acb92..484b313 100644 --- a/drivers/net/wireless/ath/ath9k/eeprom.h +++ b/drivers/net/wireless/ath/ath9k/eeprom.h @@ -241,16 +241,12 @@ enum eeprom_param { EEP_TEMPSENSE_SLOPE, EEP_TEMPSENSE_SLOPE_PAL_ON, EEP_PWR_TABLE_OFFSET, - EEP_DRIVE_STRENGTH, - EEP_INTERNAL_REGULATOR, - EEP_SWREG, EEP_PAPRD, EEP_MODAL_VER, EEP_ANT_DIV_CTL1, EEP_CHAIN_MASK_REDUCE, EEP_ANTENNA_GAIN_2G, EEP_ANTENNA_GAIN_5G, - EEP_QUICK_DROP }; enum ar5416_rates { diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_main.c b/drivers/net/wireless/ath/ath9k/htc_drv_main.c index 374c32e..c785129 100644 --- a/drivers/net/wireless/ath/ath9k/htc_drv_main.c +++ b/drivers/net/wireless/ath/ath9k/htc_drv_main.c @@ -1111,7 +1111,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw, if ((priv->ah->opmode == NL80211_IFTYPE_AP) && !test_bit(OP_ANI_RUNNING, &priv->op_flags)) { - ath9k_hw_set_tsfadjust(priv->ah, 1); + ath9k_hw_set_tsfadjust(priv->ah, true); ath9k_htc_start_ani(priv); } @@ -1351,7 +1351,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw, qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; - qi.tqi_burstTime = params->txop; + qi.tqi_burstTime = params->txop * 32; qnum = get_hw_qnum(queue, priv->hwq_map); diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c index c1659d0..cfa91ab 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -671,10 +671,6 @@ static int __ath9k_hw_init(struct ath_hw *ah) if (!AR_SREV_9300_20_OR_LATER(ah)) ah->ani_function &= ~ATH9K_ANI_MRC_CCK; - /* disable ANI for 9340 */ - if (AR_SREV_9340(ah)) - ah->config.enable_ani = false; - ath9k_hw_init_mode_regs(ah); if (!ah->is_pciexpress) @@ -2589,6 +2585,14 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah) } + if (AR_SREV_9280_20_OR_LATER(ah)) { + pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE | + ATH9K_HW_WOW_PATTERN_MATCH_EXACT; + + if (AR_SREV_9280(ah)) + pCap->hw_caps |= ATH9K_HW_WOW_PATTERN_MATCH_DWORD; + } + return 0; } @@ -2908,9 +2912,9 @@ void ath9k_hw_reset_tsf(struct ath_hw *ah) } EXPORT_SYMBOL(ath9k_hw_reset_tsf); -void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting) +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set) { - if (setting) + if (set) ah->misc_mode |= AR_PCU_TX_ADD_TSF; else ah->misc_mode &= ~AR_PCU_TX_ADD_TSF; diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h index 26da173..dd0c146 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -180,6 +180,37 @@ #define PAPRD_TABLE_SZ 24 #define PAPRD_IDEAL_AGC2_PWR_RANGE 0xe0 +/* + * Wake on Wireless + */ + +/* Keep Alive Frame */ +#define KAL_FRAME_LEN 28 +#define KAL_FRAME_TYPE 0x2 /* data frame */ +#define KAL_FRAME_SUB_TYPE 0x4 /* null data frame */ +#define KAL_DURATION_ID 0x3d +#define KAL_NUM_DATA_WORDS 6 +#define KAL_NUM_DESC_WORDS 12 +#define KAL_ANTENNA_MODE 1 +#define KAL_TO_DS 1 +#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */ +#define KAL_TIMEOUT 900 + +#define MAX_PATTERN_SIZE 256 +#define MAX_PATTERN_MASK_SIZE 32 +#define MAX_NUM_PATTERN 8 +#define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and + deauthenticate packets */ + +/* + * WoW trigger mapping to hardware code + */ + +#define AH_WOW_USER_PATTERN_EN BIT(0) +#define AH_WOW_MAGIC_PATTERN_EN BIT(1) +#define AH_WOW_LINK_CHANGE BIT(2) +#define AH_WOW_BEACON_MISS BIT(3) + enum ath_hw_txq_subtype { ATH_TXQ_AC_BE = 0, ATH_TXQ_AC_BK = 1, @@ -212,8 +243,22 @@ enum ath9k_hw_caps { ATH9K_HW_CAP_RTT = BIT(14), ATH9K_HW_CAP_MCI = BIT(15), ATH9K_HW_CAP_DFS = BIT(16), + ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(17), + ATH9K_HW_WOW_PATTERN_MATCH_EXACT = BIT(18), + ATH9K_HW_WOW_PATTERN_MATCH_DWORD = BIT(19), }; +/* + * WoW device capabilities + * @ATH9K_HW_WOW_DEVICE_CAPABLE: device revision is capable of WoW. + * @ATH9K_HW_WOW_PATTERN_MATCH_EXACT: device is capable of matching + * an exact user defined pattern or de-authentication/disassoc pattern. + * @ATH9K_HW_WOW_PATTERN_MATCH_DWORD: device requires the first four + * bytes of the pattern for user defined pattern, de-authentication and + * disassociation patterns for all types of possible frames recieved + * of those types. + */ + struct ath9k_hw_capabilities { u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */ u16 rts_aggr_limit; @@ -815,6 +860,9 @@ struct ath_hw { struct ar5416IniArray iniBank7; struct ar5416IniArray iniAddac; struct ar5416IniArray iniPcieSerdes; +#ifdef CONFIG_PM_SLEEP + struct ar5416IniArray iniPcieSerdesWow; +#endif struct ar5416IniArray iniPcieSerdesLowPower; struct ar5416IniArray iniModesFastClock; struct ar5416IniArray iniAdditional; @@ -863,6 +911,9 @@ struct ath_hw { /* Enterprise mode cap */ u32 ent_mode; +#ifdef CONFIG_PM_SLEEP + u32 wow_event_mask; +#endif bool is_clk_25mhz; int (*get_mac_revision)(void); int (*external_reset)(void); @@ -943,7 +994,7 @@ u32 ath9k_hw_gettsf32(struct ath_hw *ah); u64 ath9k_hw_gettsf64(struct ath_hw *ah); void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64); void ath9k_hw_reset_tsf(struct ath_hw *ah); -void ath9k_hw_set_tsfadjust(struct ath_hw *ah, u32 setting); +void ath9k_hw_set_tsfadjust(struct ath_hw *ah, bool set); void ath9k_hw_init_global_settings(struct ath_hw *ah); u32 ar9003_get_pll_sqsum_dvc(struct ath_hw *ah); void ath9k_hw_set11nmac2040(struct ath_hw *ah); @@ -1061,6 +1112,37 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah) } #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */ + +#ifdef CONFIG_PM_SLEEP +const char *ath9k_hw_wow_event_to_string(u32 wow_event); +void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len); +u32 ath9k_hw_wow_wakeup(struct ath_hw *ah); +void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable); +#else +static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event) +{ + return NULL; +} +static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, + u8 *user_pattern, + u8 *user_mask, + int pattern_count, + int pattern_len) +{ +} +static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) +{ + return 0; +} +static inline void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +{ +} +#endif + + + #define ATH9K_CLOCK_RATE_CCK 22 #define ATH9K_CLOCK_RATE_5GHZ_OFDM 40 #define ATH9K_CLOCK_RATE_2GHZ_OFDM 44 diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c index 9dfce1a..f337121 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -434,6 +434,7 @@ static int ath9k_init_queues(struct ath_softc *sc) for (i = 0; i < WME_NUM_AC; i++) { sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i); sc->tx.txq_map[i]->mac80211_qnum = i; + sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH; } return 0; } @@ -558,7 +559,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, spin_lock_init(&sc->debug.samp_lock); #endif tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet, + tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, (unsigned long)sc); INIT_WORK(&sc->hw_reset_work, ath_reset_work); @@ -713,6 +714,24 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS; hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL; +#ifdef CONFIG_PM_SLEEP + + if ((ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) && + device_can_wakeup(sc->dev)) { + + hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT | + WIPHY_WOWLAN_DISCONNECT; + hw->wiphy->wowlan.n_patterns = MAX_NUM_USER_PATTERN; + hw->wiphy->wowlan.pattern_min_len = 1; + hw->wiphy->wowlan.pattern_max_len = MAX_PATTERN_SIZE; + + } + + atomic_set(&sc->wow_sleep_proc_intr, -1); + atomic_set(&sc->wow_got_bmiss_intr, -1); + +#endif + hw->queues = 4; hw->max_rates = 4; hw->channel_change_time = 5000; diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c index 91650fe..d4549e9 100644 --- a/drivers/net/wireless/ath/ath9k/link.c +++ b/drivers/net/wireless/ath/ath9k/link.c @@ -50,8 +50,7 @@ void ath_tx_complete_poll_work(struct work_struct *work) if (needreset) { ath_dbg(ath9k_hw_common(sc->sc_ah), RESET, "tx hung, resetting the chip\n"); - RESET_STAT_INC(sc, RESET_TYPE_TX_HANG); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_TX_HANG); return; } @@ -69,6 +68,7 @@ void ath_hw_check(struct work_struct *work) unsigned long flags; int busy; u8 is_alive, nbeacon = 1; + enum ath_reset_type type; ath9k_ps_wakeup(sc); is_alive = ath9k_hw_check_alive(sc->sc_ah); @@ -78,7 +78,7 @@ void ath_hw_check(struct work_struct *work) else if (!is_alive && AR_SREV_9300(sc->sc_ah)) { ath_dbg(common, RESET, "DCU stuck is detected. Schedule chip reset\n"); - RESET_STAT_INC(sc, RESET_TYPE_MAC_HANG); + type = RESET_TYPE_MAC_HANG; goto sched_reset; } @@ -90,7 +90,7 @@ void ath_hw_check(struct work_struct *work) busy, sc->hw_busy_count + 1); if (busy >= 99) { if (++sc->hw_busy_count >= 3) { - RESET_STAT_INC(sc, RESET_TYPE_BB_HANG); + type = RESET_TYPE_BB_HANG; goto sched_reset; } } else if (busy >= 0) { @@ -102,7 +102,7 @@ void ath_hw_check(struct work_struct *work) goto out; sched_reset: - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, type); out: ath9k_ps_restore(sc); } @@ -119,8 +119,7 @@ static bool ath_hw_pll_rx_hang_check(struct ath_softc *sc, u32 pll_sqsum) count++; if (count == 3) { ath_dbg(common, RESET, "PLL WAR, resetting the chip\n"); - RESET_STAT_INC(sc, RESET_TYPE_PLL_HANG); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_PLL_HANG); count = 0; return true; } @@ -432,26 +431,72 @@ set_timer: } } -void ath_start_ani(struct ath_common *common) +void ath_start_ani(struct ath_softc *sc) { - struct ath_hw *ah = common->ah; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); unsigned long timestamp = jiffies_to_msecs(jiffies); - struct ath_softc *sc = (struct ath_softc *) common->priv; - - if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) - return; - if (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) + if (common->disable_ani || + !test_bit(SC_OP_ANI_RUN, &sc->sc_flags) || + (sc->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) return; common->ani.longcal_timer = timestamp; common->ani.shortcal_timer = timestamp; common->ani.checkani_timer = timestamp; + ath_dbg(common, ANI, "Starting ANI\n"); mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies((u32)ah->config.ani_poll_interval)); } +void ath_stop_ani(struct ath_softc *sc) +{ + struct ath_common *common = ath9k_hw_common(sc->sc_ah); + + ath_dbg(common, ANI, "Stopping ANI\n"); + del_timer_sync(&common->ani.timer); +} + +void ath_check_ani(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; + + /* + * Check for the various conditions in which ANI has to + * be stopped. + */ + if (ah->opmode == NL80211_IFTYPE_ADHOC) { + if (!cur_conf->enable_beacon) + goto stop_ani; + } else if (ah->opmode == NL80211_IFTYPE_AP) { + if (!cur_conf->enable_beacon) { + /* + * Disable ANI only when there are no + * associated stations. + */ + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + goto stop_ani; + } + } else if (ah->opmode == NL80211_IFTYPE_STATION) { + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + goto stop_ani; + } + + if (!test_bit(SC_OP_ANI_RUN, &sc->sc_flags)) { + set_bit(SC_OP_ANI_RUN, &sc->sc_flags); + ath_start_ani(sc); + } + + return; + +stop_ani: + clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); + ath_stop_ani(sc); +} + void ath_update_survey_nf(struct ath_softc *sc, int channel) { struct ath_hw *ah = sc->sc_ah; diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 248e5b2..6049d8b 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c @@ -19,6 +19,9 @@ #include "ath9k.h" #include "btcoex.h" +static void ath9k_set_assoc_state(struct ath_softc *sc, + struct ieee80211_vif *vif); + u8 ath9k_parse_mpdudensity(u8 mpdudensity) { /* @@ -167,8 +170,6 @@ static void ath_cancel_work(struct ath_softc *sc) static void ath_restart_work(struct ath_softc *sc) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); - ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || @@ -177,21 +178,18 @@ static void ath_restart_work(struct ath_softc *sc) msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); ath_start_rx_poll(sc, 3); - - if (!common->disable_ani) - ath_start_ani(common); + ath_start_ani(sc); } static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) { struct ath_hw *ah = sc->sc_ah; - struct ath_common *common = ath9k_hw_common(ah); bool ret = true; ieee80211_stop_queues(sc->hw); sc->hw_busy_count = 0; - del_timer_sync(&common->ani.timer); + ath_stop_ani(sc); del_timer_sync(&sc->rx_poll_timer); ath9k_debug_samp_bb_mac(sc); @@ -236,7 +234,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) goto work; - ath_set_beacon(sc); + ath9k_set_beacon(sc); if (ah->opmode == NL80211_IFTYPE_STATION && test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { @@ -365,6 +363,7 @@ void ath9k_tasklet(unsigned long data) struct ath_softc *sc = (struct ath_softc *)data; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); + enum ath_reset_type type; unsigned long flags; u32 status = sc->intrstatus; u32 rxmask; @@ -374,18 +373,13 @@ void ath9k_tasklet(unsigned long data) if ((status & ATH9K_INT_FATAL) || (status & ATH9K_INT_BB_WATCHDOG)) { -#ifdef CONFIG_ATH9K_DEBUGFS - enum ath_reset_type type; if (status & ATH9K_INT_FATAL) type = RESET_TYPE_FATAL_INT; else type = RESET_TYPE_BB_WATCHDOG; - RESET_STAT_INC(sc, type); -#endif - set_bit(SC_OP_HW_RESET, &sc->sc_flags); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, type); goto out; } @@ -493,6 +487,17 @@ irqreturn_t ath_isr(int irq, void *dev) if (status & SCHED_INTR) sched = true; +#ifdef CONFIG_PM_SLEEP + if (status & ATH9K_INT_BMISS) { + if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { + ath_dbg(common, ANY, "during WoW we got a BMISS\n"); + atomic_inc(&sc->wow_got_bmiss_intr); + atomic_dec(&sc->wow_sleep_proc_intr); + } + ath_dbg(common, INTERRUPT, "beacon miss interrupt\n"); + } +#endif + /* * If a FATAL or RXORN interrupt is received, we have to reset the * chip immediately. @@ -575,6 +580,15 @@ static int ath_reset(struct ath_softc *sc, bool retry_tx) return r; } +void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) +{ +#ifdef CONFIG_ATH9K_DEBUGFS + RESET_STAT_INC(sc, type); +#endif + set_bit(SC_OP_HW_RESET, &sc->sc_flags); + ieee80211_queue_work(sc->hw, &sc->hw_reset_work); +} + void ath_reset_work(struct work_struct *work) { struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); @@ -841,16 +855,6 @@ bool ath9k_uses_beacons(int type) } } -static void ath9k_reclaim_beacon(struct ath_softc *sc, - struct ieee80211_vif *vif) -{ - struct ath_vif *avp = (void *)vif->drv_priv; - - ath9k_set_beaconing_status(sc, false); - ath_beacon_return(sc, avp); - ath9k_set_beaconing_status(sc, true); -} - static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { struct ath9k_vif_iter_data *iter_data = data; @@ -882,6 +886,18 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) } } +static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) +{ + struct ath_softc *sc = data; + struct ath_vif *avp = (void *)vif->drv_priv; + + if (vif->type != NL80211_IFTYPE_STATION) + return; + + if (avp->primary_sta_vif) + ath9k_set_assoc_state(sc, vif); +} + /* Called with sc->mutex held. */ void ath9k_calculate_iter_data(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -915,21 +931,18 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ath9k_vif_iter_data iter_data; + enum nl80211_iftype old_opmode = ah->opmode; ath9k_calculate_iter_data(hw, vif, &iter_data); - /* Set BSSID mask. */ memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); ath_hw_setbssidmask(common); - /* Set op-mode & TSF */ if (iter_data.naps > 0) { - ath9k_hw_set_tsfadjust(ah, 1); - set_bit(SC_OP_TSF_RESET, &sc->sc_flags); + ath9k_hw_set_tsfadjust(ah, true); ah->opmode = NL80211_IFTYPE_AP; } else { - ath9k_hw_set_tsfadjust(ah, 0); - clear_bit(SC_OP_TSF_RESET, &sc->sc_flags); + ath9k_hw_set_tsfadjust(ah, false); if (iter_data.nmeshes) ah->opmode = NL80211_IFTYPE_MESH_POINT; @@ -941,9 +954,8 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ah->opmode = NL80211_IFTYPE_STATION; } - /* - * Enable MIB interrupts when there are hardware phy counters. - */ + ath9k_hw_setopmode(ah); + if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) ah->imask |= ATH9K_INT_TSFOOR; else @@ -951,34 +963,15 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, ath9k_hw_set_interrupts(ah); - /* Set up ANI */ - if (iter_data.naps > 0) { - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - if (!common->disable_ani) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); - ath_start_ani(common); - } - - } else { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); - del_timer_sync(&common->ani.timer); - } -} - -/* Called with sc->mutex held, vif counts set up properly. */ -static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, - struct ieee80211_vif *vif) -{ - struct ath_softc *sc = hw->priv; - - ath9k_calculate_summary_state(hw, vif); - - if (ath9k_uses_beacons(vif->type)) { - /* Reserve a beacon slot for the vif */ - ath9k_set_beaconing_status(sc, false); - ath_beacon_alloc(sc, vif); - ath9k_set_beaconing_status(sc, true); + /* + * If we are changing the opmode to STATION, + * a beacon sync needs to be done. + */ + if (ah->opmode == NL80211_IFTYPE_STATION && + old_opmode == NL80211_IFTYPE_AP && + test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + ieee80211_iterate_active_interfaces_atomic(sc->hw, + ath9k_sta_vif_iter, sc); } } @@ -1021,7 +1014,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, sc->nvifs++; - ath9k_do_vif_add_setup(hw, vif); + ath9k_calculate_summary_state(hw, vif); + if (ath9k_uses_beacons(vif->type)) + ath9k_beacon_assign_slot(sc, vif); + out: mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -1038,6 +1034,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, int ret = 0; ath_dbg(common, CONFIG, "Change Interface\n"); + mutex_lock(&sc->mutex); ath9k_ps_wakeup(sc); @@ -1050,15 +1047,16 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, } } - /* Clean up old vif stuff */ if (ath9k_uses_beacons(vif->type)) - ath9k_reclaim_beacon(sc, vif); + ath9k_beacon_remove_slot(sc, vif); - /* Add new settings */ vif->type = new_type; vif->p2p = p2p; - ath9k_do_vif_add_setup(hw, vif); + ath9k_calculate_summary_state(hw, vif); + if (ath9k_uses_beacons(vif->type)) + ath9k_beacon_assign_slot(sc, vif); + out: ath9k_ps_restore(sc); mutex_unlock(&sc->mutex); @@ -1078,9 +1076,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, sc->nvifs--; - /* Reclaim beacon resources */ if (ath9k_uses_beacons(vif->type)) - ath9k_reclaim_beacon(sc, vif); + ath9k_beacon_remove_slot(sc, vif); ath9k_calculate_summary_state(hw, NULL); @@ -1377,21 +1374,18 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, qi.tqi_aifs = params->aifs; qi.tqi_cwmin = params->cw_min; qi.tqi_cwmax = params->cw_max; - qi.tqi_burstTime = params->txop; + qi.tqi_burstTime = params->txop * 32; ath_dbg(common, CONFIG, "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", queue, txq->axq_qnum, params->aifs, params->cw_min, params->cw_max, params->txop); + ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime); ret = ath_txq_update(sc, txq->axq_qnum, &qi); if (ret) ath_err(common, "TXQ Update failed\n"); - if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) - if (queue == WME_AC_BE && !ret) - ath_beaconq_config(sc); - mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); @@ -1460,86 +1454,53 @@ static int ath9k_set_key(struct ieee80211_hw *hw, return ret; } -static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) + +static void ath9k_set_assoc_state(struct ath_softc *sc, + struct ieee80211_vif *vif) { - struct ath_softc *sc = data; struct ath_common *common = ath9k_hw_common(sc->sc_ah); - struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; struct ath_vif *avp = (void *)vif->drv_priv; + struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; unsigned long flags; + + set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + avp->primary_sta_vif = true; + /* - * Skip iteration if primary station vif's bss info - * was not changed + * Set the AID, BSSID and do beacon-sync only when + * the HW opmode is STATION. + * + * But the primary bit is set above in any case. */ - if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) + if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) return; - if (bss_conf->assoc) { - set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); - avp->primary_sta_vif = true; - memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); - common->curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah); - ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", - bss_conf->aid, common->curbssid); - ath_beacon_config(sc, vif); - /* - * Request a re-configuration of Beacon related timers - * on the receipt of the first Beacon frame (i.e., - * after time sync with the AP). - */ - spin_lock_irqsave(&sc->sc_pm_lock, flags); - sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; - spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - - /* Reset rssi stats */ - sc->last_rssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; + memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); + common->curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah); - ath_start_rx_poll(sc, 3); + sc->last_rssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - if (!common->disable_ani) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); - ath_start_ani(common); - } + spin_lock_irqsave(&sc->sc_pm_lock, flags); + sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; + spin_unlock_irqrestore(&sc->sc_pm_lock, flags); - } + ath_dbg(common, CONFIG, + "Primary Station interface: %pM, BSSID: %pM\n", + vif->addr, common->curbssid); } -static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) +static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) { - struct ath_common *common = ath9k_hw_common(sc->sc_ah); + struct ath_softc *sc = data; struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; - struct ath_vif *avp = (void *)vif->drv_priv; - if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) + if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) return; - /* Reconfigure bss info */ - if (avp->primary_sta_vif && !bss_conf->assoc) { - ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n", - common->curaid, common->curbssid); - clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); - clear_bit(SC_OP_BEACONS, &sc->sc_flags); - avp->primary_sta_vif = false; - memset(common->curbssid, 0, ETH_ALEN); - common->curaid = 0; - } - - ieee80211_iterate_active_interfaces_atomic( - sc->hw, ath9k_bss_iter, sc); - - /* - * None of station vifs are associated. - * Clear bssid & aid - */ - if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { - ath9k_hw_write_associd(sc->sc_ah); - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); - del_timer_sync(&common->ani.timer); - del_timer_sync(&sc->rx_poll_timer); - memset(&sc->caldata, 0, sizeof(sc->caldata)); - } + if (bss_conf->assoc) + ath9k_set_assoc_state(sc, vif); } static void ath9k_bss_info_changed(struct ieee80211_hw *hw, @@ -1547,6 +1508,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *bss_conf, u32 changed) { +#define CHECK_ANI \ + (BSS_CHANGED_ASSOC | \ + BSS_CHANGED_IBSS | \ + BSS_CHANGED_BEACON_ENABLED) + struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); @@ -1557,53 +1523,41 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, mutex_lock(&sc->mutex); if (changed & BSS_CHANGED_ASSOC) { - ath9k_config_bss(sc, vif); + ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", + bss_conf->bssid, bss_conf->assoc); - ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", - common->curbssid, common->curaid); + if (avp->primary_sta_vif && !bss_conf->assoc) { + clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); + avp->primary_sta_vif = false; + + if (ah->opmode == NL80211_IFTYPE_STATION) + clear_bit(SC_OP_BEACONS, &sc->sc_flags); + } + + ieee80211_iterate_active_interfaces_atomic(sc->hw, + ath9k_bss_assoc_iter, sc); + + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && + ah->opmode == NL80211_IFTYPE_STATION) { + memset(common->curbssid, 0, ETH_ALEN); + common->curaid = 0; + ath9k_hw_write_associd(sc->sc_ah); + } } if (changed & BSS_CHANGED_IBSS) { - /* There can be only one vif available */ memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); common->curaid = bss_conf->aid; ath9k_hw_write_associd(sc->sc_ah); - - if (bss_conf->ibss_joined) { - sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; - - if (!common->disable_ani) { - set_bit(SC_OP_ANI_RUN, &sc->sc_flags); - ath_start_ani(common); - } - - } else { - clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); - del_timer_sync(&common->ani.timer); - del_timer_sync(&sc->rx_poll_timer); - } } - /* - * In case of AP mode, the HW TSF has to be reset - * when the beacon interval changes. - */ - if ((changed & BSS_CHANGED_BEACON_INT) && - (vif->type == NL80211_IFTYPE_AP)) - set_bit(SC_OP_TSF_RESET, &sc->sc_flags); - - /* Configure beaconing (AP, IBSS, MESH) */ - if (ath9k_uses_beacons(vif->type) && - ((changed & BSS_CHANGED_BEACON) || - (changed & BSS_CHANGED_BEACON_ENABLED) || - (changed & BSS_CHANGED_BEACON_INT))) { - ath9k_set_beaconing_status(sc, false); - if (bss_conf->enable_beacon) - ath_beacon_alloc(sc, vif); - else - avp->is_bslot_active = false; - ath_beacon_config(sc, vif); - ath9k_set_beaconing_status(sc, true); + if ((changed & BSS_CHANGED_BEACON_ENABLED) || + (changed & BSS_CHANGED_BEACON_INT)) { + if (ah->opmode == NL80211_IFTYPE_AP && + bss_conf->enable_beacon) + ath9k_set_tsfadjust(sc, vif); + if (ath9k_allow_beacon_config(sc, vif)) + ath9k_beacon_config(sc, vif, changed); } if (changed & BSS_CHANGED_ERP_SLOT) { @@ -1625,8 +1579,13 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } } + if (changed & CHECK_ANI) + ath_check_ani(sc); + mutex_unlock(&sc->mutex); ath9k_ps_restore(sc); + +#undef CHECK_ANI } static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) @@ -1855,10 +1814,11 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) if (!vif) return 0; - avp = (void *)vif->drv_priv; - if (!avp->is_bslot_active) + if (!vif->bss_conf.enable_beacon) return 0; + avp = (void *)vif->drv_priv; + if (!sc->beacon.tx_processed && !edma) { tasklet_disable(&sc->bcon_tasklet); @@ -1912,12 +1872,29 @@ static u32 fill_chainmask(u32 cap, u32 new) return filled; } +static bool validate_antenna_mask(struct ath_hw *ah, u32 val) +{ + switch (val & 0x7) { + case 0x1: + case 0x3: + case 0x7: + return true; + case 0x2: + return (ah->caps.rx_chainmask == 1); + default: + return false; + } +} + static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) { struct ath_softc *sc = hw->priv; struct ath_hw *ah = sc->sc_ah; - if (!rx_ant || !tx_ant) + if (ah->caps.rx_chainmask != 1) + rx_ant |= tx_ant; + + if (!validate_antenna_mask(ah, rx_ant) || !tx_ant) return -EINVAL; sc->ant_rx = rx_ant; @@ -2075,6 +2052,362 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw, #endif +#ifdef CONFIG_PM_SLEEP + +static void ath9k_wow_map_triggers(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan, + u32 *wow_triggers) +{ + if (wowlan->disconnect) + *wow_triggers |= AH_WOW_LINK_CHANGE | + AH_WOW_BEACON_MISS; + if (wowlan->magic_pkt) + *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; + + if (wowlan->n_patterns) + *wow_triggers |= AH_WOW_USER_PATTERN_EN; + + sc->wow_enabled = *wow_triggers; + +} + +static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + struct ath9k_hw_capabilities *pcaps = &ah->caps; + int pattern_count = 0; + int i, byte_cnt; + u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; + u8 dis_deauth_mask[MAX_PATTERN_SIZE]; + + memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); + memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); + + /* + * Create Dissassociate / Deauthenticate packet filter + * + * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes + * +--------------+----------+---------+--------+--------+---- + * + Frame Control+ Duration + DA + SA + BSSID + + * +--------------+----------+---------+--------+--------+---- + * + * The above is the management frame format for disassociate/ + * deauthenticate pattern, from this we need to match the first byte + * of 'Frame Control' and DA, SA, and BSSID fields + * (skipping 2nd byte of FC and Duration feild. + * + * Disassociate pattern + * -------------------- + * Frame control = 00 00 1010 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes + * + * Deauthenticate pattern + * ---------------------- + * Frame control = 00 00 1100 + * DA, SA, BSSID = x:x:x:x:x:x + * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x + * | x:x:x:x:x:x -- 22 bytes + */ + + /* Create Disassociate Pattern first */ + + byte_cnt = 0; + + /* Fill out the mask with all FF's */ + + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) + dis_deauth_mask[i] = 0xff; + + /* copy the first byte of frame control field */ + dis_deauth_pattern[byte_cnt] = 0xa0; + byte_cnt++; + + /* skip 2nd byte of frame control and Duration field */ + byte_cnt += 3; + + /* + * need not match the destination mac address, it can be a broadcast + * mac address or an unicast to this station + */ + byte_cnt += 6; + + /* copy the source mac address */ + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + + byte_cnt += 6; + + /* copy the bssid, its same as the source mac address */ + + memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); + + /* Create Disassociate pattern mask */ + + if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { + + if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { + /* + * for AR9280, because of hardware limitation, the + * first 4 bytes have to be matched for all patterns. + * the mask for disassociation and de-auth pattern + * matching need to enable the first 4 bytes. + * also the duration field needs to be filled. + */ + dis_deauth_mask[0] = 0xf0; + + /* + * fill in duration field + FIXME: what is the exact value ? + */ + dis_deauth_pattern[2] = 0xff; + dis_deauth_pattern[3] = 0xff; + } else { + dis_deauth_mask[0] = 0xfe; + } + + dis_deauth_mask[1] = 0x03; + dis_deauth_mask[2] = 0xc0; + } else { + dis_deauth_mask[0] = 0xef; + dis_deauth_mask[1] = 0x3f; + dis_deauth_mask[2] = 0x00; + dis_deauth_mask[3] = 0xfc; + } + + ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); + + ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + + pattern_count++; + /* + * for de-authenticate pattern, only the first byte of the frame + * control field gets changed from 0xA0 to 0xC0 + */ + dis_deauth_pattern[0] = 0xC0; + + ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, + pattern_count, byte_cnt); + +} + +static void ath9k_wow_add_pattern(struct ath_softc *sc, + struct cfg80211_wowlan *wowlan) +{ + struct ath_hw *ah = sc->sc_ah; + struct ath9k_wow_pattern *wow_pattern = NULL; + struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; + int mask_len; + s8 i = 0; + + if (!wowlan->n_patterns) + return; + + /* + * Add the new user configured patterns + */ + for (i = 0; i < wowlan->n_patterns; i++) { + + wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); + + if (!wow_pattern) + return; + + /* + * TODO: convert the generic user space pattern to + * appropriate chip specific/802.11 pattern. + */ + + mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); + memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); + memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); + memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, + patterns[i].pattern_len); + memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); + wow_pattern->pattern_len = patterns[i].pattern_len; + + /* + * just need to take care of deauth and disssoc pattern, + * make sure we don't overwrite them. + */ + + ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, + wow_pattern->mask_bytes, + i + 2, + wow_pattern->pattern_len); + kfree(wow_pattern); + + } + +} + +static int ath9k_suspend(struct ieee80211_hw *hw, + struct cfg80211_wowlan *wowlan) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 wow_triggers_enabled = 0; + int ret = 0; + + mutex_lock(&sc->mutex); + + ath_cancel_work(sc); + del_timer_sync(&common->ani.timer); + del_timer_sync(&sc->rx_poll_timer); + + if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { + ath_dbg(common, ANY, "Device not present\n"); + ret = -EINVAL; + goto fail_wow; + } + + if (WARN_ON(!wowlan)) { + ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); + ret = -EINVAL; + goto fail_wow; + } + + if (!device_can_wakeup(sc->dev)) { + ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); + ret = 1; + goto fail_wow; + } + + /* + * none of the sta vifs are associated + * and we are not currently handling multivif + * cases, for instance we have to seperately + * configure 'keep alive frame' for each + * STA. + */ + + if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { + ath_dbg(common, WOW, "None of the STA vifs are associated\n"); + ret = 1; + goto fail_wow; + } + + if (sc->nvifs > 1) { + ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); + ret = 1; + goto fail_wow; + } + + ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); + + ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", + wow_triggers_enabled); + + ath9k_ps_wakeup(sc); + + ath9k_stop_btcoex(sc); + + /* + * Enable wake up on recieving disassoc/deauth + * frame by default. + */ + ath9k_wow_add_disassoc_deauth_pattern(sc); + + if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) + ath9k_wow_add_pattern(sc, wowlan); + + spin_lock_bh(&sc->sc_pcu_lock); + /* + * To avoid false wake, we enable beacon miss interrupt only + * when we go to sleep. We save the current interrupt mask + * so we can restore it after the system wakes up + */ + sc->wow_intr_before_sleep = ah->imask; + ah->imask &= ~ATH9K_INT_GLOBAL; + ath9k_hw_disable_interrupts(ah); + ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + spin_unlock_bh(&sc->sc_pcu_lock); + + /* + * we can now sync irq and kill any running tasklets, since we already + * disabled interrupts and not holding a spin lock + */ + synchronize_irq(sc->irq); + tasklet_kill(&sc->intr_tq); + + ath9k_hw_wow_enable(ah, wow_triggers_enabled); + + ath9k_ps_restore(sc); + ath_dbg(common, ANY, "WoW enabled in ath9k\n"); + atomic_inc(&sc->wow_sleep_proc_intr); + +fail_wow: + mutex_unlock(&sc->mutex); + return ret; +} + +static int ath9k_resume(struct ieee80211_hw *hw) +{ + struct ath_softc *sc = hw->priv; + struct ath_hw *ah = sc->sc_ah; + struct ath_common *common = ath9k_hw_common(ah); + u32 wow_status; + + mutex_lock(&sc->mutex); + + ath9k_ps_wakeup(sc); + + spin_lock_bh(&sc->sc_pcu_lock); + + ath9k_hw_disable_interrupts(ah); + ah->imask = sc->wow_intr_before_sleep; + ath9k_hw_set_interrupts(ah); + ath9k_hw_enable_interrupts(ah); + + spin_unlock_bh(&sc->sc_pcu_lock); + + wow_status = ath9k_hw_wow_wakeup(ah); + + if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { + /* + * some devices may not pick beacon miss + * as the reason they woke up so we add + * that here for that shortcoming. + */ + wow_status |= AH_WOW_BEACON_MISS; + atomic_dec(&sc->wow_got_bmiss_intr); + ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); + } + + atomic_dec(&sc->wow_sleep_proc_intr); + + if (wow_status) { + ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", + ath9k_hw_wow_event_to_string(wow_status), wow_status); + } + + ath_restart_work(sc); + ath9k_start_btcoex(sc); + + ath9k_ps_restore(sc); + mutex_unlock(&sc->mutex); + + return 0; +} + +static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) +{ + struct ath_softc *sc = hw->priv; + + mutex_lock(&sc->mutex); + device_init_wakeup(sc->dev, 1); + device_set_wakeup_enable(sc->dev, enabled); + mutex_unlock(&sc->mutex); +} + +#endif + struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -2104,6 +2437,12 @@ struct ieee80211_ops ath9k_ops = { .set_antenna = ath9k_set_antenna, .get_antenna = ath9k_get_antenna, +#ifdef CONFIG_PM_SLEEP + .suspend = ath9k_suspend, + .resume = ath9k_resume, + .set_wakeup = ath9k_set_wakeup, +#endif + #ifdef CONFIG_ATH9K_DEBUGFS .get_et_sset_count = ath9k_get_et_sset_count, .get_et_stats = ath9k_get_et_stats, diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c index 87acff7..fb536e7 100644 --- a/drivers/net/wireless/ath/ath9k/mci.c +++ b/drivers/net/wireless/ath/ath9k/mci.c @@ -202,7 +202,7 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload) case MCI_GPM_BT_CAL_REQ: if (mci_hw->bt_state == MCI_BT_AWAKE) { ar9003_mci_state(ah, MCI_STATE_SET_BT_CAL_START); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); + ath9k_queue_reset(sc, RESET_TYPE_MCI); } ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state); break; diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c index aa0e83a..87b89d5 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -313,6 +313,9 @@ static int ath_pci_suspend(struct device *device) struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; + if (sc->wow_enabled) + return 0; + /* The device has to be moved to FULLSLEEP forcibly. * Otherwise the chip never moved to full sleep, * when no interface is up. diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c index 11f3703..12aca02 100644 --- a/drivers/net/wireless/ath/ath9k/recv.c +++ b/drivers/net/wireless/ath/ath9k/recv.c @@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb) sc->ps_flags &= ~PS_BEACON_SYNC; ath_dbg(common, PS, "Reconfigure Beacon timers based on timestamp from the AP\n"); - ath_set_beacon(sc); + ath9k_set_beacon(sc); } if (ath_beacon_dtim_pending_cab(skb)) { diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h index 6592c07..87cac8e 100644 --- a/drivers/net/wireless/ath/ath9k/reg.h +++ b/drivers/net/wireless/ath/ath9k/reg.h @@ -696,9 +696,12 @@ #define AR_WA_BIT7 (1 << 7) #define AR_WA_BIT23 (1 << 23) #define AR_WA_D3_L1_DISABLE (1 << 14) +#define AR_WA_UNTIE_RESET_EN (1 << 15) /* Enable PCI Reset + to POR (power-on-reset) */ #define AR_WA_D3_TO_L1_DISABLE_REAL (1 << 16) #define AR_WA_ASPM_TIMER_BASED_DISABLE (1 << 17) -#define AR_WA_RESET_EN (1 << 18) /* Sw Control to enable PCI-Reset to POR (bit 15) */ +#define AR_WA_RESET_EN (1 << 18) /* Enable PCI-Reset to + POR (bit 15) */ #define AR_WA_ANALOG_SHIFT (1 << 20) #define AR_WA_POR_SHORT (1 << 21) /* PCI-E Phy reset control */ #define AR_WA_BIT22 (1 << 22) @@ -1032,6 +1035,8 @@ enum { #define AR_PCIE_PM_CTRL (AR_SREV_9340(ah) ? 0x4004 : 0x4014) #define AR_PCIE_PM_CTRL_ENA 0x00080000 +#define AR_PCIE_PHY_REG3 0x18c08 + #define AR_NUM_GPIO 14 #define AR928X_NUM_GPIO 10 #define AR9285_NUM_GPIO 12 @@ -1235,6 +1240,8 @@ enum { #define AR_RTC_PLL_CLKSEL 0x00000300 #define AR_RTC_PLL_CLKSEL_S 8 #define AR_RTC_PLL_BYPASS 0x00010000 +#define AR_RTC_PLL_NOPWD 0x00040000 +#define AR_RTC_PLL_NOPWD_S 18 #define PLL3 0x16188 #define PLL3_DO_MEAS_MASK 0x40000000 @@ -1887,6 +1894,8 @@ enum { #define AR_PCU_MISC_MODE2_HWWAR2 0x02000000 #define AR_PCU_MISC_MODE2_RESERVED2 0xFFFE0000 +#define AR_PCU_MISC_MODE3 0x83d0 + #define AR_MAC_PCU_ASYNC_FIFO_REG3 0x8358 #define AR_MAC_PCU_ASYNC_FIFO_REG3_DATAPATH_SEL 0x00000400 #define AR_MAC_PCU_ASYNC_FIFO_REG3_SOFT_RESET 0x80000000 @@ -1909,6 +1918,140 @@ enum { #define AR_RATE_DURATION_32 0x8780 #define AR_RATE_DURATION(_n) (AR_RATE_DURATION_0 + ((_n)<<2)) +/* WoW - Wake On Wireless */ + +#define AR_PMCTRL_AUX_PWR_DET 0x10000000 /* Puts Chip in L2 state */ +#define AR_PMCTRL_D3COLD_VAUX 0x00800000 +#define AR_PMCTRL_HOST_PME_EN 0x00400000 /* Send OOB WAKE_L on WoW + event */ +#define AR_PMCTRL_WOW_PME_CLR 0x00200000 /* Clear WoW event */ +#define AR_PMCTRL_PWR_STATE_MASK 0x0f000000 /* Power State Mask */ +#define AR_PMCTRL_PWR_STATE_D1D3 0x0f000000 /* Activate D1 and D3 */ +#define AR_PMCTRL_PWR_STATE_D1D3_REAL 0x0f000000 /* Activate D1 and D3 */ +#define AR_PMCTRL_PWR_STATE_D0 0x08000000 /* Activate D0 */ +#define AR_PMCTRL_PWR_PM_CTRL_ENA 0x00008000 /* Enable power mgmt */ + +#define AR_WOW_BEACON_TIMO_MAX 0xffffffff + +/* + * MAC WoW Registers + */ + +#define AR_WOW_PATTERN 0x825C +#define AR_WOW_COUNT 0x8260 +#define AR_WOW_BCN_EN 0x8270 +#define AR_WOW_BCN_TIMO 0x8274 +#define AR_WOW_KEEP_ALIVE_TIMO 0x8278 +#define AR_WOW_KEEP_ALIVE 0x827c +#define AR_WOW_US_SCALAR 0x8284 +#define AR_WOW_KEEP_ALIVE_DELAY 0x8288 +#define AR_WOW_PATTERN_MATCH 0x828c +#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */ +#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */ + +/* for AR9285 or later version of chips */ +#define AR_WOW_EXACT 0x829c +#define AR_WOW_LENGTH1 0x8360 +#define AR_WOW_LENGTH2 0X8364 +/* register to enable match for less than 256 bytes packets */ +#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368 + +#define AR_SW_WOW_CONTROL 0x20018 +#define AR_SW_WOW_ENABLE 0x1 +#define AR_SWITCH_TO_REFCLK 0x2 +#define AR_RESET_CONTROL 0x4 +#define AR_RESET_VALUE_MASK 0x8 +#define AR_HW_WOW_DISABLE 0x10 +#define AR_CLR_MAC_INTERRUPT 0x20 +#define AR_CLR_KA_INTERRUPT 0x40 + +/* AR_WOW_PATTERN register values */ +#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */ +#define AR_WOW_MAC_INTR_EN 0x00040000 +#define AR_WOW_MAGIC_EN 0x00010000 +#define AR_WOW_PATTERN_EN(x) (x & 0xff) +#define AR_WOW_PAT_FOUND_SHIFT 8 +#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT)) +#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT) +#define AR_WOW_MAGIC_PAT_FOUND 0x00020000 +#define AR_WOW_MAC_INTR 0x00080000 +#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000 +#define AR_WOW_BEACON_FAIL 0x00200000 + +#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \ + AR_WOW_MAGIC_PAT_FOUND | \ + AR_WOW_KEEP_ALIVE_FAIL | \ + AR_WOW_BEACON_FAIL)) +#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \ + AR_WOW_MAGIC_EN | \ + AR_WOW_MAC_INTR_EN | \ + AR_WOW_BEACON_FAIL | \ + AR_WOW_KEEP_ALIVE_FAIL)) + +/* AR_WOW_COUNT register values */ +#define AR_WOW_AIFS_CNT(x) (x & 0xff) +#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8) +#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16) + +/* AR_WOW_BCN_EN register */ +#define AR_WOW_BEACON_FAIL_EN 0x00000001 + +/* AR_WOW_BCN_TIMO rgister */ +#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */ + +/* AR_WOW_KEEP_ALIVE_TIMO register */ +#define AR_WOW_KEEP_ALIVE_TIMO_VALUE +#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff + +/* AR_WOW_KEEP_ALIVE register */ +#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001 +#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002 + +/* AR_WOW_KEEP_ALIVE_DELAY register */ +#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */ + + +/* + * keep it long for beacon workaround - ensure no false alarm + */ +#define AR_WOW_BMISSTHRESHOLD 0x20 + +/* AR_WOW_PATTERN_MATCH register */ +#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf) +#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8) + +/* + * default values for Wow Configuration for backoff, aifs, slot, keep-alive + * to be programmed into various registers. + */ +#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */ +#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */ +#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */ +/* + * Keepalive count applicable for AR9280 2.0 and above. + */ +#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */ + +/* WoW - Transmit buffer for keep alive frames */ +#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */ + +#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2)) + +#define AR_WOW_KA_DESC_WORD2 0xe000 + +#define AR_WOW_KA_DATA_WORD0 0xe030 + +/* WoW Transmit Buffer for patterns */ +#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8)) +#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5)) + +/* Currently Pattern 0-7 are supported - so bit 0-7 are set */ +#define AR_WOW_PATTERN_SUPPORTED 0xff +#define AR_WOW_LENGTH_MAX 0xff +#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3) +#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i)) +#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3) +#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i)) #define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */ #define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */ diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c new file mode 100644 index 0000000..44a08eb --- /dev/null +++ b/drivers/net/wireless/ath/ath9k/wow.c @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2012 Qualcomm Atheros, Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <linux/export.h> +#include "ath9k.h" +#include "reg.h" +#include "hw-ops.h" + +const char *ath9k_hw_wow_event_to_string(u32 wow_event) +{ + if (wow_event & AH_WOW_MAGIC_PATTERN_EN) + return "Magic pattern"; + if (wow_event & AH_WOW_USER_PATTERN_EN) + return "User pattern"; + if (wow_event & AH_WOW_LINK_CHANGE) + return "Link change"; + if (wow_event & AH_WOW_BEACON_MISS) + return "Beacon miss"; + + return "unknown reason"; +} +EXPORT_SYMBOL(ath9k_hw_wow_event_to_string); + +static void ath9k_hw_config_serdes_wow_sleep(struct ath_hw *ah) +{ + int i; + + for (i = 0; i < ah->iniPcieSerdesWow.ia_rows; i++) + REG_WRITE(ah, INI_RA(&ah->iniPcieSerdesWow, i, 0), + INI_RA(&ah->iniPcieSerdesWow, i, 1)); + + usleep_range(1000, 1500); +} + +static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + + /* set rx disable bit */ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0, AH_WAIT_TIMEOUT)) { + ath_err(common, "Failed to stop Rx DMA in 10ms AR_CR=0x%08x AR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return; + } else { + if (!AR_SREV_9300_20_OR_LATER(ah)) + REG_WRITE(ah, AR_RXDP, 0x0); + } + + /* AR9280 WoW has sleep issue, do not set it to sleep */ + if (AR_SREV_9280_20(ah)) + return; + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT); +} + +static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah) +{ + struct ath_common *common = ath9k_hw_common(ah); + u8 sta_mac_addr[ETH_ALEN], ap_mac_addr[ETH_ALEN]; + u32 ctl[13] = {0}; + u32 data_word[KAL_NUM_DATA_WORDS]; + u8 i; + u32 wow_ka_data_word0; + + memcpy(sta_mac_addr, common->macaddr, ETH_ALEN); + memcpy(ap_mac_addr, common->curbssid, ETH_ALEN); + + /* set the transmit buffer */ + ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16)); + + if (!(AR_SREV_9300_20_OR_LATER(ah))) + ctl[0] += (KAL_ANTENNA_MODE << 25); + + ctl[1] = 0; + ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */ + ctl[4] = 0; + ctl[7] = (ah->txchainmask) << 2; + + if (AR_SREV_9300_20_OR_LATER(ah)) + ctl[2] = 0xf << 16; /* tx_tries 0 */ + else + ctl[2] = 0x7 << 16; /* tx_tries 0 */ + + + for (i = 0; i < KAL_NUM_DESC_WORDS; i++) + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + + /* for AR9300 family 13 descriptor words */ + if (AR_SREV_9300_20_OR_LATER(ah)) + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]); + + data_word[0] = (KAL_FRAME_TYPE << 2) | (KAL_FRAME_SUB_TYPE << 4) | + (KAL_TO_DS << 8) | (KAL_DURATION_ID << 16); + data_word[1] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[2] = (sta_mac_addr[1] << 24) | (sta_mac_addr[0] << 16) | + (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + data_word[3] = (sta_mac_addr[5] << 24) | (sta_mac_addr[4] << 16) | + (sta_mac_addr[3] << 8) | (sta_mac_addr[2]); + data_word[4] = (ap_mac_addr[3] << 24) | (ap_mac_addr[2] << 16) | + (ap_mac_addr[1] << 8) | (ap_mac_addr[0]); + data_word[5] = (ap_mac_addr[5] << 8) | (ap_mac_addr[4]); + + if (AR_SREV_9462_20_OR_LATER(ah)) { + /* AR9462 2.0 has an extra descriptor word (time based + * discard) compared to other chips */ + REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + (12 * 4)), 0); + wow_ka_data_word0 = AR_WOW_TXBUF(13); + } else { + wow_ka_data_word0 = AR_WOW_TXBUF(12); + } + + for (i = 0; i < KAL_NUM_DATA_WORDS; i++) + REG_WRITE(ah, (wow_ka_data_word0 + i*4), data_word[i]); + +} + +void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern, + u8 *user_mask, int pattern_count, + int pattern_len) +{ + int i; + u32 pattern_val, mask_val; + u32 set, clr; + + /* FIXME: should check count by querying the hardware capability */ + if (pattern_count >= MAX_NUM_PATTERN) + return; + + REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count)); + + /* set the registers for pattern */ + for (i = 0; i < MAX_PATTERN_SIZE; i += 4) { + memcpy(&pattern_val, user_pattern, 4); + REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i), + pattern_val); + user_pattern += 4; + } + + /* set the registers for mask */ + for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) { + memcpy(&mask_val, user_mask, 4); + REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val); + user_mask += 4; + } + + /* set the pattern length to be matched + * + * AR_WOW_LENGTH1_REG1 + * bit 31:24 pattern 0 length + * bit 23:16 pattern 1 length + * bit 15:8 pattern 2 length + * bit 7:0 pattern 3 length + * + * AR_WOW_LENGTH1_REG2 + * bit 31:24 pattern 4 length + * bit 23:16 pattern 5 length + * bit 15:8 pattern 6 length + * bit 7:0 pattern 7 length + * + * the below logic writes out the new + * pattern length for the corresponding + * pattern_count, while masking out the + * other fields + */ + + ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT); + + if (!AR_SREV_9285_12_OR_LATER(ah)) + return; + + if (pattern_count < 4) { + /* Pattern 0-3 uses AR_WOW_LENGTH1 register */ + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN1_SHIFT(pattern_count); + clr = AR_WOW_LENGTH1_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH1, set, clr); + } else { + /* Pattern 4-7 uses AR_WOW_LENGTH2 register */ + set = (pattern_len & AR_WOW_LENGTH_MAX) << + AR_WOW_LEN2_SHIFT(pattern_count); + clr = AR_WOW_LENGTH2_MASK(pattern_count); + REG_RMW(ah, AR_WOW_LENGTH2, set, clr); + } + +} +EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern); + +u32 ath9k_hw_wow_wakeup(struct ath_hw *ah) +{ + u32 wow_status = 0; + u32 val = 0, rval; + /* + * read the WoW status register to know + * the wakeup reason + */ + rval = REG_READ(ah, AR_WOW_PATTERN); + val = AR_WOW_STATUS(rval); + + /* + * mask only the WoW events that we have enabled. Sometimes + * we have spurious WoW events from the AR_WOW_PATTERN + * register. This mask will clean it up. + */ + + val &= ah->wow_event_mask; + + if (val) { + + if (val & AR_WOW_MAGIC_PAT_FOUND) + wow_status |= AH_WOW_MAGIC_PATTERN_EN; + + if (AR_WOW_PATTERN_FOUND(val)) + wow_status |= AH_WOW_USER_PATTERN_EN; + + if (val & AR_WOW_KEEP_ALIVE_FAIL) + wow_status |= AH_WOW_LINK_CHANGE; + + if (val & AR_WOW_BEACON_FAIL) + wow_status |= AH_WOW_BEACON_MISS; + + } + + /* + * set and clear WOW_PME_CLEAR registers for the chip to + * generate next wow signal. + * disable D3 before accessing other registers ? + */ + + /* do we need to check the bit value 0x01000000 (7-10) ?? */ + REG_RMW(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR, + AR_PMCTRL_PWR_STATE_D1D3); + + /* + * clear all events + */ + REG_WRITE(ah, AR_WOW_PATTERN, + AR_WOW_CLEAR_EVENTS(REG_READ(ah, AR_WOW_PATTERN))); + + /* + * tie reset register for AR9002 family of chipsets + * NB: not tieing it back might have some repurcussions. + */ + + if (!AR_SREV_9300_20_OR_LATER(ah)) { + REG_SET_BIT(ah, AR_WA, AR_WA_UNTIE_RESET_EN | + AR_WA_POR_SHORT | AR_WA_RESET_EN); + } + + + /* + * restore the beacon threshold to init value + */ + REG_WRITE(ah, AR_RSSI_THR, INIT_RSSI_THR); + + /* + * Restore the way the PCI-E reset, Power-On-Reset, external + * PCIE_POR_SHORT pins are tied to its original value. + * Previously just before WoW sleep, we untie the PCI-E + * reset to our Chip's Power On Reset so that any PCI-E + * reset from the bus will not reset our chip + */ + + if (AR_SREV_9280_20_OR_LATER(ah) && ah->is_pciexpress) + ath9k_hw_configpcipowersave(ah, false); + + ah->wow_event_mask = 0; + + return wow_status; +} +EXPORT_SYMBOL(ath9k_hw_wow_wakeup); + +void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable) +{ + u32 wow_event_mask; + u32 set, clr; + + /* + * wow_event_mask is a mask to the AR_WOW_PATTERN register to + * indicate which WoW events we have enabled. The WoW events + * are from the 'pattern_enable' in this function and + * 'pattern_count' of ath9k_hw_wow_apply_pattern() + */ + + wow_event_mask = ah->wow_event_mask; + + /* + * Untie Power-on-Reset from the PCI-E-Reset. When we are in + * WOW sleep, we do want the Reset from the PCI-E to disturb + * our hw state + */ + + if (ah->is_pciexpress) { + + /* + * we need to untie the internal POR (power-on-reset) + * to the external PCI-E reset. We also need to tie + * the PCI-E Phy reset to the PCI-E reset. + */ + + if (AR_SREV_9300_20_OR_LATER(ah)) { + set = AR_WA_RESET_EN | AR_WA_POR_SHORT; + clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE; + REG_RMW(ah, AR_WA, set, clr); + } else { + if (AR_SREV_9285(ah) || AR_SREV_9287(ah)) + set = AR9285_WA_DEFAULT; + else + set = AR9280_WA_DEFAULT; + + /* + * In AR9280 and AR9285, bit 14 in WA register + * (disable L1) should only be set when device + * enters D3 state and be cleared when device + * comes back to D0 + */ + + if (ah->config.pcie_waen & AR_WA_D3_L1_DISABLE) + set |= AR_WA_D3_L1_DISABLE; + + clr = AR_WA_UNTIE_RESET_EN; + set |= AR_WA_RESET_EN | AR_WA_POR_SHORT; + REG_RMW(ah, AR_WA, set, clr); + + /* + * for WoW sleep, we reprogram the SerDes so that the + * PLL and CLK REQ are both enabled. This uses more + * power but otherwise WoW sleep is unstable and the + * chip may disappear. + */ + + if (AR_SREV_9285_12_OR_LATER(ah)) + ath9k_hw_config_serdes_wow_sleep(ah); + + } + } + + /* + * set the power states appropriately and enable PME + */ + set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA | + AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR; + + /* + * set and clear WOW_PME_CLEAR registers for the chip + * to generate next wow signal. + */ + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); + clr = AR_PMCTRL_WOW_PME_CLR; + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + + /* + * Setup for: + * - beacon misses + * - magic pattern + * - keep alive timeout + * - pattern matching + */ + + /* + * Program default values for pattern backoff, aifs/slot/KAL count, + * beacon miss timeout, KAL timeout, etc. + */ + + set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF); + REG_SET_BIT(ah, AR_WOW_PATTERN, set); + + set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) | + AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) | + AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT); + REG_SET_BIT(ah, AR_WOW_COUNT, set); + + if (pattern_enable & AH_WOW_BEACON_MISS) + set = AR_WOW_BEACON_TIMO; + /* We are not using beacon miss, program a large value */ + else + set = AR_WOW_BEACON_TIMO_MAX; + + REG_WRITE(ah, AR_WOW_BCN_TIMO, set); + + /* + * Keep alive timo in ms except AR9280 + */ + if (!pattern_enable || AR_SREV_9280(ah)) + set = AR_WOW_KEEP_ALIVE_NEVER; + else + set = KAL_TIMEOUT * 32; + + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set); + + /* + * Keep alive delay in us. based on 'power on clock', + * therefore in usec + */ + set = KAL_DELAY * 1000; + REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set); + + /* + * Create keep alive pattern to respond to beacons + */ + ath9k_wow_create_keep_alive_pattern(ah); + + /* + * Configure MAC WoW Registers + */ + + set = 0; + /* Send keep alive timeouts anyway */ + clr = AR_WOW_KEEP_ALIVE_AUTO_DIS; + + if (pattern_enable & AH_WOW_LINK_CHANGE) + wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL; + else + set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + + /* + * FIXME: For now disable keep alive frame + * failure. This seems to sometimes trigger + * unnecessary wake up with AR9485 chipsets. + */ + set = AR_WOW_KEEP_ALIVE_FAIL_DIS; + + REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr); + + + /* + * we are relying on a bmiss failure. ensure we have + * enough threshold to prevent false positives + */ + REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR, + AR_WOW_BMISSTHRESHOLD); + + set = 0; + clr = 0; + + if (pattern_enable & AH_WOW_BEACON_MISS) { + set = AR_WOW_BEACON_FAIL_EN; + wow_event_mask |= AR_WOW_BEACON_FAIL; + } else { + clr = AR_WOW_BEACON_FAIL_EN; + } + + REG_RMW(ah, AR_WOW_BCN_EN, set, clr); + + set = 0; + clr = 0; + /* + * Enable the magic packet registers + */ + if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) { + set = AR_WOW_MAGIC_EN; + wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND; + } else { + clr = AR_WOW_MAGIC_EN; + } + set |= AR_WOW_MAC_INTR_EN; + REG_RMW(ah, AR_WOW_PATTERN, set, clr); + + /* + * For AR9285 and later version of chipsets + * enable WoW pattern match for packets less + * than 256 bytes for all patterns + */ + if (AR_SREV_9285_12_OR_LATER(ah)) + REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B, + AR_WOW_PATTERN_SUPPORTED); + + /* + * Set the power states appropriately and enable PME + */ + clr = 0; + set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN | + AR_PMCTRL_PWR_PM_CTRL_ENA; + /* + * This is needed for AR9300 chipsets to wake-up + * the host. + */ + if (AR_SREV_9300_20_OR_LATER(ah)) + clr = AR_PCIE_PM_CTRL_ENA; + + REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr); + + if (AR_SREV_9462(ah)) { + /* + * this is needed to prevent the chip waking up + * the host within 3-4 seconds with certain + * platform/BIOS. The fix is to enable + * D1 & D3 to match original definition and + * also match the OTP value. Anyway this + * is more related to SW WOW. + */ + clr = AR_PMCTRL_PWR_STATE_D1D3; + REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr); + + set = AR_PMCTRL_PWR_STATE_D1D3_REAL; + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set); + } + + + + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM); + + if (AR_SREV_9300_20_OR_LATER(ah)) { + /* to bring down WOW power low margin */ + set = BIT(13); + REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set); + /* HW WoW */ + clr = BIT(5); + REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr); + } + + ath9k_hw_set_powermode_wow_sleep(ah); + ah->wow_event_mask = wow_event_mask; +} +EXPORT_SYMBOL(ath9k_hw_wow_enable); diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c index cafb4a0..2c9da6b 100644 --- a/drivers/net/wireless/ath/ath9k/xmit.c +++ b/drivers/net/wireless/ath/ath9k/xmit.c @@ -29,6 +29,8 @@ #define HT_LTF(_ns) (4 * (_ns)) #define SYMBOL_TIME(_ns) ((_ns) << 2) /* ns * 4 us */ #define SYMBOL_TIME_HALFGI(_ns) (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */ +#define TIME_SYMBOLS(t) ((t) >> 2) +#define TIME_SYMBOLS_HALFGI(t) (((t) * 5 - 4) / 18) #define NUM_SYMBOLS_PER_USEC(_usec) (_usec >> 2) #define NUM_SYMBOLS_PER_USEC_HALFGI(_usec) (((_usec*5)-4)/18) @@ -74,33 +76,6 @@ enum { MCS_HT40_SGI, }; -static int ath_max_4ms_framelen[4][32] = { - [MCS_HT20] = { - 3212, 6432, 9648, 12864, 19300, 25736, 28952, 32172, - 6424, 12852, 19280, 25708, 38568, 51424, 57852, 64280, - 9628, 19260, 28896, 38528, 57792, 65532, 65532, 65532, - 12828, 25656, 38488, 51320, 65532, 65532, 65532, 65532, - }, - [MCS_HT20_SGI] = { - 3572, 7144, 10720, 14296, 21444, 28596, 32172, 35744, - 7140, 14284, 21428, 28568, 42856, 57144, 64288, 65532, - 10700, 21408, 32112, 42816, 64228, 65532, 65532, 65532, - 14256, 28516, 42780, 57040, 65532, 65532, 65532, 65532, - }, - [MCS_HT40] = { - 6680, 13360, 20044, 26724, 40092, 53456, 60140, 65532, - 13348, 26700, 40052, 53400, 65532, 65532, 65532, 65532, - 20004, 40008, 60016, 65532, 65532, 65532, 65532, 65532, - 26644, 53292, 65532, 65532, 65532, 65532, 65532, 65532, - }, - [MCS_HT40_SGI] = { - 7420, 14844, 22272, 29696, 44544, 59396, 65532, 65532, - 14832, 29668, 44504, 59340, 65532, 65532, 65532, 65532, - 22232, 44464, 65532, 65532, 65532, 65532, 65532, 65532, - 29616, 59232, 65532, 65532, 65532, 65532, 65532, 65532, - } -}; - /*********************/ /* Aggregation logic */ /*********************/ @@ -614,10 +589,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, rcu_read_unlock(); - if (needreset) { - RESET_STAT_INC(sc, RESET_TYPE_TX_ERROR); - ieee80211_queue_work(sc->hw, &sc->hw_reset_work); - } + if (needreset) + ath9k_queue_reset(sc, RESET_TYPE_TX_ERROR); } static bool ath_lookup_legacy(struct ath_buf *bf) @@ -650,6 +623,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, struct ieee80211_tx_rate *rates; u32 max_4ms_framelen, frmlen; u16 aggr_limit, bt_aggr_limit, legacy = 0; + int q = tid->ac->txq->mac80211_qnum; int i; skb = bf->bf_mpdu; @@ -658,8 +632,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, /* * Find the lowest frame length among the rate series that will have a - * 4ms transmit duration. - * TODO - TXOP limit needs to be considered. + * 4ms (or TXOP limited) transmit duration. */ max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; @@ -682,7 +655,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf, if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI) modeidx++; - frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx]; + frmlen = sc->tx.max_aggr_framelen[q][modeidx][rates[i].idx]; max_4ms_framelen = min(max_4ms_framelen, frmlen); } @@ -929,6 +902,44 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen, return duration; } +static int ath_max_framelen(int usec, int mcs, bool ht40, bool sgi) +{ + int streams = HT_RC_2_STREAMS(mcs); + int symbols, bits; + int bytes = 0; + + symbols = sgi ? TIME_SYMBOLS_HALFGI(usec) : TIME_SYMBOLS(usec); + bits = symbols * bits_per_symbol[mcs % 8][ht40] * streams; + bits -= OFDM_PLCP_BITS; + bytes = bits / 8; + bytes -= L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + if (bytes > 65532) + bytes = 65532; + + return bytes; +} + +void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop) +{ + u16 *cur_ht20, *cur_ht20_sgi, *cur_ht40, *cur_ht40_sgi; + int mcs; + + /* 4ms is the default (and maximum) duration */ + if (!txop || txop > 4096) + txop = 4096; + + cur_ht20 = sc->tx.max_aggr_framelen[queue][MCS_HT20]; + cur_ht20_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT20_SGI]; + cur_ht40 = sc->tx.max_aggr_framelen[queue][MCS_HT40]; + cur_ht40_sgi = sc->tx.max_aggr_framelen[queue][MCS_HT40_SGI]; + for (mcs = 0; mcs < 32; mcs++) { + cur_ht20[mcs] = ath_max_framelen(txop, mcs, false, false); + cur_ht20_sgi[mcs] = ath_max_framelen(txop, mcs, false, true); + cur_ht40[mcs] = ath_max_framelen(txop, mcs, true, false); + cur_ht40_sgi[mcs] = ath_max_framelen(txop, mcs, true, true); + } +} + static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_info *info, int len) { @@ -1403,16 +1414,6 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int error = 0; struct ath9k_tx_queue_info qi; - if (qnum == sc->beacon.beaconq) { - /* - * XXX: for beacon queue, we just save the parameter. - * It will be picked up by ath_beaconq_config when - * it's necessary. - */ - sc->beacon.beacon_qi = *qinfo; - return 0; - } - BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum); ath9k_hw_get_txq_props(ah, qnum, &qi); @@ -1586,7 +1587,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) struct ath_atx_ac *ac, *ac_tmp, *last_ac; struct ath_atx_tid *tid, *last_tid; - if (work_pending(&sc->hw_reset_work) || list_empty(&txq->axq_acq) || + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags) || + list_empty(&txq->axq_acq) || txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH) return; @@ -1988,7 +1990,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, ath_txq_lock(sc, txq); if (txq == sc->tx.txq_map[q] && - ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) { + ++txq->pending_frames > sc->tx.txq_max_pending[q] && + !txq->stopped) { ieee80211_stop_queue(sc->hw, q); txq->stopped = true; } @@ -2047,7 +2050,8 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, if (WARN_ON(--txq->pending_frames < 0)) txq->pending_frames = 0; - if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) { + if (txq->stopped && + txq->pending_frames < sc->tx.txq_max_pending[q]) { ieee80211_wake_queue(sc->hw, q); txq->stopped = false; } @@ -2191,7 +2195,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_lock(sc, txq); for (;;) { - if (work_pending(&sc->hw_reset_work)) + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) break; if (list_empty(&txq->axq_q)) { @@ -2274,7 +2278,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc) int status; for (;;) { - if (work_pending(&sc->hw_reset_work)) + if (test_bit(SC_OP_HW_RESET, &sc->sc_flags)) break; status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts); diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index c06b6cb..7c899fc 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -870,13 +870,6 @@ struct b43_wl { * handler, only. This basically is just the IRQ mask register. */ spinlock_t hardirq_lock; - /* The number of queues that were registered with the mac80211 subsystem - * initially. This is a backup copy of hw->queues in case hw->queues has - * to be dynamically lowered at runtime (Firmware does not support QoS). - * hw->queues has to be restored to the original value before unregistering - * from the mac80211 subsystem. */ - u16 mac80211_initially_registered_queues; - /* Set this if we call ieee80211_register_hw() and check if we call * ieee80211_unregister_hw(). */ bool hw_registred; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 1b988f2..b80352b 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -2359,6 +2359,8 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx) if (err) goto err_load; + fw->opensource = (ctx->req_type == B43_FWTYPE_OPENSOURCE); + return 0; err_no_ucode: @@ -2434,6 +2436,10 @@ static void b43_request_firmware(struct work_struct *work) goto out; start_ieee80211: + wl->hw->queues = B43_QOS_QUEUE_NUM; + if (!modparam_qos || dev->fw.opensource) + wl->hw->queues = 1; + err = ieee80211_register_hw(wl->hw); if (err) goto err_one_core_detach; @@ -2537,11 +2543,9 @@ static int b43_upload_microcode(struct b43_wldev *dev) dev->fw.hdr_format = B43_FW_HDR_410; else dev->fw.hdr_format = B43_FW_HDR_351; - dev->fw.opensource = (fwdate == 0xFFFF); + WARN_ON(dev->fw.opensource != (fwdate == 0xFFFF)); - /* Default to use-all-queues. */ - dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues; - dev->qos_enabled = !!modparam_qos; + dev->qos_enabled = dev->wl->hw->queues > 1; /* Default to firmware/hardware crypto acceleration. */ dev->hwcrypto_enabled = true; @@ -2559,14 +2563,8 @@ static int b43_upload_microcode(struct b43_wldev *dev) /* Disable hardware crypto and fall back to software crypto. */ dev->hwcrypto_enabled = false; } - if (!(fwcapa & B43_FWCAPA_QOS)) { - b43info(dev->wl, "QoS not supported by firmware\n"); - /* Disable QoS. Tweak hw->queues to 1. It will be restored before - * ieee80211_unregister to make sure the networking core can - * properly free possible resources. */ - dev->wl->hw->queues = 1; - dev->qos_enabled = false; - } + /* adding QoS support should use an offline discovery mechanism */ + WARN(fwcapa & B43_FWCAPA_QOS, "QoS in OpenFW not supported\n"); } else { b43info(dev->wl, "Loading firmware version %u.%u " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", @@ -5298,8 +5296,6 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN; - hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1; - wl->mac80211_initially_registered_queues = hw->queues; wl->hw_registred = false; hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); @@ -5374,10 +5370,6 @@ static void b43_bcma_remove(struct bcma_device *core) B43_WARN_ON(!wl); if (wl->current_dev == wldev && wl->hw_registred) { - /* Restore the queues count before unregistering, because firmware detect - * might have modified it. Restoring is important, so the networking - * stack can properly free resources. */ - wl->hw->queues = wl->mac80211_initially_registered_queues; b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); } @@ -5452,10 +5444,6 @@ static void b43_ssb_remove(struct ssb_device *sdev) B43_WARN_ON(!wl); if (wl->current_dev == wldev && wl->hw_registred) { - /* Restore the queues count before unregistering, because firmware detect - * might have modified it. Restoring is important, so the networking - * stack can properly free resources. */ - wl->hw->queues = wl->mac80211_initially_registered_queues; b43_leds_stop(wldev); ieee80211_unregister_hw(wl->hw); } diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index b31ccc0..136510e 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -663,7 +663,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) u32 uninitialized_var(macstat); u16 chanid; u16 phytype; - int padding; + int padding, rate_idx; memset(&status, 0, sizeof(status)); @@ -766,16 +766,17 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) } if (phystat0 & B43_RX_PHYST0_OFDM) - status.rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, + rate_idx = b43_plcp_get_bitrate_idx_ofdm(plcp, phytype == B43_PHYTYPE_A); else - status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); - if (unlikely(status.rate_idx == -1)) { + rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); + if (unlikely(rate_idx == -1)) { /* PLCP seems to be corrupted. * Drop the frame, if we are not interested in corrupted frames. */ if (!(dev->wl->filter_flags & FIF_PLCPFAIL)) goto drop; } + status.rate_idx = rate_idx; status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* diff --git a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c index d13ae9c..28c5fbb 100644 --- a/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c +++ b/drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c @@ -691,9 +691,10 @@ scan_out: } static s32 -brcmf_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev, +brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *ndev = request->wdev->netdev; s32 err = 0; WL_TRACE("Enter\n"); @@ -919,9 +920,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev, set_bit(WL_STATUS_CONNECTING, &cfg_priv->status); if (params->bssid) - WL_CONN("BSSID: %02X %02X %02X %02X %02X %02X\n", - params->bssid[0], params->bssid[1], params->bssid[2], - params->bssid[3], params->bssid[4], params->bssid[5]); + WL_CONN("BSSID: %pM\n", params->bssid); else WL_CONN("No BSSID specified\n"); diff --git a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c index 01b190a..be5bcfb 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/ampdu.c @@ -663,9 +663,6 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi, /* patch the first MPDU */ if (count == 1) { u8 plcp0, plcp3, is40, sgi; - struct ieee80211_sta *sta; - - sta = tx_info->control.sta; if (rr) { plcp0 = plcp[0]; @@ -1195,8 +1192,8 @@ static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a) bool rc; rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false; - rc = rc && (tx_info->control.sta == NULL || ampdu_pars->sta == NULL || - tx_info->control.sta == ampdu_pars->sta); + rc = rc && (tx_info->rate_driver_data[0] == NULL || ampdu_pars->sta == NULL || + tx_info->rate_driver_data[0] == ampdu_pars->sta); rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid); return rc; } @@ -1210,8 +1207,8 @@ static void dma_cb_fn_ampdu(void *txi, void *arg_a) struct ieee80211_tx_info *tx_info = (struct ieee80211_tx_info *)txi; if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && - (tx_info->control.sta == sta || sta == NULL)) - tx_info->control.sta = NULL; + (tx_info->rate_driver_data[0] == sta || sta == NULL)) + tx_info->rate_driver_data[0] = NULL; } /* diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c index 2b57f57..9e79d47 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c @@ -267,6 +267,7 @@ static void brcms_set_basic_rate(struct brcm_rateset *rs, u16 rate, bool is_br) static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct brcms_info *wl = hw->priv; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); spin_lock_bh(&wl->lock); if (!wl->pub->up) { @@ -275,6 +276,7 @@ static void brcms_ops_tx(struct ieee80211_hw *hw, struct sk_buff *skb) goto done; } brcms_c_sendpkt_mac80211(wl->wlc, skb, hw); + tx_info->rate_driver_data[0] = tx_info->control.sta; done: spin_unlock_bh(&wl->lock); } diff --git a/drivers/net/wireless/brcm80211/brcmsmac/main.c b/drivers/net/wireless/brcm80211/brcmsmac/main.c index cb73f22..03ca653 100644 --- a/drivers/net/wireless/brcm80211/brcmsmac/main.c +++ b/drivers/net/wireless/brcm80211/brcmsmac/main.c @@ -893,7 +893,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs) tx_info = IEEE80211_SKB_CB(p); h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN); - if (tx_info->control.sta) + if (tx_info->rate_driver_data[0]) scb = &wlc->pri_scb; if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { diff --git a/drivers/net/wireless/iwlegacy/common.c b/drivers/net/wireless/iwlegacy/common.c index 0f8a770..0370403 100644 --- a/drivers/net/wireless/iwlegacy/common.c +++ b/drivers/net/wireless/iwlegacy/common.c @@ -5359,7 +5359,7 @@ il_mac_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, if (changes & BSS_CHANGED_ASSOC) { D_MAC80211("ASSOC %d\n", bss_conf->assoc); if (bss_conf->assoc) { - il->timestamp = bss_conf->last_tsf; + il->timestamp = bss_conf->sync_tsf; if (!il_is_rfkill(il)) il->ops->post_associate(il); diff --git a/drivers/net/wireless/iwlwifi/dvm/commands.h b/drivers/net/wireless/iwlwifi/dvm/commands.h index 97bea16..4a361c5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/commands.h +++ b/drivers/net/wireless/iwlwifi/dvm/commands.h @@ -1905,6 +1905,7 @@ struct iwl_bt_cmd { #define IWLAGN_BT_PRIO_BOOST_MAX 0xFF #define IWLAGN_BT_PRIO_BOOST_MIN 0x00 #define IWLAGN_BT_PRIO_BOOST_DEFAULT 0xF0 +#define IWLAGN_BT_PRIO_BOOST_DEFAULT32 0xF0F0F0F0 #define IWLAGN_BT_MAX_KILL_DEFAULT 5 diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c index 207ae91..bef88c1 100644 --- a/drivers/net/wireless/iwlwifi/dvm/lib.c +++ b/drivers/net/wireless/iwlwifi/dvm/lib.c @@ -265,6 +265,8 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv) bt_cmd_v2.tx_prio_boost = 0; bt_cmd_v2.rx_prio_boost = 0; } else { + /* older version only has 8 bits */ + WARN_ON(priv->cfg->bt_params->bt_prio_boost & ~0xFF); bt_cmd_v1.prio_boost = priv->cfg->bt_params->bt_prio_boost; bt_cmd_v1.tx_prio_boost = 0; diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c index 612f05d..84d3db5 100644 --- a/drivers/net/wireless/iwlwifi/dvm/main.c +++ b/drivers/net/wireless/iwlwifi/dvm/main.c @@ -1232,7 +1232,6 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans, struct iwl_trans_config trans_cfg; static const u8 no_reclaim_cmds[] = { REPLY_RX_PHY_CMD, - REPLY_RX, REPLY_RX_MPDU_CMD, REPLY_COMPRESSED_BA, STATISTICS_NOTIFICATION, diff --git a/drivers/net/wireless/iwlwifi/dvm/rx.c b/drivers/net/wireless/iwlwifi/dvm/rx.c index c1f7a18..fee5cff 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rx.c +++ b/drivers/net/wireless/iwlwifi/dvm/rx.c @@ -88,7 +88,6 @@ const char *iwl_dvm_cmd_strings[REPLY_MAX] = { IWL_CMD_ENTRY(REPLY_PHY_CALIBRATION_CMD), IWL_CMD_ENTRY(REPLY_RX_PHY_CMD), IWL_CMD_ENTRY(REPLY_RX_MPDU_CMD), - IWL_CMD_ENTRY(REPLY_RX), IWL_CMD_ENTRY(REPLY_COMPRESSED_BA), IWL_CMD_ENTRY(CALIBRATION_CFG_CMD), IWL_CMD_ENTRY(CALIBRATION_RES_NOTIFICATION), @@ -895,8 +894,7 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv, return max_rssi - agc - IWLAGN_RSSI_OFFSET; } -/* Called for REPLY_RX (legacy ABG frames), or - * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */ +/* Called for REPLY_RX_MPDU_CMD */ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb, struct iwl_device_cmd *cmd) @@ -911,37 +909,17 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv, u32 ampdu_status; u32 rate_n_flags; - /** - * REPLY_RX and REPLY_RX_MPDU_CMD are handled differently. - * REPLY_RX: physical layer info is in this buffer - * REPLY_RX_MPDU_CMD: physical layer info was sent in separate - * command and cached in priv->last_phy_res - * - * Here we set up local variables depending on which command is - * received. - */ - if (pkt->hdr.cmd == REPLY_RX) { - phy_res = (struct iwl_rx_phy_res *)pkt->data; - header = (struct ieee80211_hdr *)(pkt->data + sizeof(*phy_res) - + phy_res->cfg_phy_cnt); - - len = le16_to_cpu(phy_res->byte_count); - rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*phy_res) + - phy_res->cfg_phy_cnt + len); - ampdu_status = le32_to_cpu(rx_pkt_status); - } else { - if (!priv->last_phy_res_valid) { - IWL_ERR(priv, "MPDU frame without cached PHY data\n"); - return 0; - } - phy_res = &priv->last_phy_res; - amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; - header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu)); - len = le16_to_cpu(amsdu->byte_count); - rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len); - ampdu_status = iwlagn_translate_rx_status(priv, - le32_to_cpu(rx_pkt_status)); + if (!priv->last_phy_res_valid) { + IWL_ERR(priv, "MPDU frame without cached PHY data\n"); + return 0; } + phy_res = &priv->last_phy_res; + amsdu = (struct iwl_rx_mpdu_res_start *)pkt->data; + header = (struct ieee80211_hdr *)(pkt->data + sizeof(*amsdu)); + len = le16_to_cpu(amsdu->byte_count); + rx_pkt_status = *(__le32 *)(pkt->data + sizeof(*amsdu) + len); + ampdu_status = iwlagn_translate_rx_status(priv, + le32_to_cpu(rx_pkt_status)); if ((unlikely(phy_res->cfg_phy_cnt > 20))) { IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d\n", diff --git a/drivers/net/wireless/iwlwifi/dvm/rxon.c b/drivers/net/wireless/iwlwifi/dvm/rxon.c index 6ee940f..1089639 100644 --- a/drivers/net/wireless/iwlwifi/dvm/rxon.c +++ b/drivers/net/wireless/iwlwifi/dvm/rxon.c @@ -1447,7 +1447,7 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw, if (changes & BSS_CHANGED_ASSOC) { if (bss_conf->assoc) { - priv->timestamp = bss_conf->last_tsf; + priv->timestamp = bss_conf->sync_tsf; ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK; } else { /* diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h index 10e4793..87f465a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-config.h +++ b/drivers/net/wireless/iwlwifi/iwl-config.h @@ -177,7 +177,7 @@ struct iwl_base_params { struct iwl_bt_params { bool advanced_bt_coexist; u8 bt_init_traffic_load; - u8 bt_prio_boost; + u32 bt_prio_boost; u16 agg_time_limit; bool bt_sco_disable; bool bt_session_2; diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h index 867d8e1..92576a3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-trans.h +++ b/drivers/net/wireless/iwlwifi/iwl-trans.h @@ -458,6 +458,7 @@ struct iwl_trans { /* The following fields are internal only */ struct kmem_cache *dev_cmd_pool; size_t dev_cmd_headroom; + char dev_cmd_pool_name[50]; /* pointer to trans specific struct */ /*Ensure that this pointer will always be aligned to sizeof pointer */ diff --git a/drivers/net/wireless/iwlwifi/pcie/2000.c b/drivers/net/wireless/iwlwifi/pcie/2000.c index fd4e78f..9fbde32 100644 --- a/drivers/net/wireless/iwlwifi/pcie/2000.c +++ b/drivers/net/wireless/iwlwifi/pcie/2000.c @@ -112,7 +112,7 @@ static const struct iwl_bt_params iwl2030_bt_params = { .advanced_bt_coexist = true, .agg_time_limit = BT_AGG_THRESHOLD_DEF, .bt_init_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_NONE, - .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT, + .bt_prio_boost = IWLAGN_BT_PRIO_BOOST_DEFAULT32, .bt_sco_disable = true, .bt_session_2 = true, }; diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c index 09795af..939c2f7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/trans.c +++ b/drivers/net/wireless/iwlwifi/pcie/trans.c @@ -2080,7 +2080,6 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, { struct iwl_trans_pcie *trans_pcie; struct iwl_trans *trans; - char cmd_pool_name[100]; u16 pci_cmd; int err; @@ -2178,12 +2177,12 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev, init_waitqueue_head(&trans->wait_command_queue); spin_lock_init(&trans->reg_lock); - snprintf(cmd_pool_name, sizeof(cmd_pool_name), "iwl_cmd_pool:%s", - dev_name(trans->dev)); + snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name), + "iwl_cmd_pool:%s", dev_name(trans->dev)); trans->dev_cmd_headroom = 0; trans->dev_cmd_pool = - kmem_cache_create(cmd_pool_name, + kmem_cache_create(trans->dev_cmd_pool_name, sizeof(struct iwl_device_cmd) + trans->dev_cmd_headroom, sizeof(void *), diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c index f4a2030..eb5de80 100644 --- a/drivers/net/wireless/libertas/cfg.c +++ b/drivers/net/wireless/libertas/cfg.c @@ -805,7 +805,6 @@ void lbs_scan_done(struct lbs_private *priv) } static int lbs_cfg_scan(struct wiphy *wiphy, - struct net_device *dev, struct cfg80211_scan_request *request) { struct lbs_private *priv = wiphy_priv(wiphy); @@ -2181,13 +2180,15 @@ int lbs_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request) { struct lbs_private *priv = wiphy_priv(wiphy); - int ret; + int ret = 0; lbs_deb_enter_args(LBS_DEB_CFG80211, "cfg80211 regulatory domain " "callback for domain %c%c\n", request->alpha2[0], request->alpha2[1]); - ret = lbs_set_11d_domain_info(priv, request, wiphy->bands); + memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2)); + if (lbs_iface_active(priv)) + ret = lbs_set_11d_domain_info(priv); lbs_deb_leave(LBS_DEB_CFG80211); return ret; diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index d798bcc..26e6832 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -733,15 +733,13 @@ int lbs_get_rssi(struct lbs_private *priv, s8 *rssi, s8 *nf) * to the firmware * * @priv: pointer to &struct lbs_private - * @request: cfg80211 regulatory request structure - * @bands: the device's supported bands and channels * * returns: 0 on success, error code on failure */ -int lbs_set_11d_domain_info(struct lbs_private *priv, - struct regulatory_request *request, - struct ieee80211_supported_band **bands) +int lbs_set_11d_domain_info(struct lbs_private *priv) { + struct wiphy *wiphy = priv->wdev->wiphy; + struct ieee80211_supported_band **bands = wiphy->bands; struct cmd_ds_802_11d_domain_info cmd; struct mrvl_ie_domain_param_set *domain = &cmd.domain; struct ieee80211_country_ie_triplet *t; @@ -752,21 +750,23 @@ int lbs_set_11d_domain_info(struct lbs_private *priv, u8 first_channel = 0, next_chan = 0, max_pwr = 0; u8 i, flag = 0; size_t triplet_size; - int ret; + int ret = 0; lbs_deb_enter(LBS_DEB_11D); + if (!priv->country_code[0]) + goto out; memset(&cmd, 0, sizeof(cmd)); cmd.action = cpu_to_le16(CMD_ACT_SET); lbs_deb_11d("Setting country code '%c%c'\n", - request->alpha2[0], request->alpha2[1]); + priv->country_code[0], priv->country_code[1]); domain->header.type = cpu_to_le16(TLV_TYPE_DOMAIN); /* Set country code */ - domain->country_code[0] = request->alpha2[0]; - domain->country_code[1] = request->alpha2[1]; + domain->country_code[0] = priv->country_code[0]; + domain->country_code[1] = priv->country_code[1]; domain->country_code[2] = ' '; /* Now set up the channel triplets; firmware is somewhat picky here @@ -848,6 +848,7 @@ int lbs_set_11d_domain_info(struct lbs_private *priv, ret = lbs_cmd_with_response(priv, CMD_802_11D_DOMAIN_INFO, &cmd); +out: lbs_deb_leave_args(LBS_DEB_11D, "ret %d", ret); return ret; } @@ -1019,9 +1020,9 @@ static void lbs_submit_command(struct lbs_private *priv, if (ret) { netdev_info(priv->dev, "DNLD_CMD: hw_host_to_card failed: %d\n", ret); - /* Let the timer kick in and retry, and potentially reset - the whole thing if the condition persists */ - timeo = HZ/4; + /* Reset dnld state machine, report failure */ + priv->dnld_sent = DNLD_RES_RECEIVED; + lbs_complete_command(priv, cmdnode, ret); } if (command == CMD_802_11_DEEP_SLEEP) { diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index b280ef7..ab07608 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -128,9 +128,7 @@ int lbs_set_monitor_mode(struct lbs_private *priv, int enable); int lbs_get_rssi(struct lbs_private *priv, s8 *snr, s8 *nf); -int lbs_set_11d_domain_info(struct lbs_private *priv, - struct regulatory_request *request, - struct ieee80211_supported_band **bands); +int lbs_set_11d_domain_info(struct lbs_private *priv); int lbs_get_reg(struct lbs_private *priv, u16 reg, u16 offset, u32 *value); diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index 60996ce..6bd1608 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -49,6 +49,7 @@ struct lbs_private { bool wiphy_registered; struct cfg80211_scan_request *scan_req; u8 assoc_bss[ETH_ALEN]; + u8 country_code[IEEE80211_COUNTRY_STRING_LEN]; u8 disassoc_reason; /* Mesh */ diff --git a/drivers/net/wireless/libertas/firmware.c b/drivers/net/wireless/libertas/firmware.c index 601f207..c0f9e7e 100644 --- a/drivers/net/wireless/libertas/firmware.c +++ b/drivers/net/wireless/libertas/firmware.c @@ -4,9 +4,7 @@ #include <linux/sched.h> #include <linux/firmware.h> -#include <linux/firmware.h> #include <linux/module.h> -#include <linux/sched.h> #include "dev.h" #include "decl.h" diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index 64b7dc5..55a77e4 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -309,7 +309,6 @@ static void if_usb_disconnect(struct usb_interface *intf) cardp->surprise_removed = 1; if (priv) { - priv->surpriseremoved = 1; lbs_stop_card(priv); lbs_remove_card(priv); } diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index e96ee0a..5804818 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -152,6 +152,12 @@ int lbs_start_iface(struct lbs_private *priv) goto err; } + ret = lbs_set_11d_domain_info(priv); + if (ret) { + lbs_deb_net("set 11d domain info failed\n"); + goto err; + } + lbs_update_channel(priv); priv->iface_running = true; diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 200bcc0..643f968 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -1540,11 +1540,6 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2, /* now send back TX status */ txi = IEEE80211_SKB_CB(skb); - if (txi->control.vif) - hwsim_check_magic(txi->control.vif); - if (txi->control.sta) - hwsim_check_sta_magic(txi->control.sta); - ieee80211_tx_info_clear_status(txi); for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c index c7a177c..fe42137 100644 --- a/drivers/net/wireless/mwifiex/cfg80211.c +++ b/drivers/net/wireless/mwifiex/cfg80211.c @@ -48,10 +48,9 @@ static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = { * Others -> IEEE80211_HT_PARAM_CHA_SEC_NONE */ static u8 -mwifiex_cfg80211_channel_type_to_sec_chan_offset(enum nl80211_channel_type - channel_type) +mwifiex_chan_type_to_sec_chan_offset(enum nl80211_channel_type chan_type) { - switch (channel_type) { + switch (chan_type) { case NL80211_CHAN_NO_HT: case NL80211_CHAN_HT20: return IEEE80211_HT_PARAM_CHA_SEC_NONE; @@ -339,79 +338,6 @@ static int mwifiex_reg_notifier(struct wiphy *wiphy, } /* - * This function sets the RF channel. - * - * This function creates multiple IOCTL requests, populates them accordingly - * and issues them to set the band/channel and frequency. - */ -static int -mwifiex_set_rf_channel(struct mwifiex_private *priv, - struct ieee80211_channel *chan, - enum nl80211_channel_type channel_type) -{ - struct mwifiex_chan_freq_power cfp; - u32 config_bands = 0; - struct wiphy *wiphy = priv->wdev->wiphy; - struct mwifiex_adapter *adapter = priv->adapter; - - if (chan) { - /* Set appropriate bands */ - if (chan->band == IEEE80211_BAND_2GHZ) { - if (channel_type == NL80211_CHAN_NO_HT) - if (priv->adapter->config_bands == BAND_B || - priv->adapter->config_bands == BAND_G) - config_bands = - priv->adapter->config_bands; - else - config_bands = BAND_B | BAND_G; - else - config_bands = BAND_B | BAND_G | BAND_GN; - } else { - if (channel_type == NL80211_CHAN_NO_HT) - config_bands = BAND_A; - else - config_bands = BAND_AN | BAND_A; - } - - if (!((config_bands | adapter->fw_bands) & - ~adapter->fw_bands)) { - adapter->config_bands = config_bands; - if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { - adapter->adhoc_start_band = config_bands; - if ((config_bands & BAND_GN) || - (config_bands & BAND_AN)) - adapter->adhoc_11n_enabled = true; - else - adapter->adhoc_11n_enabled = false; - } - } - adapter->sec_chan_offset = - mwifiex_cfg80211_channel_type_to_sec_chan_offset - (channel_type); - adapter->channel_type = channel_type; - - mwifiex_send_domain_info_cmd_fw(wiphy); - } - - wiphy_dbg(wiphy, "info: setting band %d, chan offset %d, mode %d\n", - config_bands, adapter->sec_chan_offset, priv->bss_mode); - if (!chan) - return 0; - - memset(&cfp, 0, sizeof(cfp)); - cfp.freq = chan->center_freq; - cfp.channel = ieee80211_frequency_to_channel(chan->center_freq); - - if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) { - if (mwifiex_bss_set_channel(priv, &cfp)) - return -EFAULT; - return mwifiex_drv_change_adhoc_chan(priv, cfp.channel); - } - - return 0; -} - -/* * This function sets the fragmentation threshold. * * The fragmentation threshold value must lie between MWIFIEX_FRAG_MIN_VALUE @@ -626,7 +552,7 @@ static int mwifiex_dump_station_info(struct mwifiex_private *priv, struct station_info *sinfo) { - struct mwifiex_rate_cfg rate; + u32 rate; sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES | STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS | @@ -652,9 +578,9 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, /* * Bit 0 in tx_htinfo indicates that current Tx rate is 11n rate. Valid - * MCS index values for us are 0 to 7. + * MCS index values for us are 0 to 15. */ - if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 8)) { + if ((priv->tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) { sinfo->txrate.mcs = priv->tx_rate; sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; /* 40MHz rate */ @@ -672,7 +598,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv, sinfo->tx_packets = priv->stats.tx_packets; sinfo->signal = priv->bcn_rssi_avg; /* bit rate is in 500 kb/s units. Convert it to 100kb/s units */ - sinfo->txrate.legacy = rate.rate * 5; + sinfo->txrate.legacy = rate * 5; if (priv->bss_mode == NL80211_IFTYPE_STATION) { sinfo->filled |= STATION_INFO_BSS_PARAM; @@ -827,8 +753,8 @@ static const u32 mwifiex_cipher_suites[] = { /* * CFG802.11 operation handler for setting bit rates. * - * Function selects legacy bang B/G/BG from corresponding bitrates selection. - * Currently only 2.4GHz band is supported. + * Function configures data rates to firmware using bitrate mask + * provided by cfg80211. */ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *dev, @@ -836,43 +762,36 @@ static int mwifiex_cfg80211_set_bitrate_mask(struct wiphy *wiphy, const struct cfg80211_bitrate_mask *mask) { struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); - int index = 0, mode = 0, i; - struct mwifiex_adapter *adapter = priv->adapter; + u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; + enum ieee80211_band band; - /* Currently only 2.4GHz is supported */ - for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { - /* - * Rates below 6 Mbps in the table are CCK rates; 802.11b - * and from 6 they are OFDM; 802.11G - */ - if (mwifiex_rates[i].bitrate == 60) { - index = 1 << i; - break; - } + if (!priv->media_connected) { + dev_err(priv->adapter->dev, + "Can not set Tx data rate in disconnected state\n"); + return -EINVAL; } - if (mask->control[IEEE80211_BAND_2GHZ].legacy < index) { - mode = BAND_B; - } else { - mode = BAND_G; - if (mask->control[IEEE80211_BAND_2GHZ].legacy % index) - mode |= BAND_B; - } + band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - if (!((mode | adapter->fw_bands) & ~adapter->fw_bands)) { - adapter->config_bands = mode; - if (priv->bss_mode == NL80211_IFTYPE_ADHOC) { - adapter->adhoc_start_band = mode; - adapter->adhoc_11n_enabled = false; - } - } - adapter->sec_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; - adapter->channel_type = NL80211_CHAN_NO_HT; + memset(bitmap_rates, 0, sizeof(bitmap_rates)); - wiphy_debug(wiphy, "info: device configured in 802.11%s%s mode\n", - (mode & BAND_B) ? "b" : "", (mode & BAND_G) ? "g" : ""); + /* Fill HR/DSSS rates. */ + if (band == IEEE80211_BAND_2GHZ) + bitmap_rates[0] = mask->control[band].legacy & 0x000f; - return 0; + /* Fill OFDM rates */ + if (band == IEEE80211_BAND_2GHZ) + bitmap_rates[1] = (mask->control[band].legacy & 0x0ff0) >> 4; + else + bitmap_rates[1] = mask->control[band].legacy; + + /* Fill MCS rates */ + bitmap_rates[2] = mask->control[band].mcs[0]; + if (priv->adapter->hw_dev_mcs_support == HT_STREAM_2X2) + bitmap_rates[2] |= mask->control[band].mcs[1] << 8; + + return mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, + HostCmd_ACT_GEN_SET, 0, bitmap_rates); } /* @@ -1007,6 +926,7 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, { struct mwifiex_uap_bss_param *bss_cfg; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + u8 config_bands = 0; if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) return -1; @@ -1047,13 +967,25 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy, (u8)ieee80211_frequency_to_channel(params->channel->center_freq); bss_cfg->band_cfg = BAND_CONFIG_MANUAL; - if (mwifiex_set_rf_channel(priv, params->channel, - params->channel_type)) { - kfree(bss_cfg); - wiphy_err(wiphy, "Failed to set band config information!\n"); - return -1; + /* Set appropriate bands */ + if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (params->channel_type == NL80211_CHAN_NO_HT) + config_bands = BAND_B | BAND_G; + else + config_bands = BAND_B | BAND_G | BAND_GN; + } else { + if (params->channel_type == NL80211_CHAN_NO_HT) + config_bands = BAND_A; + else + config_bands = BAND_AN | BAND_A; } + if (!((config_bands | priv->adapter->fw_bands) & + ~priv->adapter->fw_bands)) + priv->adapter->config_bands = config_bands; + + mwifiex_send_domain_info_cmd_fw(wiphy); + if (mwifiex_set_secure_params(priv, bss_cfg, params)) { kfree(bss_cfg); wiphy_err(wiphy, "Failed to parse secuirty parameters!\n"); @@ -1187,7 +1119,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, struct cfg80211_ssid req_ssid; int ret, auth_type = 0; struct cfg80211_bss *bss = NULL; - u8 is_scanning_required = 0; + u8 is_scanning_required = 0, config_bands = 0; memset(&req_ssid, 0, sizeof(struct cfg80211_ssid)); @@ -1206,9 +1138,19 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid, /* disconnect before try to associate */ mwifiex_deauthenticate(priv, NULL); - if (channel) - ret = mwifiex_set_rf_channel(priv, channel, - priv->adapter->channel_type); + if (channel) { + if (mode == NL80211_IFTYPE_STATION) { + if (channel->band == IEEE80211_BAND_2GHZ) + config_bands = BAND_B | BAND_G | BAND_GN; + else + config_bands = BAND_A | BAND_AN; + + if (!((config_bands | priv->adapter->fw_bands) & + ~priv->adapter->fw_bands)) + priv->adapter->config_bands = config_bands; + } + mwifiex_send_domain_info_cmd_fw(priv->wdev->wiphy); + } /* As this is new association, clear locally stored * keys and security related flags */ @@ -1373,6 +1315,76 @@ done: } /* + * This function sets following parameters for ibss network. + * - channel + * - start band + * - 11n flag + * - secondary channel offset + */ +static int mwifiex_set_ibss_params(struct mwifiex_private *priv, + struct cfg80211_ibss_params *params) +{ + struct wiphy *wiphy = priv->wdev->wiphy; + struct mwifiex_adapter *adapter = priv->adapter; + int index = 0, i; + u8 config_bands = 0; + + if (params->channel->band == IEEE80211_BAND_2GHZ) { + if (!params->basic_rates) { + config_bands = BAND_B | BAND_G; + } else { + for (i = 0; i < mwifiex_band_2ghz.n_bitrates; i++) { + /* + * Rates below 6 Mbps in the table are CCK + * rates; 802.11b and from 6 they are OFDM; + * 802.11G + */ + if (mwifiex_rates[i].bitrate == 60) { + index = 1 << i; + break; + } + } + + if (params->basic_rates < index) { + config_bands = BAND_B; + } else { + config_bands = BAND_G; + if (params->basic_rates % index) + config_bands |= BAND_B; + } + } + + if (params->channel_type != NL80211_CHAN_NO_HT) + config_bands |= BAND_GN; + } else { + if (params->channel_type == NL80211_CHAN_NO_HT) + config_bands = BAND_A; + else + config_bands = BAND_AN | BAND_A; + } + + if (!((config_bands | adapter->fw_bands) & ~adapter->fw_bands)) { + adapter->config_bands = config_bands; + adapter->adhoc_start_band = config_bands; + + if ((config_bands & BAND_GN) || (config_bands & BAND_AN)) + adapter->adhoc_11n_enabled = true; + else + adapter->adhoc_11n_enabled = false; + } + + adapter->sec_chan_offset = + mwifiex_chan_type_to_sec_chan_offset(params->channel_type); + priv->adhoc_channel = + ieee80211_frequency_to_channel(params->channel->center_freq); + + wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n", + config_bands, priv->adhoc_channel, adapter->sec_chan_offset); + + return 0; +} + +/* * CFG802.11 operation handler to join an IBSS. * * This function does not work in any mode other than Ad-Hoc, or if @@ -1394,6 +1406,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev, wiphy_dbg(wiphy, "info: trying to join to %s and bssid %pM\n", (char *) params->ssid, params->bssid); + mwifiex_set_ibss_params(priv, params); + ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid, params->bssid, priv->bss_mode, params->channel, NULL, params->privacy); @@ -1440,9 +1454,10 @@ mwifiex_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev) * it also informs the results. */ static int -mwifiex_cfg80211_scan(struct wiphy *wiphy, struct net_device *dev, +mwifiex_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *dev = request->wdev->netdev; struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); int i; struct ieee80211_channel *chan; @@ -1576,11 +1591,11 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info, /* * create a new virtual interface with the given name */ -struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy); struct mwifiex_private *priv; @@ -1701,16 +1716,16 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_init(priv); #endif - return dev; + return wdev; } EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf); /* * del_virtual_intf: remove the virtual interface determined by dev */ -int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev) { - struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev); + struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev); #ifdef CONFIG_DEBUG_FS mwifiex_dev_debugfs_remove(priv); @@ -1722,11 +1737,11 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev) if (netif_carrier_ok(priv->netdev)) netif_carrier_off(priv->netdev); - if (dev->reg_state == NETREG_REGISTERED) - unregister_netdevice(dev); + if (wdev->netdev->reg_state == NETREG_REGISTERED) + unregister_netdevice(wdev->netdev); - if (dev->reg_state == NETREG_UNREGISTERED) - free_netdev(dev); + if (wdev->netdev->reg_state == NETREG_UNREGISTERED) + free_netdev(wdev->netdev); /* Clear the priv in adapter */ priv->netdev = NULL; @@ -1818,6 +1833,8 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter) wiphy->available_antennas_tx = BIT(adapter->number_of_antenna) - 1; wiphy->available_antennas_rx = BIT(adapter->number_of_antenna) - 1; + wiphy->features = NL80211_FEATURE_HT_IBSS; + /* Reserve space for mwifiex specific private data for BSS */ wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv); diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c index 560871b..f69300f 100644 --- a/drivers/net/wireless/mwifiex/cfp.c +++ b/drivers/net/wireless/mwifiex/cfp.c @@ -167,23 +167,6 @@ u32 mwifiex_index_to_data_rate(struct mwifiex_private *priv, u8 index, } /* - * This function maps a data rate value into corresponding index in supported - * rates table. - */ -u8 mwifiex_data_rate_to_index(u32 rate) -{ - u16 *ptr; - - if (rate) { - ptr = memchr(mwifiex_data_rates, rate, - sizeof(mwifiex_data_rates)); - if (ptr) - return (u8) (ptr - mwifiex_data_rates); - } - return 0; -} - -/* * This function returns the current active data rates. * * The result may vary depending upon connection status. @@ -277,20 +260,6 @@ mwifiex_is_rate_auto(struct mwifiex_private *priv) } /* - * This function converts rate bitmap into rate index. - */ -int mwifiex_get_rate_index(u16 *rate_bitmap, int size) -{ - int i; - - for (i = 0; i < size * 8; i++) - if (rate_bitmap[i / 16] & (1 << (i % 16))) - return i; - - return 0; -} - -/* * This function gets the supported data rates. * * The function works in both Ad-Hoc and infra mode by printing the diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h index f918f66..070ef25 100644 --- a/drivers/net/wireless/mwifiex/decl.h +++ b/drivers/net/wireless/mwifiex/decl.h @@ -41,16 +41,7 @@ #define MWIFIEX_AMPDU_DEF_RXWINSIZE 16 #define MWIFIEX_DEFAULT_BLOCK_ACK_TIMEOUT 0xffff -#define MWIFIEX_RATE_INDEX_HRDSSS0 0 -#define MWIFIEX_RATE_INDEX_HRDSSS3 3 -#define MWIFIEX_RATE_INDEX_OFDM0 4 -#define MWIFIEX_RATE_INDEX_OFDM7 11 -#define MWIFIEX_RATE_INDEX_MCS0 12 - -#define MWIFIEX_RATE_BITMAP_OFDM0 16 -#define MWIFIEX_RATE_BITMAP_OFDM7 23 #define MWIFIEX_RATE_BITMAP_MCS0 32 -#define MWIFIEX_RATE_BITMAP_MCS127 159 #define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024) #define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024) diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h index 14e985d..e831b44 100644 --- a/drivers/net/wireless/mwifiex/fw.h +++ b/drivers/net/wireless/mwifiex/fw.h @@ -225,7 +225,6 @@ enum MWIFIEX_802_11_PRIVACY_FILTER { #define HostCmd_CMD_BBP_REG_ACCESS 0x001a #define HostCmd_CMD_RF_REG_ACCESS 0x001b #define HostCmd_CMD_PMIC_REG_ACCESS 0x00ad -#define HostCmd_CMD_802_11_RF_CHANNEL 0x001d #define HostCmd_CMD_RF_TX_PWR 0x001e #define HostCmd_CMD_RF_ANTENNA 0x0020 #define HostCmd_CMD_802_11_DEAUTHENTICATE 0x0024 @@ -1292,14 +1291,6 @@ struct host_cmd_tlv_channel_band { u8 channel; } __packed; -struct host_cmd_ds_802_11_rf_channel { - __le16 action; - __le16 current_channel; - __le16 rf_type; - __le16 reserved; - u8 reserved_1[32]; -} __packed; - struct host_cmd_ds_version_ext { u8 version_str_sel; char version_str[128]; @@ -1384,7 +1375,6 @@ struct host_cmd_ds_command { struct host_cmd_ds_802_11_rssi_info rssi_info; struct host_cmd_ds_802_11_rssi_info_rsp rssi_info_rsp; struct host_cmd_ds_802_11_snmp_mib smib; - struct host_cmd_ds_802_11_rf_channel rf_channel; struct host_cmd_ds_tx_rate_query tx_rate; struct host_cmd_ds_tx_rate_cfg tx_rate_cfg; struct host_cmd_ds_txpwr_cfg txp_cfg; diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c index b543a4d..21fdc6c 100644 --- a/drivers/net/wireless/mwifiex/init.c +++ b/drivers/net/wireless/mwifiex/init.c @@ -344,7 +344,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter) adapter->adhoc_awake_period = 0; 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 e121294..5019153 100644 --- a/drivers/net/wireless/mwifiex/ioctl.h +++ b/drivers/net/wireless/mwifiex/ioctl.h @@ -225,12 +225,6 @@ struct mwifiex_ds_encrypt_key { u8 wapi_rxpn[WAPI_RXPN_LEN]; }; -struct mwifiex_rate_cfg { - u32 action; - u32 is_rate_auto; - u32 rate; -}; - struct mwifiex_power_cfg { u32 is_power_auto; u32 power_level; diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c index f0219efc..4680362 100644 --- a/drivers/net/wireless/mwifiex/main.c +++ b/drivers/net/wireless/mwifiex/main.c @@ -377,7 +377,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context) goto done; err_add_intf: - mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); err_init_fw: pr_debug("info: %s: unregister device\n", __func__); @@ -844,7 +844,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem) rtnl_lock(); if (priv->wdev && priv->netdev) - mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev); + mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev); rtnl_unlock(); } diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h index 9e63653..e7c2a82 100644 --- a/drivers/net/wireless/mwifiex/main.h +++ b/drivers/net/wireless/mwifiex/main.h @@ -678,7 +678,6 @@ struct mwifiex_adapter { u8 hw_dev_mcs_support; u8 adhoc_11n_enabled; u8 sec_chan_offset; - enum nl80211_channel_type channel_type; struct mwifiex_dbg dbg; u8 arp_filter[ARP_FILTER_MAX_BUF_SIZE]; u32 arp_filter_size; @@ -824,9 +823,7 @@ int mwifiex_cmd_append_vsie_tlv(struct mwifiex_private *priv, u16 vsie_mask, u32 mwifiex_get_active_data_rates(struct mwifiex_private *priv, u8 *rates); u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates); -u8 mwifiex_data_rate_to_index(u32 rate); u8 mwifiex_is_rate_auto(struct mwifiex_private *priv); -int mwifiex_get_rate_index(u16 *rateBitmap, int size); extern u16 region_code_index[MWIFIEX_MAX_REGION_CODE]; void mwifiex_save_curr_bcn(struct mwifiex_private *priv); void mwifiex_free_curr_bcn(struct mwifiex_private *priv); @@ -945,16 +942,13 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss, int mwifiex_cancel_hs(struct mwifiex_private *priv, int cmd_type); int mwifiex_enable_hs(struct mwifiex_adapter *adapter); int mwifiex_disable_auto_ds(struct mwifiex_private *priv); -int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, - struct mwifiex_rate_cfg *rate); +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate); int mwifiex_request_scan(struct mwifiex_private *priv, struct cfg80211_ssid *req_ssid); int mwifiex_scan_networks(struct mwifiex_private *priv, const struct mwifiex_user_scan_cfg *user_scan_in); int mwifiex_set_radio(struct mwifiex_private *priv, u8 option); -int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel); - int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key, int key_len, u8 key_index, const u8 *mac_addr, int disable); @@ -993,8 +987,6 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv, int mwifiex_main_process(struct mwifiex_adapter *); -int mwifiex_bss_set_channel(struct mwifiex_private *, - struct mwifiex_chan_freq_power *cfp); int mwifiex_get_bss_info(struct mwifiex_private *, struct mwifiex_bss_info *); int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv, @@ -1005,10 +997,12 @@ int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter, int mwifiex_check_network_compatibility(struct mwifiex_private *priv, struct mwifiex_bssdescriptor *bss_desc); -struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy, - char *name, enum nl80211_iftype type, - u32 *flags, struct vif_params *params); -int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev); +struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); +int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev); void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config); diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c index 225d4c7..df3a33c 100644 --- a/drivers/net/wireless/mwifiex/sta_cmd.c +++ b/drivers/net/wireless/mwifiex/sta_cmd.c @@ -745,40 +745,6 @@ static int mwifiex_cmd_802_11d_domain_info(struct mwifiex_private *priv, } /* - * This function prepares command to set/get RF channel. - * - * Preparation includes - - * - Setting command ID, action and proper size - * - Setting RF type and current RF channel (for SET only) - * - Ensuring correct endian-ness - */ -static int mwifiex_cmd_802_11_rf_channel(struct mwifiex_private *priv, - struct host_cmd_ds_command *cmd, - u16 cmd_action, u16 *channel) -{ - struct host_cmd_ds_802_11_rf_channel *rf_chan = - &cmd->params.rf_channel; - uint16_t rf_type = le16_to_cpu(rf_chan->rf_type); - - cmd->command = cpu_to_le16(HostCmd_CMD_802_11_RF_CHANNEL); - cmd->size = cpu_to_le16(sizeof(struct host_cmd_ds_802_11_rf_channel) - + S_DS_GEN); - - if (cmd_action == HostCmd_ACT_GEN_SET) { - if ((priv->adapter->adhoc_start_band & BAND_A) || - (priv->adapter->adhoc_start_band & BAND_AN)) - rf_chan->rf_type = - cpu_to_le16(HostCmd_SCAN_RADIO_TYPE_A); - - rf_type = le16_to_cpu(rf_chan->rf_type); - SET_SECONDARYCHAN(rf_type, priv->adapter->sec_chan_offset); - rf_chan->current_channel = cpu_to_le16(*channel); - } - rf_chan->action = cpu_to_le16(cmd_action); - return 0; -} - -/* * This function prepares command to set/get IBSS coalescing status. * * Preparation includes - @@ -1169,10 +1135,6 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no, S_DS_GEN); ret = 0; break; - case HostCmd_CMD_802_11_RF_CHANNEL: - ret = mwifiex_cmd_802_11_rf_channel(priv, cmd_ptr, cmd_action, - data_buf); - break; case HostCmd_CMD_FUNC_INIT: if (priv->adapter->hw_status == MWIFIEX_HW_STATUS_RESET) priv->adapter->hw_status = MWIFIEX_HW_STATUS_READY; diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c index 97715df..0b09004 100644 --- a/drivers/net/wireless/mwifiex/sta_cmdresp.c +++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c @@ -267,12 +267,10 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv, * * Based on the new rate bitmaps, the function re-evaluates if * auto data rate has been activated. If not, it sends another - * query to the firmware to get the current Tx data rate and updates - * the driver value. + * query to the firmware to get the current Tx data rate. */ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - struct mwifiex_rate_cfg *ds_rate) + struct host_cmd_ds_command *resp) { struct host_cmd_ds_tx_rate_cfg *rate_cfg = &resp->params.tx_rate_cfg; struct mwifiex_rate_scope *rate_scope; @@ -280,7 +278,6 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, u16 tlv, tlv_buf_len; u8 *tlv_buf; u32 i; - int ret = 0; tlv_buf = ((u8 *)rate_cfg) + sizeof(struct host_cmd_ds_tx_rate_cfg); @@ -318,33 +315,11 @@ static int mwifiex_ret_tx_rate_cfg(struct mwifiex_private *priv, if (priv->is_data_rate_auto) priv->data_rate = 0; else - ret = mwifiex_send_cmd_async(priv, - HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); - - if (!ds_rate) - return ret; - - if (le16_to_cpu(rate_cfg->action) == HostCmd_ACT_GEN_GET) { - if (priv->is_data_rate_auto) { - ds_rate->is_rate_auto = 1; - return ret; - } - ds_rate->rate = mwifiex_get_rate_index(priv->bitmap_rates, - sizeof(priv->bitmap_rates)); - - if (ds_rate->rate >= MWIFIEX_RATE_BITMAP_OFDM0 && - ds_rate->rate <= MWIFIEX_RATE_BITMAP_OFDM7) - ds_rate->rate -= (MWIFIEX_RATE_BITMAP_OFDM0 - - MWIFIEX_RATE_INDEX_OFDM0); - - if (ds_rate->rate >= MWIFIEX_RATE_BITMAP_MCS0 && - ds_rate->rate <= MWIFIEX_RATE_BITMAP_MCS127) - ds_rate->rate -= (MWIFIEX_RATE_BITMAP_MCS0 - - MWIFIEX_RATE_INDEX_MCS0); - } + return mwifiex_send_cmd_async(priv, + HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); - return ret; + return 0; } /* @@ -656,34 +631,6 @@ static int mwifiex_ret_802_11d_domain_info(struct mwifiex_private *priv, } /* - * This function handles the command response of get RF channel. - * - * Handling includes changing the header fields into CPU format - * and saving the new channel in driver. - */ -static int mwifiex_ret_802_11_rf_channel(struct mwifiex_private *priv, - struct host_cmd_ds_command *resp, - u16 *data_buf) -{ - struct host_cmd_ds_802_11_rf_channel *rf_channel = - &resp->params.rf_channel; - u16 new_channel = le16_to_cpu(rf_channel->current_channel); - - if (priv->curr_bss_params.bss_descriptor.channel != new_channel) { - dev_dbg(priv->adapter->dev, "cmd: Channel Switch: %d to %d\n", - priv->curr_bss_params.bss_descriptor.channel, - new_channel); - /* Update the channel again */ - priv->curr_bss_params.bss_descriptor.channel = new_channel; - } - - if (data_buf) - *data_buf = new_channel; - - return 0; -} - -/* * This function handles the command response of get extended version. * * Handling includes forming the extended version string and sending it @@ -878,7 +825,7 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, ret = mwifiex_ret_mac_multicast_adr(priv, resp); break; case HostCmd_CMD_TX_RATE_CFG: - ret = mwifiex_ret_tx_rate_cfg(priv, resp, data_buf); + ret = mwifiex_ret_tx_rate_cfg(priv, resp); break; case HostCmd_CMD_802_11_SCAN: ret = mwifiex_ret_802_11_scan(priv, resp); @@ -929,9 +876,6 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no, case HostCmd_CMD_802_11_TX_RATE_QUERY: ret = mwifiex_ret_802_11_tx_rate_query(priv, resp); break; - case HostCmd_CMD_802_11_RF_CHANNEL: - ret = mwifiex_ret_802_11_rf_channel(priv, resp, data_buf); - break; case HostCmd_CMD_VERSION_EXT: ret = mwifiex_ret_ver_ext(priv, resp, data_buf); break; diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c index f2fd242..fb21360 100644 --- a/drivers/net/wireless/mwifiex/sta_ioctl.c +++ b/drivers/net/wireless/mwifiex/sta_ioctl.c @@ -497,297 +497,24 @@ int mwifiex_disable_auto_ds(struct mwifiex_private *priv) EXPORT_SYMBOL_GPL(mwifiex_disable_auto_ds); /* - * IOCTL request handler to set/get active channel. - * - * This function performs validity checking on channel/frequency - * compatibility and returns failure if not valid. - */ -int mwifiex_bss_set_channel(struct mwifiex_private *priv, - struct mwifiex_chan_freq_power *chan) -{ - struct mwifiex_adapter *adapter = priv->adapter; - struct mwifiex_chan_freq_power *cfp = NULL; - - if (!chan) - return -1; - - if (!chan->channel && !chan->freq) - return -1; - if (adapter->adhoc_start_band & BAND_AN) - adapter->adhoc_start_band = BAND_G | BAND_B | BAND_GN; - else if (adapter->adhoc_start_band & BAND_A) - adapter->adhoc_start_band = BAND_G | BAND_B; - if (chan->channel) { - if (chan->channel <= MAX_CHANNEL_BAND_BG) - cfp = mwifiex_get_cfp(priv, 0, (u16) chan->channel, 0); - if (!cfp) { - cfp = mwifiex_get_cfp(priv, BAND_A, - (u16) chan->channel, 0); - if (cfp) { - if (adapter->adhoc_11n_enabled) - adapter->adhoc_start_band = BAND_A - | BAND_AN; - else - adapter->adhoc_start_band = BAND_A; - } - } - } else { - if (chan->freq <= MAX_FREQUENCY_BAND_BG) - cfp = mwifiex_get_cfp(priv, 0, 0, chan->freq); - if (!cfp) { - cfp = mwifiex_get_cfp(priv, BAND_A, 0, chan->freq); - if (cfp) { - if (adapter->adhoc_11n_enabled) - adapter->adhoc_start_band = BAND_A - | BAND_AN; - else - adapter->adhoc_start_band = BAND_A; - } - } - } - if (!cfp || !cfp->channel) { - dev_err(adapter->dev, "invalid channel/freq\n"); - return -1; - } - priv->adhoc_channel = (u8) cfp->channel; - chan->channel = cfp->channel; - chan->freq = cfp->freq; - - return 0; -} - -/* - * IOCTL request handler to set/get Ad-Hoc channel. - * - * This function prepares the correct firmware command and - * issues it to set or get the ad-hoc channel. - */ -static int mwifiex_bss_ioctl_ibss_channel(struct mwifiex_private *priv, - u16 action, u16 *channel) -{ - if (action == HostCmd_ACT_GEN_GET) { - if (!priv->media_connected) { - *channel = priv->adhoc_channel; - return 0; - } - } else { - priv->adhoc_channel = (u8) *channel; - } - - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_RF_CHANNEL, - action, 0, channel); -} - -/* - * IOCTL request handler to change Ad-Hoc channel. - * - * This function allocates the IOCTL request buffer, fills it - * with requisite parameters and calls the IOCTL handler. - * - * The function follows the following steps to perform the change - - * - Get current IBSS information - * - Get current channel - * - If no change is required, return - * - If not connected, change channel and return - * - If connected, - * - Disconnect - * - Change channel - * - Perform specific SSID scan with same SSID - * - Start/Join the IBSS - */ -int -mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel) -{ - int ret; - struct mwifiex_bss_info bss_info; - struct mwifiex_ssid_bssid ssid_bssid; - u16 curr_chan = 0; - struct cfg80211_bss *bss = NULL; - struct ieee80211_channel *chan; - enum ieee80211_band band; - - memset(&bss_info, 0, sizeof(bss_info)); - - /* Get BSS information */ - if (mwifiex_get_bss_info(priv, &bss_info)) - return -1; - - /* Get current channel */ - ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_GET, - &curr_chan); - - if (curr_chan == channel) { - ret = 0; - goto done; - } - dev_dbg(priv->adapter->dev, "cmd: updating channel from %d to %d\n", - curr_chan, channel); - - if (!bss_info.media_connected) { - ret = 0; - goto done; - } - - /* Do disonnect */ - memset(&ssid_bssid, 0, ETH_ALEN); - ret = mwifiex_deauthenticate(priv, ssid_bssid.bssid); - - ret = mwifiex_bss_ioctl_ibss_channel(priv, HostCmd_ACT_GEN_SET, - &channel); - - /* Do specific SSID scanning */ - if (mwifiex_request_scan(priv, &bss_info.ssid)) { - ret = -1; - goto done; - } - - band = mwifiex_band_to_radio_type(priv->curr_bss_params.band); - chan = __ieee80211_get_channel(priv->wdev->wiphy, - ieee80211_channel_to_frequency(channel, - band)); - - /* Find the BSS we want using available scan results */ - bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid, - bss_info.ssid.ssid, bss_info.ssid.ssid_len, - WLAN_CAPABILITY_ESS, WLAN_CAPABILITY_ESS); - if (!bss) - wiphy_warn(priv->wdev->wiphy, "assoc: bss %pM not in scan results\n", - bss_info.bssid); - - ret = mwifiex_bss_start(priv, bss, &bss_info.ssid); -done: - return ret; -} - -/* - * IOCTL request handler to get rate. - * - * This function prepares the correct firmware command and - * issues it to get the current rate if it is connected, - * otherwise, the function returns the lowest supported rate - * for the band. - */ -static int mwifiex_rate_ioctl_get_rate_value(struct mwifiex_private *priv, - struct mwifiex_rate_cfg *rate_cfg) -{ - rate_cfg->is_rate_auto = priv->is_data_rate_auto; - return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, - HostCmd_ACT_GEN_GET, 0, NULL); -} - -/* - * IOCTL request handler to set rate. - * - * This function prepares the correct firmware command and - * issues it to set the current rate. - * - * The function also performs validation checking on the supplied value. - */ -static int mwifiex_rate_ioctl_set_rate_value(struct mwifiex_private *priv, - struct mwifiex_rate_cfg *rate_cfg) -{ - u8 rates[MWIFIEX_SUPPORTED_RATES]; - u8 *rate; - int rate_index, ret; - u16 bitmap_rates[MAX_BITMAP_RATES_SIZE]; - u32 i; - struct mwifiex_adapter *adapter = priv->adapter; - - if (rate_cfg->is_rate_auto) { - memset(bitmap_rates, 0, sizeof(bitmap_rates)); - /* Support all HR/DSSS rates */ - bitmap_rates[0] = 0x000F; - /* Support all OFDM rates */ - bitmap_rates[1] = 0x00FF; - /* Support all HT-MCSs rate */ - for (i = 0; i < ARRAY_SIZE(priv->bitmap_rates) - 3; i++) - bitmap_rates[i + 2] = 0xFFFF; - bitmap_rates[9] = 0x3FFF; - } else { - memset(rates, 0, sizeof(rates)); - mwifiex_get_active_data_rates(priv, rates); - rate = rates; - for (i = 0; (rate[i] && i < MWIFIEX_SUPPORTED_RATES); i++) { - dev_dbg(adapter->dev, "info: rate=%#x wanted=%#x\n", - rate[i], rate_cfg->rate); - if ((rate[i] & 0x7f) == (rate_cfg->rate & 0x7f)) - break; - } - if ((i == MWIFIEX_SUPPORTED_RATES) || !rate[i]) { - dev_err(adapter->dev, "fixed data rate %#x is out " - "of range\n", rate_cfg->rate); - return -1; - } - memset(bitmap_rates, 0, sizeof(bitmap_rates)); - - rate_index = mwifiex_data_rate_to_index(rate_cfg->rate); - - /* Only allow b/g rates to be set */ - if (rate_index >= MWIFIEX_RATE_INDEX_HRDSSS0 && - rate_index <= MWIFIEX_RATE_INDEX_HRDSSS3) { - bitmap_rates[0] = 1 << rate_index; - } else { - rate_index -= 1; /* There is a 0x00 in the table */ - if (rate_index >= MWIFIEX_RATE_INDEX_OFDM0 && - rate_index <= MWIFIEX_RATE_INDEX_OFDM7) - bitmap_rates[1] = 1 << (rate_index - - MWIFIEX_RATE_INDEX_OFDM0); - } - } - - ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_TX_RATE_CFG, - HostCmd_ACT_GEN_SET, 0, bitmap_rates); - - return ret; -} - -/* - * IOCTL request handler to set/get rate. - * - * This function can be used to set/get either the rate value or the - * rate index. - */ -static int mwifiex_rate_ioctl_cfg(struct mwifiex_private *priv, - struct mwifiex_rate_cfg *rate_cfg) -{ - int status; - - if (!rate_cfg) - return -1; - - if (rate_cfg->action == HostCmd_ACT_GEN_GET) - status = mwifiex_rate_ioctl_get_rate_value(priv, rate_cfg); - else - status = mwifiex_rate_ioctl_set_rate_value(priv, rate_cfg); - - return status; -} - -/* * Sends IOCTL request to get the data rate. * * This function allocates the IOCTL request buffer, fills it * with requisite parameters and calls the IOCTL handler. */ -int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, - struct mwifiex_rate_cfg *rate) +int mwifiex_drv_get_data_rate(struct mwifiex_private *priv, u32 *rate) { int ret; - memset(rate, 0, sizeof(struct mwifiex_rate_cfg)); - rate->action = HostCmd_ACT_GEN_GET; - ret = mwifiex_rate_ioctl_cfg(priv, rate); + ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_TX_RATE_QUERY, + HostCmd_ACT_GEN_GET, 0, NULL); if (!ret) { - if (rate->is_rate_auto) - rate->rate = mwifiex_index_to_data_rate(priv, - priv->tx_rate, - priv->tx_htinfo - ); + if (priv->is_data_rate_auto) + *rate = mwifiex_index_to_data_rate(priv, priv->tx_rate, + priv->tx_htinfo); else - rate->rate = priv->data_rate; - } else { - ret = -1; + *rate = priv->data_rate; } return ret; diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c index cf7bdc6..224e03a 100644 --- a/drivers/net/wireless/mwl8k.c +++ b/drivers/net/wireless/mwl8k.c @@ -1665,7 +1665,9 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) info = IEEE80211_SKB_CB(skb); if (ieee80211_is_data(wh->frame_control)) { - sta = info->control.sta; + rcu_read_lock(); + sta = ieee80211_find_sta_by_ifaddr(hw, wh->addr1, + wh->addr2); if (sta) { sta_info = MWL8K_STA(sta); BUG_ON(sta_info == NULL); @@ -1682,6 +1684,7 @@ mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int limit, int force) sta_info->is_ampdu_allowed = true; } } + rcu_read_unlock(); } ieee80211_tx_info_clear_status(info); diff --git a/drivers/net/wireless/orinoco/cfg.c b/drivers/net/wireless/orinoco/cfg.c index e156755..7b751fb 100644 --- a/drivers/net/wireless/orinoco/cfg.c +++ b/drivers/net/wireless/orinoco/cfg.c @@ -138,7 +138,7 @@ static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev, return err; } -static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev, +static int orinoco_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { struct orinoco_private *priv = wiphy_priv(wiphy); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index dfcd02a..241162e 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -484,7 +484,7 @@ static int rndis_change_virtual_intf(struct wiphy *wiphy, enum nl80211_iftype type, u32 *flags, struct vif_params *params); -static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, +static int rndis_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request); static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed); @@ -1941,9 +1941,10 @@ static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm) } #define SCAN_DELAY_JIFFIES (6 * HZ) -static int rndis_scan(struct wiphy *wiphy, struct net_device *dev, +static int rndis_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { + struct net_device *dev = request->wdev->netdev; struct usbnet *usbdev = netdev_priv(dev); struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev); int ret; diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index e7361d9..49a63e9 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -102,7 +102,7 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, /* Update the AID, this is needed for dynamic PS support */ rt2x00dev->aid = bss_conf->assoc ? bss_conf->aid : 0; - rt2x00dev->last_beacon = bss_conf->last_tsf; + rt2x00dev->last_beacon = bss_conf->sync_tsf; /* Update global beacon interval time, this is needed for PS support */ rt2x00dev->beacon_int = bss_conf->beacon_int; diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c index 58e1f7b..942e56b 100644 --- a/drivers/net/wireless/rtlwifi/base.c +++ b/drivers/net/wireless/rtlwifi/base.c @@ -167,7 +167,7 @@ static const u8 tid_to_ac[] = { 0, /* IEEE80211_AC_VO */ }; -u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid) +u8 rtl_tid_to_ac(u8 tid) { return tid_to_ac[tid]; } diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h index 5a23a6d..f35af0f 100644 --- a/drivers/net/wireless/rtlwifi/base.h +++ b/drivers/net/wireless/rtlwifi/base.h @@ -138,7 +138,7 @@ int rtl_send_smps_action(struct ieee80211_hw *hw, enum ieee80211_smps_mode smps); u8 *rtl_find_ie(u8 *data, unsigned int len, u8 ie); void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len); -u8 rtl_tid_to_ac(struct ieee80211_hw *hw, u8 tid); +u8 rtl_tid_to_ac(u8 tid); extern struct attribute_group rtl_attribute_group; int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, u8 desc_rate, bool first_ampdu); diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 31138fd..80f75d3 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -480,7 +480,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw) /* we juse use em for BE/BK/VI/VO */ for (tid = 7; tid >= 0; tid--) { - u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)]; + u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)]; struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue]; while (!mac->act_scanning && rtlpriv->psc.rfpwr_state == ERFON) { diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c index 18380a7..4420312 100644 --- a/drivers/net/wireless/rtlwifi/rtl8192de/phy.c +++ b/drivers/net/wireless/rtlwifi/rtl8192de/phy.c @@ -3345,21 +3345,21 @@ void rtl92d_phy_config_macphymode_info(struct ieee80211_hw *hw) switch (rtlhal->macphymode) { case DUALMAC_SINGLEPHY: rtlphy->rf_type = RF_2T2R; - rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->version |= RF_TYPE_2T2R; rtlhal->bandset = BAND_ON_BOTH; rtlhal->current_bandtype = BAND_ON_2_4G; break; case SINGLEMAC_SINGLEPHY: rtlphy->rf_type = RF_2T2R; - rtlhal->version |= CHIP_92D_SINGLEPHY; + rtlhal->version |= RF_TYPE_2T2R; rtlhal->bandset = BAND_ON_BOTH; rtlhal->current_bandtype = BAND_ON_2_4G; break; case DUALMAC_DUALPHY: rtlphy->rf_type = RF_1T1R; - rtlhal->version &= (~CHIP_92D_SINGLEPHY); + rtlhal->version &= RF_TYPE_1T1R; /* Now we let MAC0 run on 5G band. */ if (rtlhal->interfaceindex == 0) { rtlhal->bandset = BAND_ON_5G; diff --git a/drivers/net/wireless/rtlwifi/usb.c b/drivers/net/wireless/rtlwifi/usb.c index a6049d7..aa970fc 100644 --- a/drivers/net/wireless/rtlwifi/usb.c +++ b/drivers/net/wireless/rtlwifi/usb.c @@ -131,15 +131,19 @@ static u32 _usb_read_sync(struct rtl_priv *rtlpriv, u32 addr, u16 len) u8 request; u16 wvalue; u16 index; - __le32 *data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + __le32 *data; + unsigned long flags; + spin_lock_irqsave(&rtlpriv->locks.usb_lock, flags); + if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) + rtlpriv->usb_data_index = 0; + data = &rtlpriv->usb_data[rtlpriv->usb_data_index]; + spin_unlock_irqrestore(&rtlpriv->locks.usb_lock, flags); request = REALTEK_USB_VENQT_CMD_REQ; index = REALTEK_USB_VENQT_CMD_IDX; /* n/a */ wvalue = (u16)addr; _usbctrl_vendorreq_sync_read(udev, request, wvalue, index, data, len); - if (++rtlpriv->usb_data_index >= RTL_USB_MAX_RX_COUNT) - rtlpriv->usb_data_index = 0; return le32_to_cpu(*data); } @@ -951,6 +955,10 @@ int __devinit rtl_usb_probe(struct usb_interface *intf, GFP_KERNEL); if (!rtlpriv->usb_data) return -ENOMEM; + + /* this spin lock must be initialized early */ + spin_lock_init(&rtlpriv->locks.usb_lock); + rtlpriv->usb_data_index = 0; init_completion(&rtlpriv->firmware_loading_complete); SET_IEEE80211_DEV(hw, &intf->dev); diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h index bd816ae..cdaa21f 100644 --- a/drivers/net/wireless/rtlwifi/wifi.h +++ b/drivers/net/wireless/rtlwifi/wifi.h @@ -1555,6 +1555,7 @@ struct rtl_locks { spinlock_t rf_ps_lock; spinlock_t rf_lock; spinlock_t waitq_lock; + spinlock_t usb_lock; /*Dual mac*/ spinlock_t cck_and_rw_pagea_lock; diff --git a/drivers/net/wireless/ti/wl12xx/cmd.c b/drivers/net/wireless/ti/wl12xx/cmd.c index 30be784..6222062 100644 --- a/drivers/net/wireless/ti/wl12xx/cmd.c +++ b/drivers/net/wireless/ti/wl12xx/cmd.c @@ -85,7 +85,11 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - if (gp->tx_bip_fem_auto_detect) + /* If we started in PLT FEM_DETECT mode, force auto detect */ + if (wl->plt_mode == PLT_FEM_DETECT) + gen_parms->general_params.tx_bip_fem_auto_detect = true; + + if (gen_parms->general_params.tx_bip_fem_auto_detect) answer = true; /* Override the REF CLK from the NVS with the one from platform data */ @@ -106,8 +110,17 @@ int wl1271_cmd_general_parms(struct wl1271 *wl) goto out; } + /* If we are in calibrator based fem auto detect - save fem nr */ + if (wl->plt_mode == PLT_FEM_DETECT) + wl->fem_manuf = gp->tx_bip_fem_manufacturer; + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", - answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + answer == false ? + "manual" : + wl->plt_mode == PLT_FEM_DETECT ? + "calibrator_fem_detect" : + "auto", + gp->tx_bip_fem_manufacturer); out: kfree(gen_parms); @@ -139,7 +152,11 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) memcpy(&gen_parms->general_params, gp, sizeof(*gp)); - if (gp->tx_bip_fem_auto_detect) + /* If we started in PLT FEM_DETECT mode, force auto detect */ + if (wl->plt_mode == PLT_FEM_DETECT) + gen_parms->general_params.tx_bip_fem_auto_detect = true; + + if (gen_parms->general_params.tx_bip_fem_auto_detect) answer = true; /* Replace REF and TCXO CLKs with the ones from platform data */ @@ -161,8 +178,17 @@ int wl128x_cmd_general_parms(struct wl1271 *wl) goto out; } + /* If we are in calibrator based fem auto detect - save fem nr */ + if (wl->plt_mode == PLT_FEM_DETECT) + wl->fem_manuf = gp->tx_bip_fem_manufacturer; + wl1271_debug(DEBUG_CMD, "FEM autodetect: %s, manufacturer: %d\n", - answer ? "auto" : "manual", gp->tx_bip_fem_manufacturer); + answer == false ? + "manual" : + wl->plt_mode == PLT_FEM_DETECT ? + "calibrator_fem_detect" : + "auto", + gp->tx_bip_fem_manufacturer); out: kfree(gen_parms); diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c index 3d6c71b..f429fc1 100644 --- a/drivers/net/wireless/ti/wl12xx/main.c +++ b/drivers/net/wireless/ti/wl12xx/main.c @@ -1339,6 +1339,14 @@ static int wl12xx_hw_init(struct wl1271 *wl) ret = wl128x_cmd_general_parms(wl); if (ret < 0) goto out; + + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + ret = wl128x_cmd_radio_parms(wl); if (ret < 0) goto out; @@ -1355,6 +1363,14 @@ static int wl12xx_hw_init(struct wl1271 *wl) ret = wl1271_cmd_general_parms(wl); if (ret < 0) goto out; + + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + ret = wl1271_cmd_radio_parms(wl); if (ret < 0) goto out; @@ -1500,6 +1516,13 @@ static int wl12xx_plt_init(struct wl1271 *wl) if (ret < 0) goto out_irq_disable; + /* + * If we are in calibrator based auto detect then we got the FEM nr + * in wl->fem_manuf. No need to continue further + */ + if (wl->plt_mode == PLT_FEM_DETECT) + goto out; + ret = wl1271_acx_init_mem_config(wl); if (ret < 0) goto out_irq_disable; diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h index fac0b7e..4d426cc 100644 --- a/drivers/net/wireless/ti/wl18xx/conf.h +++ b/drivers/net/wireless/ti/wl18xx/conf.h @@ -23,7 +23,7 @@ #define __WL18XX_CONF_H__ #define WL18XX_CONF_MAGIC 0x10e100ca -#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0002) +#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0003) #define WL18XX_CONF_MASK 0x0000ffff #define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \ sizeof(struct wl18xx_priv_conf)) @@ -84,7 +84,26 @@ struct wl18xx_mac_and_phy_params { u8 padding[1]; } __packed; +enum wl18xx_ht_mode { + /* Default - use MIMO, fallback to SISO20 */ + HT_MODE_DEFAULT = 0, + + /* Wide - use SISO40 */ + HT_MODE_WIDE = 1, + + /* Use SISO20 */ + HT_MODE_SISO20 = 2, +}; + +struct wl18xx_ht_settings { + /* DEFAULT / WIDE / SISO20 */ + u8 mode; +} __packed; + struct wl18xx_priv_conf { + /* Module params structures */ + struct wl18xx_ht_settings ht; + /* this structure is copied wholesale to FW */ struct wl18xx_mac_and_phy_params phy; } __packed; diff --git a/drivers/net/wireless/ti/wl18xx/io.c b/drivers/net/wireless/ti/wl18xx/io.c index 0c06ccf..f0abf3e 100644 --- a/drivers/net/wireless/ti/wl18xx/io.c +++ b/drivers/net/wireless/ti/wl18xx/io.c @@ -54,7 +54,7 @@ out: int wl18xx_top_reg_read(struct wl1271 *wl, int addr, u16 *out) { - u32 val; + u32 val = 0; int ret; if (WARN_ON(addr % 2)) diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c index b378b34..69042bb 100644 --- a/drivers/net/wireless/ti/wl18xx/main.c +++ b/drivers/net/wireless/ti/wl18xx/main.c @@ -43,8 +43,8 @@ #define WL18XX_RX_CHECKSUM_MASK 0x40 -static char *ht_mode_param = "default"; -static char *board_type_param = "hdk"; +static char *ht_mode_param = NULL; +static char *board_type_param = NULL; static bool checksum_param = false; static bool enable_11a_param = true; static int num_rx_desc_param = -1; @@ -494,16 +494,20 @@ static struct wlcore_conf wl18xx_conf = { }; static struct wl18xx_priv_conf wl18xx_default_priv_conf = { + .ht = { + .mode = HT_MODE_DEFAULT, + }, .phy = { .phy_standalone = 0x00, .primary_clock_setting_time = 0x05, .clock_valid_on_wake_up = 0x00, .secondary_clock_setting_time = 0x05, + .board_type = BOARD_TYPE_HDK_18XX, .rdl = 0x01, .auto_detect = 0x00, .dedicated_fem = FEM_NONE, .low_band_component = COMPONENT_2_WAY_SWITCH, - .low_band_component_type = 0x05, + .low_band_component_type = 0x06, .high_band_component = COMPONENT_2_WAY_SWITCH, .high_band_component_type = 0x09, .tcxo_ldo_voltage = 0x00, @@ -772,16 +776,24 @@ out: static int wl18xx_set_mac_and_phy(struct wl1271 *wl) { struct wl18xx_priv *priv = wl->priv; + struct wl18xx_mac_and_phy_params *params; int ret; + params = kmemdup(&priv->conf.phy, sizeof(*params), GFP_KERNEL); + if (!params) { + ret = -ENOMEM; + goto out; + } + ret = wlcore_set_partition(wl, &wl->ptable[PART_PHY_INIT]); if (ret < 0) goto out; - ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, (u8 *)&priv->conf.phy, - sizeof(struct wl18xx_mac_and_phy_params), false); + ret = wlcore_write(wl, WL18XX_PHY_INIT_MEM_ADDR, params, + sizeof(*params), false); out: + kfree(params); return ret; } @@ -1001,6 +1013,13 @@ static void wl18xx_set_rx_csum(struct wl1271 *wl, skb->ip_summed = CHECKSUM_UNNECESSARY; } +static bool wl18xx_is_mimo_supported(struct wl1271 *wl) +{ + struct wl18xx_priv *priv = wl->priv; + + return priv->conf.phy.number_of_assembled_ant2_4 >= 2; +} + /* * TODO: instead of having these two functions to get the rate mask, * we should modify the wlvif->rate_set instead @@ -1017,6 +1036,9 @@ static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, /* we don't support MIMO in wide-channel mode */ hw_rate_set &= ~CONF_TX_MIMO_RATES; + } else if (wl18xx_is_mimo_supported(wl)) { + wl1271_debug(DEBUG_ACX, "using MIMO channel rate mask"); + hw_rate_set |= CONF_TX_MIMO_RATES; } return hw_rate_set; @@ -1025,8 +1047,6 @@ static u32 wl18xx_sta_get_ap_rate_mask(struct wl1271 *wl, static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, struct wl12xx_vif *wlvif) { - struct wl18xx_priv *priv = wl->priv; - if (wlvif->channel_type == NL80211_CHAN_HT40MINUS || wlvif->channel_type == NL80211_CHAN_HT40PLUS) { wl1271_debug(DEBUG_ACX, "using wide channel rate mask"); @@ -1036,7 +1056,7 @@ static u32 wl18xx_ap_get_mimo_wide_rate_mask(struct wl1271 *wl, return 0; return CONF_TX_RATE_USE_WIDE_CHAN; - } else if (priv->conf.phy.number_of_assembled_ant2_4 >= 2 && + } else if (wl18xx_is_mimo_supported(wl) && wlvif->band == IEEE80211_BAND_2GHZ) { wl1271_debug(DEBUG_ACX, "using MIMO rate mask"); /* @@ -1136,6 +1156,12 @@ static int wl18xx_plt_init(struct wl1271 *wl) { int ret; + /* calibrator based auto/fem detect not supported for 18xx */ + if (wl->plt_mode == PLT_FEM_DETECT) { + wl1271_error("wl18xx_plt_init: PLT FEM_DETECT not supported"); + return -EINVAL; + } + ret = wlcore_write32(wl, WL18XX_SCR_PAD8, WL18XX_SCR_PAD8_PLT); if (ret < 0) return ret; @@ -1383,27 +1409,44 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) if (ret < 0) goto out_free; - if (!strcmp(board_type_param, "fpga")) { - priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX; - } else if (!strcmp(board_type_param, "hdk")) { - priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX; - /* HACK! Just for now we hardcode HDK to 0x06 */ - priv->conf.phy.low_band_component_type = 0x06; - } else if (!strcmp(board_type_param, "dvp")) { - priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX; - } else if (!strcmp(board_type_param, "evb")) { - priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX; - } else if (!strcmp(board_type_param, "com8")) { - priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX; - /* HACK! Just for now we hardcode COM8 to 0x06 */ + /* If the module param is set, update it in conf */ + if (board_type_param) { + if (!strcmp(board_type_param, "fpga")) { + priv->conf.phy.board_type = BOARD_TYPE_FPGA_18XX; + } else if (!strcmp(board_type_param, "hdk")) { + priv->conf.phy.board_type = BOARD_TYPE_HDK_18XX; + } else if (!strcmp(board_type_param, "dvp")) { + priv->conf.phy.board_type = BOARD_TYPE_DVP_18XX; + } else if (!strcmp(board_type_param, "evb")) { + priv->conf.phy.board_type = BOARD_TYPE_EVB_18XX; + } else if (!strcmp(board_type_param, "com8")) { + priv->conf.phy.board_type = BOARD_TYPE_COM8_18XX; + } else { + wl1271_error("invalid board type '%s'", + board_type_param); + ret = -EINVAL; + goto out_free; + } + } + + /* HACK! Just for now we hardcode COM8 and HDK to 0x06 */ + switch (priv->conf.phy.board_type) { + case BOARD_TYPE_HDK_18XX: + case BOARD_TYPE_COM8_18XX: priv->conf.phy.low_band_component_type = 0x06; - } else { - wl1271_error("invalid board type '%s'", board_type_param); + break; + case BOARD_TYPE_FPGA_18XX: + case BOARD_TYPE_DVP_18XX: + case BOARD_TYPE_EVB_18XX: + priv->conf.phy.low_band_component_type = 0x05; + break; + default: + wl1271_error("invalid board type '%d'", + priv->conf.phy.board_type); ret = -EINVAL; goto out_free; } - /* If the module param is set, update it in conf */ if (low_band_component_param != -1) priv->conf.phy.low_band_component = low_band_component_param; if (low_band_component_type_param != -1) @@ -1424,12 +1467,26 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) if (dc2dc_param != -1) priv->conf.phy.external_pa_dc2dc = dc2dc_param; - if (!strcmp(ht_mode_param, "default")) { + if (ht_mode_param) { + if (!strcmp(ht_mode_param, "default")) + priv->conf.ht.mode = HT_MODE_DEFAULT; + else if (!strcmp(ht_mode_param, "wide")) + priv->conf.ht.mode = HT_MODE_WIDE; + else if (!strcmp(ht_mode_param, "siso20")) + priv->conf.ht.mode = HT_MODE_SISO20; + else { + wl1271_error("invalid ht_mode '%s'", ht_mode_param); + ret = -EINVAL; + goto out_free; + } + } + + if (priv->conf.ht.mode == HT_MODE_DEFAULT) { /* * Only support mimo with multiple antennas. Fall back to * siso20. */ - if (priv->conf.phy.number_of_assembled_ant2_4 >= 2) + if (wl18xx_is_mimo_supported(wl)) wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl18xx_mimo_ht_cap_2ghz); else @@ -1439,20 +1496,16 @@ static int __devinit wl18xx_probe(struct platform_device *pdev) /* 5Ghz is always wide */ wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl18xx_siso40_ht_cap_5ghz); - } else if (!strcmp(ht_mode_param, "wide")) { + } else if (priv->conf.ht.mode == HT_MODE_WIDE) { wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl18xx_siso40_ht_cap_2ghz); wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl18xx_siso40_ht_cap_5ghz); - } else if (!strcmp(ht_mode_param, "siso20")) { + } else if (priv->conf.ht.mode == HT_MODE_SISO20) { wlcore_set_ht_cap(wl, IEEE80211_BAND_2GHZ, &wl18xx_siso20_ht_cap); wlcore_set_ht_cap(wl, IEEE80211_BAND_5GHZ, &wl18xx_siso20_ht_cap); - } else { - wl1271_error("invalid ht_mode '%s'", ht_mode_param); - ret = -EINVAL; - goto out_free; } if (!checksum_param) { diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c index a23949c..20e1bd9 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c @@ -497,6 +497,7 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) { struct wl12xx_cmd_role_stop *cmd; int ret; + bool timeout = false; if (WARN_ON(wlvif->sta.hlid == WL12XX_INVALID_LINK_ID)) return -EINVAL; @@ -519,6 +520,17 @@ int wl12xx_cmd_role_stop_sta(struct wl1271 *wl, struct wl12xx_vif *wlvif) goto out_free; } + /* + * Sometimes the firmware doesn't send this event, so we just + * time out without failing. Queue recovery for other + * failures. + */ + ret = wl1271_cmd_wait_for_event_or_timeout(wl, + ROLE_STOP_COMPLETE_EVENT_ID, + &timeout); + if (ret) + wl12xx_queue_recovery_work(wl); + wl12xx_free_link(wl, wlvif, &wlvif->sta.hlid); out_free: diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h index d7d9f80..4ef0b09 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h @@ -192,7 +192,7 @@ enum cmd_templ { #define WL1271_COMMAND_TIMEOUT 2000 #define WL1271_CMD_TEMPL_DFLT_SIZE 252 #define WL1271_CMD_TEMPL_MAX_SIZE 512 -#define WL1271_EVENT_TIMEOUT 1000 +#define WL1271_EVENT_TIMEOUT 1500 struct wl1271_cmd_header { __le16 id; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c index 9f04b64..7254860 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c @@ -1064,10 +1064,17 @@ out: return ret; } -int wl1271_plt_start(struct wl1271 *wl) +int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode) { int retries = WL1271_BOOT_RETRIES; struct wiphy *wiphy = wl->hw->wiphy; + + static const char* const PLT_MODE[] = { + "PLT_OFF", + "PLT_ON", + "PLT_FEM_DETECT" + }; + int ret; mutex_lock(&wl->mutex); @@ -1081,6 +1088,10 @@ int wl1271_plt_start(struct wl1271 *wl) goto out; } + /* Indicate to lower levels that we are now in PLT mode */ + wl->plt = true; + wl->plt_mode = plt_mode; + while (retries) { retries--; ret = wl12xx_chip_wakeup(wl, true); @@ -1091,9 +1102,9 @@ int wl1271_plt_start(struct wl1271 *wl) if (ret < 0) goto power_off; - wl->plt = true; wl->state = WL1271_STATE_ON; - wl1271_notice("firmware booted in PLT mode (%s)", + wl1271_notice("firmware booted in PLT mode %s (%s)", + PLT_MODE[plt_mode], wl->chip.fw_ver_str); /* update hw/fw version info in wiphy struct */ @@ -1107,6 +1118,9 @@ power_off: wl1271_power_off(wl); } + wl->plt = false; + wl->plt_mode = PLT_OFF; + wl1271_error("firmware boot in PLT mode failed despite %d retries", WL1271_BOOT_RETRIES); out: @@ -1159,6 +1173,7 @@ int wl1271_plt_stop(struct wl1271 *wl) wl->sleep_auth = WL1271_PSM_ILLEGAL; wl->state = WL1271_STATE_OFF; wl->plt = false; + wl->plt_mode = PLT_OFF; wl->rx_counter = 0; mutex_unlock(&wl->mutex); @@ -1585,6 +1600,12 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl, if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) goto out; + if ((wl->conf.conn.suspend_wake_up_event == + wl->conf.conn.wake_up_event) && + (wl->conf.conn.suspend_listen_interval == + wl->conf.conn.listen_interval)) + goto out; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) goto out; @@ -1648,6 +1669,13 @@ static void wl1271_configure_resume(struct wl1271 *wl, if ((!is_ap) && (!is_sta)) return; + if (is_sta && + ((wl->conf.conn.suspend_wake_up_event == + wl->conf.conn.wake_up_event) && + (wl->conf.conn.suspend_listen_interval == + wl->conf.conn.listen_interval))) + return; + ret = wl1271_ps_elp_wakeup(wl); if (ret < 0) return; @@ -2364,7 +2392,14 @@ deinit: else wl->sta_count--; - /* Last AP, have more stations. Configure according to STA. */ + /* + * Last AP, have more stations. Configure sleep auth according to STA. + * Don't do thin on unintended recovery. + */ + if (test_bit(WL1271_FLAG_RECOVERY_IN_PROGRESS, &wl->flags) && + !test_bit(WL1271_FLAG_INTENDED_FW_RECOVERY, &wl->flags)) + goto unlock; + if (wl->ap_count == 0 && is_ap && wl->sta_count) { u8 sta_auth = wl->conf.conn.sta_sleep_auth; /* Configure for power according to debugfs */ @@ -2378,6 +2413,7 @@ deinit: wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP); } +unlock: mutex_unlock(&wl->mutex); del_timer_sync(&wlvif->rx_streaming_timer); diff --git a/drivers/net/wireless/ti/wlcore/testmode.c b/drivers/net/wireless/ti/wlcore/testmode.c index d6f57e2..49e5ee1 100644 --- a/drivers/net/wireless/ti/wlcore/testmode.c +++ b/drivers/net/wireless/ti/wlcore/testmode.c @@ -129,8 +129,12 @@ static int wl1271_tm_cmd_test(struct wl1271 *wl, struct nlattr *tb[]) goto out_sleep; } - if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) - goto nla_put_failure; + if (nla_put(skb, WL1271_TM_ATTR_DATA, buf_len, buf)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out_sleep; + } + ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out_sleep; @@ -142,11 +146,6 @@ out: mutex_unlock(&wl->mutex); return ret; - -nla_put_failure: - kfree_skb(skb); - ret = -EMSGSIZE; - goto out_sleep; } static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) @@ -192,8 +191,12 @@ static int wl1271_tm_cmd_interrogate(struct wl1271 *wl, struct nlattr *tb[]) goto out_free; } - if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) - goto nla_put_failure; + if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(*cmd), cmd)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out_free; + } + ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out_free; @@ -206,11 +209,6 @@ out: mutex_unlock(&wl->mutex); return ret; - -nla_put_failure: - kfree_skb(skb); - ret = -EMSGSIZE; - goto out_free; } static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) @@ -245,6 +243,43 @@ static int wl1271_tm_cmd_configure(struct wl1271 *wl, struct nlattr *tb[]) return 0; } +static int wl1271_tm_detect_fem(struct wl1271 *wl, struct nlattr *tb[]) +{ + /* return FEM type */ + int ret, len; + struct sk_buff *skb; + + ret = wl1271_plt_start(wl, PLT_FEM_DETECT); + if (ret < 0) + goto out; + + mutex_lock(&wl->mutex); + + len = nla_total_size(sizeof(wl->fem_manuf)); + skb = cfg80211_testmode_alloc_reply_skb(wl->hw->wiphy, len); + if (!skb) { + ret = -ENOMEM; + goto out_mutex; + } + + if (nla_put(skb, WL1271_TM_ATTR_DATA, sizeof(wl->fem_manuf), + &wl->fem_manuf)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out_mutex; + } + + ret = cfg80211_testmode_reply(skb); + +out_mutex: + mutex_unlock(&wl->mutex); + + /* We always stop plt after DETECT mode */ + wl1271_plt_stop(wl); +out: + return ret; +} + static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) { u32 val; @@ -258,11 +293,14 @@ static int wl1271_tm_cmd_set_plt_mode(struct wl1271 *wl, struct nlattr *tb[]) val = nla_get_u32(tb[WL1271_TM_ATTR_PLT_MODE]); switch (val) { - case 0: + case PLT_OFF: ret = wl1271_plt_stop(wl); break; - case 1: - ret = wl1271_plt_start(wl); + case PLT_ON: + ret = wl1271_plt_start(wl, PLT_ON); + break; + case PLT_FEM_DETECT: + ret = wl1271_tm_detect_fem(wl, tb); break; default: ret = -EINVAL; @@ -303,8 +341,12 @@ static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) goto out; } - if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) - goto nla_put_failure; + if (nla_put(skb, WL1271_TM_ATTR_DATA, ETH_ALEN, mac_addr)) { + kfree_skb(skb); + ret = -EMSGSIZE; + goto out; + } + ret = cfg80211_testmode_reply(skb); if (ret < 0) goto out; @@ -312,11 +354,6 @@ static int wl12xx_tm_cmd_get_mac(struct wl1271 *wl, struct nlattr *tb[]) out: mutex_unlock(&wl->mutex); return ret; - -nla_put_failure: - kfree_skb(skb); - ret = -EMSGSIZE; - goto out; } int wl1271_tm_cmd(struct ieee80211_hw *hw, void *data, int len) diff --git a/drivers/net/wireless/ti/wlcore/tx.c b/drivers/net/wireless/ti/wlcore/tx.c index 8038a50..f0081f7 100644 --- a/drivers/net/wireless/ti/wlcore/tx.c +++ b/drivers/net/wireless/ti/wlcore/tx.c @@ -306,22 +306,24 @@ static void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, rate_idx = 0; else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { /* - * if the packets are destined for AP (have a STA entry) + * if the packets are data packets * send them with AP rate policies (EAPOLs are an exception), * otherwise use default basic rates */ - if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) - rate_idx = wlvif->sta.p2p_rate_idx; - else if (skb->protocol == cpu_to_be16(ETH_P_PAE)) + if (skb->protocol == cpu_to_be16(ETH_P_PAE)) rate_idx = wlvif->sta.basic_rate_idx; - else if (control->control.sta) + else if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) + rate_idx = wlvif->sta.p2p_rate_idx; + else if (ieee80211_is_data(frame_control)) rate_idx = wlvif->sta.ap_rate_idx; else rate_idx = wlvif->sta.basic_rate_idx; } else { if (hlid == wlvif->ap.global_hlid) rate_idx = wlvif->ap.mgmt_rate_idx; - else if (hlid == wlvif->ap.bcast_hlid) + else if (hlid == wlvif->ap.bcast_hlid || + skb->protocol == cpu_to_be16(ETH_P_PAE)) + /* send AP bcast and EAPOLs using the min basic rate */ rate_idx = wlvif->ap.bcast_rate_idx; else rate_idx = wlvif->ap.ucast_rate_idx[ac]; diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h index 27ccc27..0ce7a8e 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore.h +++ b/drivers/net/wireless/ti/wlcore/wlcore.h @@ -156,6 +156,8 @@ struct wl1271 { enum wl1271_state state; enum wl12xx_fw_type fw_type; bool plt; + enum plt_mode plt_mode; + u8 fem_manuf; u8 last_vif_count; struct mutex mutex; diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h index 0187eef..c050563 100644 --- a/drivers/net/wireless/ti/wlcore/wlcore_i.h +++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h @@ -293,6 +293,12 @@ enum rx_filter_action { FILTER_FW_HANDLE = 2 }; +enum plt_mode { + PLT_OFF = 0, + PLT_ON = 1, + PLT_FEM_DETECT = 2, +}; + struct wl12xx_rx_filter_field { __le16 offset; u8 len; @@ -459,7 +465,7 @@ struct ieee80211_vif *wl12xx_wlvif_to_vif(struct wl12xx_vif *wlvif) #define wl12xx_for_each_wlvif_ap(wl, wlvif) \ wl12xx_for_each_wlvif_bss_type(wl, wlvif, BSS_TYPE_AP_BSS) -int wl1271_plt_start(struct wl1271 *wl); +int wl1271_plt_start(struct wl1271 *wl, const enum plt_mode plt_mode); 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); diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h index 03b2f30..1954a4e 100644 --- a/include/linux/bcma/bcma.h +++ b/include/linux/bcma/bcma.h @@ -7,6 +7,7 @@ #include <linux/bcma/bcma_driver_chipcommon.h> #include <linux/bcma/bcma_driver_pci.h> #include <linux/bcma/bcma_driver_mips.h> +#include <linux/bcma/bcma_driver_gmac_cmn.h> #include <linux/ssb/ssb.h> /* SPROM sharing */ #include "bcma_regs.h" @@ -252,6 +253,7 @@ struct bcma_bus { struct bcma_drv_cc drv_cc; struct bcma_drv_pci drv_pci; struct bcma_drv_mips drv_mips; + struct bcma_drv_gmac_cmn drv_gmac_cmn; /* We decided to share SPROM struct with SSB as long as we do not need * any hacks for BCMA. This simplifies drivers code. */ diff --git a/include/linux/bcma/bcma_driver_chipcommon.h b/include/linux/bcma/bcma_driver_chipcommon.h index fbd0d49..3c80885 100644 --- a/include/linux/bcma/bcma_driver_chipcommon.h +++ b/include/linux/bcma/bcma_driver_chipcommon.h @@ -24,7 +24,7 @@ #define BCMA_CC_FLASHT_NONE 0x00000000 /* No flash */ #define BCMA_CC_FLASHT_STSER 0x00000100 /* ST serial flash */ #define BCMA_CC_FLASHT_ATSER 0x00000200 /* Atmel serial flash */ -#define BCMA_CC_FLASHT_NFLASH 0x00000200 +#define BCMA_CC_FLASHT_NFLASH 0x00000200 /* NAND flash */ #define BCMA_CC_FLASHT_PARA 0x00000700 /* Parallel flash */ #define BCMA_CC_CAP_PLLT 0x00038000 /* PLL Type */ #define BCMA_PLLTYPE_NONE 0x00000000 @@ -45,6 +45,7 @@ #define BCMA_CC_CAP_PMU 0x10000000 /* PMU available (rev >= 20) */ #define BCMA_CC_CAP_ECI 0x20000000 /* ECI available (rev >= 20) */ #define BCMA_CC_CAP_SPROM 0x40000000 /* SPROM present */ +#define BCMA_CC_CAP_NFLASH 0x80000000 /* NAND flash present (rev >= 35 or BCM4706?) */ #define BCMA_CC_CORECTL 0x0008 #define BCMA_CC_CORECTL_UARTCLK0 0x00000001 /* Drive UART with internal clock */ #define BCMA_CC_CORECTL_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ @@ -122,10 +123,58 @@ #define BCMA_CC_JCTL_EXT_EN 2 /* Enable external targets */ #define BCMA_CC_JCTL_EN 1 /* Enable Jtag master */ #define BCMA_CC_FLASHCTL 0x0040 +/* Start/busy bit in flashcontrol */ +#define BCMA_CC_FLASHCTL_OPCODE 0x000000ff +#define BCMA_CC_FLASHCTL_ACTION 0x00000700 +#define BCMA_CC_FLASHCTL_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ #define BCMA_CC_FLASHCTL_START 0x80000000 #define BCMA_CC_FLASHCTL_BUSY BCMA_CC_FLASHCTL_START +/* Flashcontrol action + opcodes for ST flashes */ +#define BCMA_CC_FLASHCTL_ST_WREN 0x0006 /* Write Enable */ +#define BCMA_CC_FLASHCTL_ST_WRDIS 0x0004 /* Write Disable */ +#define BCMA_CC_FLASHCTL_ST_RDSR 0x0105 /* Read Status Register */ +#define BCMA_CC_FLASHCTL_ST_WRSR 0x0101 /* Write Status Register */ +#define BCMA_CC_FLASHCTL_ST_READ 0x0303 /* Read Data Bytes */ +#define BCMA_CC_FLASHCTL_ST_PP 0x0302 /* Page Program */ +#define BCMA_CC_FLASHCTL_ST_SE 0x02d8 /* Sector Erase */ +#define BCMA_CC_FLASHCTL_ST_BE 0x00c7 /* Bulk Erase */ +#define BCMA_CC_FLASHCTL_ST_DP 0x00b9 /* Deep Power-down */ +#define BCMA_CC_FLASHCTL_ST_RES 0x03ab /* Read Electronic Signature */ +#define BCMA_CC_FLASHCTL_ST_CSA 0x1000 /* Keep chip select asserted */ +#define BCMA_CC_FLASHCTL_ST_SSE 0x0220 /* Sub-sector Erase */ +/* Flashcontrol action + opcodes for Atmel flashes */ +#define BCMA_CC_FLASHCTL_AT_READ 0x07e8 +#define BCMA_CC_FLASHCTL_AT_PAGE_READ 0x07d2 +#define BCMA_CC_FLASHCTL_AT_STATUS 0x01d7 +#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE 0x0384 +#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE 0x0387 +#define BCMA_CC_FLASHCTL_AT_BUF1_ERASE_PROGRAM 0x0283 +#define BCMA_CC_FLASHCTL_AT_BUF2_ERASE_PROGRAM 0x0286 +#define BCMA_CC_FLASHCTL_AT_BUF1_PROGRAM 0x0288 +#define BCMA_CC_FLASHCTL_AT_BUF2_PROGRAM 0x0289 +#define BCMA_CC_FLASHCTL_AT_PAGE_ERASE 0x0281 +#define BCMA_CC_FLASHCTL_AT_BLOCK_ERASE 0x0250 +#define BCMA_CC_FLASHCTL_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 +#define BCMA_CC_FLASHCTL_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 +#define BCMA_CC_FLASHCTL_AT_BUF1_LOAD 0x0253 +#define BCMA_CC_FLASHCTL_AT_BUF2_LOAD 0x0255 +#define BCMA_CC_FLASHCTL_AT_BUF1_COMPARE 0x0260 +#define BCMA_CC_FLASHCTL_AT_BUF2_COMPARE 0x0261 +#define BCMA_CC_FLASHCTL_AT_BUF1_REPROGRAM 0x0258 +#define BCMA_CC_FLASHCTL_AT_BUF2_REPROGRAM 0x0259 #define BCMA_CC_FLASHADDR 0x0044 #define BCMA_CC_FLASHDATA 0x0048 +/* Status register bits for ST flashes */ +#define BCMA_CC_FLASHDATA_ST_WIP 0x01 /* Write In Progress */ +#define BCMA_CC_FLASHDATA_ST_WEL 0x02 /* Write Enable Latch */ +#define BCMA_CC_FLASHDATA_ST_BP_MASK 0x1c /* Block Protect */ +#define BCMA_CC_FLASHDATA_ST_BP_SHIFT 2 +#define BCMA_CC_FLASHDATA_ST_SRWD 0x80 /* Status Register Write Disable */ +/* Status register bits for Atmel flashes */ +#define BCMA_CC_FLASHDATA_AT_READY 0x80 +#define BCMA_CC_FLASHDATA_AT_MISMATCH 0x40 +#define BCMA_CC_FLASHDATA_AT_ID_MASK 0x38 +#define BCMA_CC_FLASHDATA_AT_ID_SHIFT 3 #define BCMA_CC_BCAST_ADDR 0x0050 #define BCMA_CC_BCAST_DATA 0x0054 #define BCMA_CC_GPIOPULLUP 0x0058 /* Rev >= 20 only */ diff --git a/include/linux/bcma/bcma_driver_gmac_cmn.h b/include/linux/bcma/bcma_driver_gmac_cmn.h new file mode 100644 index 0000000..def894b --- /dev/null +++ b/include/linux/bcma/bcma_driver_gmac_cmn.h @@ -0,0 +1,100 @@ +#ifndef LINUX_BCMA_DRIVER_GMAC_CMN_H_ +#define LINUX_BCMA_DRIVER_GMAC_CMN_H_ + +#include <linux/types.h> + +#define BCMA_GMAC_CMN_STAG0 0x000 +#define BCMA_GMAC_CMN_STAG1 0x004 +#define BCMA_GMAC_CMN_STAG2 0x008 +#define BCMA_GMAC_CMN_STAG3 0x00C +#define BCMA_GMAC_CMN_PARSER_CTL 0x020 +#define BCMA_GMAC_CMN_MIB_MAX_LEN 0x024 +#define BCMA_GMAC_CMN_PHY_ACCESS 0x100 +#define BCMA_GMAC_CMN_PA_DATA_MASK 0x0000ffff +#define BCMA_GMAC_CMN_PA_ADDR_MASK 0x001f0000 +#define BCMA_GMAC_CMN_PA_ADDR_SHIFT 16 +#define BCMA_GMAC_CMN_PA_REG_MASK 0x1f000000 +#define BCMA_GMAC_CMN_PA_REG_SHIFT 24 +#define BCMA_GMAC_CMN_PA_WRITE 0x20000000 +#define BCMA_GMAC_CMN_PA_START 0x40000000 +#define BCMA_GMAC_CMN_PHY_CTL 0x104 +#define BCMA_GMAC_CMN_PC_EPA_MASK 0x0000001f +#define BCMA_GMAC_CMN_PC_MCT_MASK 0x007f0000 +#define BCMA_GMAC_CMN_PC_MCT_SHIFT 16 +#define BCMA_GMAC_CMN_PC_MTE 0x00800000 +#define BCMA_GMAC_CMN_GMAC0_RGMII_CTL 0x110 +#define BCMA_GMAC_CMN_CFP_ACCESS 0x200 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA0 0x210 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA1 0x214 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA2 0x218 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA3 0x21C +#define BCMA_GMAC_CMN_CFP_TCAM_DATA4 0x220 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA5 0x224 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA6 0x228 +#define BCMA_GMAC_CMN_CFP_TCAM_DATA7 0x22C +#define BCMA_GMAC_CMN_CFP_TCAM_MASK0 0x230 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK1 0x234 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK2 0x238 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK3 0x23C +#define BCMA_GMAC_CMN_CFP_TCAM_MASK4 0x240 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK5 0x244 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK6 0x248 +#define BCMA_GMAC_CMN_CFP_TCAM_MASK7 0x24C +#define BCMA_GMAC_CMN_CFP_ACTION_DATA 0x250 +#define BCMA_GMAC_CMN_TCAM_BIST_CTL 0x2A0 +#define BCMA_GMAC_CMN_TCAM_BIST_STATUS 0x2A4 +#define BCMA_GMAC_CMN_TCAM_CMP_STATUS 0x2A8 +#define BCMA_GMAC_CMN_TCAM_DISABLE 0x2AC +#define BCMA_GMAC_CMN_TCAM_TEST_CTL 0x2F0 +#define BCMA_GMAC_CMN_UDF_0_A3_A0 0x300 +#define BCMA_GMAC_CMN_UDF_0_A7_A4 0x304 +#define BCMA_GMAC_CMN_UDF_0_A8 0x308 +#define BCMA_GMAC_CMN_UDF_1_A3_A0 0x310 +#define BCMA_GMAC_CMN_UDF_1_A7_A4 0x314 +#define BCMA_GMAC_CMN_UDF_1_A8 0x318 +#define BCMA_GMAC_CMN_UDF_2_A3_A0 0x320 +#define BCMA_GMAC_CMN_UDF_2_A7_A4 0x324 +#define BCMA_GMAC_CMN_UDF_2_A8 0x328 +#define BCMA_GMAC_CMN_UDF_0_B3_B0 0x330 +#define BCMA_GMAC_CMN_UDF_0_B7_B4 0x334 +#define BCMA_GMAC_CMN_UDF_0_B8 0x338 +#define BCMA_GMAC_CMN_UDF_1_B3_B0 0x340 +#define BCMA_GMAC_CMN_UDF_1_B7_B4 0x344 +#define BCMA_GMAC_CMN_UDF_1_B8 0x348 +#define BCMA_GMAC_CMN_UDF_2_B3_B0 0x350 +#define BCMA_GMAC_CMN_UDF_2_B7_B4 0x354 +#define BCMA_GMAC_CMN_UDF_2_B8 0x358 +#define BCMA_GMAC_CMN_UDF_0_C3_C0 0x360 +#define BCMA_GMAC_CMN_UDF_0_C7_C4 0x364 +#define BCMA_GMAC_CMN_UDF_0_C8 0x368 +#define BCMA_GMAC_CMN_UDF_1_C3_C0 0x370 +#define BCMA_GMAC_CMN_UDF_1_C7_C4 0x374 +#define BCMA_GMAC_CMN_UDF_1_C8 0x378 +#define BCMA_GMAC_CMN_UDF_2_C3_C0 0x380 +#define BCMA_GMAC_CMN_UDF_2_C7_C4 0x384 +#define BCMA_GMAC_CMN_UDF_2_C8 0x388 +#define BCMA_GMAC_CMN_UDF_0_D3_D0 0x390 +#define BCMA_GMAC_CMN_UDF_0_D7_D4 0x394 +#define BCMA_GMAC_CMN_UDF_0_D11_D8 0x394 + +struct bcma_drv_gmac_cmn { + struct bcma_device *core; + + /* Drivers accessing BCMA_GMAC_CMN_PHY_ACCESS and + * BCMA_GMAC_CMN_PHY_CTL need to take that mutex first. */ + struct mutex phy_mutex; +}; + +/* Register access */ +#define gmac_cmn_read16(gc, offset) bcma_read16((gc)->core, offset) +#define gmac_cmn_read32(gc, offset) bcma_read32((gc)->core, offset) +#define gmac_cmn_write16(gc, offset, val) bcma_write16((gc)->core, offset, val) +#define gmac_cmn_write32(gc, offset, val) bcma_write32((gc)->core, offset, val) + +#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN +extern void __devinit bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc); +#else +static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { } +#endif + +#endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */ diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index db961a5..2f38788 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -771,6 +771,9 @@ enum nl80211_commands { * @NL80211_ATTR_IFNAME: network interface name * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype * + * @NL80211_ATTR_WDEV: wireless device identifier, used for pseudo-devices + * that don't have a netdev (u64) + * * @NL80211_ATTR_MAC: MAC address (various uses) * * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of @@ -1242,6 +1245,12 @@ enum nl80211_commands { * @NL80211_ATTR_BG_SCAN_PERIOD: Background scan period in seconds * or 0 to disable background scan. * + * @NL80211_ATTR_USER_REG_HINT_TYPE: type of regulatory hint passed from + * userspace. If unset it is assumed the hint comes directly from + * a user. If set code could specify exactly what type of source + * was used to provide the hint. For the different types of + * allowed user regulatory hints see nl80211_user_reg_hint_type. + * * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use */ @@ -1493,6 +1502,10 @@ enum nl80211_attrs { NL80211_ATTR_BG_SCAN_PERIOD, + NL80211_ATTR_WDEV, + + NL80211_ATTR_USER_REG_HINT_TYPE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -1545,6 +1558,8 @@ enum nl80211_attrs { /* default RSSI threshold for scan results if none specified. */ #define NL80211_SCAN_RSSI_THOLD_OFF -300 +#define NL80211_CQM_TXE_MAX_INTVL 1800 + /** * enum nl80211_iftype - (virtual) interface types * @@ -2054,6 +2069,26 @@ enum nl80211_dfs_regions { }; /** + * enum nl80211_user_reg_hint_type - type of user regulatory hint + * + * @NL80211_USER_REG_HINT_USER: a user sent the hint. This is always + * assumed if the attribute is not set. + * @NL80211_USER_REG_HINT_CELL_BASE: the hint comes from a cellular + * base station. Device drivers that have been tested to work + * properly to support this type of hint can enable these hints + * by setting the NL80211_FEATURE_CELL_BASE_REG_HINTS feature + * capability on the struct wiphy. The wireless core will + * ignore all cell base station hints until at least one device + * present has been registered with the wireless core that + * has listed NL80211_FEATURE_CELL_BASE_REG_HINTS as a + * supported feature. + */ +enum nl80211_user_reg_hint_type { + NL80211_USER_REG_HINT_USER = 0, + NL80211_USER_REG_HINT_CELL_BASE = 1, +}; + +/** * enum nl80211_survey_info - survey information * * These attribute types are used with %NL80211_ATTR_SURVEY_INFO @@ -2584,6 +2619,17 @@ enum nl80211_ps_state { * @NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT: RSSI threshold event * @NL80211_ATTR_CQM_PKT_LOSS_EVENT: a u32 value indicating that this many * consecutive packets were not acknowledged by the peer + * @NL80211_ATTR_CQM_TXE_RATE: TX error rate in %. Minimum % of TX failures + * during the given %NL80211_ATTR_CQM_TXE_INTVL before an + * %NL80211_CMD_NOTIFY_CQM with reported %NL80211_ATTR_CQM_TXE_RATE and + * %NL80211_ATTR_CQM_TXE_PKTS is generated. + * @NL80211_ATTR_CQM_TXE_PKTS: number of attempted packets in a given + * %NL80211_ATTR_CQM_TXE_INTVL before %NL80211_ATTR_CQM_TXE_RATE is + * checked. + * @NL80211_ATTR_CQM_TXE_INTVL: interval in seconds. Specifies the periodic + * interval in which %NL80211_ATTR_CQM_TXE_PKTS and + * %NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an + * %NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting. * @__NL80211_ATTR_CQM_AFTER_LAST: internal * @NL80211_ATTR_CQM_MAX: highest key attribute */ @@ -2593,6 +2639,9 @@ enum nl80211_attr_cqm { NL80211_ATTR_CQM_RSSI_HYST, NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT, NL80211_ATTR_CQM_PKT_LOSS_EVENT, + NL80211_ATTR_CQM_TXE_RATE, + NL80211_ATTR_CQM_TXE_PKTS, + NL80211_ATTR_CQM_TXE_INTVL, /* keep last */ __NL80211_ATTR_CQM_AFTER_LAST, @@ -2942,11 +2991,15 @@ enum nl80211_ap_sme_features { * @NL80211_FEATURE_HT_IBSS: This driver supports IBSS with HT datarates. * @NL80211_FEATURE_INACTIVITY_TIMER: This driver takes care of freeing up * the connected inactive stations in AP mode. + * @NL80211_FEATURE_CELL_BASE_REG_HINTS: This driver has been tested + * to work properly to suppport receiving regulatory hints from + * cellular base stations. */ enum nl80211_feature_flags { NL80211_FEATURE_SK_TX_STATUS = 1 << 0, NL80211_FEATURE_HT_IBSS = 1 << 1, NL80211_FEATURE_INACTIVITY_TIMER = 1 << 2, + NL80211_FEATURE_CELL_BASE_REG_HINTS = 1 << 3, }; /** diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2a6b0b8..ccd723e 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -139,11 +139,12 @@ enum { #define HCIINQUIRY _IOR('H', 240, int) /* HCI timeouts */ -#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ -#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */ -#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ -#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */ -#define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */ +#define HCI_DISCONN_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ +#define HCI_PAIRING_TIMEOUT msecs_to_jiffies(60000) /* 60 seconds */ +#define HCI_INIT_TIMEOUT msecs_to_jiffies(10000) /* 10 seconds */ +#define HCI_CMD_TIMEOUT msecs_to_jiffies(1000) /* 1 second */ +#define HCI_ACL_TX_TIMEOUT msecs_to_jiffies(45000) /* 45 seconds */ +#define HCI_AUTO_OFF_TIMEOUT msecs_to_jiffies(2000) /* 2 seconds */ /* HCI data types */ #define HCI_COMMAND_PKT 0x01 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 20fd573..475b8c0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -587,18 +587,24 @@ void hci_conn_put_device(struct hci_conn *conn); static inline void hci_conn_hold(struct hci_conn *conn) { + BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt), + atomic_read(&conn->refcnt) + 1); + atomic_inc(&conn->refcnt); cancel_delayed_work(&conn->disc_work); } static inline void hci_conn_put(struct hci_conn *conn) { + BT_DBG("hcon %p refcnt %d -> %d", conn, atomic_read(&conn->refcnt), + atomic_read(&conn->refcnt) - 1); + if (atomic_dec_and_test(&conn->refcnt)) { unsigned long timeo; if (conn->type == ACL_LINK || conn->type == LE_LINK) { del_timer(&conn->idle_timer); if (conn->state == BT_CONNECTED) { - timeo = msecs_to_jiffies(conn->disc_timeout); + timeo = conn->disc_timeout; if (!conn->out) timeo *= 2; } else { diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d80e3f0..a7679f8 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -464,6 +464,7 @@ struct l2cap_chan { __u16 tx_win; __u16 tx_win_max; + __u16 ack_win; __u8 max_tx; __u16 retrans_timeout; __u16 monitor_timeout; @@ -672,11 +673,15 @@ enum { static inline void l2cap_chan_hold(struct l2cap_chan *c) { + BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); + atomic_inc(&c->refcnt); } static inline void l2cap_chan_put(struct l2cap_chan *c) { + BT_DBG("chan %p orig refcnt %d", c, atomic_read(&c->refcnt)); + if (atomic_dec_and_test(&c->refcnt)) kfree(c); } diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 23fd054..4348ee8 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -444,7 +444,7 @@ struct mgmt_ev_auth_failed { struct mgmt_ev_device_found { struct mgmt_addr_info addr; __s8 rssi; - __u8 flags[4]; + __le32 flags; __le16 eir_len; __u8 eir[0]; } __packed; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 51f67a9..493fa0c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -999,7 +999,7 @@ struct cfg80211_ssid { * @ie_len: length of ie in octets * @rates: bitmap of rates to advertise for each band * @wiphy: the wiphy this was for - * @dev: the interface + * @wdev: the wireless device to scan for * @aborted: (internal) scan request was notified as aborted * @no_cck: used to send probe requests at non CCK rate in 2GHz band */ @@ -1012,9 +1012,10 @@ struct cfg80211_scan_request { u32 rates[IEEE80211_NUM_BANDS]; + struct wireless_dev *wdev; + /* internal */ struct wiphy *wiphy; - struct net_device *dev; bool aborted; bool no_cck; @@ -1435,10 +1436,10 @@ struct cfg80211_gtk_rekey_data { * * @add_virtual_intf: create a new virtual interface with the given name, * must set the struct wireless_dev's iftype. Beware: You must create - * the new netdev in the wiphy's network namespace! Returns the netdev, - * or an ERR_PTR. + * the new netdev in the wiphy's network namespace! Returns the struct + * wireless_dev, or an ERR_PTR. * - * @del_virtual_intf: remove the virtual interface determined by ifindex. + * @del_virtual_intf: remove the virtual interface * * @change_virtual_intf: change type/configuration of virtual interface, * keep the struct wireless_dev's iftype updated. @@ -1503,8 +1504,6 @@ struct cfg80211_gtk_rekey_data { * interfaces are active this callback should reject the configuration. * If no interfaces are active or the device is down, the channel should * be stored for when a monitor interface becomes active. - * @set_monitor_enabled: Notify driver that there are only monitor - * interfaces running. * * @scan: Request to do a scan. If returning zero, the scan request is given * the driver, and will be valid until passed to cfg80211_scan_done(). @@ -1574,6 +1573,8 @@ struct cfg80211_gtk_rekey_data { * @set_power_mgmt: Configure WLAN power management. A timeout value of -1 * allows the driver to adjust the dynamic ps timeout value. * @set_cqm_rssi_config: Configure connection quality monitor RSSI threshold. + * @set_cqm_txe_config: Configure connection quality monitor TX error + * thresholds. * @sched_scan_start: Tell the driver to start a scheduled scan. * @sched_scan_stop: Tell the driver to stop an ongoing scheduled * scan. The driver_initiated flag specifies whether the driver @@ -1611,18 +1612,23 @@ struct cfg80211_gtk_rekey_data { * @get_et_strings: Ethtool API to get a set of strings to describe stats * and perhaps other supported types of ethtool data-sets. * See @ethtool_ops.get_strings + * + * @get_channel: Get the current operating channel for the virtual interface. + * For monitor interfaces, it should return %NULL unless there's a single + * current monitoring channel. */ struct cfg80211_ops { int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*resume)(struct wiphy *wiphy); void (*set_wakeup)(struct wiphy *wiphy, bool enabled); - struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, - char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params); - int (*del_virtual_intf)(struct wiphy *wiphy, struct net_device *dev); + struct wireless_dev * (*add_virtual_intf)(struct wiphy *wiphy, + char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params); + int (*del_virtual_intf)(struct wiphy *wiphy, + struct wireless_dev *wdev); int (*change_virtual_intf)(struct wiphy *wiphy, struct net_device *dev, enum nl80211_iftype type, u32 *flags, @@ -1699,7 +1705,7 @@ struct cfg80211_ops { struct ieee80211_channel *chan, enum nl80211_channel_type channel_type); - int (*scan)(struct wiphy *wiphy, struct net_device *dev, + int (*scan)(struct wiphy *wiphy, struct cfg80211_scan_request *request); int (*auth)(struct wiphy *wiphy, struct net_device *dev, @@ -1753,23 +1759,23 @@ struct cfg80211_ops { int (*flush_pmksa)(struct wiphy *wiphy, struct net_device *netdev); int (*remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie); int (*cancel_remain_on_channel)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie); - int (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev, + int (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie); int (*mgmt_tx_cancel_wait)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie); int (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev, @@ -1779,8 +1785,12 @@ struct cfg80211_ops { struct net_device *dev, s32 rssi_thold, u32 rssi_hyst); + int (*set_cqm_txe_config)(struct wiphy *wiphy, + struct net_device *dev, + u32 rate, u32 pkts, u32 intvl); + void (*mgmt_frame_register)(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg); int (*set_antenna)(struct wiphy *wiphy, u32 tx_ant, u32 rx_ant); @@ -1818,7 +1828,10 @@ struct cfg80211_ops { void (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev, u32 sset, u8 *data); - void (*set_monitor_enabled)(struct wiphy *wiphy, bool enabled); + struct ieee80211_channel * + (*get_channel)(struct wiphy *wiphy, + struct wireless_dev *wdev, + enum nl80211_channel_type *type); }; /* @@ -2341,17 +2354,25 @@ struct cfg80211_internal_bss; struct cfg80211_cached_keys; /** - * struct wireless_dev - wireless per-netdev state + * struct wireless_dev - wireless device state + * + * For netdevs, this structure must be allocated by the driver + * that uses the ieee80211_ptr field in struct net_device (this + * is intentional so it can be allocated along with the netdev.) + * It need not be registered then as netdev registration will + * be intercepted by cfg80211 to see the new wireless device. * - * This structure must be allocated by the driver/stack - * that uses the ieee80211_ptr field in struct net_device - * (this is intentional so it can be allocated along with - * the netdev.) + * For non-netdev uses, it must also be allocated by the driver + * in response to the cfg80211 callbacks that require it, as + * there's no netdev registration in that case it may not be + * allocated outside of callback operations that return it. * * @wiphy: pointer to hardware description * @iftype: interface type * @list: (private) Used to collect the interfaces - * @netdev: (private) Used to reference back to the netdev + * @netdev: (private) Used to reference back to the netdev, may be %NULL + * @identifier: (private) Identifier used in nl80211 to identify this + * wireless device if it has no netdev * @current_bss: (private) Used by the internal configuration code * @channel: (private) Used by the internal configuration code to track * the user-set AP, monitor and WDS channel @@ -2383,6 +2404,8 @@ struct wireless_dev { struct list_head list; struct net_device *netdev; + u32 identifier; + struct list_head mgmt_registrations; spinlock_t mgmt_registrations_lock; @@ -3269,7 +3292,7 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, /** * cfg80211_ready_on_channel - notification of remain_on_channel start - * @dev: network device + * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) * @channel_type: Channel type @@ -3277,21 +3300,20 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason, * channel * @gfp: allocation flags */ -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, +void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); /** * cfg80211_remain_on_channel_expired - remain_on_channel duration expired - * @dev: network device + * @wdev: wireless device * @cookie: the request cookie * @chan: The current channel (from remain_on_channel request) * @channel_type: Channel type * @gfp: allocation flags */ -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, +void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp); @@ -3319,7 +3341,7 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); /** * cfg80211_rx_mgmt - notification of received, unprocessed management frame - * @dev: network device + * @wdev: wireless device receiving the frame * @freq: Frequency on which the frame was received in MHz * @sig_dbm: signal strength in mBm, or 0 if unknown * @buf: Management frame (header + body) @@ -3334,12 +3356,12 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp); * This function is called whenever an Action frame is received for a station * mode interface, but is not processed in kernel. */ -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, +bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); /** * cfg80211_mgmt_tx_status - notification of TX status for management frame - * @dev: network device + * @wdev: wireless device receiving the frame * @cookie: Cookie returned by cfg80211_ops::mgmt_tx() * @buf: Management frame (header + body) * @len: length of the frame data @@ -3350,7 +3372,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_dbm, * transmitted with cfg80211_ops::mgmt_tx() to report the TX status of the * transmission attempt. */ -void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, +void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp); @@ -3380,6 +3402,21 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, const u8 *peer, u32 num_packets, gfp_t gfp); /** + * cfg80211_cqm_txe_notify - TX error rate event + * @dev: network device + * @peer: peer's MAC address + * @num_packets: how many packets were lost + * @rate: % of packets which failed transmission + * @intvl: interval (in s) over which the TX failure threshold was breached. + * @gfp: context flags + * + * Notify userspace when configured % TX failures over number of packets in a + * given interval is exceeded. + */ +void cfg80211_cqm_txe_notify(struct net_device *dev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); + +/** * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying * @dev: network device * @bssid: BSSID of AP (to avoid races) diff --git a/include/net/mac80211.h b/include/net/mac80211.h index e3fa90c..bb86aa6 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -233,8 +233,10 @@ enum ieee80211_rssi_event { * valid in station mode only while @assoc is true and if also * requested by %IEEE80211_HW_NEED_DTIM_PERIOD (cf. also hw conf * @ps_dtim_period) - * @last_tsf: last beacon's/probe response's TSF timestamp (could be old + * @sync_tsf: last beacon's/probe response's TSF timestamp (could be old * as it may have been received during scanning long ago) + * @sync_device_ts: the device timestamp corresponding to the sync_tsf, + * the driver/device can use this to calculate synchronisation * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp * @basic_rates: bitmap of basic rates, each bit stands for an @@ -281,7 +283,8 @@ struct ieee80211_bss_conf { u8 dtim_period; u16 beacon_int; u16 assoc_capability; - u64 last_tsf; + u64 sync_tsf; + u32 sync_device_ts; u32 basic_rates; int mcast_rate[IEEE80211_NUM_BANDS]; u16 ht_operation_mode; @@ -696,6 +699,8 @@ enum mac80211_rx_flags { * * @mactime: value in microseconds of the 64-bit Time Synchronization Function * (TSF) timer when the first data symbol (MPDU) arrived at the hardware. + * @device_timestamp: arbitrary timestamp for the device, mac80211 doesn't use + * it but can store it and pass it back to the driver for synchronisation * @band: the active band when this frame was received * @freq: frequency the radio was tuned to when receiving this frame, in MHz * @signal: signal strength when receiving this frame, either in dBm, in dB or @@ -709,13 +714,14 @@ enum mac80211_rx_flags { */ struct ieee80211_rx_status { u64 mactime; - enum ieee80211_band band; - int freq; - int signal; - int antenna; - int rate_idx; - int flag; - unsigned int rx_flags; + u32 device_timestamp; + u16 flag; + u16 freq; + u8 rate_idx; + u8 rx_flags; + u8 band; + u8 antenna; + s8 signal; }; /** @@ -3592,22 +3598,6 @@ void ieee80211_request_smps(struct ieee80211_vif *vif, enum ieee80211_smps_mode smps_mode); /** - * ieee80211_key_removed - disable hw acceleration for key - * @key_conf: The key hw acceleration should be disabled for - * - * This allows drivers to indicate that the given key has been - * removed from hardware acceleration, due to a new key that - * was added. Don't use this if the key can continue to be used - * for TX, if the key restriction is on RX only it is permitted - * to keep the key for TX only and not call this function. - * - * Due to locking constraints, it may only be called during - * @set_key. This function must be allowed to sleep, and the - * key it tries to disable may still be used until it returns. - */ -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf); - -/** * ieee80211_ready_on_channel - notification of remain-on-channel start * @hw: pointer as obtained from ieee80211_alloc_hw() */ diff --git a/include/net/regulatory.h b/include/net/regulatory.h index a5f7993..7dcaa27 100644 --- a/include/net/regulatory.h +++ b/include/net/regulatory.h @@ -52,6 +52,10 @@ enum environment_cap { * DFS master operation on a known DFS region (NL80211_DFS_*), * dfs_region represents that region. Drivers can use this and the * @alpha2 to adjust their device's DFS parameters as required. + * @user_reg_hint_type: if the @initiator was of type + * %NL80211_REGDOM_SET_BY_USER, this classifies the type + * of hint passed. This could be any of the %NL80211_USER_REG_HINT_* + * types. * @intersect: indicates whether the wireless core should intersect * the requested regulatory domain with the presently set regulatory * domain. @@ -70,6 +74,7 @@ enum environment_cap { struct regulatory_request { int wiphy_idx; enum nl80211_reg_initiator initiator; + enum nl80211_user_reg_hint_type user_reg_hint_type; char alpha2[2]; u8 dfs_region; bool intersect; diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c index fb93250..4ff0bf3 100644 --- a/net/bluetooth/a2mp.c +++ b/net/bluetooth/a2mp.c @@ -501,7 +501,7 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn) /* AMP Manager functions */ void amp_mgr_get(struct amp_mgr *mgr) { - BT_DBG("mgr %p", mgr); + BT_DBG("mgr %p orig refcnt %d", mgr, atomic_read(&mgr->kref.refcount)); kref_get(&mgr->kref); } @@ -517,7 +517,7 @@ static void amp_mgr_destroy(struct kref *kref) int amp_mgr_put(struct amp_mgr *mgr) { - BT_DBG("mgr %p", mgr); + BT_DBG("mgr %p orig refcnt %d", mgr, atomic_read(&mgr->kref.refcount)); return kref_put(&mgr->kref, &_mgr_destroy); } diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 2fcced3..5ad7da2 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -107,7 +107,7 @@ static void hci_acl_connect_cancel(struct hci_conn *conn) { struct hci_cp_create_conn_cancel cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2) return; @@ -120,7 +120,7 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) { struct hci_cp_disconnect cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_DISCONN; @@ -134,7 +134,7 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) struct hci_dev *hdev = conn->hdev; struct hci_cp_add_sco cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_CONNECT; conn->out = true; @@ -152,7 +152,7 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) struct hci_dev *hdev = conn->hdev; struct hci_cp_setup_sync_conn cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); conn->state = BT_CONNECT; conn->out = true; @@ -196,7 +196,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8], struct hci_dev *hdev = conn->hdev; struct hci_cp_le_start_enc cp; - BT_DBG("%p", conn); + BT_DBG("hcon %p", conn); memset(&cp, 0, sizeof(cp)); @@ -213,11 +213,11 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) { struct hci_conn *sco = conn->link; - BT_DBG("%p", conn); - if (!sco) return; + BT_DBG("hcon %p", conn); + if (!status) { if (lmp_esco_capable(conn->hdev)) hci_setup_sync(sco, conn->handle); @@ -235,7 +235,7 @@ static void hci_conn_timeout(struct work_struct *work) disc_work.work); __u8 reason; - BT_DBG("conn %p state %s", conn, state_to_string(conn->state)); + BT_DBG("hcon %p state %s", conn, state_to_string(conn->state)); if (atomic_read(&conn->refcnt)) return; @@ -266,7 +266,7 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - BT_DBG("conn %p mode %d", conn, conn->mode); + BT_DBG("hcon %p mode %d", conn, conn->mode); if (test_bit(HCI_RAW, &hdev->flags)) return; @@ -301,7 +301,7 @@ static void hci_conn_idle(unsigned long arg) { struct hci_conn *conn = (void *) arg; - BT_DBG("conn %p mode %d", conn, conn->mode); + BT_DBG("hcon %p mode %d", conn, conn->mode); hci_conn_enter_sniff_mode(conn); } @@ -382,7 +382,7 @@ int hci_conn_del(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; - BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); + BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle); del_timer(&conn->idle_timer); @@ -442,7 +442,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) list_for_each_entry(d, &hci_dev_list, list) { if (!test_bit(HCI_UP, &d->flags) || - test_bit(HCI_RAW, &d->flags)) + test_bit(HCI_RAW, &d->flags) || + d->dev_type != HCI_BREDR) continue; /* Simple routing: @@ -557,7 +558,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, /* Check link security requirement */ int hci_conn_check_link_mode(struct hci_conn *conn) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT)) return 0; @@ -568,7 +569,7 @@ int hci_conn_check_link_mode(struct hci_conn *conn) /* Authenticate remote device */ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (conn->pending_sec_level > sec_level) sec_level = conn->pending_sec_level; @@ -602,7 +603,7 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) /* Encrypt the the link */ static void hci_conn_encrypt(struct hci_conn *conn) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { struct hci_cp_set_conn_encrypt cp; @@ -616,7 +617,7 @@ static void hci_conn_encrypt(struct hci_conn *conn) /* Enable security */ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) @@ -669,7 +670,7 @@ EXPORT_SYMBOL(hci_conn_security); /* Check secure link requirement */ int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (sec_level != BT_SECURITY_HIGH) return 1; /* Accept if non-secure is required */ @@ -684,7 +685,7 @@ EXPORT_SYMBOL(hci_conn_check_secure); /* Change link key */ int hci_conn_change_link_key(struct hci_conn *conn) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) { struct hci_cp_change_conn_link_key cp; @@ -699,7 +700,7 @@ int hci_conn_change_link_key(struct hci_conn *conn) /* Switch role */ int hci_conn_switch_role(struct hci_conn *conn, __u8 role) { - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); if (!role && conn->link_mode & HCI_LM_MASTER) return 1; @@ -720,7 +721,7 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active) { struct hci_dev *hdev = conn->hdev; - BT_DBG("conn %p mode %d", conn, conn->mode); + BT_DBG("hcon %p mode %d", conn, conn->mode); if (test_bit(HCI_RAW, &hdev->flags)) return; @@ -894,7 +895,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn) struct hci_dev *hdev = conn->hdev; struct hci_chan *chan; - BT_DBG("%s conn %p", hdev->name, conn); + BT_DBG("%s hcon %p", hdev->name, conn); chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); if (!chan) @@ -913,7 +914,7 @@ int hci_chan_del(struct hci_chan *chan) struct hci_conn *conn = chan->conn; struct hci_dev *hdev = conn->hdev; - BT_DBG("%s conn %p chan %p", hdev->name, conn, chan); + BT_DBG("%s hcon %p chan %p", hdev->name, conn, chan); list_del_rcu(&chan->list); @@ -929,7 +930,7 @@ void hci_chan_list_flush(struct hci_conn *conn) { struct hci_chan *chan, *n; - BT_DBG("conn %p", conn); + BT_DBG("hcon %p", conn); list_for_each_entry_safe(chan, n, &conn->chan_list, list) hci_chan_del(chan); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 08994ec..d4de5db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -33,8 +33,6 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#define AUTO_OFF_TIMEOUT 2000 - static void hci_rx_work(struct work_struct *work); static void hci_cmd_work(struct work_struct *work); static void hci_tx_work(struct work_struct *work); @@ -61,7 +59,7 @@ static void hci_notify(struct hci_dev *hdev, int event) void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) { - BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result); + BT_DBG("%s command 0x%4.4x result 0x%2.2x", hdev->name, cmd, result); /* If this is the init phase check if the completed command matches * the last init command, and if not just return. @@ -188,12 +186,6 @@ static void bredr_init(struct hci_dev *hdev) /* Mandatory initialization */ - /* Reset */ - if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { - set_bit(HCI_RESET, &hdev->flags); - hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); - } - /* Read Local Supported Features */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); @@ -234,9 +226,6 @@ static void amp_init(struct hci_dev *hdev) { hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_BLOCK_BASED; - /* Reset */ - hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); - /* Read Local Version */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL); @@ -262,6 +251,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) } skb_queue_purge(&hdev->driver_init); + /* Reset */ + if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) + hci_reset_req(hdev, 0); + switch (hdev->dev_type) { case HCI_BREDR: bredr_init(hdev); @@ -690,12 +683,11 @@ int hci_dev_open(__u16 dev) set_bit(HCI_INIT, &hdev->flags); hdev->init_last_cmd = 0; - ret = __hci_request(hdev, hci_init_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); if (lmp_host_le_capable(hdev)) ret = __hci_request(hdev, hci_le_init_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); clear_bit(HCI_INIT, &hdev->flags); } @@ -782,8 +774,7 @@ static int hci_dev_do_close(struct hci_dev *hdev) if (!test_bit(HCI_RAW, &hdev->flags) && test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) { set_bit(HCI_INIT, &hdev->flags); - __hci_request(hdev, hci_reset_req, 0, - msecs_to_jiffies(250)); + __hci_request(hdev, hci_reset_req, 0, HCI_CMD_TIMEOUT); clear_bit(HCI_INIT, &hdev->flags); } @@ -872,8 +863,7 @@ int hci_dev_reset(__u16 dev) hdev->acl_cnt = 0; hdev->sco_cnt = 0; hdev->le_cnt = 0; if (!test_bit(HCI_RAW, &hdev->flags)) - ret = __hci_request(hdev, hci_reset_req, 0, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); done: hci_req_unlock(hdev); @@ -913,7 +903,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) switch (cmd) { case HCISETAUTH: err = hci_request(hdev, hci_auth_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); break; case HCISETENCRYPT: @@ -925,23 +915,23 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) if (!test_bit(HCI_AUTH, &hdev->flags)) { /* Auth must be enabled first */ err = hci_request(hdev, hci_auth_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); if (err) break; } err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); break; case HCISETSCAN: err = hci_request(hdev, hci_scan_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); break; case HCISETLINKPOL: err = hci_request(hdev, hci_linkpol_req, dr.dev_opt, - msecs_to_jiffies(HCI_INIT_TIMEOUT)); + HCI_INIT_TIMEOUT); break; case HCISETLINKMODE: @@ -1091,8 +1081,7 @@ static void hci_power_on(struct work_struct *work) return; if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) - schedule_delayed_work(&hdev->power_off, - msecs_to_jiffies(AUTO_OFF_TIMEOUT)); + schedule_delayed_work(&hdev->power_off, HCI_AUTO_OFF_TIMEOUT); if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags)) mgmt_index_added(hdev); @@ -1369,11 +1358,19 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) } /* HCI command timer function */ -static void hci_cmd_timer(unsigned long arg) +static void hci_cmd_timeout(unsigned long arg) { struct hci_dev *hdev = (void *) arg; - BT_ERR("%s command tx timeout", hdev->name); + if (hdev->sent_cmd) { + struct hci_command_hdr *sent = (void *) hdev->sent_cmd->data; + u16 opcode = __le16_to_cpu(sent->opcode); + + BT_ERR("%s command 0x%4.4x tx timeout", hdev->name, opcode); + } else { + BT_ERR("%s command tx timeout", hdev->name); + } + atomic_set(&hdev->cmd_cnt, 1); queue_work(hdev->workqueue, &hdev->cmd_work); } @@ -1671,7 +1668,7 @@ struct hci_dev *hci_alloc_dev(void) init_waitqueue_head(&hdev->req_wait_q); - setup_timer(&hdev->cmd_timer, hci_cmd_timer, (unsigned long) hdev); + setup_timer(&hdev->cmd_timer, hci_cmd_timeout, (unsigned long) hdev); hci_init_sysfs(hdev); discovery_init(hdev); @@ -1746,8 +1743,11 @@ int hci_register_dev(struct hci_dev *hdev) } } - set_bit(HCI_AUTO_OFF, &hdev->dev_flags); set_bit(HCI_SETUP, &hdev->dev_flags); + + if (hdev->dev_type != HCI_AMP) + set_bit(HCI_AUTO_OFF, &hdev->dev_flags); + schedule_work(&hdev->power_on); hci_notify(hdev, HCI_DEV_REG); @@ -2087,7 +2087,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param) struct hci_command_hdr *hdr; struct sk_buff *skb; - BT_DBG("%s opcode 0x%x plen %d", hdev->name, opcode, plen); + BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen); skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) { @@ -2129,7 +2129,7 @@ void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode) if (hdr->opcode != cpu_to_le16(opcode)) return NULL; - BT_DBG("%s opcode 0x%x", hdev->name, opcode); + BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); return hdev->sent_cmd->data + HCI_COMMAND_HDR_SIZE; } @@ -2199,7 +2199,7 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) struct hci_conn *conn = chan->conn; struct hci_dev *hdev = conn->hdev; - BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags); + BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags); skb->dev = (void *) hdev; @@ -2455,7 +2455,7 @@ static void __check_timeout(struct hci_dev *hdev, unsigned int cnt) /* ACL tx timeout must be longer than maximum * link supervision timeout (40.9 seconds) */ if (!cnt && time_after(jiffies, hdev->acl_last_tx + - msecs_to_jiffies(HCI_ACL_TX_TIMEOUT))) + HCI_ACL_TX_TIMEOUT)) hci_link_tx_to(hdev, ACL_LINK); } } @@ -2699,7 +2699,7 @@ static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) flags = hci_flags(handle); handle = hci_handle(handle); - BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, + BT_DBG("%s len %d handle 0x%4.4x flags 0x%4.4x", hdev->name, skb->len, handle, flags); hdev->stat.acl_rx++; @@ -2741,7 +2741,7 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb) handle = __le16_to_cpu(hdr->handle); - BT_DBG("%s len %d handle 0x%x", hdev->name, skb->len, handle); + BT_DBG("%s len %d handle 0x%4.4x", hdev->name, skb->len, handle); hdev->stat.sco_rx++; @@ -2821,7 +2821,8 @@ static void hci_cmd_work(struct work_struct *work) struct hci_dev *hdev = container_of(work, struct hci_dev, cmd_work); struct sk_buff *skb; - BT_DBG("%s cmd %d", hdev->name, atomic_read(&hdev->cmd_cnt)); + BT_DBG("%s cmd_cnt %d cmd queued %d", hdev->name, + atomic_read(&hdev->cmd_cnt), skb_queue_len(&hdev->cmd_q)); /* Send queued commands */ if (atomic_read(&hdev->cmd_cnt)) { @@ -2839,7 +2840,7 @@ static void hci_cmd_work(struct work_struct *work) del_timer(&hdev->cmd_timer); else mod_timer(&hdev->cmd_timer, - jiffies + msecs_to_jiffies(HCI_CMD_TIMEOUT)); + jiffies + HCI_CMD_TIMEOUT); } else { skb_queue_head(&hdev->cmd_q, skb); queue_work(hdev->workqueue, &hdev->cmd_work); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 1ba929c..41ff978 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -36,7 +36,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (status) { hci_dev_lock(hdev); @@ -60,7 +60,7 @@ 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); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (status) return; @@ -72,7 +72,7 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (status) return; @@ -93,7 +93,7 @@ static void hci_cc_role_discovery(struct hci_dev *hdev, struct sk_buff *skb) struct hci_rp_role_discovery *rp = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -116,7 +116,7 @@ static void hci_cc_read_link_policy(struct hci_dev *hdev, struct sk_buff *skb) struct hci_rp_read_link_policy *rp = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -136,7 +136,7 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb) struct hci_conn *conn; void *sent; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -159,7 +159,7 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, { struct hci_rp_read_def_link_policy *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -173,7 +173,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_DEF_LINK_POLICY); if (!sent) @@ -189,7 +189,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); clear_bit(HCI_RESET, &hdev->flags); @@ -207,7 +207,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) @@ -229,7 +229,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_local_name *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -243,7 +243,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_AUTH_ENABLE); if (!sent) @@ -269,7 +269,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_ENCRYPT_MODE); if (!sent) @@ -293,7 +293,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) int old_pscan, old_iscan; void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SCAN_ENABLE); if (!sent) @@ -340,7 +340,7 @@ static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_class_of_dev *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -356,7 +356,7 @@ static void hci_cc_write_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_CLASS_OF_DEV); if (!sent) @@ -378,7 +378,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) struct hci_rp_read_voice_setting *rp = (void *) skb->data; __u16 setting; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -390,7 +390,7 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb) hdev->voice_setting = setting; - BT_DBG("%s voice setting 0x%04x", hdev->name, setting); + BT_DBG("%s voice setting 0x%4.4x", hdev->name, setting); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); @@ -403,7 +403,7 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, __u16 setting; void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (status) return; @@ -419,7 +419,7 @@ static void hci_cc_write_voice_setting(struct hci_dev *hdev, hdev->voice_setting = setting; - BT_DBG("%s voice setting 0x%04x", hdev->name, setting); + BT_DBG("%s voice setting 0x%4.4x", hdev->name, setting); if (hdev->notify) hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING); @@ -429,7 +429,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); } @@ -439,7 +439,7 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) __u8 status = *((__u8 *) skb->data); void *sent; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); if (!sent) @@ -597,7 +597,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_local_version *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) goto done; @@ -608,7 +608,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) hdev->manufacturer = __le16_to_cpu(rp->manufacturer); hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver); - BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, + BT_DBG("%s manufacturer 0x%4.4x hci ver %d:%d", hdev->name, hdev->manufacturer, hdev->hci_ver, hdev->hci_rev); if (test_bit(HCI_INIT, &hdev->flags)) @@ -641,7 +641,7 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, { struct hci_rp_read_local_commands *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) goto done; @@ -660,7 +660,7 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, { struct hci_rp_read_local_features *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -732,7 +732,7 @@ static void hci_cc_read_local_ext_features(struct hci_dev *hdev, { struct hci_rp_read_local_ext_features *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) goto done; @@ -758,7 +758,7 @@ static void hci_cc_read_flow_control_mode(struct hci_dev *hdev, { struct hci_rp_read_flow_control_mode *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -772,7 +772,7 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_buffer_size *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -798,7 +798,7 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_read_bd_addr *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (!rp->status) bacpy(&hdev->bdaddr, &rp->bdaddr); @@ -811,7 +811,7 @@ static void hci_cc_read_data_block_size(struct hci_dev *hdev, { struct hci_rp_read_data_block_size *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -832,7 +832,7 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status); } @@ -842,7 +842,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, { struct hci_rp_read_local_amp_info *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -866,7 +866,7 @@ static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status); } @@ -875,7 +875,7 @@ static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status); } @@ -885,7 +885,7 @@ static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status); } @@ -895,7 +895,7 @@ static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, { struct hci_rp_read_inq_rsp_tx_power *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (!rp->status) hdev->inq_tx_power = rp->tx_power; @@ -907,7 +907,7 @@ static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status); } @@ -918,7 +918,7 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb) struct hci_cp_pin_code_reply *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -944,7 +944,7 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_pin_code_neg_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -960,7 +960,7 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev, { struct hci_rp_le_read_buffer_size *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -979,7 +979,7 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -995,7 +995,7 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -1010,7 +1010,7 @@ static void hci_cc_user_passkey_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -1026,7 +1026,7 @@ static void hci_cc_user_passkey_neg_reply(struct hci_dev *hdev, { struct hci_rp_user_confirm_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); @@ -1042,7 +1042,7 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, { struct hci_rp_read_local_oob_data *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); hci_dev_lock(hdev); mgmt_read_local_oob_data_reply_complete(hdev, rp->hash, @@ -1054,7 +1054,7 @@ static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb) { __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_LE_SET_SCAN_PARAM, status); @@ -1072,7 +1072,7 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev, struct hci_cp_le_set_scan_enable *cp; __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); cp = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_SCAN_ENABLE); if (!cp) @@ -1127,7 +1127,7 @@ static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_le_ltk_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -1139,7 +1139,7 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_rp_le_ltk_neg_reply *rp = (void *) skb->data; - BT_DBG("%s status 0x%x", hdev->name, rp->status); + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); if (rp->status) return; @@ -1153,7 +1153,7 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, struct hci_cp_write_le_host_supported *sent; __u8 status = *((__u8 *) skb->data); - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED); if (!sent) @@ -1175,7 +1175,7 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (status) { hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1199,7 +1199,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) struct hci_cp_create_conn *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_CONN); if (!cp) @@ -1209,7 +1209,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&cp->bdaddr), conn); + BT_DBG("%s bdaddr %s hcon %p", hdev->name, batostr(&cp->bdaddr), conn); if (status) { if (conn && conn->state == BT_CONNECT) { @@ -1240,7 +1240,7 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) struct hci_conn *acl, *sco; __u16 handle; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1251,7 +1251,7 @@ static void hci_cs_add_sco(struct hci_dev *hdev, __u8 status) handle = __le16_to_cpu(cp->handle); - BT_DBG("%s handle %d", hdev->name, handle); + BT_DBG("%s handle 0x%4.4x", hdev->name, handle); hci_dev_lock(hdev); @@ -1274,7 +1274,7 @@ static void hci_cs_auth_requested(struct hci_dev *hdev, __u8 status) struct hci_cp_auth_requested *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1301,7 +1301,7 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status) struct hci_cp_set_conn_encrypt *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1413,7 +1413,7 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) struct hci_cp_remote_name_req *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); /* If successful wait for the name req complete event before * checking for the need to do authentication */ @@ -1452,7 +1452,7 @@ static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status) struct hci_cp_read_remote_features *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1479,7 +1479,7 @@ static void hci_cs_read_remote_ext_features(struct hci_dev *hdev, __u8 status) struct hci_cp_read_remote_ext_features *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1507,7 +1507,7 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) struct hci_conn *acl, *sco; __u16 handle; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1518,7 +1518,7 @@ static void hci_cs_setup_sync_conn(struct hci_dev *hdev, __u8 status) handle = __le16_to_cpu(cp->handle); - BT_DBG("%s handle %d", hdev->name, handle); + BT_DBG("%s handle 0x%4.4x", hdev->name, handle); hci_dev_lock(hdev); @@ -1541,7 +1541,7 @@ static void hci_cs_sniff_mode(struct hci_dev *hdev, __u8 status) struct hci_cp_sniff_mode *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1568,7 +1568,7 @@ static void hci_cs_exit_sniff_mode(struct hci_dev *hdev, __u8 status) struct hci_cp_exit_sniff_mode *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); if (!status) return; @@ -1617,7 +1617,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) struct hci_cp_le_create_conn *cp; struct hci_conn *conn; - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN); if (!cp) @@ -1655,7 +1655,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) { - BT_DBG("%s status 0x%x", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); } static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) @@ -1664,7 +1664,7 @@ static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct discovery_state *discov = &hdev->discovery; struct inquiry_entry *e; - BT_DBG("%s status %d", hdev->name, status); + BT_DBG("%s status 0x%2.2x", hdev->name, status); hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1893,7 +1893,7 @@ static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_disconn_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -1930,7 +1930,7 @@ static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_auth_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2035,7 +2035,7 @@ static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_encrypt_change *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2079,7 +2079,7 @@ static void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct hci_ev_change_link_key_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2102,7 +2102,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev, struct hci_ev_remote_features *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2364,7 +2364,7 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) break; default: - BT_DBG("%s opcode 0x%x", hdev->name, opcode); + BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; } @@ -2445,7 +2445,7 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) break; default: - BT_DBG("%s opcode 0x%x", hdev->name, opcode); + BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); break; } @@ -2464,7 +2464,7 @@ static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_role_change *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2605,7 +2605,7 @@ static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_mode_change *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2763,7 +2763,7 @@ static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_clock_offset *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2786,7 +2786,7 @@ static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_pkt_type_change *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2930,7 +2930,7 @@ static void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct hci_ev_sync_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -2989,7 +2989,7 @@ static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_sniff_subrate *ev = (void *) skb->data; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); } static void hci_extended_inquiry_result_evt(struct hci_dev *hdev, @@ -3046,7 +3046,7 @@ static void hci_key_refresh_complete_evt(struct hci_dev *hdev, struct hci_ev_key_refresh_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %u handle %u", hdev->name, ev->status, + BT_DBG("%s status 0x%2.2x handle 0x%4.4x", hdev->name, ev->status, __le16_to_cpu(ev->handle)); hci_dev_lock(hdev); @@ -3346,7 +3346,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_ev_le_conn_complete *ev = (void *) skb->data; struct hci_conn *conn; - BT_DBG("%s status %d", hdev->name, ev->status); + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); hci_dev_lock(hdev); @@ -3421,7 +3421,7 @@ static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) struct hci_conn *conn; struct smp_ltk *ltk; - BT_DBG("%s handle %d", hdev->name, __le16_to_cpu(ev->handle)); + BT_DBG("%s handle 0x%4.4x", hdev->name, __le16_to_cpu(ev->handle)); hci_dev_lock(hdev); @@ -3645,7 +3645,7 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) break; default: - BT_DBG("%s event 0x%x", hdev->name, event); + BT_DBG("%s event 0x%2.2x", hdev->name, event); break; } diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d42dfdc..a8964db 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -431,6 +431,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan) chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; + chan->ack_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; set_bit(FLAG_FORCE_ACTIVE, &chan->flags); @@ -1657,7 +1658,7 @@ static void l2cap_streaming_send(struct l2cap_chan *chan, l2cap_do_send(chan, skb); - BT_DBG("Sent txseq %d", (int)control->txseq); + BT_DBG("Sent txseq %u", control->txseq); chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq); chan->frames_sent++; @@ -1722,11 +1723,11 @@ static int l2cap_ertm_send(struct l2cap_chan *chan) chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); l2cap_do_send(chan, tx_skb); - BT_DBG("Sent txseq %d", (int)control->txseq); + BT_DBG("Sent txseq %u", control->txseq); } - BT_DBG("Sent %d, %d unacked, %d in ERTM queue", sent, - (int) chan->unacked_frames, skb_queue_len(&chan->tx_q)); + BT_DBG("Sent %d, %u unacked, %u in ERTM queue", sent, + chan->unacked_frames, skb_queue_len(&chan->tx_q)); return sent; } @@ -1877,14 +1878,14 @@ static void l2cap_send_ack(struct l2cap_chan *chan) frames_to_ack = 0; } - /* Ack now if the tx window is 3/4ths full. + /* Ack now if the window is 3/4ths full. * Calculate without mul or div */ - threshold = chan->tx_win; + threshold = chan->ack_win; threshold += threshold << 1; threshold >>= 2; - BT_DBG("frames_to_ack %d, threshold %d", (int)frames_to_ack, + BT_DBG("frames_to_ack %u, threshold %d", frames_to_ack, threshold); if (frames_to_ack >= threshold) { @@ -1946,15 +1947,15 @@ static inline int l2cap_skbuff_fromiovec(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len, + u32 priority) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d priority %u", chan, (int)len, priority); + BT_DBG("chan %p len %zu priority %u", chan, len, priority); count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1980,15 +1981,15 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, } static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, - struct msghdr *msg, size_t len, - u32 priority) + struct msghdr *msg, size_t len, + u32 priority) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d", chan, (int)len); + BT_DBG("chan %p len %zu", chan, len); count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len); @@ -2013,15 +2014,15 @@ 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, - u16 sdulen) + struct msghdr *msg, size_t len, + u16 sdulen) { struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen; struct l2cap_hdr *lh; - BT_DBG("chan %p len %d", chan, (int)len); + BT_DBG("chan %p len %zu", chan, len); if (!conn) return ERR_PTR(-ENOTCONN); @@ -2075,7 +2076,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan, size_t pdu_len; u8 sar; - BT_DBG("chan %p, msg %p, len %d", chan, msg, (int)len); + BT_DBG("chan %p, msg %p, len %zu", chan, msg, len); /* It is critical that ERTM PDUs fit in a single HCI fragment, * so fragmented skbs are not used. The HCI layer's handling @@ -2219,7 +2220,7 @@ static void l2cap_send_srej(struct l2cap_chan *chan, u16 txseq) struct l2cap_ctrl control; u16 seq; - BT_DBG("chan %p, txseq %d", chan, txseq); + BT_DBG("chan %p, txseq %u", chan, txseq); memset(&control, 0, sizeof(control)); control.sframe = 1; @@ -2259,7 +2260,7 @@ static void l2cap_send_srej_list(struct l2cap_chan *chan, u16 txseq) u16 initial_head; u16 seq; - BT_DBG("chan %p, txseq %d", chan, txseq); + BT_DBG("chan %p, txseq %u", chan, txseq); memset(&control, 0, sizeof(control)); control.sframe = 1; @@ -2284,12 +2285,12 @@ static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) struct sk_buff *acked_skb; u16 ackseq; - BT_DBG("chan %p, reqseq %d", chan, reqseq); + BT_DBG("chan %p, reqseq %u", chan, reqseq); if (chan->unacked_frames == 0 || reqseq == chan->expected_ack_seq) return; - BT_DBG("expected_ack_seq %d, unacked_frames %d", + BT_DBG("expected_ack_seq %u, unacked_frames %u", chan->expected_ack_seq, chan->unacked_frames); for (ackseq = chan->expected_ack_seq; ackseq != reqseq; @@ -2308,7 +2309,7 @@ static void l2cap_process_reqseq(struct l2cap_chan *chan, u16 reqseq) if (chan->unacked_frames == 0) __clear_retrans_timer(chan); - BT_DBG("unacked_frames %d", (int) chan->unacked_frames); + BT_DBG("unacked_frames %u", chan->unacked_frames); } static void l2cap_abort_rx_srej_sent(struct l2cap_chan *chan) @@ -2534,16 +2535,16 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) } /* ---- L2CAP signalling commands ---- */ -static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, - u8 code, u8 ident, u16 dlen, void *data) +static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, + u8 ident, u16 dlen, void *data) { struct sk_buff *skb, **frag; struct l2cap_cmd_hdr *cmd; struct l2cap_hdr *lh; int len, count; - BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %d", - conn, code, ident, dlen); + BT_DBG("conn %p, code 0x%2.2x, ident 0x%2.2x, len %u", + conn, code, ident, dlen); len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen; count = min_t(unsigned int, conn->mtu, len); @@ -2626,7 +2627,7 @@ static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned break; } - BT_DBG("type 0x%2.2x len %d val 0x%lx", *type, opt->len, *val); + BT_DBG("type 0x%2.2x len %u val 0x%lx", *type, opt->len, *val); return len; } @@ -2634,7 +2635,7 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) { struct l2cap_conf_opt *opt = *ptr; - BT_DBG("type 0x%2.2x len %d val 0x%lx", type, len, val); + BT_DBG("type 0x%2.2x len %u val 0x%lx", type, len, val); opt->type = type; opt->len = len; @@ -2786,6 +2787,7 @@ static inline void l2cap_txwin_setup(struct l2cap_chan *chan) L2CAP_DEFAULT_TX_WINDOW); chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW; } + chan->ack_win = chan->tx_win; } static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) @@ -3175,10 +3177,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi break; case L2CAP_CONF_EWS: - chan->tx_win = min_t(u16, val, - L2CAP_DEFAULT_EXT_WINDOW); + chan->ack_win = min_t(u16, val, chan->ack_win); l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2, - chan->tx_win); + chan->tx_win); break; case L2CAP_CONF_EFS: @@ -3207,6 +3208,9 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); chan->mps = le16_to_cpu(rfc.max_pdu_size); + if (!test_bit(FLAG_EXT_CTRL, &chan->flags)) + chan->ack_win = min_t(u16, chan->ack_win, + rfc.txwin_size); if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) { chan->local_msdu = le16_to_cpu(efs.msdu); @@ -3268,7 +3272,17 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { int type, olen; unsigned long val; - struct l2cap_conf_rfc rfc; + /* Use sane default values in case a misbehaving remote device + * did not send an RFC or extended window size option. + */ + u16 txwin_ext = chan->ack_win; + struct l2cap_conf_rfc rfc = { + .mode = chan->mode, + .retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO), + .monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO), + .max_pdu_size = cpu_to_le16(chan->imtu), + .txwin_size = min_t(u16, chan->ack_win, L2CAP_DEFAULT_TX_WINDOW), + }; BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); @@ -3278,32 +3292,27 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); - if (type != L2CAP_CONF_RFC) - continue; - - if (olen != sizeof(rfc)) + switch (type) { + case L2CAP_CONF_RFC: + if (olen == sizeof(rfc)) + memcpy(&rfc, (void *)val, olen); break; - - memcpy(&rfc, (void *)val, olen); - goto done; + case L2CAP_CONF_EWS: + txwin_ext = val; + break; + } } - /* Use sane default values in case a misbehaving remote device - * did not send an RFC option. - */ - rfc.mode = chan->mode; - rfc.retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO); - rfc.monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO); - rfc.max_pdu_size = cpu_to_le16(chan->imtu); - - BT_ERR("Expected RFC option was not found, using defaults"); - -done: switch (rfc.mode) { case L2CAP_MODE_ERTM: chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - chan->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); + if (test_bit(FLAG_EXT_CTRL, &chan->flags)) + chan->ack_win = min_t(u16, chan->ack_win, txwin_ext); + else + chan->ack_win = min_t(u16, chan->ack_win, + rfc.txwin_size); break; case L2CAP_MODE_STREAMING: chan->mps = le16_to_cpu(rfc.max_pdu_size); @@ -3949,7 +3958,7 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn, psm = le16_to_cpu(req->psm); scid = le16_to_cpu(req->scid); - BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id); + BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id); /* Placeholder: Always reject */ rsp.dcid = 0; @@ -3972,11 +3981,11 @@ static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn, } static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, - u16 icid, u16 result) + u16 icid, u16 result) { struct l2cap_move_chan_rsp rsp; - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); rsp.icid = cpu_to_le16(icid); rsp.result = cpu_to_le16(result); @@ -3985,12 +3994,13 @@ static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident, } static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, - struct l2cap_chan *chan, u16 icid, u16 result) + struct l2cap_chan *chan, + u16 icid, u16 result) { struct l2cap_move_chan_cfm cfm; u8 ident; - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); ident = l2cap_get_ident(conn); if (chan) @@ -4003,18 +4013,19 @@ static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn, } static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident, - u16 icid) + u16 icid) { struct l2cap_move_chan_cfm_rsp rsp; - BT_DBG("icid %d", icid); + BT_DBG("icid 0x%4.4x", icid); rsp.icid = cpu_to_le16(icid); l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp); } static inline int l2cap_move_channel_req(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_req *req = data; u16 icid = 0; @@ -4025,7 +4036,7 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, icid = le16_to_cpu(req->icid); - BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id); + BT_DBG("icid 0x%4.4x, dest_amp_id %d", icid, req->dest_amp_id); if (!enable_hs) return -EINVAL; @@ -4037,7 +4048,8 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn, } static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_rsp *rsp = data; u16 icid, result; @@ -4048,7 +4060,7 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, icid = le16_to_cpu(rsp->icid); result = le16_to_cpu(rsp->result); - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); /* Placeholder: Always unconfirmed */ l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED); @@ -4057,7 +4069,8 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn, } static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_cfm *cfm = data; u16 icid, result; @@ -4068,7 +4081,7 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, icid = le16_to_cpu(cfm->icid); result = le16_to_cpu(cfm->result); - BT_DBG("icid %d, result %d", icid, result); + BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result); l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid); @@ -4076,7 +4089,8 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn, } static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, - struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data) + struct l2cap_cmd_hdr *cmd, + u16 cmd_len, void *data) { struct l2cap_move_chan_cfm_rsp *rsp = data; u16 icid; @@ -4086,7 +4100,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn, icid = le16_to_cpu(rsp->icid); - BT_DBG("icid %d", icid); + BT_DBG("icid 0x%4.4x", icid); return 0; } @@ -5374,7 +5388,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!conn) return 0; - BT_DBG("conn %p", conn); + BT_DBG("conn %p status 0x%2.2x encrypt %u", conn, status, encrypt); if (hcon->type == LE_LINK) { if (!status && encrypt) @@ -5387,7 +5401,8 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) list_for_each_entry(chan, &conn->chan_l, list) { l2cap_chan_lock(chan); - BT_DBG("chan->scid %d", chan->scid); + BT_DBG("chan %p scid 0x%4.4x state %s", chan, chan->scid, + state_to_string(chan->state)); if (chan->scid == L2CAP_CID_LE_DATA) { if (!status && encrypt) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a6e0f3d..ad6613d 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -210,7 +210,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status) BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status); - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC); + skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL); if (!skb) return -ENOMEM; @@ -241,7 +241,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status, BT_DBG("sock %p", sk); - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC); + skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -687,14 +687,14 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, { struct pending_cmd *cmd; - cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC); + cmd = kmalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) return NULL; cmd->opcode = opcode; cmd->index = hdev->id; - cmd->param = kmalloc(len, GFP_ATOMIC); + cmd->param = kmalloc(len, GFP_KERNEL); if (!cmd->param) { kfree(cmd); return NULL; @@ -812,7 +812,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len, struct sk_buff *skb; struct mgmt_hdr *hdr; - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); + skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL); if (!skb) return -ENOMEM; @@ -1268,7 +1268,7 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) goto failed; } - uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); + uuid = kmalloc(sizeof(*uuid), GFP_KERNEL); if (!uuid) { err = -ENOMEM; goto failed; @@ -1611,7 +1611,7 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data, } dc.handle = cpu_to_le16(conn->handle); - dc.reason = 0x13; /* Remote User Terminated Connection */ + dc.reason = HCI_ERROR_REMOTE_USER_TERM; err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc); if (err < 0) @@ -1667,7 +1667,7 @@ static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data, } rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info)); - rp = kmalloc(rp_len, GFP_ATOMIC); + rp = kmalloc(rp_len, GFP_KERNEL); if (!rp) { err = -ENOMEM; goto unlock; @@ -1778,29 +1778,6 @@ failed: return err; } -static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, - void *data, u16 len) -{ - struct mgmt_cp_pin_code_neg_reply *cp = data; - int err; - - BT_DBG(""); - - hci_dev_lock(hdev); - - if (!hdev_is_powered(hdev)) { - err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, - MGMT_STATUS_NOT_POWERED); - goto failed; - } - - err = send_pin_code_neg_reply(sk, hdev, cp); - -failed: - hci_dev_unlock(hdev); - return err; -} - static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2083,6 +2060,18 @@ done: return err; } +static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev, + void *data, u16 len) +{ + struct mgmt_cp_pin_code_neg_reply *cp = data; + + BT_DBG(""); + + return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type, + MGMT_OP_PIN_CODE_NEG_REPLY, + HCI_OP_PIN_CODE_NEG_REPLY, 0); +} + static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) { @@ -2607,8 +2596,8 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev, if (cp->val) { type = PAGE_SCAN_TYPE_INTERLACED; - /* 22.5 msec page scan interval */ - acp.interval = __constant_cpu_to_le16(0x0024); + /* 160 msec page scan interval */ + acp.interval = __constant_cpu_to_le16(0x0100); } else { type = PAGE_SCAN_TYPE_STANDARD; /* default */ @@ -3546,9 +3535,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_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; + ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME); if (!ssp) - ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING; + ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING); if (eir_len > 0) memcpy(ev->eir, eir, eir_len); @@ -3558,7 +3547,6 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, dev_class, 3); ev->eir_len = cpu_to_le16(eir_len); - ev_size = sizeof(*ev) + eir_len; return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL); diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c index 5cc1bf7..d0deb3e 100644 --- a/net/mac80211/agg-tx.c +++ b/net/mac80211/agg-tx.c @@ -135,7 +135,8 @@ void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn) bar->control = cpu_to_le16(bar_control); bar->start_seq_num = cpu_to_le16(ssn); - IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT; + IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT | + IEEE80211_TX_CTL_REQ_TX_STATUS; ieee80211_tx_skb_tid(sdata, skb, tid); } EXPORT_SYMBOL(ieee80211_send_bar); diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index ccbe241..d41974a 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -20,31 +20,31 @@ #include "rate.h" #include "mesh.h" -static struct net_device *ieee80211_add_iface(struct wiphy *wiphy, char *name, - enum nl80211_iftype type, - u32 *flags, - struct vif_params *params) +static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy, char *name, + enum nl80211_iftype type, + u32 *flags, + struct vif_params *params) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct net_device *dev; + struct wireless_dev *wdev; struct ieee80211_sub_if_data *sdata; int err; - err = ieee80211_if_add(local, name, &dev, type, params); + err = ieee80211_if_add(local, name, &wdev, type, params); if (err) return ERR_PTR(err); if (type == NL80211_IFTYPE_MONITOR && flags) { - sdata = IEEE80211_DEV_TO_SUB_IF(dev); + sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); sdata->u.mntr_flags = *flags; } - return dev; + return wdev; } -static int ieee80211_del_iface(struct wiphy *wiphy, struct net_device *dev) +static int ieee80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) { - ieee80211_if_remove(IEEE80211_DEV_TO_SUB_IF(dev)); + ieee80211_if_remove(IEEE80211_WDEV_TO_SUB_IF(wdev)); return 0; } @@ -917,6 +917,7 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) kfree_rcu(old, rcu_head); + sta_info_flush(sdata->local, sdata); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); return 0; @@ -1741,6 +1742,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy, return -EINVAL; } + ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_QOS); + return 0; } @@ -1761,10 +1764,11 @@ static int ieee80211_resume(struct wiphy *wiphy) #endif static int ieee80211_scan(struct wiphy *wiphy, - struct net_device *dev, struct cfg80211_scan_request *req) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata; + + sdata = IEEE80211_WDEV_TO_SUB_IF(req->wdev); switch (ieee80211_vif_type_p2p(&sdata->vif)) { case NL80211_IFTYPE_STATION: @@ -2297,13 +2301,13 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local, } static int ieee80211_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; int ret; @@ -2390,23 +2394,23 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local, } static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; return ieee80211_cancel_roc(local, cookie, false); } -static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, +static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct sta_info *sta; @@ -2490,6 +2494,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, skb->dev = sdata->dev; if (!need_offchan) { + *cookie = (unsigned long) skb; ieee80211_tx_skb(sdata, skb); ret = 0; goto out_unlock; @@ -2511,21 +2516,20 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev, } static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u64 cookie) { - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; + struct ieee80211_local *local = wiphy_priv(wiphy); return ieee80211_cancel_roc(local, cookie, true); } static void ieee80211_mgmt_frame_register(struct wiphy *wiphy, - struct net_device *dev, + struct wireless_dev *wdev, u16 frame_type, bool reg) { struct ieee80211_local *local = wiphy_priv(wiphy); - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); + struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev); switch (frame_type) { case IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH: @@ -2980,14 +2984,14 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev, return 0; } -static void ieee80211_set_monitor_enabled(struct wiphy *wiphy, bool enabled) +static struct ieee80211_channel * +ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev, + enum nl80211_channel_type *type) { struct ieee80211_local *local = wiphy_priv(wiphy); - if (enabled) - WARN_ON(ieee80211_add_virtual_monitor(local)); - else - ieee80211_del_virtual_monitor(local); + *type = local->_oper_channel_type; + return local->oper_channel; } #ifdef CONFIG_PM @@ -3064,11 +3068,11 @@ struct cfg80211_ops mac80211_config_ops = { .tdls_mgmt = ieee80211_tdls_mgmt, .probe_client = ieee80211_probe_client, .set_noack_map = ieee80211_set_noack_map, - .set_monitor_enabled = ieee80211_set_monitor_enabled, #ifdef CONFIG_PM .set_wakeup = ieee80211_set_wakeup, #endif .get_et_sset_count = ieee80211_get_et_sset_count, .get_et_stats = ieee80211_get_et_stats, .get_et_strings = ieee80211_get_et_strings, + .get_channel = ieee80211_cfg_get_channel, }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 778e591..b8dfb44 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -325,8 +325,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->rx_handlers_drop_defrag); DEBUGFS_STATS_ADD(rx_handlers_drop_short, local->rx_handlers_drop_short); - DEBUGFS_STATS_ADD(rx_handlers_drop_passive_scan, - local->rx_handlers_drop_passive_scan); DEBUGFS_STATS_ADD(tx_expand_skb_head, local->tx_expand_skb_head); DEBUGFS_STATS_ADD(tx_expand_skb_head_cloned, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index e0423f8..bb61f77 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -85,6 +85,8 @@ struct ieee80211_bss { size_t ssid_len; u8 ssid[IEEE80211_MAX_SSID_LEN]; + u32 device_ts; + u8 dtim_period; bool wmm_used; @@ -207,7 +209,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * enum ieee80211_packet_rx_flags - packet RX flags * @IEEE80211_RX_RA_MATCH: frame is destined to interface currently processed * (incl. multicast frames) - * @IEEE80211_RX_IN_SCAN: received while scanning * @IEEE80211_RX_FRAGMENTED: fragmented frame * @IEEE80211_RX_AMSDU: a-MSDU packet * @IEEE80211_RX_MALFORMED_ACTION_FRM: action frame is malformed @@ -217,7 +218,6 @@ typedef unsigned __bitwise__ ieee80211_rx_result; * @rx_flags field of &struct ieee80211_rx_status. */ enum ieee80211_packet_rx_flags { - IEEE80211_RX_IN_SCAN = BIT(0), IEEE80211_RX_RA_MATCH = BIT(1), IEEE80211_RX_FRAGMENTED = BIT(2), IEEE80211_RX_AMSDU = BIT(3), @@ -965,14 +965,14 @@ struct ieee80211_local { int scan_channel_idx; int scan_ies_len; - bool sched_scanning; struct ieee80211_sched_scan_ies sched_scan_ies; struct work_struct sched_scan_stopped_work; + struct ieee80211_sub_if_data __rcu *sched_scan_sdata; unsigned long leave_oper_channel_time; enum mac80211_scan_state next_scan_state; struct delayed_work scan_work; - struct ieee80211_sub_if_data *scan_sdata; + struct ieee80211_sub_if_data __rcu *scan_sdata; enum nl80211_channel_type _oper_channel_type; struct ieee80211_channel *oper_channel, *csa_channel; @@ -1014,7 +1014,6 @@ struct ieee80211_local { unsigned int rx_handlers_drop_nullfunc; unsigned int rx_handlers_drop_defrag; unsigned int rx_handlers_drop_short; - unsigned int rx_handlers_drop_passive_scan; unsigned int tx_expand_skb_head; unsigned int tx_expand_skb_head_cloned; unsigned int rx_expand_skb_head; @@ -1091,6 +1090,12 @@ IEEE80211_DEV_TO_SUB_IF(struct net_device *dev) return netdev_priv(dev); } +static inline struct ieee80211_sub_if_data * +IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev) +{ + return container_of(wdev, struct ieee80211_sub_if_data, wdev); +} + /* this struct represents 802.11n's RA/TID combination */ struct ieee80211_ra_tid { u8 ra[ETH_ALEN]; @@ -1241,8 +1246,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata, struct cfg80211_scan_request *req); void ieee80211_scan_cancel(struct ieee80211_local *local); void ieee80211_run_deferred_scan(struct ieee80211_local *local); -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb); +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb); void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local); struct ieee80211_bss * @@ -1278,7 +1282,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc); int ieee80211_iface_init(void); void ieee80211_iface_exit(void); int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params); int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, enum nl80211_iftype type); @@ -1487,10 +1491,6 @@ int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata, int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, bool need_basic); -/* virtual monitor */ -int ieee80211_add_virtual_monitor(struct ieee80211_local *local); -void ieee80211_del_virtual_monitor(struct ieee80211_local *local); - /* channel management */ enum ieee80211_chan_mode { CHAN_MODE_UNDEFINED, diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index fbef7a1..bfb57dc 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -112,10 +112,11 @@ static u32 __ieee80211_recalc_idle(struct ieee80211_local *local) } } - if (local->scan_sdata && - !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); + if (sdata && !(local->hw.flags & IEEE80211_HW_SCAN_WHILE_IDLE)) { scanning = true; - local->scan_sdata->vif.bss_conf.idle = false; + sdata->vif.bss_conf.idle = false; } list_for_each_entry(sdata, &local->interfaces, list) { @@ -330,20 +331,24 @@ static void ieee80211_set_default_queues(struct ieee80211_sub_if_data *sdata) sdata->vif.cab_queue = IEEE80211_INVAL_HW_QUEUE; } -int ieee80211_add_virtual_monitor(struct ieee80211_local *local) +static int ieee80211_add_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; - int ret; + int ret = 0; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return 0; + mutex_lock(&local->iflist_mtx); + if (local->monitor_sdata) - return 0; + goto out_unlock; sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL); - if (!sdata) - return -ENOMEM; + if (!sdata) { + ret = -ENOMEM; + goto out_unlock; + } /* set up data */ sdata->local = local; @@ -357,31 +362,34 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local) if (WARN_ON(ret)) { /* ok .. stupid driver, it asked for this! */ kfree(sdata); - return ret; + goto out_unlock; } ret = ieee80211_check_queues(sdata); if (ret) { kfree(sdata); - return ret; + goto out_unlock; } rcu_assign_pointer(local->monitor_sdata, sdata); - - return 0; + out_unlock: + mutex_unlock(&local->iflist_mtx); + return ret; } -void ieee80211_del_virtual_monitor(struct ieee80211_local *local) +static void ieee80211_del_virtual_monitor(struct ieee80211_local *local) { struct ieee80211_sub_if_data *sdata; if (!(local->hw.flags & IEEE80211_HW_WANT_MONITOR_VIF)) return; - sdata = rtnl_dereference(local->monitor_sdata); + mutex_lock(&local->iflist_mtx); + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); if (!sdata) - return; + goto out_unlock; rcu_assign_pointer(local->monitor_sdata, NULL); synchronize_net(); @@ -389,6 +397,8 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local) drv_remove_interface(local, sdata); kfree(sdata); + out_unlock: + mutex_unlock(&local->iflist_mtx); } /* @@ -487,6 +497,12 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) break; } + if (local->monitors == 0 && local->open_count == 0) { + res = ieee80211_add_virtual_monitor(local); + if (res) + goto err_stop; + } + /* must be before the call to ieee80211_configure_filter */ local->monitors++; if (local->monitors == 1) { @@ -501,6 +517,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up) break; default: if (coming_up) { + ieee80211_del_virtual_monitor(local); + res = drv_add_interface(local, sdata); if (res) goto err_stop; @@ -628,7 +646,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, clear_bit(SDATA_STATE_RUNNING, &sdata->state); - if (local->scan_sdata == sdata) + if (rcu_access_pointer(local->scan_sdata) == sdata) ieee80211_scan_cancel(local); /* @@ -735,6 +753,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, if (local->monitors == 0) { local->hw.conf.flags &= ~IEEE80211_CONF_MONITOR; hw_reconf_flags |= IEEE80211_CONF_CHANGE_MONITOR; + ieee80211_del_virtual_monitor(local); } ieee80211_adjust_monitor_flags(sdata, -1); @@ -808,6 +827,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, } } spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); + + if (local->monitors == local->open_count && local->monitors > 0) + ieee80211_add_virtual_monitor(local); } static int ieee80211_stop(struct net_device *dev) @@ -1373,7 +1395,7 @@ static void ieee80211_assign_perm_addr(struct ieee80211_local *local, } int ieee80211_if_add(struct ieee80211_local *local, const char *name, - struct net_device **new_dev, enum nl80211_iftype type, + struct wireless_dev **new_wdev, enum nl80211_iftype type, struct vif_params *params) { struct net_device *ndev; @@ -1463,8 +1485,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name, list_add_tail_rcu(&sdata->list, &local->interfaces); mutex_unlock(&local->iflist_mtx); - if (new_dev) - *new_dev = ndev; + if (new_wdev) + *new_wdev = &sdata->wdev; return 0; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index b3b7e52..7ae678b 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -194,26 +194,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; } -void ieee80211_key_removed(struct ieee80211_key_conf *key_conf) -{ - struct ieee80211_key *key; - - key = container_of(key_conf, struct ieee80211_key, conf); - - might_sleep(); - assert_key_lock(key->local); - - key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; - - /* - * Flush TX path to avoid attempts to use this key - * after this function returns. Until then, drivers - * must be prepared to handle the key. - */ - synchronize_rcu(); -} -EXPORT_SYMBOL_GPL(ieee80211_key_removed); - static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx, bool uni, bool multi) { diff --git a/net/mac80211/main.c b/net/mac80211/main.c index c794101..c26e231 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -322,7 +322,8 @@ static void ieee80211_restart_work(struct work_struct *work) mutex_lock(&local->mtx); WARN(test_bit(SCAN_HW_SCANNING, &local->scanning) || - local->sched_scanning, + rcu_dereference_protected(local->sched_scan_sdata, + lockdep_is_held(&local->mtx)), "%s called with hardware scan in progress\n", __func__); mutex_unlock(&local->mtx); diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index f49f14f..cef0c9e 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -1108,7 +1108,7 @@ void ieee80211_dynamic_ps_timer(unsigned long data) } /* MLME */ -static void ieee80211_sta_wmm_params(struct ieee80211_local *local, +static bool ieee80211_sta_wmm_params(struct ieee80211_local *local, struct ieee80211_sub_if_data *sdata, u8 *wmm_param, size_t wmm_param_len) { @@ -1119,23 +1119,23 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, u8 *pos, uapsd_queues = 0; if (!local->ops->conf_tx) - return; + return false; if (local->hw.queues < IEEE80211_NUM_ACS) - return; + return false; if (!wmm_param) - return; + return false; if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1) - return; + return false; if (ifmgd->flags & IEEE80211_STA_UAPSD_ENABLED) uapsd_queues = ifmgd->uapsd_queues; count = wmm_param[6] & 0x0f; if (count == ifmgd->wmm_last_param_set) - return; + return false; ifmgd->wmm_last_param_set = count; pos = wmm_param + 8; @@ -1202,6 +1202,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, /* enable WMM or activate new settings */ sdata->vif.bss_conf.qos = true; + return true; } static void __ieee80211_stop_poll(struct ieee80211_sub_if_data *sdata) @@ -1268,11 +1269,6 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; bss_info_changed |= BSS_CHANGED_ASSOC; - /* set timing information */ - bss_conf->beacon_int = cbss->beacon_interval; - bss_conf->last_tsf = cbss->tsf; - - bss_info_changed |= BSS_CHANGED_BEACON_INT; bss_info_changed |= ieee80211_handle_bss_capability(sdata, bss_conf->assoc_capability, bss->has_erp_value, bss->erp_value); @@ -1364,6 +1360,17 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, } mutex_unlock(&local->sta_mtx); + /* + * if we want to get out of ps before disassoc (why?) we have + * to do it before sending disassoc, as otherwise the null-packet + * won't be valid. + */ + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + local->ps_sdata = NULL; + /* flush out any pending frame (e.g. DELBA) before deauth/disassoc */ if (tx) drv_flush(local, false); @@ -1399,12 +1406,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, del_timer_sync(&local->dynamic_ps_timer); cancel_work_sync(&local->dynamic_ps_enable_work); - if (local->hw.conf.flags & IEEE80211_CONF_PS) { - local->hw.conf.flags &= ~IEEE80211_CONF_PS; - ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); - } - local->ps_sdata = NULL; - /* Disable ARP filtering */ if (sdata->vif.bss_conf.arp_filter_enabled) { sdata->vif.bss_conf.arp_filter_enabled = false; @@ -2435,14 +2436,6 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, directed_tim = ieee80211_check_tim(elems.tim, elems.tim_len, ifmgd->aid); - if (ncrc != ifmgd->beacon_crc || !ifmgd->beacon_crc_valid) { - ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, - true); - - ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, - elems.wmm_param_len); - } - if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) { if (directed_tim) { if (local->hw.conf.dynamic_ps_timeout > 0) { @@ -2473,6 +2466,13 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ifmgd->beacon_crc = ncrc; ifmgd->beacon_crc_valid = true; + ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, + true); + + if (ieee80211_sta_wmm_params(local, sdata, elems.wmm_param, + elems.wmm_param_len)) + changed |= BSS_CHANGED_QOS; + if (elems.erp_info && elems.erp_info_len >= 1) { erp_valid = true; erp_value = elems.erp_info[0]; @@ -2974,7 +2974,7 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) /* scan finished notification */ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) { - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; /* Restart STA timers */ rcu_read_lock(); @@ -3132,9 +3132,15 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, memcpy(ifmgd->bssid, cbss->bssid, ETH_ALEN); - /* tell driver about BSSID and basic rates */ + /* set timing information */ + sdata->vif.bss_conf.beacon_int = cbss->beacon_interval; + sdata->vif.bss_conf.sync_tsf = cbss->tsf; + sdata->vif.bss_conf.sync_device_ts = bss->device_ts; + + /* tell driver about BSSID, basic rates and timing */ ieee80211_bss_info_change_notify(sdata, - BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES); + BSS_CHANGED_BSSID | BSS_CHANGED_BASIC_RATES | + BSS_CHANGED_BEACON_INT); if (assoc) sta_info_pre_move_state(sta, IEEE80211_STA_AUTH); diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c index b0fb6a2..635c325 100644 --- a/net/mac80211/offchannel.c +++ b/net/mac80211/offchannel.c @@ -191,7 +191,7 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc) roc->frame = NULL; } } else { - cfg80211_ready_on_channel(roc->sdata->dev, (unsigned long)roc, + cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc, roc->chan, roc->chan_type, roc->req_duration, GFP_KERNEL); } @@ -299,7 +299,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) /* was never transmitted */ if (roc->frame) { - cfg80211_mgmt_tx_status(roc->sdata->dev, + cfg80211_mgmt_tx_status(&roc->sdata->wdev, (unsigned long)roc->frame, roc->frame->data, roc->frame->len, false, GFP_KERNEL); @@ -307,7 +307,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc) } if (!roc->mgmt_tx_cookie) - cfg80211_remain_on_channel_expired(roc->sdata->dev, + cfg80211_remain_on_channel_expired(&roc->sdata->wdev, (unsigned long)roc, roc->chan, roc->chan_type, GFP_KERNEL); @@ -324,6 +324,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) container_of(work, struct ieee80211_roc_work, work.work); struct ieee80211_sub_if_data *sdata = roc->sdata; struct ieee80211_local *local = sdata->local; + bool started; mutex_lock(&local->mtx); @@ -366,9 +367,10 @@ void ieee80211_sw_roc_work(struct work_struct *work) /* finish this ROC */ finish: list_del(&roc->list); + started = roc->started; ieee80211_roc_notify_destroy(roc); - if (roc->started) { + if (started) { drv_flush(local, false); local->tmp_channel = NULL; @@ -379,7 +381,7 @@ void ieee80211_sw_roc_work(struct work_struct *work) ieee80211_recalc_idle(local); - if (roc->started) + if (started) ieee80211_start_next_roc(local); } diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c index f9e51ef..fb1d4aa 100644 --- a/net/mac80211/rc80211_minstrel_ht.c +++ b/net/mac80211/rc80211_minstrel_ht.c @@ -626,8 +626,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, #ifdef CONFIG_MAC80211_DEBUGFS /* use fixed index if set */ - if (mp->fixed_rate_idx != -1) - sample_idx = mp->fixed_rate_idx; + if (mp->fixed_rate_idx != -1) { + mi->max_tp_rate = mp->fixed_rate_idx; + mi->max_tp_rate2 = mp->fixed_rate_idx; + mi->max_prob_rate = mp->fixed_rate_idx; + sample_idx = -1; + } #endif if (sample_idx >= 0) { diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index 67edd69..0cb4ede 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -413,29 +413,6 @@ static void ieee80211_verify_alignment(struct ieee80211_rx_data *rx) /* rx handlers */ -static ieee80211_rx_result debug_noinline -ieee80211_rx_h_passive_scan(struct ieee80211_rx_data *rx) -{ - struct ieee80211_local *local = rx->local; - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); - struct sk_buff *skb = rx->skb; - - if (likely(!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !local->sched_scanning)) - return RX_CONTINUE; - - if (test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - local->sched_scanning) - return ieee80211_scan_rx(rx->sdata, skb); - - /* scanning finished during invoking of handlers */ - I802_DEBUG_INC(local->rx_handlers_drop_passive_scan); - return RX_DROP_UNUSABLE; -} - - static int ieee80211_is_unicast_robust_mgmt_frame(struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; @@ -2404,7 +2381,7 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx) if (rx->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) sig = status->signal; - if (cfg80211_rx_mgmt(rx->sdata->dev, status->freq, sig, + if (cfg80211_rx_mgmt(&rx->sdata->wdev, status->freq, sig, rx->skb->data, rx->skb->len, GFP_ATOMIC)) { if (rx->sta) @@ -2695,7 +2672,6 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx) goto rxh_next; \ } while (0); - CALL_RXH(ieee80211_rx_h_passive_scan) CALL_RXH(ieee80211_rx_h_check) ieee80211_rx_reorder_ampdu(rx); @@ -2765,11 +2741,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, return 0; if (ieee80211_is_beacon(hdr->frame_control)) { return 1; - } - else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN)) - return 0; - status->rx_flags &= ~IEEE80211_RX_RA_MATCH; + } else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) { + return 0; } else if (!multicast && !ether_addr_equal(sdata->vif.addr, hdr->addr1)) { if (!(sdata->dev->flags & IFF_PROMISC)) @@ -2807,11 +2780,9 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx, * and location updates. Note that mac80211 * itself never looks at these frames. */ - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - ieee80211_is_public_action(hdr, skb->len)) + if (ieee80211_is_public_action(hdr, skb->len)) return 1; - if (!(status->rx_flags & IEEE80211_RX_IN_SCAN) && - !ieee80211_is_beacon(hdr->frame_control)) + if (!ieee80211_is_beacon(hdr->frame_control)) return 0; status->rx_flags &= ~IEEE80211_RX_RA_MATCH; } @@ -2877,7 +2848,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, struct sk_buff *skb) { - struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb); struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_sub_if_data *sdata; struct ieee80211_hdr *hdr; @@ -2895,11 +2865,6 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, if (ieee80211_is_data(fc) || ieee80211_is_mgmt(fc)) local->dot11ReceivedFragmentCount++; - if (unlikely(test_bit(SCAN_HW_SCANNING, &local->scanning) || - test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) || - test_bit(SCAN_SW_SCANNING, &local->scanning))) - status->rx_flags |= IEEE80211_RX_IN_SCAN; - if (ieee80211_is_mgmt(fc)) err = skb_linearize(skb); else @@ -2914,6 +2879,10 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, ieee80211_parse_qos(&rx); ieee80211_verify_alignment(&rx); + if (unlikely(ieee80211_is_probe_resp(hdr->frame_control) || + ieee80211_is_beacon(hdr->frame_control))) + ieee80211_scan_rx(local, skb); + if (ieee80211_is_data(fc)) { prev_sta = NULL; diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 267b294..bcaee5d 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -83,13 +83,14 @@ ieee80211_bss_info_update(struct ieee80211_local *local, cbss = cfg80211_inform_bss_frame(local->hw.wiphy, channel, mgmt, len, signal, GFP_ATOMIC); - if (!cbss) return NULL; cbss->free_priv = ieee80211_rx_bss_free; bss = (void *)cbss->priv; + bss->device_ts = rx_status->device_timestamp; + if (elems->parse_error) { if (beacon) bss->corrupt_data |= IEEE80211_BSS_CORRUPT_BEACON; @@ -164,52 +165,47 @@ ieee80211_bss_info_update(struct ieee80211_local *local, return bss; } -ieee80211_rx_result -ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) +void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb) { struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb); - struct ieee80211_mgmt *mgmt; + struct ieee80211_sub_if_data *sdata1, *sdata2; + struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_bss *bss; u8 *elements; struct ieee80211_channel *channel; size_t baselen; int freq; - __le16 fc; - bool presp, beacon = false; + bool beacon; struct ieee802_11_elems elems; - if (skb->len < 2) - return RX_DROP_UNUSABLE; - - mgmt = (struct ieee80211_mgmt *) skb->data; - fc = mgmt->frame_control; + if (skb->len < 24 || + (!ieee80211_is_probe_resp(mgmt->frame_control) && + !ieee80211_is_beacon(mgmt->frame_control))) + return; - if (ieee80211_is_ctl(fc)) - return RX_CONTINUE; + sdata1 = rcu_dereference(local->scan_sdata); + sdata2 = rcu_dereference(local->sched_scan_sdata); - if (skb->len < 24) - return RX_CONTINUE; + if (likely(!sdata1 && !sdata2)) + return; - presp = ieee80211_is_probe_resp(fc); - if (presp) { + if (ieee80211_is_probe_resp(mgmt->frame_control)) { /* ignore ProbeResp to foreign address */ - if (!ether_addr_equal(mgmt->da, sdata->vif.addr)) - return RX_DROP_MONITOR; + if ((!sdata1 || !ether_addr_equal(mgmt->da, sdata1->vif.addr)) && + (!sdata2 || !ether_addr_equal(mgmt->da, sdata2->vif.addr))) + return; - presp = true; elements = mgmt->u.probe_resp.variable; baselen = offsetof(struct ieee80211_mgmt, u.probe_resp.variable); + beacon = false; } else { - beacon = ieee80211_is_beacon(fc); baselen = offsetof(struct ieee80211_mgmt, u.beacon.variable); elements = mgmt->u.beacon.variable; + beacon = true; } - if (!presp && !beacon) - return RX_CONTINUE; - if (baselen > skb->len) - return RX_DROP_MONITOR; + return; ieee802_11_parse_elems(elements, skb->len - baselen, &elems); @@ -219,22 +215,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb) else freq = rx_status->freq; - channel = ieee80211_get_channel(sdata->local->hw.wiphy, freq); + channel = ieee80211_get_channel(local->hw.wiphy, freq); if (!channel || channel->flags & IEEE80211_CHAN_DISABLED) - return RX_DROP_MONITOR; + return; - bss = ieee80211_bss_info_update(sdata->local, rx_status, + bss = ieee80211_bss_info_update(local, rx_status, mgmt, skb->len, &elems, channel, beacon); if (bss) - ieee80211_rx_bss_put(sdata->local, bss); - - if (channel == sdata->local->oper_channel) - return RX_CONTINUE; - - dev_kfree_skb(skb); - return RX_QUEUED; + ieee80211_rx_bss_put(local, bss); } /* return false if no more work */ @@ -292,7 +282,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted, return; if (was_hw_scan && !aborted && ieee80211_prep_hw_scan(local)) { - int rc = drv_hw_scan(local, local->scan_sdata, local->hw_scan_req); + int rc; + + rc = drv_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)), + local->hw_scan_req); + if (rc == 0) return; } @@ -393,7 +389,10 @@ void ieee80211_run_deferred_scan(struct ieee80211_local *local) if (!local->scan_req || local->scanning) return; - if (!ieee80211_can_scan(local, local->scan_sdata)) + if (!ieee80211_can_scan(local, + rcu_dereference_protected( + local->scan_sdata, + lockdep_is_held(&local->mtx)))) return; ieee80211_queue_delayed_work(&local->hw, &local->scan_work, @@ -404,9 +403,12 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local, unsigned long *next_delay) { int i; - struct ieee80211_sub_if_data *sdata = local->scan_sdata; + struct ieee80211_sub_if_data *sdata; enum ieee80211_band band = local->hw.conf.channel->band; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx));; + for (i = 0; i < local->scan_req->n_ssids; i++) ieee80211_send_probe_req( sdata, NULL, @@ -438,7 +440,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, if (!ieee80211_can_scan(local, sdata)) { /* wait for the work to finish/time out */ local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); return 0; } @@ -472,7 +474,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, } local->scan_req = req; - local->scan_sdata = sdata; + rcu_assign_pointer(local->scan_sdata, sdata); if (local->ops->hw_scan) { __set_bit(SCAN_HW_SCANNING, &local->scanning); @@ -532,7 +534,7 @@ static int __ieee80211_start_scan(struct ieee80211_sub_if_data *sdata, ieee80211_recalc_idle(local); local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); } return rc; @@ -719,7 +721,8 @@ void ieee80211_scan_work(struct work_struct *work) mutex_lock(&local->mtx); - sdata = local->scan_sdata; + sdata = rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx)); /* When scanning on-channel, the first-callback means completed. */ if (test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning)) { @@ -740,7 +743,7 @@ void ieee80211_scan_work(struct work_struct *work) int rc; local->scan_req = NULL; - local->scan_sdata = NULL; + rcu_assign_pointer(local->scan_sdata, NULL); rc = __ieee80211_start_scan(sdata, req); if (rc) { @@ -892,7 +895,9 @@ void ieee80211_scan_cancel(struct ieee80211_local *local) if (test_bit(SCAN_HW_SCANNING, &local->scanning)) { if (local->ops->cancel_hw_scan) - drv_cancel_hw_scan(local, local->scan_sdata); + drv_cancel_hw_scan(local, + rcu_dereference_protected(local->scan_sdata, + lockdep_is_held(&local->mtx))); goto out; } @@ -914,9 +919,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; int ret, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { ret = -EBUSY; goto out; } @@ -927,6 +932,9 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, } for (i = 0; i < IEEE80211_NUM_BANDS; i++) { + if (!local->hw.wiphy->bands[i]) + continue; + local->sched_scan_ies.ie[i] = kzalloc(2 + IEEE80211_MAX_SSID_LEN + local->scan_ies_len + @@ -947,7 +955,7 @@ int ieee80211_request_sched_scan_start(struct ieee80211_sub_if_data *sdata, ret = drv_sched_scan_start(local, sdata, req, &local->sched_scan_ies); if (ret == 0) { - local->sched_scanning = true; + rcu_assign_pointer(local->sched_scan_sdata, sdata); goto out; } @@ -955,7 +963,7 @@ out_free: while (i > 0) kfree(local->sched_scan_ies.ie[--i]); out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -964,22 +972,22 @@ int ieee80211_request_sched_scan_stop(struct ieee80211_sub_if_data *sdata) struct ieee80211_local *local = sdata->local; int ret = 0, i; - mutex_lock(&sdata->local->mtx); + mutex_lock(&local->mtx); if (!local->ops->sched_scan_stop) { ret = -ENOTSUPP; goto out; } - if (local->sched_scanning) { + if (rcu_access_pointer(local->sched_scan_sdata)) { for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); drv_sched_scan_stop(local, sdata); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); } out: - mutex_unlock(&sdata->local->mtx); + mutex_unlock(&local->mtx); return ret; } @@ -1003,7 +1011,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) mutex_lock(&local->mtx); - if (!local->sched_scanning) { + if (!rcu_access_pointer(local->sched_scan_sdata)) { mutex_unlock(&local->mtx); return; } @@ -1011,7 +1019,7 @@ void ieee80211_sched_scan_stopped_work(struct work_struct *work) for (i = 0; i < IEEE80211_NUM_BANDS; i++) kfree(local->sched_scan_ies.ie[i]); - local->sched_scanning = false; + rcu_assign_pointer(local->sched_scan_sdata, NULL); mutex_unlock(&local->mtx); diff --git a/net/mac80211/status.c b/net/mac80211/status.c index 2ed2f27..8cd7291 100644 --- a/net/mac80211/status.c +++ b/net/mac80211/status.c @@ -519,14 +519,19 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) u64 cookie = (unsigned long)skb; acked = info->flags & IEEE80211_TX_STAT_ACK; + /* + * TODO: When we have non-netdev frame TX, + * we cannot use skb->dev->ieee80211_ptr + */ + if (ieee80211_is_nullfunc(hdr->frame_control) || ieee80211_is_qos_nullfunc(hdr->frame_control)) cfg80211_probe_status(skb->dev, hdr->addr1, cookie, acked, GFP_ATOMIC); else cfg80211_mgmt_tx_status( - skb->dev, cookie, skb->data, skb->len, - acked, GFP_ATOMIC); + skb->dev->ieee80211_ptr, cookie, skb->data, + skb->len, acked, GFP_ATOMIC); } if (unlikely(info->ack_frame_id)) { diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h index e1e9d10..c6d33b5 100644 --- a/net/mac80211/trace.h +++ b/net/mac80211/trace.h @@ -306,7 +306,8 @@ TRACE_EVENT(drv_bss_info_changed, __field(u8, dtimper) __field(u16, bcnint) __field(u16, assoc_cap) - __field(u64, timestamp) + __field(u64, sync_tsf) + __field(u32, sync_device_ts) __field(u32, basic_rates) __field(u32, changed) __field(bool, enable_beacon) @@ -325,7 +326,8 @@ TRACE_EVENT(drv_bss_info_changed, __entry->dtimper = info->dtim_period; __entry->bcnint = info->beacon_int; __entry->assoc_cap = info->assoc_capability; - __entry->timestamp = info->last_tsf; + __entry->sync_tsf = info->sync_tsf; + __entry->sync_device_ts = info->sync_device_ts; __entry->basic_rates = info->basic_rates; __entry->enable_beacon = info->enable_beacon; __entry->ht_operation_mode = info->ht_operation_mode; diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index c9d2175..acf712f 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -523,7 +523,7 @@ ieee80211_tx_h_check_control_port_protocol(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) { - struct ieee80211_key *key = NULL; + struct ieee80211_key *key; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; @@ -542,16 +542,23 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) else if (!is_multicast_ether_addr(hdr->addr1) && (key = rcu_dereference(tx->sdata->default_unicast_key))) tx->key = key; - else if (tx->sdata->drop_unencrypted && - (tx->skb->protocol != tx->sdata->control_port_protocol) && - !(info->flags & IEEE80211_TX_CTL_INJECTED) && - (!ieee80211_is_robust_mgmt_frame(hdr) || - (ieee80211_is_action(hdr->frame_control) && - tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP)))) { + else if (info->flags & IEEE80211_TX_CTL_INJECTED) + tx->key = NULL; + else if (!tx->sdata->drop_unencrypted) + tx->key = NULL; + else if (tx->skb->protocol == tx->sdata->control_port_protocol) + tx->key = NULL; + else if (ieee80211_is_robust_mgmt_frame(hdr) && + !(ieee80211_is_action(hdr->frame_control) && + tx->sta && test_sta_flag(tx->sta, WLAN_STA_MFP))) + tx->key = NULL; + else if (ieee80211_is_mgmt(hdr->frame_control) && + !ieee80211_is_robust_mgmt_frame(hdr)) + tx->key = NULL; + else { I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); return TX_DROP; - } else - tx->key = NULL; + } if (tx->key) { bool skip_hw = false; @@ -1817,6 +1824,9 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, /* RA TA mDA mSA AE:DA SA */ mesh_da = mppath->mpp; is_mesh_mcast = 0; + } else if (mpath) { + mesh_da = mpath->dst; + is_mesh_mcast = 0; } else { /* DA TA mSA AE:SA */ mesh_da = bcast; @@ -2714,7 +2724,7 @@ EXPORT_SYMBOL(ieee80211_get_buffered_bc); void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb, int tid) { - int ac = ieee802_1d_to_ac[tid]; + int ac = ieee802_1d_to_ac[tid & 7]; skb_set_mac_header(skb, 0); skb_set_network_header(skb, 0); diff --git a/net/mac80211/util.c b/net/mac80211/util.c index 64493a7..39b82fe 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -529,6 +529,11 @@ void ieee80211_iterate_active_interfaces( &sdata->vif); } + sdata = rcu_dereference_protected(local->monitor_sdata, + lockdep_is_held(&local->iflist_mtx)); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + mutex_unlock(&local->iflist_mtx); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces); @@ -557,6 +562,10 @@ void ieee80211_iterate_active_interfaces_atomic( &sdata->vif); } + sdata = rcu_dereference(local->monitor_sdata); + if (sdata) + iterator(data, sdata->vif.addr, &sdata->vif); + rcu_read_unlock(); } EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces_atomic); @@ -999,6 +1008,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer, int ext_rates_len; sband = local->hw.wiphy->bands[band]; + if (WARN_ON_ONCE(!sband)) + return 0; pos = buffer; diff --git a/net/nfc/hci/core.c b/net/nfc/hci/core.c index 36717ce..1ac7b3f 100644 --- a/net/nfc/hci/core.c +++ b/net/nfc/hci/core.c @@ -187,6 +187,7 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) struct nfc_target *targets; struct sk_buff *atqa_skb = NULL; struct sk_buff *sak_skb = NULL; + struct sk_buff *uid_skb = NULL; int r; pr_debug("from gate %d\n", gate); @@ -222,6 +223,19 @@ static int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate) targets->sens_res = be16_to_cpu(*(u16 *)atqa_skb->data); targets->sel_res = sak_skb->data[0]; + r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE, + NFC_HCI_RF_READER_A_UID, &uid_skb); + if (r < 0) + goto exit; + + if (uid_skb->len == 0 || uid_skb->len > NFC_NFCID1_MAXSIZE) { + r = -EPROTO; + goto exit; + } + + memcpy(targets->nfcid1, uid_skb->data, uid_skb->len); + targets->nfcid1_len = uid_skb->len; + if (hdev->ops->complete_target_discovered) { r = hdev->ops->complete_target_discovered(hdev, gate, targets); @@ -257,6 +271,7 @@ exit: kfree(targets); kfree_skb(atqa_skb); kfree_skb(sak_skb); + kfree_skb(uid_skb); return r; } @@ -695,13 +710,12 @@ EXPORT_SYMBOL(nfc_hci_register_device); void nfc_hci_unregister_device(struct nfc_hci_dev *hdev) { - struct hci_msg *msg; + struct hci_msg *msg, *n; skb_queue_purge(&hdev->rx_hcp_frags); skb_queue_purge(&hdev->msg_rx_queue); - while ((msg = list_first_entry(&hdev->msg_tx_queue, struct hci_msg, - msg_l)) != NULL) { + list_for_each_entry_safe(msg, n, &hdev->msg_tx_queue, msg_l) { list_del(&msg->msg_l); skb_queue_purge(&msg->msg_frags); kfree(msg); diff --git a/net/nfc/hci/hcp.c b/net/nfc/hci/hcp.c index 7212cf2..f4dad1a 100644 --- a/net/nfc/hci/hcp.c +++ b/net/nfc/hci/hcp.c @@ -105,7 +105,7 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, } mutex_lock(&hdev->msg_tx_mutex); - list_add_tail(&hdev->msg_tx_queue, &cmd->msg_l); + list_add_tail(&cmd->msg_l, &hdev->msg_tx_queue); mutex_unlock(&hdev->msg_tx_mutex); queue_work(hdev->msg_tx_wq, &hdev->msg_tx_work); diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c index 5bb4da6..f81efe1 100644 --- a/net/nfc/nci/core.c +++ b/net/nfc/nci/core.c @@ -27,6 +27,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ +#include <linux/module.h> #include <linux/types.h> #include <linux/workqueue.h> #include <linux/completion.h> @@ -880,3 +881,5 @@ static void nci_cmd_work(struct work_struct *work) jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT)); } } + +MODULE_LICENSE("GPL"); diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 4d2b1ec..fe4adb1 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -74,6 +74,27 @@ config CFG80211_REG_DEBUG If unsure, say N. +config CFG80211_CERTIFICATION_ONUS + bool "cfg80211 certification onus" + depends on CFG80211 && EXPERT + default n + ---help--- + You should disable this option unless you are both capable + and willing to ensure your system will remain regulatory + compliant with the features available under this option. + Some options may still be under heavy development and + for whatever reason regulatory compliance has not or + cannot yet be verified. Regulatory verification may at + times only be possible until you have the final system + in place. + + This option should only be enabled by system integrators + or distributions that have done work necessary to ensure + regulatory certification on the system with the enabled + features. Alternatively you can enable this option if + you are a wireless researcher and are working in a controlled + and approved environment by your local regulatory agency. + config CFG80211_DEFAULT_PS bool "enable powersave by default" depends on CFG80211 diff --git a/net/wireless/chan.c b/net/wireless/chan.c index 434c56b..d355f67 100644 --- a/net/wireless/chan.c +++ b/net/wireless/chan.c @@ -82,7 +82,6 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, int freq, enum nl80211_channel_type chantype) { struct ieee80211_channel *chan; - int err; if (!rdev->ops->set_monitor_channel) return -EOPNOTSUPP; @@ -93,25 +92,17 @@ int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev, if (!chan) return -EINVAL; - err = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); - if (!err) { - rdev->monitor_channel = chan; - rdev->monitor_channel_type = chantype; - } - - return err; + return rdev->ops->set_monitor_channel(&rdev->wiphy, chan, chantype); } void -cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, +cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, enum cfg80211_chan_mode *chanmode) { *chan = NULL; *chanmode = CHAN_MODE_UNDEFINED; - ASSERT_RDEV_LOCK(rdev); ASSERT_WDEV_LOCK(wdev); if (!netif_running(wdev->netdev)) @@ -136,9 +127,16 @@ cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_P2P_GO: + if (wdev->beacon_interval) { + *chan = wdev->channel; + *chanmode = CHAN_MODE_SHARED; + } + return; case NL80211_IFTYPE_MESH_POINT: - *chan = wdev->channel; - *chanmode = CHAN_MODE_SHARED; + if (wdev->mesh_id_len) { + *chan = wdev->channel; + *chanmode = CHAN_MODE_SHARED; + } return; case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_AP_VLAN: diff --git a/net/wireless/core.c b/net/wireless/core.c index eb60410..31b40cc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -176,7 +176,9 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, if (!(rdev->wiphy.flags & WIPHY_FLAG_NETNS_OK)) return -EOPNOTSUPP; - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { + if (!wdev->netdev) + continue; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); if (err) @@ -188,8 +190,10 @@ int cfg80211_switch_netns(struct cfg80211_registered_device *rdev, /* failed -- clean up to old netns */ net = wiphy_net(&rdev->wiphy); - list_for_each_entry_continue_reverse(wdev, &rdev->netdev_list, + list_for_each_entry_continue_reverse(wdev, &rdev->wdev_list, list) { + if (!wdev->netdev) + continue; wdev->netdev->features &= ~NETIF_F_NETNS_LOCAL; err = dev_change_net_namespace(wdev->netdev, net, "wlan%d"); @@ -226,8 +230,9 @@ static int cfg80211_rfkill_set_block(void *data, bool blocked) rtnl_lock(); mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) - dev_close(wdev->netdev); + list_for_each_entry(wdev, &rdev->wdev_list, list) + if (wdev->netdev) + dev_close(wdev->netdev); mutex_unlock(&rdev->devlist_mtx); rtnl_unlock(); @@ -304,7 +309,7 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) mutex_init(&rdev->mtx); mutex_init(&rdev->devlist_mtx); mutex_init(&rdev->sched_scan_mtx); - INIT_LIST_HEAD(&rdev->netdev_list); + INIT_LIST_HEAD(&rdev->wdev_list); spin_lock_init(&rdev->bss_lock); INIT_LIST_HEAD(&rdev->bss_list); INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done); @@ -537,7 +542,7 @@ int wiphy_register(struct wiphy *wiphy) } /* set up regulatory info */ - regulatory_update(wiphy, NL80211_REGDOM_SET_BY_CORE); + wiphy_regulatory_register(wiphy); list_add_rcu(&rdev->list, &cfg80211_rdev_list); cfg80211_rdev_list_generation++; @@ -622,7 +627,7 @@ void wiphy_unregister(struct wiphy *wiphy) __count == 0; })); mutex_lock(&rdev->devlist_mtx); - BUG_ON(!list_empty(&rdev->netdev_list)); + BUG_ON(!list_empty(&rdev->wdev_list)); mutex_unlock(&rdev->devlist_mtx); /* @@ -647,9 +652,11 @@ void wiphy_unregister(struct wiphy *wiphy) /* nothing */ cfg80211_unlock_rdev(rdev); - /* If this device got a regulatory hint tell core its - * free to listen now to a new shiny device regulatory hint */ - reg_device_remove(wiphy); + /* + * If this device got a regulatory hint tell core its + * free to listen now to a new shiny device regulatory hint + */ + wiphy_regulatory_deregister(wiphy); cfg80211_rdev_list_generation++; device_del(&rdev->wiphy.dev); @@ -703,7 +710,7 @@ static void wdev_cleanup_work(struct work_struct *work) cfg80211_lock_rdev(rdev); - if (WARN_ON(rdev->scan_req && rdev->scan_req->dev == wdev->netdev)) { + if (WARN_ON(rdev->scan_req && rdev->scan_req->wdev == wdev)) { rdev->scan_req->aborted = true; ___cfg80211_scan_done(rdev, true); } @@ -731,59 +738,14 @@ static struct device_type wiphy_type = { .name = "wlan", }; -static struct ieee80211_channel * -cfg80211_get_any_chan(struct cfg80211_registered_device *rdev) -{ - struct ieee80211_supported_band *sband; - int i; - - for (i = 0; i < IEEE80211_NUM_BANDS; i++) { - sband = rdev->wiphy.bands[i]; - if (sband && sband->n_channels > 0) - return &sband->channels[0]; - } - - return NULL; -} - -static void cfg80211_init_mon_chan(struct cfg80211_registered_device *rdev) -{ - struct ieee80211_channel *chan; - - chan = cfg80211_get_any_chan(rdev); - if (WARN_ON(!chan)) - return; - - mutex_lock(&rdev->devlist_mtx); - WARN_ON(cfg80211_set_monitor_channel(rdev, chan->center_freq, - NL80211_CHAN_NO_HT)); - mutex_unlock(&rdev->devlist_mtx); -} - void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev, enum nl80211_iftype iftype, int num) { - bool has_monitors_only_old = cfg80211_has_monitors_only(rdev); - bool has_monitors_only_new; - ASSERT_RTNL(); rdev->num_running_ifaces += num; if (iftype == NL80211_IFTYPE_MONITOR) rdev->num_running_monitor_ifaces += num; - - has_monitors_only_new = cfg80211_has_monitors_only(rdev); - if (has_monitors_only_new != has_monitors_only_old) { - rdev->ops->set_monitor_enabled(&rdev->wiphy, - has_monitors_only_new); - - if (!has_monitors_only_new) { - rdev->monitor_channel = NULL; - rdev->monitor_channel_type = NL80211_CHAN_NO_HT; - } else { - cfg80211_init_mon_chan(rdev); - } - } } static int cfg80211_netdev_notifier_call(struct notifier_block *nb, @@ -820,7 +782,8 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, spin_lock_init(&wdev->mgmt_registrations_lock); mutex_lock(&rdev->devlist_mtx); - list_add_rcu(&wdev->list, &rdev->netdev_list); + wdev->identifier = ++rdev->wdev_id; + list_add_rcu(&wdev->list, &rdev->wdev_list); rdev->devlist_generation++; /* can only change netns with wiphy */ dev->features |= NETIF_F_NETNS_LOCAL; @@ -905,6 +868,7 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, mutex_unlock(&rdev->devlist_mtx); dev_put(dev); } + cfg80211_update_iface_num(rdev, wdev->iftype, 1); cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); wdev_lock(wdev); @@ -999,7 +963,6 @@ static int cfg80211_netdev_notifier_call(struct notifier_block *nb, mutex_unlock(&rdev->devlist_mtx); if (ret) return notifier_from_errno(ret); - cfg80211_update_iface_num(rdev, wdev->iftype, 1); break; } diff --git a/net/wireless/core.h b/net/wireless/core.h index 377dc39..5206c68 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -47,11 +47,11 @@ struct cfg80211_registered_device { /* wiphy index, internal only */ int wiphy_idx; - /* associate netdev list */ + /* associated wireless interfaces */ struct mutex devlist_mtx; /* protected by devlist_mtx or RCU */ - struct list_head netdev_list; - int devlist_generation; + struct list_head wdev_list; + int devlist_generation, wdev_id; int opencount; /* also protected by devlist_mtx */ wait_queue_head_t dev_wait; @@ -61,9 +61,6 @@ struct cfg80211_registered_device { int num_running_ifaces; int num_running_monitor_ifaces; - struct ieee80211_channel *monitor_channel; - enum nl80211_channel_type monitor_channel_type; - /* BSSes/scanning */ spinlock_t bss_lock; struct list_head bss_list; @@ -372,7 +369,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid); void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev); int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, @@ -463,8 +460,7 @@ cfg80211_can_use_chan(struct cfg80211_registered_device *rdev, } void -cfg80211_get_chan_state(struct cfg80211_registered_device *rdev, - struct wireless_dev *wdev, +cfg80211_get_chan_state(struct wireless_dev *wdev, struct ieee80211_channel **chan, enum cfg80211_chan_mode *chanmode); diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c index d4fece3..1cdb1d5 100644 --- a/net/wireless/mlme.c +++ b/net/wireless/mlme.c @@ -567,29 +567,28 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev, } } -void cfg80211_ready_on_channel(struct net_device *dev, u64 cookie, +void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_remain_on_channel(rdev, dev, cookie, chan, channel_type, + nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type, duration, gfp); } EXPORT_SYMBOL(cfg80211_ready_on_channel); -void cfg80211_remain_on_channel_expired(struct net_device *dev, - u64 cookie, +void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp) { - struct wiphy *wiphy = dev->ieee80211_ptr->wiphy; + struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); - nl80211_send_remain_on_channel_cancel(rdev, dev, cookie, chan, + nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, channel_type, gfp); } EXPORT_SYMBOL(cfg80211_remain_on_channel_expired); @@ -678,8 +677,7 @@ int cfg80211_mlme_register_mgmt(struct wireless_dev *wdev, u32 snd_pid, list_add(&nreg->list, &wdev->mgmt_registrations); if (rdev->ops->mgmt_frame_register) - rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, - frame_type, true); + rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, true); out: spin_unlock_bh(&wdev->mgmt_registrations_lock); @@ -702,7 +700,7 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid) if (rdev->ops->mgmt_frame_register) { u16 frame_type = le16_to_cpu(reg->frame_type); - rdev->ops->mgmt_frame_register(wiphy, wdev->netdev, + rdev->ops->mgmt_frame_register(wiphy, wdev, frame_type, false); } @@ -731,14 +729,14 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev) } int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, - struct net_device *dev, + struct wireless_dev *wdev, struct ieee80211_channel *chan, bool offchan, enum nl80211_channel_type channel_type, bool channel_type_valid, unsigned int wait, const u8 *buf, size_t len, bool no_cck, bool dont_wait_for_ack, u64 *cookie) { - struct wireless_dev *wdev = dev->ieee80211_ptr; + struct net_device *dev = wdev->netdev; const struct ieee80211_mgmt *mgmt; u16 stype; @@ -825,16 +823,15 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev, return -EINVAL; /* Transmit the Action frame as requested by user space */ - return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan, + return rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type, channel_type_valid, wait, buf, len, no_cck, dont_wait_for_ack, cookie); } -bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, +bool cfg80211_rx_mgmt(struct wireless_dev *wdev, int freq, int sig_mbm, const u8 *buf, size_t len, gfp_t gfp) { - struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); struct cfg80211_mgmt_registration *reg; @@ -871,7 +868,7 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, /* found match! */ /* Indicate the received Action frame to user space */ - if (nl80211_send_mgmt(rdev, dev, reg->nlpid, + if (nl80211_send_mgmt(rdev, wdev, reg->nlpid, freq, sig_mbm, buf, len, gfp)) continue; @@ -886,15 +883,14 @@ bool cfg80211_rx_mgmt(struct net_device *dev, int freq, int sig_mbm, } EXPORT_SYMBOL(cfg80211_rx_mgmt); -void cfg80211_mgmt_tx_status(struct net_device *dev, u64 cookie, +void cfg80211_mgmt_tx_status(struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { - struct wireless_dev *wdev = dev->ieee80211_ptr; struct wiphy *wiphy = wdev->wiphy; struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); /* Indicate TX status of the Action frame to user space */ - nl80211_send_mgmt_tx_status(rdev, dev, cookie, buf, len, ack, gfp); + nl80211_send_mgmt_tx_status(rdev, wdev, cookie, buf, len, ack, gfp); } EXPORT_SYMBOL(cfg80211_mgmt_tx_status); @@ -923,6 +919,19 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev, } EXPORT_SYMBOL(cfg80211_cqm_pktloss_notify); +void cfg80211_cqm_txe_notify(struct net_device *dev, + const u8 *peer, u32 num_packets, + u32 rate, u32 intvl, gfp_t gfp) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct wiphy *wiphy = wdev->wiphy; + struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy); + + nl80211_send_cqm_txe_notify(rdev, dev, peer, num_packets, + rate, intvl, gfp); +} +EXPORT_SYMBOL(cfg80211_cqm_txe_notify); + void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid, const u8 *replay_ctr, gfp_t gfp) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 0249cea..97026f3 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -46,28 +46,60 @@ static struct genl_family nl80211_fam = { .post_doit = nl80211_post_doit, }; -/* internal helper: get rdev and dev */ -static int get_rdev_dev_by_ifindex(struct net *netns, struct nlattr **attrs, - struct cfg80211_registered_device **rdev, - struct net_device **dev) +/* returns ERR_PTR values */ +static struct wireless_dev * +__cfg80211_wdev_from_attrs(struct net *netns, struct nlattr **attrs) { - int ifindex; + struct cfg80211_registered_device *rdev; + struct wireless_dev *result = NULL; + bool have_ifidx = attrs[NL80211_ATTR_IFINDEX]; + bool have_wdev_id = attrs[NL80211_ATTR_WDEV]; + u64 wdev_id; + int wiphy_idx = -1; + int ifidx = -1; - if (!attrs[NL80211_ATTR_IFINDEX]) - return -EINVAL; + assert_cfg80211_lock(); - ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); - *dev = dev_get_by_index(netns, ifindex); - if (!*dev) - return -ENODEV; + if (!have_ifidx && !have_wdev_id) + return ERR_PTR(-EINVAL); - *rdev = cfg80211_get_dev_from_ifindex(netns, ifindex); - if (IS_ERR(*rdev)) { - dev_put(*dev); - return PTR_ERR(*rdev); + if (have_ifidx) + ifidx = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); + if (have_wdev_id) { + wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); + wiphy_idx = wdev_id >> 32; } - return 0; + list_for_each_entry(rdev, &cfg80211_rdev_list, list) { + struct wireless_dev *wdev; + + if (wiphy_net(&rdev->wiphy) != netns) + continue; + + if (have_wdev_id && rdev->wiphy_idx != wiphy_idx) + continue; + + mutex_lock(&rdev->devlist_mtx); + list_for_each_entry(wdev, &rdev->wdev_list, list) { + if (have_ifidx && wdev->netdev && + wdev->netdev->ifindex == ifidx) { + result = wdev; + break; + } + if (have_wdev_id && wdev->identifier == (u32)wdev_id) { + result = wdev; + break; + } + } + mutex_unlock(&rdev->devlist_mtx); + + if (result) + break; + } + + if (result) + return result; + return ERR_PTR(-ENODEV); } static struct cfg80211_registered_device * @@ -79,13 +111,40 @@ __cfg80211_rdev_from_attrs(struct net *netns, struct nlattr **attrs) assert_cfg80211_lock(); if (!attrs[NL80211_ATTR_WIPHY] && - !attrs[NL80211_ATTR_IFINDEX]) + !attrs[NL80211_ATTR_IFINDEX] && + !attrs[NL80211_ATTR_WDEV]) return ERR_PTR(-EINVAL); if (attrs[NL80211_ATTR_WIPHY]) rdev = cfg80211_rdev_by_wiphy_idx( nla_get_u32(attrs[NL80211_ATTR_WIPHY])); + if (attrs[NL80211_ATTR_WDEV]) { + u64 wdev_id = nla_get_u64(attrs[NL80211_ATTR_WDEV]); + struct wireless_dev *wdev; + bool found = false; + + tmp = cfg80211_rdev_by_wiphy_idx(wdev_id >> 32); + if (tmp) { + /* make sure wdev exists */ + mutex_lock(&tmp->devlist_mtx); + list_for_each_entry(wdev, &tmp->wdev_list, list) { + if (wdev->identifier != (u32)wdev_id) + continue; + found = true; + break; + } + mutex_unlock(&tmp->devlist_mtx); + + if (!found) + tmp = NULL; + + if (rdev && tmp != rdev) + return ERR_PTR(-EINVAL); + rdev = tmp; + } + } + if (attrs[NL80211_ATTR_IFINDEX]) { int ifindex = nla_get_u32(attrs[NL80211_ATTR_IFINDEX]); netdev = dev_get_by_index(netns, ifindex); @@ -294,6 +353,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = { [NL80211_ATTR_NOACK_MAP] = { .type = NLA_U16 }, [NL80211_ATTR_INACTIVITY_TIMEOUT] = { .type = NLA_U16 }, [NL80211_ATTR_BG_SCAN_PERIOD] = { .type = NLA_U16 }, + [NL80211_ATTR_WDEV] = { .type = NLA_U64 }, + [NL80211_ATTR_USER_REG_HINT_TYPE] = { .type = NLA_U32 }, }; /* policy for the key attributes */ @@ -1668,32 +1729,48 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) return result; } +static inline u64 wdev_id(struct wireless_dev *wdev) +{ + return (u64)wdev->identifier | + ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32); +} static int nl80211_send_iface(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct cfg80211_registered_device *rdev, - struct net_device *dev) + struct wireless_dev *wdev) { + struct net_device *dev = wdev->netdev; void *hdr; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_INTERFACE); if (!hdr) return -1; - if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || - nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || - nla_put_u32(msg, NL80211_ATTR_IFTYPE, - dev->ieee80211_ptr->iftype) || + if (dev && + (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) || + nla_put_string(msg, NL80211_ATTR_IFNAME, dev->name) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dev->dev_addr))) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFTYPE, wdev->iftype) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || nla_put_u32(msg, NL80211_ATTR_GENERATION, rdev->devlist_generation ^ (cfg80211_rdev_list_generation << 2))) goto nla_put_failure; - if (rdev->monitor_channel) { - if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, - rdev->monitor_channel->center_freq) || - nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, - rdev->monitor_channel_type)) + if (rdev->ops->get_channel) { + struct ieee80211_channel *chan; + enum nl80211_channel_type channel_type; + + chan = rdev->ops->get_channel(&rdev->wiphy, wdev, + &channel_type); + if (chan && + (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, + chan->center_freq) || + nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, + channel_type))) goto nla_put_failure; } @@ -1724,14 +1801,14 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback * if_idx = 0; mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { if (if_idx < if_start) { if_idx++; continue; } if (nl80211_send_iface(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, - rdev, wdev->netdev) < 0) { + rdev, wdev) < 0) { mutex_unlock(&rdev->devlist_mtx); goto out; } @@ -1754,14 +1831,14 @@ static int nl80211_get_interface(struct sk_buff *skb, struct genl_info *info) { struct sk_buff *msg; struct cfg80211_registered_device *dev = info->user_ptr[0]; - struct net_device *netdev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); if (!msg) return -ENOMEM; if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, - dev, netdev) < 0) { + dev, wdev) < 0) { nlmsg_free(msg); return -ENOBUFS; } @@ -1901,7 +1978,8 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct vif_params params; - struct net_device *dev; + struct wireless_dev *wdev; + struct sk_buff *msg; int err; enum nl80211_iftype type = NL80211_IFTYPE_UNSPECIFIED; u32 flags; @@ -1928,19 +2006,23 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) return err; } + msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!msg) + return -ENOMEM; + err = parse_monitor_flags(type == NL80211_IFTYPE_MONITOR ? info->attrs[NL80211_ATTR_MNTR_FLAGS] : NULL, &flags); - dev = rdev->ops->add_virtual_intf(&rdev->wiphy, + wdev = rdev->ops->add_virtual_intf(&rdev->wiphy, nla_data(info->attrs[NL80211_ATTR_IFNAME]), type, err ? NULL : &flags, ¶ms); - if (IS_ERR(dev)) - return PTR_ERR(dev); + if (IS_ERR(wdev)) { + nlmsg_free(msg); + return PTR_ERR(wdev); + } if (type == NL80211_IFTYPE_MESH_POINT && info->attrs[NL80211_ATTR_MESH_ID]) { - struct wireless_dev *wdev = dev->ieee80211_ptr; - wdev_lock(wdev); BUILD_BUG_ON(IEEE80211_MAX_SSID_LEN != IEEE80211_MAX_MESH_ID_LEN); @@ -1951,18 +2033,34 @@ static int nl80211_new_interface(struct sk_buff *skb, struct genl_info *info) wdev_unlock(wdev); } - return 0; + if (nl80211_send_iface(msg, info->snd_pid, info->snd_seq, 0, + rdev, wdev) < 0) { + nlmsg_free(msg); + return -ENOBUFS; + } + + return genlmsg_reply(msg, info); } static int nl80211_del_interface(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; if (!rdev->ops->del_virtual_intf) return -EOPNOTSUPP; - return rdev->ops->del_virtual_intf(&rdev->wiphy, dev); + /* + * If we remove a wireless device without a netdev then clear + * user_ptr[1] so that nl80211_post_doit won't dereference it + * to check if it needs to do dev_put(). Otherwise it crashes + * since the wdev has been freed, unlike with a netdev where + * we need the dev_put() for the netdev to really be freed. + */ + if (!wdev->netdev) + info->user_ptr[1] = NULL; + + return rdev->ops->del_virtual_intf(&rdev->wiphy, wdev); } static int nl80211_set_noack_map(struct sk_buff *skb, struct genl_info *info) @@ -2350,7 +2448,7 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev, mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { if (wdev->iftype != NL80211_IFTYPE_AP && wdev->iftype != NL80211_IFTYPE_P2P_GO) continue; @@ -3485,6 +3583,7 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) { int r; char *data = NULL; + enum nl80211_user_reg_hint_type user_reg_hint_type; /* * You should only get this when cfg80211 hasn't yet initialized @@ -3504,7 +3603,21 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) data = nla_data(info->attrs[NL80211_ATTR_REG_ALPHA2]); - r = regulatory_hint_user(data); + if (info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]) + user_reg_hint_type = + nla_get_u32(info->attrs[NL80211_ATTR_USER_REG_HINT_TYPE]); + else + user_reg_hint_type = NL80211_USER_REG_HINT_USER; + + switch (user_reg_hint_type) { + case NL80211_USER_REG_HINT_USER: + case NL80211_USER_REG_HINT_CELL_BASE: + break; + default: + return -EINVAL; + } + + r = regulatory_hint_user(data, user_reg_hint_type); return r; } @@ -3874,6 +3987,11 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info) cfg80211_regdomain->dfs_region))) goto nla_put_failure; + if (reg_last_request_cell_base() && + nla_put_u32(msg, NL80211_ATTR_USER_REG_HINT_TYPE, + NL80211_USER_REG_HINT_CELL_BASE)) + goto nla_put_failure; + nl_reg_rules = nla_nest_start(msg, NL80211_ATTR_REG_RULES); if (!nl_reg_rules) goto nla_put_failure; @@ -4039,7 +4157,7 @@ static int validate_scan_freqs(struct nlattr *freqs) static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct cfg80211_scan_request *request; struct nlattr *attr; struct wiphy *wiphy; @@ -4199,15 +4317,16 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info) request->no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]); - request->dev = dev; + request->wdev = wdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; - err = rdev->ops->scan(&rdev->wiphy, dev, request); + err = rdev->ops->scan(&rdev->wiphy, request); if (!err) { - nl80211_send_scan_start(rdev, dev); - dev_hold(dev); + nl80211_send_scan_start(rdev, wdev); + if (wdev->netdev) + dev_hold(wdev->netdev); } else { out_free: rdev->scan_req = NULL; @@ -5685,7 +5804,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct ieee80211_channel *chan; struct sk_buff *msg; void *hdr; @@ -5733,7 +5852,7 @@ static int nl80211_remain_on_channel(struct sk_buff *skb, goto free_msg; } - err = rdev->ops->remain_on_channel(&rdev->wiphy, dev, chan, + err = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan, channel_type, duration, &cookie); if (err) @@ -5757,7 +5876,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u64 cookie; if (!info->attrs[NL80211_ATTR_COOKIE]) @@ -5768,7 +5887,7 @@ static int nl80211_cancel_remain_on_channel(struct sk_buff *skb, cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, dev, cookie); + return rdev->ops->cancel_remain_on_channel(&rdev->wiphy, wdev, cookie); } static u32 rateset_to_mask(struct ieee80211_supported_band *sband, @@ -5917,7 +6036,7 @@ static int nl80211_set_tx_bitrate_mask(struct sk_buff *skb, static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u16 frame_type = IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ACTION; if (!info->attrs[NL80211_ATTR_FRAME_MATCH]) @@ -5926,21 +6045,24 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_FRAME_TYPE]) frame_type = nla_get_u16(info->attrs[NL80211_ATTR_FRAME_TYPE]); - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } /* not much point in registering if we can't reply */ if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; - return cfg80211_mlme_register_mgmt(dev->ieee80211_ptr, info->snd_pid, - frame_type, + return cfg80211_mlme_register_mgmt(wdev, info->snd_pid, frame_type, nla_data(info->attrs[NL80211_ATTR_FRAME_MATCH]), nla_len(info->attrs[NL80211_ATTR_FRAME_MATCH])); } @@ -5948,7 +6070,7 @@ static int nl80211_register_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; struct ieee80211_channel *chan; enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; bool channel_type_valid = false; @@ -5969,14 +6091,18 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) if (!rdev->ops->mgmt_tx) return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_MESH_POINT: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } if (info->attrs[NL80211_ATTR_DURATION]) { if (!(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX)) @@ -6025,7 +6151,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) } } - err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type, + err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type, channel_type_valid, wait, nla_data(info->attrs[NL80211_ATTR_FRAME]), nla_len(info->attrs[NL80211_ATTR_FRAME]), @@ -6053,7 +6179,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info) static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; - struct net_device *dev = info->user_ptr[1]; + struct wireless_dev *wdev = info->user_ptr[1]; u64 cookie; if (!info->attrs[NL80211_ATTR_COOKIE]) @@ -6062,17 +6188,21 @@ static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *in if (!rdev->ops->mgmt_tx_cancel_wait) return -EOPNOTSUPP; - if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN && - dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) + switch (wdev->iftype) { + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_P2P_CLIENT: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: + case NL80211_IFTYPE_P2P_GO: + break; + default: return -EOPNOTSUPP; + } cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]); - return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie); + return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, wdev, cookie); } static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info) @@ -6158,8 +6288,35 @@ nl80211_attr_cqm_policy[NL80211_ATTR_CQM_MAX + 1] __read_mostly = { [NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U32 }, [NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_RATE] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_PKTS] = { .type = NLA_U32 }, + [NL80211_ATTR_CQM_TXE_INTVL] = { .type = NLA_U32 }, }; +static int nl80211_set_cqm_txe(struct genl_info *info, + u32 rate, u32 pkts, u32 intvl) +{ + struct cfg80211_registered_device *rdev = info->user_ptr[0]; + struct wireless_dev *wdev; + struct net_device *dev = info->user_ptr[1]; + + if ((rate < 0 || rate > 100) || + (intvl < 0 || intvl > NL80211_CQM_TXE_MAX_INTVL)) + return -EINVAL; + + wdev = dev->ieee80211_ptr; + + if (!rdev->ops->set_cqm_txe_config) + return -EOPNOTSUPP; + + if (wdev->iftype != NL80211_IFTYPE_STATION && + wdev->iftype != NL80211_IFTYPE_P2P_CLIENT) + return -EOPNOTSUPP; + + return rdev->ops->set_cqm_txe_config(wdev->wiphy, dev, + rate, pkts, intvl); +} + static int nl80211_set_cqm_rssi(struct genl_info *info, s32 threshold, u32 hysteresis) { @@ -6207,6 +6364,14 @@ static int nl80211_set_cqm(struct sk_buff *skb, struct genl_info *info) threshold = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_THOLD]); hysteresis = nla_get_u32(attrs[NL80211_ATTR_CQM_RSSI_HYST]); err = nl80211_set_cqm_rssi(info, threshold, hysteresis); + } else if (attrs[NL80211_ATTR_CQM_TXE_RATE] && + attrs[NL80211_ATTR_CQM_TXE_PKTS] && + attrs[NL80211_ATTR_CQM_TXE_INTVL]) { + u32 rate, pkts, intvl; + rate = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_RATE]); + pkts = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_PKTS]); + intvl = nla_get_u32(attrs[NL80211_ATTR_CQM_TXE_INTVL]); + err = nl80211_set_cqm_txe(info, rate, pkts, intvl); } else err = -EINVAL; @@ -6363,8 +6528,8 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev = info->user_ptr[0]; struct nlattr *tb[NUM_NL80211_WOWLAN_TRIG]; - struct cfg80211_wowlan no_triggers = {}; struct cfg80211_wowlan new_triggers = {}; + struct cfg80211_wowlan *ntrig; struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; int err, i; bool prev_enabled = rdev->wowlan; @@ -6372,8 +6537,11 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) return -EOPNOTSUPP; - if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) - goto no_triggers; + if (!info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]) { + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = NULL; + goto set_wakeup; + } err = nla_parse(tb, MAX_NL80211_WOWLAN_TRIG, nla_data(info->attrs[NL80211_ATTR_WOWLAN_TRIGGERS]), @@ -6484,22 +6652,15 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) } } - if (memcmp(&new_triggers, &no_triggers, sizeof(new_triggers))) { - struct cfg80211_wowlan *ntrig; - ntrig = kmemdup(&new_triggers, sizeof(new_triggers), - GFP_KERNEL); - if (!ntrig) { - err = -ENOMEM; - goto error; - } - cfg80211_rdev_free_wowlan(rdev); - rdev->wowlan = ntrig; - } else { - no_triggers: - cfg80211_rdev_free_wowlan(rdev); - rdev->wowlan = NULL; + ntrig = kmemdup(&new_triggers, sizeof(new_triggers), GFP_KERNEL); + if (!ntrig) { + err = -ENOMEM; + goto error; } + cfg80211_rdev_free_wowlan(rdev); + rdev->wowlan = ntrig; + set_wakeup: if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan) rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan); @@ -6655,13 +6816,17 @@ static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info) #define NL80211_FLAG_CHECK_NETDEV_UP 0x08 #define NL80211_FLAG_NEED_NETDEV_UP (NL80211_FLAG_NEED_NETDEV |\ NL80211_FLAG_CHECK_NETDEV_UP) +#define NL80211_FLAG_NEED_WDEV 0x10 +/* If a netdev is associated, it must be UP */ +#define NL80211_FLAG_NEED_WDEV_UP (NL80211_FLAG_NEED_WDEV |\ + NL80211_FLAG_CHECK_NETDEV_UP) static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; + struct wireless_dev *wdev; struct net_device *dev; - int err; bool rtnl = ops->internal_flags & NL80211_FLAG_NEED_RTNL; if (rtnl) @@ -6675,24 +6840,51 @@ static int nl80211_pre_doit(struct genl_ops *ops, struct sk_buff *skb, return PTR_ERR(rdev); } info->user_ptr[0] = rdev; - } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { - err = get_rdev_dev_by_ifindex(genl_info_net(info), info->attrs, - &rdev, &dev); - if (err) { + } else if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV || + ops->internal_flags & NL80211_FLAG_NEED_WDEV) { + mutex_lock(&cfg80211_mutex); + wdev = __cfg80211_wdev_from_attrs(genl_info_net(info), + info->attrs); + if (IS_ERR(wdev)) { + mutex_unlock(&cfg80211_mutex); if (rtnl) rtnl_unlock(); - return err; + return PTR_ERR(wdev); } - if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && - !netif_running(dev)) { - cfg80211_unlock_rdev(rdev); - dev_put(dev); - if (rtnl) - rtnl_unlock(); - return -ENETDOWN; + + dev = wdev->netdev; + rdev = wiphy_to_dev(wdev->wiphy); + + if (ops->internal_flags & NL80211_FLAG_NEED_NETDEV) { + if (!dev) { + mutex_unlock(&cfg80211_mutex); + if (rtnl) + rtnl_unlock(); + return -EINVAL; + } + + info->user_ptr[1] = dev; + } else { + info->user_ptr[1] = wdev; } + + if (dev) { + if (ops->internal_flags & NL80211_FLAG_CHECK_NETDEV_UP && + !netif_running(dev)) { + mutex_unlock(&cfg80211_mutex); + if (rtnl) + rtnl_unlock(); + return -ENETDOWN; + } + + dev_hold(dev); + } + + cfg80211_lock_rdev(rdev); + + mutex_unlock(&cfg80211_mutex); + info->user_ptr[0] = rdev; - info->user_ptr[1] = dev; } return 0; @@ -6703,8 +6895,16 @@ static void nl80211_post_doit(struct genl_ops *ops, struct sk_buff *skb, { if (info->user_ptr[0]) cfg80211_unlock_rdev(info->user_ptr[0]); - if (info->user_ptr[1]) - dev_put(info->user_ptr[1]); + if (info->user_ptr[1]) { + if (ops->internal_flags & NL80211_FLAG_NEED_WDEV) { + struct wireless_dev *wdev = info->user_ptr[1]; + + if (wdev->netdev) + dev_put(wdev->netdev); + } else { + dev_put(info->user_ptr[1]); + } + } if (ops->internal_flags & NL80211_FLAG_NEED_RTNL) rtnl_unlock(); } @@ -6731,7 +6931,7 @@ static struct genl_ops nl80211_ops[] = { .dumpit = nl80211_dump_interface, .policy = nl80211_policy, /* can be retrieved by unprivileged users */ - .internal_flags = NL80211_FLAG_NEED_NETDEV, + .internal_flags = NL80211_FLAG_NEED_WDEV, }, { .cmd = NL80211_CMD_SET_INTERFACE, @@ -6754,7 +6954,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_del_interface, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_WDEV | NL80211_FLAG_NEED_RTNL, }, { @@ -6925,7 +7125,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_trigger_scan, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7066,7 +7266,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7074,7 +7274,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_cancel_remain_on_channel, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7090,7 +7290,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_register_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV | + .internal_flags = NL80211_FLAG_NEED_WDEV | NL80211_FLAG_NEED_RTNL, }, { @@ -7098,7 +7298,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7106,7 +7306,7 @@ static struct genl_ops nl80211_ops[] = { .doit = nl80211_tx_mgmt_cancel_wait, .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, - .internal_flags = NL80211_FLAG_NEED_NETDEV_UP | + .internal_flags = NL80211_FLAG_NEED_WDEV_UP | NL80211_FLAG_NEED_RTNL, }, { @@ -7317,7 +7517,7 @@ static int nl80211_add_scan_req(struct sk_buff *msg, static int nl80211_send_scan_msg(struct sk_buff *msg, struct cfg80211_registered_device *rdev, - struct net_device *netdev, + struct wireless_dev *wdev, u32 pid, u32 seq, int flags, u32 cmd) { @@ -7328,7 +7528,9 @@ static int nl80211_send_scan_msg(struct sk_buff *msg, return -1; if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex)) + (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + wdev->netdev->ifindex)) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev))) goto nla_put_failure; /* ignore errors and send incomplete event anyway */ @@ -7365,7 +7567,7 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg, } void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7373,7 +7575,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_TRIGGER_SCAN) < 0) { nlmsg_free(msg); return; @@ -7384,7 +7586,7 @@ void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, } void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7392,7 +7594,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_NEW_SCAN_RESULTS) < 0) { nlmsg_free(msg); return; @@ -7403,7 +7605,7 @@ void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, } void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct net_device *netdev) + struct wireless_dev *wdev) { struct sk_buff *msg; @@ -7411,7 +7613,7 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, if (!msg) return; - if (nl80211_send_scan_msg(msg, rdev, netdev, 0, 0, 0, + if (nl80211_send_scan_msg(msg, rdev, wdev, 0, 0, 0, NL80211_CMD_SCAN_ABORTED) < 0) { nlmsg_free(msg); return; @@ -7934,7 +8136,7 @@ nla_put_failure: static void nl80211_send_remain_on_chan_event( int cmd, struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) @@ -7953,7 +8155,9 @@ static void nl80211_send_remain_on_chan_event( } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (wdev->netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + wdev->netdev->ifindex)) || + nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) || nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie)) @@ -7975,23 +8179,24 @@ static void nl80211_send_remain_on_chan_event( } void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, + rdev, wdev, cookie, chan, channel_type, duration, gfp); } void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, + struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp) { nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, - rdev, netdev, cookie, chan, + rdev, wdev, cookie, chan, channel_type, 0, gfp); } @@ -8105,10 +8310,11 @@ bool nl80211_unexpected_4addr_frame(struct net_device *dev, } int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, + struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp) { + struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; @@ -8123,7 +8329,8 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + netdev->ifindex)) || nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) || (sig_dbm && nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) || @@ -8141,10 +8348,11 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, } void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp) { + struct net_device *netdev = wdev->netdev; struct sk_buff *msg; void *hdr; @@ -8159,7 +8367,8 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, } if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || - nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + (netdev && nla_put_u32(msg, NL80211_ATTR_IFINDEX, + netdev->ifindex)) || nla_put(msg, NL80211_ATTR_FRAME, len, buf) || nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie) || (ack && nla_put_flag(msg, NL80211_ATTR_ACK))) @@ -8343,6 +8552,56 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev, } void +nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp) +{ + struct sk_buff *msg; + struct nlattr *pinfoattr; + void *hdr; + + msg = nlmsg_new(NLMSG_GOODSIZE, gfp); + if (!msg) + return; + + hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_NOTIFY_CQM); + if (!hdr) { + nlmsg_free(msg); + return; + } + + if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) || + nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) || + nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) + goto nla_put_failure; + + pinfoattr = nla_nest_start(msg, NL80211_ATTR_CQM); + if (!pinfoattr) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_PKTS, num_packets)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_RATE, rate)) + goto nla_put_failure; + + if (nla_put_u32(msg, NL80211_ATTR_CQM_TXE_INTVL, intvl)) + goto nla_put_failure; + + nla_nest_end(msg, pinfoattr); + + genlmsg_end(msg, hdr); + + genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0, + nl80211_mlme_mcgrp.id, gfp); + return; + + nla_put_failure: + genlmsg_cancel(msg, hdr); + nlmsg_free(msg); +} + +void nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *peer, u32 num_packets, gfp_t gfp) @@ -8483,7 +8742,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb, rcu_read_lock(); list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) { - list_for_each_entry_rcu(wdev, &rdev->netdev_list, list) + list_for_each_entry_rcu(wdev, &rdev->wdev_list, list) cfg80211_mlme_unregister_socket(wdev, notify->pid); if (rdev->ap_beacons_nlpid == notify->pid) rdev->ap_beacons_nlpid = 0; diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h index 01a1122..9f2616f 100644 --- a/net/wireless/nl80211.h +++ b/net/wireless/nl80211.h @@ -7,11 +7,11 @@ int nl80211_init(void); void nl80211_exit(void); void nl80211_notify_dev_rename(struct cfg80211_registered_device *rdev); void nl80211_send_scan_start(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_scan_done(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev, - struct net_device *netdev); + struct wireless_dev *wdev); void nl80211_send_sched_scan(struct cfg80211_registered_device *rdev, struct net_device *netdev, u32 cmd); void nl80211_send_sched_scan_results(struct cfg80211_registered_device *rdev, @@ -74,13 +74,13 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev, gfp_t gfp); void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev, - struct net_device *netdev, - u64 cookie, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, unsigned int duration, gfp_t gfp); void nl80211_send_remain_on_channel_cancel( - struct cfg80211_registered_device *rdev, struct net_device *netdev, + struct cfg80211_registered_device *rdev, + struct wireless_dev *wdev, u64 cookie, struct ieee80211_channel *chan, enum nl80211_channel_type channel_type, gfp_t gfp); @@ -92,11 +92,11 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev, gfp_t gfp); int nl80211_send_mgmt(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u32 nlpid, + struct wireless_dev *wdev, u32 nlpid, int freq, int sig_dbm, const u8 *buf, size_t len, gfp_t gfp); void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev, - struct net_device *netdev, u64 cookie, + struct wireless_dev *wdev, u64 cookie, const u8 *buf, size_t len, bool ack, gfp_t gfp); @@ -110,6 +110,11 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *peer, u32 num_packets, gfp_t gfp); +void +nl80211_send_cqm_txe_notify(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *peer, + u32 num_packets, u32 rate, u32 intvl, gfp_t gfp); + void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev, struct net_device *netdev, const u8 *bssid, const u8 *replay_ctr, gfp_t gfp); diff --git a/net/wireless/reg.c b/net/wireless/reg.c index b2b3222..2303ee7 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -97,9 +97,16 @@ const struct ieee80211_regdomain *cfg80211_regdomain; * - cfg80211_world_regdom * - cfg80211_regdom * - last_request + * - reg_num_devs_support_basehint */ static DEFINE_MUTEX(reg_mutex); +/* + * Number of devices that registered to the core + * that support cellular base station regulatory hints + */ +static int reg_num_devs_support_basehint; + static inline void assert_reg_lock(void) { lockdep_assert_held(®_mutex); @@ -911,6 +918,61 @@ static void handle_band(struct wiphy *wiphy, handle_channel(wiphy, initiator, band, i); } +static bool reg_request_cell_base(struct regulatory_request *request) +{ + if (request->initiator != NL80211_REGDOM_SET_BY_USER) + return false; + if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE) + return false; + return true; +} + +bool reg_last_request_cell_base(void) +{ + bool val; + assert_cfg80211_lock(); + + mutex_lock(®_mutex); + val = reg_request_cell_base(last_request); + mutex_unlock(®_mutex); + return val; +} + +#ifdef CONFIG_CFG80211_CERTIFICATION_ONUS + +/* Core specific check */ +static int reg_ignore_cell_hint(struct regulatory_request *pending_request) +{ + if (!reg_num_devs_support_basehint) + return -EOPNOTSUPP; + + if (reg_request_cell_base(last_request)) { + if (!regdom_changes(pending_request->alpha2)) + return -EALREADY; + return 0; + } + return 0; +} + +/* Device specific check */ +static bool reg_dev_ignore_cell_hint(struct wiphy *wiphy) +{ + if (!(wiphy->features & NL80211_FEATURE_CELL_BASE_REG_HINTS)) + return true; + return false; +} +#else +static int reg_ignore_cell_hint(struct regulatory_request *pending_request) +{ + return -EOPNOTSUPP; +} +static int reg_dev_ignore_cell_hint(struct wiphy *wiphy) +{ + return true; +} +#endif + + static bool ignore_reg_update(struct wiphy *wiphy, enum nl80211_reg_initiator initiator) { @@ -944,6 +1006,9 @@ static bool ignore_reg_update(struct wiphy *wiphy, return true; } + if (reg_request_cell_base(last_request)) + return reg_dev_ignore_cell_hint(wiphy); + return false; } @@ -1169,14 +1234,6 @@ static void wiphy_update_regulatory(struct wiphy *wiphy, wiphy->reg_notifier(wiphy, last_request); } -void regulatory_update(struct wiphy *wiphy, - enum nl80211_reg_initiator setby) -{ - mutex_lock(®_mutex); - wiphy_update_regulatory(wiphy, setby); - mutex_unlock(®_mutex); -} - static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator) { struct cfg80211_registered_device *rdev; @@ -1307,6 +1364,13 @@ static int ignore_request(struct wiphy *wiphy, return 0; case NL80211_REGDOM_SET_BY_COUNTRY_IE: + if (reg_request_cell_base(last_request)) { + /* Trust a Cell base station over the AP's country IE */ + if (regdom_changes(pending_request->alpha2)) + return -EOPNOTSUPP; + return -EALREADY; + } + last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx); if (unlikely(!is_an_alpha2(pending_request->alpha2))) @@ -1351,6 +1415,12 @@ static int ignore_request(struct wiphy *wiphy, return REG_INTERSECT; case NL80211_REGDOM_SET_BY_USER: + if (reg_request_cell_base(pending_request)) + return reg_ignore_cell_hint(pending_request); + + if (reg_request_cell_base(last_request)) + return -EOPNOTSUPP; + if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) return REG_INTERSECT; /* @@ -1640,7 +1710,8 @@ static int regulatory_hint_core(const char *alpha2) } /* User hints */ -int regulatory_hint_user(const char *alpha2) +int regulatory_hint_user(const char *alpha2, + enum nl80211_user_reg_hint_type user_reg_hint_type) { struct regulatory_request *request; @@ -1654,6 +1725,7 @@ int regulatory_hint_user(const char *alpha2) request->alpha2[0] = alpha2[0]; request->alpha2[1] = alpha2[1]; request->initiator = NL80211_REGDOM_SET_BY_USER; + request->user_reg_hint_type = user_reg_hint_type; queue_regulatory_request(request); @@ -1906,7 +1978,7 @@ static void restore_regulatory_settings(bool reset_user) * settings, user regulatory settings takes precedence. */ if (is_an_alpha2(alpha2)) - regulatory_hint_user(user_alpha2); + regulatory_hint_user(user_alpha2, NL80211_USER_REG_HINT_USER); if (list_empty(&tmp_reg_req_list)) return; @@ -2081,9 +2153,16 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) else { if (is_unknown_alpha2(rd->alpha2)) pr_info("Regulatory domain changed to driver built-in settings (unknown country)\n"); - else - pr_info("Regulatory domain changed to country: %c%c\n", - rd->alpha2[0], rd->alpha2[1]); + else { + if (reg_request_cell_base(last_request)) + pr_info("Regulatory domain changed " + "to country: %c%c by Cell Station\n", + rd->alpha2[0], rd->alpha2[1]); + else + pr_info("Regulatory domain changed " + "to country: %c%c\n", + rd->alpha2[0], rd->alpha2[1]); + } } print_dfs_region(rd->dfs_region); print_rd_rules(rd); @@ -2128,7 +2207,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) * checking if the alpha2 changes if CRDA was already called */ if (!regdom_changes(rd->alpha2)) - return -EINVAL; + return -EALREADY; } /* @@ -2248,6 +2327,9 @@ int set_regdom(const struct ieee80211_regdomain *rd) /* Note that this doesn't update the wiphys, this is done below */ r = __set_regdom(rd); if (r) { + if (r == -EALREADY) + reg_set_request_processed(); + kfree(rd); mutex_unlock(®_mutex); return r; @@ -2290,8 +2372,22 @@ int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env) } #endif /* CONFIG_HOTPLUG */ +void wiphy_regulatory_register(struct wiphy *wiphy) +{ + assert_cfg80211_lock(); + + mutex_lock(®_mutex); + + if (!reg_dev_ignore_cell_hint(wiphy)) + reg_num_devs_support_basehint++; + + wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE); + + mutex_unlock(®_mutex); +} + /* Caller must hold cfg80211_mutex */ -void reg_device_remove(struct wiphy *wiphy) +void wiphy_regulatory_deregister(struct wiphy *wiphy) { struct wiphy *request_wiphy = NULL; @@ -2299,6 +2395,9 @@ void reg_device_remove(struct wiphy *wiphy) mutex_lock(®_mutex); + if (!reg_dev_ignore_cell_hint(wiphy)) + reg_num_devs_support_basehint--; + kfree(wiphy->regd); if (last_request) @@ -2364,7 +2463,8 @@ int __init regulatory_init(void) * as a user hint. */ if (!is_world_regdom(ieee80211_regdom)) - regulatory_hint_user(ieee80211_regdom); + regulatory_hint_user(ieee80211_regdom, + NL80211_USER_REG_HINT_USER); return 0; } diff --git a/net/wireless/reg.h b/net/wireless/reg.h index e2aaaf5..f023c8a 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -22,17 +22,19 @@ bool is_world_regdom(const char *alpha2); bool reg_is_valid_request(const char *alpha2); bool reg_supported_dfs_region(u8 dfs_region); -int regulatory_hint_user(const char *alpha2); +int regulatory_hint_user(const char *alpha2, + enum nl80211_user_reg_hint_type user_reg_hint_type); int reg_device_uevent(struct device *dev, struct kobj_uevent_env *env); -void reg_device_remove(struct wiphy *wiphy); +void wiphy_regulatory_register(struct wiphy *wiphy); +void wiphy_regulatory_deregister(struct wiphy *wiphy); int __init regulatory_init(void); void regulatory_exit(void); int set_regdom(const struct ieee80211_regdomain *rd); -void regulatory_update(struct wiphy *wiphy, enum nl80211_reg_initiator setby); +bool reg_last_request_cell_base(void); /** * regulatory_hint_found_beacon - hints a beacon was found on a channel diff --git a/net/wireless/scan.c b/net/wireless/scan.c index af2b1ca..848523a 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -23,7 +23,7 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) { struct cfg80211_scan_request *request; - struct net_device *dev; + struct wireless_dev *wdev; #ifdef CONFIG_CFG80211_WEXT union iwreq_data wrqu; #endif @@ -35,29 +35,31 @@ void ___cfg80211_scan_done(struct cfg80211_registered_device *rdev, bool leak) if (!request) return; - dev = request->dev; + wdev = request->wdev; /* * This must be before sending the other events! * Otherwise, wpa_supplicant gets completely confused with * wext events. */ - cfg80211_sme_scan_done(dev); + if (wdev->netdev) + cfg80211_sme_scan_done(wdev->netdev); if (request->aborted) - nl80211_send_scan_aborted(rdev, dev); + nl80211_send_scan_aborted(rdev, wdev); else - nl80211_send_scan_done(rdev, dev); + nl80211_send_scan_done(rdev, wdev); #ifdef CONFIG_CFG80211_WEXT - if (!request->aborted) { + if (wdev->netdev && !request->aborted) { memset(&wrqu, 0, sizeof(wrqu)); - wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL); + wireless_send_event(wdev->netdev, SIOCGIWSCAN, &wrqu, NULL); } #endif - dev_put(dev); + if (wdev->netdev) + dev_put(wdev->netdev); rdev->scan_req = NULL; @@ -955,7 +957,7 @@ int cfg80211_wext_siwscan(struct net_device *dev, } creq->wiphy = wiphy; - creq->dev = dev; + creq->wdev = dev->ieee80211_ptr; /* SSIDs come after channels */ creq->ssids = (void *)&creq->channels[n_channels]; creq->n_channels = n_channels; @@ -1024,12 +1026,12 @@ int cfg80211_wext_siwscan(struct net_device *dev, creq->rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1; rdev->scan_req = creq; - err = rdev->ops->scan(wiphy, dev, creq); + err = rdev->ops->scan(wiphy, creq); if (err) { rdev->scan_req = NULL; /* creq will be freed below */ } else { - nl80211_send_scan_start(rdev, dev); + nl80211_send_scan_start(rdev, dev->ieee80211_ptr); /* creq now owned by driver */ creq = NULL; dev_hold(dev); diff --git a/net/wireless/sme.c b/net/wireless/sme.c index f7e937f..6f39cb8 100644 --- a/net/wireless/sme.c +++ b/net/wireless/sme.c @@ -51,7 +51,7 @@ static bool cfg80211_is_all_idle(void) */ list_for_each_entry(rdev, &cfg80211_rdev_list, list) { cfg80211_lock_rdev(rdev); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { wdev_lock(wdev); if (wdev->sme_state != CFG80211_SME_IDLE) is_all_idle = false; @@ -136,15 +136,15 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev) wdev->conn->params.ssid_len); request->ssids[0].ssid_len = wdev->conn->params.ssid_len; - request->dev = wdev->netdev; + request->wdev = wdev; request->wiphy = &rdev->wiphy; rdev->scan_req = request; - err = rdev->ops->scan(wdev->wiphy, wdev->netdev, request); + err = rdev->ops->scan(wdev->wiphy, request); if (!err) { wdev->conn->state = CFG80211_CONN_SCANNING; - nl80211_send_scan_start(rdev, wdev->netdev); + nl80211_send_scan_start(rdev, wdev); dev_hold(wdev->netdev); } else { rdev->scan_req = NULL; @@ -221,7 +221,7 @@ void cfg80211_conn_work(struct work_struct *work) cfg80211_lock_rdev(rdev); mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { wdev_lock(wdev); if (!netif_running(wdev->netdev)) { wdev_unlock(wdev); diff --git a/net/wireless/util.c b/net/wireless/util.c index e31f1db..26f8cd3 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -793,7 +793,7 @@ void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev) mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) + list_for_each_entry(wdev, &rdev->wdev_list, list) cfg80211_process_wdev_events(wdev); mutex_unlock(&rdev->devlist_mtx); @@ -994,7 +994,7 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev, mutex_lock(&rdev->devlist_mtx); - list_for_each_entry(wdev, &rdev->netdev_list, list) { + list_for_each_entry(wdev, &rdev->wdev_list, list) { if (!wdev->beacon_interval) continue; if (wdev->beacon_interval != beacon_int) { @@ -1050,7 +1050,7 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, break; } - list_for_each_entry(wdev_iter, &rdev->netdev_list, list) { + list_for_each_entry(wdev_iter, &rdev->wdev_list, list) { if (wdev_iter == wdev) continue; if (!netif_running(wdev_iter->netdev)) @@ -1059,7 +1059,16 @@ int cfg80211_can_use_iftype_chan(struct cfg80211_registered_device *rdev, if (rdev->wiphy.software_iftypes & BIT(wdev_iter->iftype)) continue; - cfg80211_get_chan_state(rdev, wdev_iter, &ch, &chmode); + /* + * We may be holding the "wdev" mutex, but now need to lock + * wdev_iter. This is OK because once we get here wdev_iter + * is not wdev (tested above), but we need to use the nested + * locking for lockdep. + */ + mutex_lock_nested(&wdev_iter->mtx, 1); + __acquire(wdev_iter->mtx); + cfg80211_get_chan_state(wdev_iter, &ch, &chmode); + wdev_unlock(wdev_iter); switch (chmode) { case CHAN_MODE_UNDEFINED: diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c index 7df42f5..494379e 100644 --- a/net/wireless/wext-compat.c +++ b/net/wireless/wext-compat.c @@ -827,6 +827,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, { struct wireless_dev *wdev = dev->ieee80211_ptr; struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy); + struct ieee80211_channel *chan; + enum nl80211_channel_type channel_type; switch (wdev->iftype) { case NL80211_IFTYPE_STATION: @@ -834,10 +836,13 @@ static int cfg80211_wext_giwfreq(struct net_device *dev, case NL80211_IFTYPE_ADHOC: return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra); case NL80211_IFTYPE_MONITOR: - if (!rdev->monitor_channel) + if (!rdev->ops->get_channel) return -EINVAL; - freq->m = rdev->monitor_channel->center_freq; + chan = rdev->ops->get_channel(wdev->wiphy, wdev, &channel_type); + if (!chan) + return -EINVAL; + freq->m = chan->center_freq; freq->e = 6; return 0; default: |