]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 17 Nov 2011 18:11:43 +0000 (13:11 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 17 Nov 2011 18:11:43 +0000 (13:11 -0500)
Conflicts:
include/net/bluetooth/bluetooth.h

205 files changed:
arch/alpha/include/asm/socket.h
arch/arm/include/asm/socket.h
arch/avr32/include/asm/socket.h
arch/cris/include/asm/socket.h
arch/frv/include/asm/socket.h
arch/h8300/include/asm/socket.h
arch/ia64/include/asm/socket.h
arch/m32r/include/asm/socket.h
arch/m68k/include/asm/socket.h
arch/mips/include/asm/socket.h
arch/mn10300/include/asm/socket.h
arch/parisc/include/asm/socket.h
arch/powerpc/include/asm/socket.h
arch/s390/include/asm/socket.h
arch/sparc/include/asm/socket.h
arch/xtensa/include/asm/socket.h
drivers/bluetooth/ath3k.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bluecard_cs.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btuart_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/dtl1_cs.c
drivers/bluetooth/hci_vhci.c
drivers/net/wireless/Makefile
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/Makefile
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/mci.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/regd.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43/xmit.h
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmchip.h
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/aiutils.h
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/dma.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.h
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_cmn.c
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_int.h
drivers/net/wireless/brcm80211/brcmsmac/phy/phy_n.c
drivers/net/wireless/brcm80211/brcmsmac/pmu.c
drivers/net/wireless/brcm80211/brcmsmac/pub.h
drivers/net/wireless/brcm80211/brcmsmac/rate.h
drivers/net/wireless/brcm80211/brcmsmac/srom.c
drivers/net/wireless/brcm80211/brcmsmac/srom.h
drivers/net/wireless/brcm80211/brcmutil/utils.c
drivers/net/wireless/brcm80211/include/brcmu_utils.h
drivers/net/wireless/brcm80211/include/defs.h
drivers/net/wireless/brcm80211/include/soc.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rx.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-sta.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-cfg.h
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-mac80211.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sv-open.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwmc3200wifi/cfg80211.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n_rxreorder.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/fw.h
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/pcie.c
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sta_rx.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
drivers/net/wireless/wl12xx/scan.c
include/asm-generic/socket.h
include/linux/errqueue.h
include/linux/ieee80211.h
include/linux/nl80211.h
include/linux/skbuff.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/cfg80211.h
include/net/ieee80211_radiotap.h
include/net/mac80211.h
include/net/nfc/nci.h
include/net/nfc/nci_core.h
include/net/sock.h
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/smp.c
net/core/skbuff.c
net/core/sock.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_hwmp.c
net/mac80211/mesh_pathtbl.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/pm.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/mac80211/work.c
net/mac80211/wpa.c
net/nfc/nci/core.c
net/nfc/nci/data.c
net/nfc/nci/lib.c
net/nfc/nci/ntf.c
net/nfc/nci/rsp.c
net/rfkill/core.c
net/socket.c
net/wireless/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/scan.c
net/wireless/wext-compat.c

index 06edfefc337332915833c7141fac17f2b1a60bba..082355f159e67930c284b76d33a4bb7f9a090b3a 100644 (file)
@@ -69,6 +69,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index 90ffd04b8e74fb191a47ab79211cf1e128ad7b87..dec6f9afb3cf949de01bb4928dc9ba1429bc9b59 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index c8d1fae494763c2459279afd824dc576b7471795..247b88c760bef0615b9b470defb29e8b7645bd1d 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* __ASM_AVR32_SOCKET_H */
index 1a4a61909ca8705b3d0f11f186c717ba3b5141f1..e269264df7c4f38b35c8aafa07579a935afd1a23 100644 (file)
@@ -64,6 +64,9 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
 
index a6b26880c1ec2e79e316ff5a0f32bbc7fe09a79e..ce80fdadcce57ad1975c9daab73c823721a21f10 100644 (file)
@@ -62,5 +62,8 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
 
index 04c0f4596eb5b8ae072109677a35069a7c15d4a4..cf1daab6f27efb11007af681ee93fb29f64bb63c 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 51427eaa51ba996031aa40bf6800f35917a430b3..4b03664e3fb50534b27d9429c951f8b78a272210 100644 (file)
@@ -71,4 +71,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_IA64_SOCKET_H */
index 469787c30098aea921ddc988087162749840b3de..e8b8c5bb053c12135328d43fbc00fbe12b7db1b9 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_M32R_SOCKET_H */
index 9bf49c87d954a6c5ecf89cc2779ae8642dbe4f34..d4708ce466e068d6bc8935cc222eb923fc27b1a7 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 9de5190f248743a5c8a3926993ad88e5025d4437..ad5c0a7a02a7e34eaff203cf40d0d4b2f235c795 100644 (file)
@@ -82,6 +82,9 @@ To add: #define SO_REUSEPORT 0x0200   /* Allow local address and port reuse.  */
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #ifdef __KERNEL__
 
 /** sock_type - Socket types
index 4e60c42812880b8e3dcc05ddaf90e1815cfc198c..876356d7852248898968f012c8f70c22ad474e1d 100644 (file)
@@ -62,4 +62,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 225b7d6a1a0af44447521de4b133efa6be591bf8..d28c51b61067edab8da863ef0bd76861e2a0b4ff 100644 (file)
@@ -61,6 +61,9 @@
 
 #define SO_RXQ_OVFL             0x4021
 
+#define SO_WIFI_STATUS         0x4022
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* O_NONBLOCK clashes with the bits used for socket types.  Therefore we
  * have to define SOCK_NONBLOCK to a different value here.
  */
index 866f7606da6803924f17d71f74ac4ed70309f8f3..2fc2af8fbf59b892598844db7a254da4f4251b57 100644 (file)
@@ -69,4 +69,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_POWERPC_SOCKET_H */
index fdff1e995c73d45145ceb56afcf0f26a948636e6..67b5c1b14b51177851efca5e6d86f5a2729e61ea 100644 (file)
@@ -70,4 +70,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _ASM_SOCKET_H */
index 9d3fefcff2f576b277ebc776c3bd7ddcada49272..8af1b64168b3abb17ddcf2711b9de2ca07b5ce58 100644 (file)
@@ -58,6 +58,9 @@
 
 #define SO_RXQ_OVFL             0x0024
 
+#define SO_WIFI_STATUS         0x0025
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 /* Security levels - as per NRL IPv6 - don't actually do anything */
 #define SO_SECURITY_AUTHENTICATION             0x5001
 #define SO_SECURITY_ENCRYPTION_TRANSPORT       0x5002
index cbdf2ffaacff9cdc82afb41be8723a55b141c390..bb06968be227b0337ab7d77dbee537204fa898c4 100644 (file)
@@ -73,4 +73,7 @@
 
 #define SO_RXQ_OVFL             40
 
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS                SO_WIFI_STATUS
+
 #endif /* _XTENSA_SOCKET_H */
index 106beb194f3c8d438e105dab8d12aaecb8716103..1622772f802d9b4c2a94ad48ae62f16e3518a44b 100644 (file)
@@ -30,6 +30,7 @@
 #include <net/bluetooth/bluetooth.h>
 
 #define VERSION "1.0"
+#define ATH3K_FIRMWARE "ath3k-1.fw"
 
 #define ATH3K_DNLOAD                           0x01
 #define ATH3K_GETSTATE                         0x05
@@ -400,9 +401,15 @@ static int ath3k_probe(struct usb_interface *intf,
                return 0;
        }
 
-       if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
-               BT_ERR("Error loading firmware");
-               return -EIO;
+       ret = request_firmware(&firmware, ATH3K_FIRMWARE, &udev->dev);
+       if (ret < 0) {
+               if (ret == -ENOENT)
+                       BT_ERR("Firmware file \"%s\" not found",
+                                                       ATH3K_FIRMWARE);
+               else
+                       BT_ERR("Firmware file \"%s\" request failed (err=%d)",
+                                                       ATH3K_FIRMWARE, ret);
+               return ret;
        }
 
        ret = ath3k_load_firmware(udev, firmware);
@@ -441,4 +448,4 @@ MODULE_AUTHOR("Atheros Communications");
 MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("ath3k-1.fw");
+MODULE_FIRMWARE(ATH3K_FIRMWARE);
index 61b591470a90827280005b50b000907a7e7c2ac2..a936763b8c3d97885baa577daa547b822c30ee79 100644 (file)
@@ -751,9 +751,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
 
        bfusb_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 }
 
index aed1904ea67b54f54d1c033073a6af281f3b0070..c6a0c6103743838fef1dd30157681e9d916115c7 100644 (file)
@@ -844,9 +844,7 @@ static int bluecard_close(bluecard_info_t *info)
        /* Turn FPGA off */
        outb(0x80, iobase + 0x30);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 4fc01949d39981a77b6e9dca90606ab94ae259b8..0c97e5d514b635b0574d3832d6b593263146f56e 100644 (file)
@@ -636,9 +636,7 @@ static int bt3c_close(bt3c_info_t *info)
 
        bt3c_hci_close(hdev);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 526b61807d945dda8a6983758b348fe7ea0bd233..200b3a2877d69c43754d6210bc0ad2feb5be81c4 100644 (file)
@@ -565,9 +565,7 @@ static int btuart_close(btuart_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index f9b726091ad0bba89464bad3a59f363318eba508..2bd87d45f1c2313be3efc5a3728a8fcbe687b0d7 100644 (file)
@@ -100,6 +100,9 @@ static struct usb_device_id btusb_table[] = {
        /* Canyon CN-BTU1 with HID interfaces */
        { USB_DEVICE(0x0c10, 0x0000) },
 
+       /* Broadcom BCM20702A0 */
+       { USB_DEVICE(0x413c, 0x8197) },
+
        { }     /* Terminating entry */
 };
 
@@ -312,7 +315,8 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -397,7 +401,8 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -520,7 +525,8 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
 
        err = usb_submit_urb(urb, mem_flags);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed (%d)",
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -724,6 +730,9 @@ static int btusb_send_frame(struct sk_buff *skb)
                usb_fill_bulk_urb(urb, data->udev, pipe,
                                skb->data, skb->len, btusb_tx_complete, skb);
 
+               if (skb->priority >= HCI_PRIO_MAX - 1)
+                       urb->transfer_flags  = URB_ISO_ASAP;
+
                hdev->stat.acl_tx++;
                break;
 
@@ -767,7 +776,9 @@ skip_waking:
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p submission failed", hdev->name, urb);
+               if (err != -EPERM && err != -ENODEV)
+                       BT_ERR("%s urb %p submission failed (%d)",
+                                               hdev->name, urb, -err);
                kfree(urb->setup_packet);
                usb_unanchor_urb(urb);
        } else {
index 5e4c2de9fc3f778bf71c71c89d9222edce4bcd36..969bb22e493f530977ab1c5258f55067963a6cac 100644 (file)
@@ -551,9 +551,7 @@ static int dtl1_close(dtl1_info_t *info)
 
        spin_unlock_irqrestore(&(info->lock), flags);
 
-       if (hci_unregister_dev(hdev) < 0)
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        return 0;
index 67c180c2c1e0fbf27951862e30a0787deba4d4a0..2e302a11ab5528ccd078f41f9439c1067fd9704f 100644 (file)
@@ -264,10 +264,7 @@ static int vhci_release(struct inode *inode, struct file *file)
        struct vhci_data *data = file->private_data;
        struct hci_dev *hdev = data->hdev;
 
-       if (hci_unregister_dev(hdev) < 0) {
-               BT_ERR("Can't unregister HCI device %s", hdev->name);
-       }
-
+       hci_unregister_dev(hdev);
        hci_free_dev(hdev);
 
        file->private_data = NULL;
index 0a304b060b6c5154393bea75bb3d21537b708027..c1c0678b1fb64a8b6e9b56757b48700f095473fa 100644 (file)
@@ -58,6 +58,6 @@ obj-$(CONFIG_WL12XX_PLATFORM_DATA)    += wl12xx/
 obj-$(CONFIG_IWM)      += iwmc3200wifi/
 
 obj-$(CONFIG_MWIFIEX)  += mwifiex/
-obj-$(CONFIG_BRCMFMAC) += brcm80211/
-obj-$(CONFIG_BRCMUMAC) += brcm80211/
-obj-$(CONFIG_BRCMSMAC) += brcm80211/
+
+obj-$(CONFIG_BRCMFMAC) += brcm80211/
+obj-$(CONFIG_BRCMSMAC) += brcm80211/
index 0f9ee46cfc970eb8b898bf215bb48099165758de..4596c33a7a69c462c297d98219e13e3af3c48f37 100644 (file)
@@ -239,6 +239,7 @@ enum ATH_DEBUG {
        ATH_DBG_BTCOEX          = 0x00002000,
        ATH_DBG_WMI             = 0x00004000,
        ATH_DBG_BSTUCK          = 0x00008000,
+       ATH_DBG_MCI             = 0x00010000,
        ATH_DBG_ANY             = 0xffffffff
 };
 
index f517eb8f7b44b6ba13e07bc02a4de80586ef6444..5ac2bc2ebee6e64fe2013fa72ada50884d3132a0 100644 (file)
@@ -1734,7 +1734,8 @@ static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                          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, u64 *cookie)
+                         const u8 *buf, size_t len, bool no_cck,
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct ath6kl *ar = ath6kl_priv(dev);
        u32 id;
index c1d2366704b5d89ad4dbad2b2a90629e10e6c849..81e0031012caa0c7f8ef7033102abe2ec5348d75 100644 (file)
@@ -1548,7 +1548,8 @@ static int ath6kl_init(struct net_device *dev)
        ar->conf_flags = ATH6KL_CONF_IGNORE_ERP_BARKER |
                         ATH6KL_CONF_ENABLE_11N | ATH6KL_CONF_ENABLE_TX_BURST;
 
-       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM;
+       ar->wdev->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
+                                 WIPHY_FLAG_HAVE_AP_SME;
 
        status = ath6kl_target_config_wlan_params(ar);
        if (!status)
index d9c08c619a3ab045fe7950aff6dc6f50d1f08b49..7b4c074e12fafde174793dbf50f1f6b9574ee2e8 100644 (file)
@@ -25,6 +25,7 @@ config ATH9K
 
 config ATH9K_PCI
        bool "Atheros ath9k PCI/PCIe bus support"
+       default y
        depends on ATH9K && PCI
        ---help---
          This option enables the PCI bus support in ath9k.
index 36ed3c46fec60afe7634092e90208292af0d423a..49d3f25f509d0a4ed3953cab6b77b7ded0bccfd2 100644 (file)
@@ -4,6 +4,7 @@ ath9k-y +=      beacon.o \
                main.o \
                recv.o \
                xmit.o \
+               mci.o \
 
 ath9k-$(CONFIG_ATH9K_RATE_CONTROL) += rc.o
 ath9k-$(CONFIG_ATH9K_PCI) += pci.o
index 3b262ba6b17214e6bba4abc816ab13d716d9ae13..a93bd63ad23bd8834f91fb9af42b76543ec8d666 100644 (file)
@@ -121,10 +121,8 @@ static const struct ar9300_eeprom ar9300_default = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -144,7 +142,7 @@ static const struct ar9300_eeprom ar9300_default = {
         },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -323,10 +321,8 @@ static const struct ar9300_eeprom ar9300_default = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -698,10 +694,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -721,7 +715,7 @@ static const struct ar9300_eeprom ar9300_x113 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -900,10 +894,8 @@ static const struct ar9300_eeprom ar9300_x113 = {
                .spurChans = {FREQ2FBIN(5500, 0), 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0xf,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1276,10 +1268,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1291,20 +1281,20 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .txEndToRxOn = 0x2,
                .txFrameToXpaOn = 0xe,
                .thresh62 = 28,
-               .papdRateMaskHt20 = LE32(0x80c080),
-               .papdRateMaskHt40 = LE32(0x80c080),
+               .papdRateMaskHt20 = LE32(0x0c80c080),
+               .papdRateMaskHt40 = LE32(0x0080c080),
                .futureModal = {
                        0, 0, 0, 0, 0, 0, 0, 0,
                },
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
        },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -1314,7 +1304,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
        },
        .calTarget_freqbin_Cck = {
                FREQ2FBIN(2412, 1),
-               FREQ2FBIN(2484, 1),
+               FREQ2FBIN(2472, 1),
        },
        .calTarget_freqbin_2G = {
                FREQ2FBIN(2412, 1),
@@ -1478,10 +1468,8 @@ static const struct ar9300_eeprom ar9300_h112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1515,7 +1503,7 @@ static const struct ar9300_eeprom ar9300_h112 = {
                FREQ2FBIN(5500, 0),
                FREQ2FBIN(5600, 0),
                FREQ2FBIN(5700, 0),
-               FREQ2FBIN(5825, 0)
+               FREQ2FBIN(5785, 0)
        },
        .calPierData5G = {
                {
@@ -1854,10 +1842,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -1877,7 +1863,7 @@ static const struct ar9300_eeprom ar9300_x112 = {
        },
        .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
@@ -2056,10 +2042,8 @@ static const struct ar9300_eeprom ar9300_x112 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshch check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2431,10 +2415,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                 * if the register is per chain
                 */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {1, 1, 1},/* 3 chain */
-               .db_stage2 = {1, 1, 1}, /* 3 chain  */
-               .db_stage3 = {0, 0, 0},
-               .db_stage4 = {0, 0, 0},
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2454,12 +2436,12 @@ static const struct ar9300_eeprom ar9300_h116 = {
         },
         .base_ext1 = {
                .ant_div_control = 0,
-               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+               .future = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
         },
        .calFreqPier2G = {
                FREQ2FBIN(2412, 1),
                FREQ2FBIN(2437, 1),
-               FREQ2FBIN(2472, 1),
+               FREQ2FBIN(2462, 1),
         },
        /* ar9300_cal_data_per_freq_op_loop 2g */
        .calPierData2G = {
@@ -2633,10 +2615,8 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .spurChans = {0, 0, 0, 0, 0},
                /* noiseFloorThreshCh Check if the register is per chain */
                .noiseFloorThreshCh = {-1, 0, 0},
-               .ob = {3, 3, 3}, /* 3 chain */
-               .db_stage2 = {3, 3, 3}, /* 3 chain */
-               .db_stage3 = {3, 3, 3}, /* doesn't exist for 2G */
-               .db_stage4 = {3, 3, 3},  /* don't exist for 2G */
+               .reserved = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+               .quick_drop = 0,
                .xpaBiasLvl = 0,
                .txFrameToDataStart = 0x0e,
                .txFrameToPaOn = 0x0e,
@@ -2663,7 +2643,7 @@ static const struct ar9300_eeprom ar9300_h116 = {
                .xatten1MarginHigh = {0, 0, 0}
         },
        .calFreqPier5G = {
-               FREQ2FBIN(5180, 0),
+               FREQ2FBIN(5160, 0),
                FREQ2FBIN(5220, 0),
                FREQ2FBIN(5320, 0),
                FREQ2FBIN(5400, 0),
@@ -3023,6 +3003,8 @@ 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;
        }
@@ -3428,25 +3410,14 @@ static u32 ar9003_dump_modal_eeprom(char *buf, u32 len, u32 size,
        PR_EEP("Chain0 NF Threshold", modal_hdr->noiseFloorThreshCh[0]);
        PR_EEP("Chain1 NF Threshold", modal_hdr->noiseFloorThreshCh[1]);
        PR_EEP("Chain2 NF Threshold", modal_hdr->noiseFloorThreshCh[2]);
+       PR_EEP("Quick Drop", modal_hdr->quick_drop);
+       PR_EEP("txEndToXpaOff", modal_hdr->txEndToXpaOff);
        PR_EEP("xPA Bias Level", modal_hdr->xpaBiasLvl);
        PR_EEP("txFrameToDataStart", modal_hdr->txFrameToDataStart);
        PR_EEP("txFrameToPaOn", modal_hdr->txFrameToPaOn);
        PR_EEP("txFrameToXpaOn", modal_hdr->txFrameToXpaOn);
        PR_EEP("txClip", modal_hdr->txClip);
        PR_EEP("ADC Desired size", modal_hdr->adcDesiredSize);
-       PR_EEP("Chain0 ob", modal_hdr->ob[0]);
-       PR_EEP("Chain1 ob", modal_hdr->ob[1]);
-       PR_EEP("Chain2 ob", modal_hdr->ob[2]);
-
-       PR_EEP("Chain0 db_stage2", modal_hdr->db_stage2[0]);
-       PR_EEP("Chain1 db_stage2", modal_hdr->db_stage2[1]);
-       PR_EEP("Chain2 db_stage2", modal_hdr->db_stage2[2]);
-       PR_EEP("Chain0 db_stage3", modal_hdr->db_stage3[0]);
-       PR_EEP("Chain1 db_stage3", modal_hdr->db_stage3[1]);
-       PR_EEP("Chain2 db_stage3", modal_hdr->db_stage3[2]);
-       PR_EEP("Chain0 db_stage4", modal_hdr->db_stage4[0]);
-       PR_EEP("Chain1 db_stage4", modal_hdr->db_stage4[1]);
-       PR_EEP("Chain2 db_stage4", modal_hdr->db_stage4[2]);
 
        return len;
 }
@@ -3503,6 +3474,7 @@ static u32 ath9k_hw_ar9003_dump_eeprom(struct ath_hw *ah, bool dump_base_hdr,
        PR_EEP("Internal regulator", !!(pBase->featureEnable & BIT(4)));
        PR_EEP("Enable Paprd", !!(pBase->featureEnable & BIT(5)));
        PR_EEP("Driver Strength", !!(pBase->miscConfiguration & BIT(0)));
+       PR_EEP("Quick Drop", !!(pBase->miscConfiguration & BIT(1)));
        PR_EEP("Chain mask Reduce", (pBase->miscConfiguration >> 0x3) & 0x1);
        PR_EEP("Write enable Gpio", pBase->eepromWriteEnableGpio);
        PR_EEP("WLAN Disable Gpio", pBase->wlanDisableGpio);
@@ -3965,6 +3937,40 @@ 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);
+       s32 t[3], f[3] = {5180, 5500, 5785};
+
+       if (!quick_drop)
+               return;
+
+       if (freq < 4000)
+               quick_drop = eep->modalHeader2G.quick_drop;
+       else {
+               t[0] = eep->base_ext1.quick_drop_low;
+               t[1] = eep->modalHeader5G.quick_drop;
+               t[2] = eep->base_ext1.quick_drop_high;
+               quick_drop = ar9003_hw_power_interpolate(freq, f, t, 3);
+       }
+       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)
+{
+       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
+       u32 value;
+
+       value = (freq < 4000) ? eep->modalHeader2G.txEndToXpaOff :
+                               eep->modalHeader5G.txEndToXpaOff;
+
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAB_OFF, value);
+       REG_RMW_FIELD(ah, AR_PHY_XPA_TIMING_CTL,
+                     AR_PHY_XPA_TIMING_CTL_TX_END_XPAA_OFF, value);
+}
+
 static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
                                             struct ath9k_channel *chan)
 {
@@ -3972,10 +3978,12 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        ar9003_hw_ant_ctrl_apply(ah, IS_CHAN_2GHZ(chan));
        ar9003_hw_drive_strength_apply(ah);
        ar9003_hw_atten_apply(ah, chan);
+       ar9003_hw_quick_drop_apply(ah, chan->channel);
        if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
                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);
 }
 
 static void ath9k_hw_ar9300_set_addac(struct ath_hw *ah,
@@ -5051,6 +5059,8 @@ static void ath9k_hw_ar9300_set_txpower(struct ath_hw *ah,
                        regulatory->max_power_level = targetPowerValT2[i];
        }
 
+       ath9k_hw_update_regulatory_maxpower(ah);
+
        if (test)
                return;
 
index 6335a867527e13db33598f15efe63df3581909c7..bb223fe82816fdc892327b60e6f473f7c254851e 100644 (file)
@@ -216,10 +216,8 @@ struct ar9300_modal_eep_header {
        u8 spurChans[AR_EEPROM_MODAL_SPURS];
        /* 3  Check if the register is per chain */
        int8_t noiseFloorThreshCh[AR9300_MAX_CHAINS];
-       u8 ob[AR9300_MAX_CHAINS];
-       u8 db_stage2[AR9300_MAX_CHAINS];
-       u8 db_stage3[AR9300_MAX_CHAINS];
-       u8 db_stage4[AR9300_MAX_CHAINS];
+       u8 reserved[11];
+       int8_t quick_drop;
        u8 xpaBiasLvl;
        u8 txFrameToDataStart;
        u8 txFrameToPaOn;
@@ -269,7 +267,9 @@ struct cal_ctl_data_5g {
 
 struct ar9300_BaseExtension_1 {
        u8 ant_div_control;
-       u8 future[13];
+       u8 future[11];
+       int8_t quick_drop_low;
+       int8_t quick_drop_high;
 } __packed;
 
 struct ar9300_BaseExtension_2 {
index 2330e7ede19946a88cacdd7359e52192da45bf01..e41d26939ab8799d66d71b30b0699799aad4eca1 100644 (file)
@@ -199,12 +199,14 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
                        synth_freq = chan->channel;
                }
        } else {
-               range = 10;
+               range = AR_SREV_9462(ah) ? 5 : 10;
                max_spur_cnts = 4;
                synth_freq = chan->channel;
        }
 
        for (i = 0; i < max_spur_cnts; i++) {
+               if (AR_SREV_9462(ah) && (i == 0 || i == 3))
+                       continue;
                negative = 0;
                if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah))
                        cur_bb_spur = FBIN2FREQ(spur_fbin_ptr[i],
index 4114fe752c6b4f85485ef13024350dc6b9d55f8f..497d7461838a95a337abff04a2fae61137abfafd 100644 (file)
 #define AR_PHY_DAG_CTRLCCK_RSSI_THR_S   10
 
 #define AR_PHY_RIFS_INIT_DELAY         0x3ff0000
+#define AR_PHY_AGC_QUICK_DROP       0x03c00000
+#define AR_PHY_AGC_QUICK_DROP_S     22
 #define AR_PHY_AGC_COARSE_LOW       0x00007F80
 #define AR_PHY_AGC_COARSE_LOW_S     7
 #define AR_PHY_AGC_COARSE_HIGH      0x003F8000
index 9c51b395b4ffdb104cce7a5bb1e7176908007d80..259a6f312afba81277e6a8cf4ece24bc315e2925 100644 (file)
@@ -43,16 +43,16 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
        {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
-       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
-       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x00009824, 0x5ac640de, 0x5ac640d0, 0x5ac640d0, 0x5ac640de},
+       {0x00009828, 0x0796be89, 0x0696b081, 0x0696b881, 0x0796be89},
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
        {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
        {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
        {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
-       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
-       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3039605e, 0x33795d5e},
+       {0x00009e10, 0x92c88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x92c84d2e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
        {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
@@ -688,8 +688,8 @@ static const u32 ar9462_2p0_mac_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys3ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
@@ -717,8 +717,8 @@ static const u32 ar9462_2p0_baseband_postamble_emulation[][5] = {
 static const u32 ar9462_2p0_radio_postamble_sys2ant[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000160ac, 0xa4646c08, 0xa4646c08, 0x24645808, 0x24645808},
-       {0x00016140, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
-       {0x00016540, 0x10804008, 0x10804008, 0x90804008, 0x90804008},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804008, 0x50804008},
 };
 
 static const u32 ar9462_common_wo_xlna_rx_gain_table_2p0[][2] = {
@@ -1059,7 +1059,7 @@ static const u32 ar9462_modes_low_ob_db_tx_gain_table_2p0[][5] = {
 
 static const u32 ar9462_2p0_soc_postamble[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
-       {0x00007010, 0x00002233, 0x00002233, 0x00002233, 0x00002233},
+       {0x00007010, 0x00000033, 0x00000033, 0x00000033, 0x00000033},
 };
 
 static const u32 ar9462_2p0_baseband_core[][2] = {
@@ -1257,8 +1257,8 @@ static const u32 ar9462_modes_high_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
@@ -1850,8 +1850,8 @@ static const u32 ar9462_modes_green_ob_db_tx_gain_table_2p0[][5] = {
        {0x0000a540, 0x48025e6c, 0x48025e6c, 0x38001660, 0x38001660},
        {0x0000a544, 0x4e025e8e, 0x4e025e8e, 0x3b001861, 0x3b001861},
        {0x0000a548, 0x53025eb2, 0x53025eb2, 0x3e001a81, 0x3e001a81},
-       {0x0000a54c, 0x59025eb2, 0x59025eb2, 0x42001a83, 0x42001a83},
-       {0x0000a550, 0x5f025ef6, 0x5f025ef6, 0x44001c84, 0x44001c84},
+       {0x0000a54c, 0x59025eb6, 0x59025eb6, 0x42001a83, 0x42001a83},
+       {0x0000a550, 0x5d025ef6, 0x5d025ef6, 0x44001c84, 0x44001c84},
        {0x0000a554, 0x62025f56, 0x62025f56, 0x48001ce3, 0x48001ce3},
        {0x0000a558, 0x66027f56, 0x66027f56, 0x4c001ce5, 0x4c001ce5},
        {0x0000a55c, 0x6a029f56, 0x6a029f56, 0x50001ce9, 0x50001ce9},
index 1c269f50822b32245eaf596ffdc7f3384afb0277..93b45b4b3033a5b7d90b8e42c3cade525c5d2fec 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "debug.h"
 #include "common.h"
+#include "mci.h"
 
 /*
  * Header for the ath9k.ko driver core *only* -- hw code nor any other driver
@@ -252,6 +253,7 @@ struct ath_node {
 #ifdef CONFIG_ATH9K_DEBUGFS
        struct list_head list; /* for sc->nodes */
        struct ieee80211_sta *sta; /* station struct we're part of */
+       struct ieee80211_vif *vif; /* interface with which we're associated */
 #endif
        struct ath_atx_tid tid[WME_NUM_TID];
        struct ath_atx_ac ac[WME_NUM_AC];
@@ -443,7 +445,9 @@ struct ath_btcoex {
        u32 btcoex_no_stomp; /* in usec */
        u32 btcoex_period; /* in usec */
        u32 btscan_no_stomp; /* in usec */
+       u32 duty_cycle;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
+       struct ath_mci_profile mci;
 };
 
 int ath_init_btcoex_timer(struct ath_softc *sc);
index 2741203e803f2dadb4204eefae82dd2896e11649..6fb719d85b3748c2cc0704e5214e767e0076e859 100644 (file)
@@ -709,24 +709,29 @@ static ssize_t read_file_stations(struct file *file, char __user *user_buf,
 
        len += snprintf(buf + len, size - len,
                        "Stations:\n"
-                       " tid: addr sched paused buf_q-empty an ac\n"
+                       " tid: addr sched paused buf_q-empty an ac baw\n"
                        " ac: addr sched tid_q-empty txq\n");
 
        spin_lock(&sc->nodes_lock);
        list_for_each_entry(an, &sc->nodes, list) {
+               unsigned short ma = an->maxampdu;
+               if (ma == 0)
+                       ma = 65535; /* see ath_lookup_rate */
                len += snprintf(buf + len, size - len,
-                               "%pM\n", an->sta->addr);
+                               "iface: %pM  sta: %pM max-ampdu: %hu mpdu-density: %uus\n",
+                               an->vif->addr, an->sta->addr, ma,
+                               (unsigned int)(an->mpdudensity));
                if (len >= size)
                        goto done;
 
                for (q = 0; q < WME_NUM_TID; q++) {
                        struct ath_atx_tid *tid = &(an->tid[q]);
                        len += snprintf(buf + len, size - len,
-                                       " tid: %p %s %s %i %p %p\n",
+                                       " tid: %p %s %s %i %p %p %hu\n",
                                        tid, tid->sched ? "sched" : "idle",
                                        tid->paused ? "paused" : "running",
                                        skb_queue_empty(&tid->buf_q),
-                                       tid->an, tid->ac);
+                                       tid->an, tid->ac, tid->baw_size);
                        if (len >= size)
                                goto done;
                }
index 49abd34be74182712b644e89c1e2f719189b0902..5ff7ab96512036b35ab74beec9f22ebe78917a7c 100644 (file)
@@ -249,7 +249,8 @@ enum eeprom_param {
        EEP_ANT_DIV_CTL1,
        EEP_CHAIN_MASK_REDUCE,
        EEP_ANTENNA_GAIN_2G,
-       EEP_ANTENNA_GAIN_5G
+       EEP_ANTENNA_GAIN_5G,
+       EEP_QUICK_DROP
 };
 
 enum ar5416_rates {
index 655576c8fdab7276a233b8010f33406de9988e40..2c279dcaf4ba8cb8813997c39472bb4ac869dc7d 100644 (file)
@@ -189,8 +189,8 @@ static void ath_btcoex_period_timer(unsigned long data)
        bool is_btscan;
 
        ath9k_ps_wakeup(sc);
-       ath_detect_bt_priority(sc);
-
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+               ath_detect_bt_priority(sc);
        is_btscan = sc->sc_flags & SC_OP_BT_SCAN;
 
        spin_lock_bh(&btcoex->btcoex_lock);
@@ -212,8 +212,9 @@ static void ath_btcoex_period_timer(unsigned long data)
        }
 
        ath9k_ps_restore(sc);
+       timer_period = btcoex->btcoex_period / 1000;
        mod_timer(&btcoex->period_timer, jiffies +
-                                 msecs_to_jiffies(ATH_BTCOEX_DEF_BT_PERIOD));
+                                 msecs_to_jiffies(timer_period));
 }
 
 /*
index 2f91acccb7dbc80499e7988b74ac62521bd06799..662ab7e9a0f0e7e7e31d7f1370e8a724ef7084d6 100644 (file)
@@ -2335,7 +2335,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        ah->enabled_cals |= TX_IQ_ON_AGC_CAL;
        }
        if (AR_SREV_9462(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_RTT;
+               pCap->hw_caps |= ATH9K_HW_CAP_RTT | ATH9K_HW_CAP_MCI;
 
        return 0;
 }
@@ -2583,7 +2583,7 @@ void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
        struct ath9k_channel *chan = ah->curchan;
        struct ieee80211_channel *channel = chan->chan;
 
-       reg->power_limit = min_t(int, limit, MAX_RATE_POWER);
+       reg->power_limit = min_t(u32, limit, MAX_RATE_POWER);
        if (test)
                channel->max_power = MAX_RATE_POWER / 2;
 
index f389b3c93cf3f4431a8af0ec57f14b332212b7e6..33e8f2f9d4256605e539b5be58eabef6fc850315 100644 (file)
@@ -203,6 +203,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_5GHZ                       = BIT(14),
        ATH9K_HW_CAP_APM                        = BIT(15),
        ATH9K_HW_CAP_RTT                        = BIT(16),
+       ATH9K_HW_CAP_MCI                        = BIT(17),
 };
 
 struct ath9k_hw_capabilities {
@@ -419,6 +420,16 @@ enum ath9k_rx_qtype {
        ATH9K_RX_QUEUE_MAX,
 };
 
+enum ath_mci_gpm_coex_profile_type {
+       MCI_GPM_COEX_PROFILE_UNKNOWN,
+       MCI_GPM_COEX_PROFILE_RFCOMM,
+       MCI_GPM_COEX_PROFILE_A2DP,
+       MCI_GPM_COEX_PROFILE_HID,
+       MCI_GPM_COEX_PROFILE_BNEP,
+       MCI_GPM_COEX_PROFILE_VOICE,
+       MCI_GPM_COEX_PROFILE_MAX
+};
+
 struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
index d4c909f8e474d793d71d52af3bd8d34a9c0f9843..e046de94836a2d6c83ccf2338d1e3d5d78ab9fd7 100644 (file)
@@ -424,6 +424,8 @@ static int ath9k_init_btcoex(struct ath_softc *sc)
                txq = sc->tx.txq_map[WME_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               sc->btcoex.duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+               INIT_LIST_HEAD(&sc->btcoex.mci.info);
                break;
        default:
                WARN_ON(1);
@@ -695,6 +697,7 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
 
        hw->wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
+       hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
 
        hw->queues = 4;
        hw->max_rates = 4;
index 93fbe6f4089890df98b98904921879ab97835b98..e43c41cff25b87cc9087f6c0a695fb4f9626b06b 100644 (file)
@@ -630,7 +630,8 @@ set_timer:
        }
 }
 
-static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
+static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
+                           struct ieee80211_vif *vif)
 {
        struct ath_node *an;
        an = (struct ath_node *)sta->drv_priv;
@@ -640,6 +641,7 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
        list_add(&an->list, &sc->nodes);
        spin_unlock(&sc->nodes_lock);
        an->sta = sta;
+       an->vif = vif;
 #endif
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
@@ -1133,8 +1135,9 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        if ((ah->btcoex_hw.scheme != ATH_BTCOEX_CFG_NONE) &&
            !ah->btcoex_hw.enabled) {
-               ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
-                                          AR_STOMP_LOW_WLAN_WGHT);
+               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI))
+                       ath9k_hw_btcoex_set_weight(ah, AR_BT_COEX_WGHT,
+                                                  AR_STOMP_LOW_WLAN_WGHT);
                ath9k_hw_btcoex_enable(ah);
 
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -1237,6 +1240,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
                ath9k_hw_btcoex_disable(ah);
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
                        ath9k_btcoex_timer_pause(sc);
+               ath_mci_flush_profile(&sc->btcoex.mci);
        }
 
        spin_lock_bh(&sc->sc_pcu_lock);
@@ -1798,7 +1802,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
        struct ath_node *an = (struct ath_node *) sta->drv_priv;
        struct ieee80211_key_conf ps_key = { };
 
-       ath_node_attach(sc, sta);
+       ath_node_attach(sc, sta, vif);
 
        if (vif->type != NL80211_IFTYPE_AP &&
            vif->type != NL80211_IFTYPE_AP_VLAN)
diff --git a/drivers/net/wireless/ath/ath9k/mci.c b/drivers/net/wireless/ath/ath9k/mci.c
new file mode 100644 (file)
index 0000000..0fbb141
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications 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 "ath9k.h"
+#include "mci.h"
+
+u8 ath_mci_duty_cycle[] = { 0, 50, 60, 70, 80, 85, 90, 95, 98 };
+
+static struct ath_mci_profile_info*
+ath_mci_find_profile(struct ath_mci_profile *mci,
+                    struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       list_for_each_entry(entry, &mci->info, list) {
+               if (entry->conn_handle == info->conn_handle)
+                       break;
+       }
+       return entry;
+}
+
+static bool ath_mci_add_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       if ((mci->num_sco == ATH_MCI_MAX_SCO_PROFILE) &&
+           (info->type == MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many SCO profile, failed to add new profile\n");
+               return false;
+       }
+
+       if (((NUM_PROF(mci) - mci->num_sco) == ATH_MCI_MAX_ACL_PROFILE) &&
+           (info->type != MCI_GPM_COEX_PROFILE_VOICE)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Too many ACL profile, failed to add new profile\n");
+               return false;
+       }
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (entry)
+               memcpy(entry, info, 10);
+       else {
+               entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+               if (!entry)
+                       return false;
+
+               memcpy(entry, info, 10);
+               INC_PROF(mci, info);
+               list_add_tail(&info->list, &mci->info);
+       }
+       return true;
+}
+
+static void ath_mci_del_profile(struct ath_common *common,
+                               struct ath_mci_profile *mci,
+                               struct ath_mci_profile_info *info)
+{
+       struct ath_mci_profile_info *entry;
+
+       entry = ath_mci_find_profile(mci, info);
+
+       if (!entry) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Profile to be deleted not found\n");
+               return;
+       }
+       DEC_PROF(mci, entry);
+       list_del(&entry->list);
+       kfree(entry);
+}
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci)
+{
+       struct ath_mci_profile_info *info, *tinfo;
+
+       list_for_each_entry_safe(info, tinfo, &mci->info, list) {
+               list_del(&info->list);
+               DEC_PROF(mci, info);
+               kfree(info);
+       }
+       mci->aggr_limit = 0;
+}
+
+static void ath_mci_adjust_aggr_limit(struct ath_btcoex *btcoex)
+{
+       struct ath_mci_profile *mci = &btcoex->mci;
+       u32 wlan_airtime = btcoex->btcoex_period *
+                               (100 - btcoex->duty_cycle) / 100;
+
+       /*
+        * Scale: wlan_airtime is in ms, aggr_limit is in 0.25 ms.
+        * When wlan_airtime is less than 4ms, aggregation limit has to be
+        * adjusted half of wlan_airtime to ensure that the aggregation can fit
+        * without collision with BT traffic.
+        */
+       if ((wlan_airtime <= 4) &&
+           (!mci->aggr_limit || (mci->aggr_limit > (2 * wlan_airtime))))
+               mci->aggr_limit = 2 * wlan_airtime;
+}
+
+static void ath_mci_update_scheme(struct ath_softc *sc)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info *info;
+       u32 num_profile = NUM_PROF(mci);
+
+       if (num_profile == 1) {
+               info = list_first_entry(&mci->info,
+                                       struct ath_mci_profile_info,
+                                       list);
+               if (mci->num_sco && info->T == 12) {
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single SCO, aggregation limit 2 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_BNEP) &&
+                          !info->master) {
+                       btcoex->btcoex_period = 60;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Single slave PAN/FTP, bt period 60 ms\n");
+               } else if ((info->type == MCI_GPM_COEX_PROFILE_HID) &&
+                        (info->T > 0 && info->T < 50) &&
+                        (info->A > 1 || info->W > 1)) {
+                       btcoex->duty_cycle = 30;
+                       mci->aggr_limit = 8;
+                       ath_dbg(common, ATH_DBG_MCI,
+                               "Multiple attempt/timeout single HID "
+                               "aggregation limit 2 ms dutycycle 30%%\n");
+               }
+       } else if ((num_profile == 2) && (mci->num_hid == 2)) {
+               btcoex->duty_cycle = 30;
+               mci->aggr_limit = 8;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Two HIDs aggregation limit 2 ms dutycycle 30%%\n");
+       } else if (num_profile > 3) {
+               mci->aggr_limit = 6;
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Three or more profiles aggregation limit 1.5 ms\n");
+       }
+
+       if (IS_CHAN_2GHZ(sc->sc_ah->curchan)) {
+               if (IS_CHAN_HT(sc->sc_ah->curchan))
+                       ath_mci_adjust_aggr_limit(btcoex);
+               else
+                       btcoex->btcoex_period >>= 1;
+       }
+
+       ath9k_hw_btcoex_disable(sc->sc_ah);
+       ath9k_btcoex_timer_pause(sc);
+
+       if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
+               return;
+
+       btcoex->duty_cycle += (mci->num_bdr ? ATH_MCI_MAX_DUTY_CYCLE : 0);
+       if (btcoex->duty_cycle > ATH_MCI_MAX_DUTY_CYCLE)
+               btcoex->duty_cycle = ATH_MCI_MAX_DUTY_CYCLE;
+
+       btcoex->btcoex_period *= 1000;
+       btcoex->btcoex_no_stomp =  btcoex->btcoex_period *
+                                       (100 - btcoex->duty_cycle) / 100;
+
+       ath9k_hw_btcoex_enable(sc->sc_ah);
+       ath9k_btcoex_timer_resume(sc);
+}
+
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+
+       if (info->start) {
+               if (!ath_mci_add_profile(common, mci, info))
+                       return;
+       } else
+               ath_mci_del_profile(common, mci, info);
+
+       btcoex->btcoex_period = ATH_MCI_DEF_BT_PERIOD;
+       mci->aggr_limit = mci->num_sco ? 6 : 0;
+       if (NUM_PROF(mci)) {
+               btcoex->bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ath_mci_duty_cycle[NUM_PROF(mci)];
+       } else {
+               btcoex->bt_stomp_type = mci->num_mgmt ? ATH_BTCOEX_STOMP_ALL :
+                                                       ATH_BTCOEX_STOMP_LOW;
+               btcoex->duty_cycle = ATH_BTCOEX_DEF_DUTY_CYCLE;
+       }
+
+       ath_mci_update_scheme(sc);
+}
+
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status)
+{
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+       struct ath_mci_profile_info info;
+       int i = 0, old_num_mgmt = mci->num_mgmt;
+
+       /* Link status type are not handled */
+       if (status->is_link) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip link type status update\n");
+               return;
+       }
+
+       memset(&info, 0, sizeof(struct ath_mci_profile_info));
+
+       info.conn_handle = status->conn_handle;
+       if (ath_mci_find_profile(mci, &info)) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Skip non link state update for existing profile %d\n",
+                       status->conn_handle);
+               return;
+       }
+       if (status->conn_handle >= ATH_MCI_MAX_PROFILE) {
+               ath_dbg(common, ATH_DBG_MCI,
+                       "Ignore too many non-link update\n");
+               return;
+       }
+       if (status->is_critical)
+               __set_bit(status->conn_handle, mci->status);
+       else
+               __clear_bit(status->conn_handle, mci->status);
+
+       mci->num_mgmt = 0;
+       do {
+               if (test_bit(i, mci->status))
+                       mci->num_mgmt++;
+       } while (++i < ATH_MCI_MAX_PROFILE);
+
+       if (old_num_mgmt != mci->num_mgmt)
+               ath_mci_update_scheme(sc);
+}
diff --git a/drivers/net/wireless/ath/ath9k/mci.h b/drivers/net/wireless/ath/ath9k/mci.h
new file mode 100644 (file)
index 0000000..9590c61
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef MCI_H
+#define MCI_H
+
+#define ATH_MCI_DEF_BT_PERIOD          40
+#define ATH_MCI_BDR_DUTY_CYCLE         20
+#define ATH_MCI_MAX_DUTY_CYCLE         90
+
+#define ATH_MCI_DEF_AGGR_LIMIT         6 /* in 0.24 ms */
+#define ATH_MCI_MAX_ACL_PROFILE                7
+#define ATH_MCI_MAX_SCO_PROFILE                1
+#define ATH_MCI_MAX_PROFILE            (ATH_MCI_MAX_ACL_PROFILE +\
+                                        ATH_MCI_MAX_SCO_PROFILE)
+
+#define INC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl++;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp++;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr++; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan++;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco++;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define DEC_PROF(_mci, _info) do {              \
+               switch (_info->type) {           \
+               case MCI_GPM_COEX_PROFILE_RFCOMM:\
+                       _mci->num_other_acl--;   \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_A2DP:  \
+                       _mci->num_a2dp--;        \
+                       if (!_info->edr)         \
+                               _mci->num_bdr--; \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_HID:   \
+                       _mci->num_hid--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_BNEP:  \
+                       _mci->num_pan--;         \
+                       break;                   \
+               case MCI_GPM_COEX_PROFILE_VOICE: \
+                       _mci->num_sco--;         \
+                       break;                   \
+               default:                         \
+                       break;                   \
+               }                                \
+       } while (0)
+
+#define NUM_PROF(_mci) (_mci->num_other_acl + _mci->num_a2dp + \
+                        _mci->num_hid + _mci->num_pan + _mci->num_sco)
+
+struct ath_mci_profile_info {
+       u8 type;
+       u8 conn_handle;
+       bool start;
+       bool master;
+       bool edr;
+       u8 voice_type;
+       u16 T;          /* Voice: Tvoice, HID: Tsniff,        in slots */
+       u8 W;           /* Voice: Wvoice, HID: Sniff timeout, in slots */
+       u8 A;           /*                HID: Sniff attempt, in slots */
+       struct list_head list;
+};
+
+struct ath_mci_profile_status {
+       bool is_critical;
+       bool is_link;
+       u8 conn_handle;
+};
+
+struct ath_mci_profile {
+       struct list_head info;
+       DECLARE_BITMAP(status, ATH_MCI_MAX_PROFILE);
+       u16 aggr_limit;
+       u8 num_mgmt;
+       u8 num_sco;
+       u8 num_a2dp;
+       u8 num_hid;
+       u8 num_pan;
+       u8 num_other_acl;
+       u8 num_bdr;
+};
+
+void ath_mci_flush_profile(struct ath_mci_profile *mci);
+void ath_mci_process_profile(struct ath_softc *sc,
+                            struct ath_mci_profile_info *info);
+void ath_mci_process_status(struct ath_softc *sc,
+                           struct ath_mci_profile_status *status);
+#endif
index 03b0a651a591c39e79b331ca3c303cc0f08e6d93..55d077e7135d1549aeed07cb839f84874e4fff96 100644 (file)
@@ -601,6 +601,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
+       struct ath_mci_profile *mci = &sc->btcoex.mci;
        u32 max_4ms_framelen, frmlen;
        u16 aggr_limit, legacy = 0;
        int i;
@@ -645,7 +646,9 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        if (tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE || legacy)
                return 0;
 
-       if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
+       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_MCI) && mci->aggr_limit)
+               aggr_limit = (max_4ms_framelen * mci->aggr_limit) >> 4;
+       else if (sc->sc_flags & SC_OP_BT_PRIORITY_DETECTED)
                aggr_limit = min((max_4ms_framelen * 3) / 8,
                                 (u32)ATH_AMPDU_LIMIT_MAX);
        else
index 85fa9cc73502c8f30b70a8d15da73dd28071fdcf..65ecb5bab25a2a0a0c1e64d5122397238ab1e0ca 100644 (file)
@@ -254,6 +254,8 @@ ath_reg_apply_active_scan_flags(struct wiphy *wiphy,
        int r;
 
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
+       if (!sband)
+               return;
 
        /*
         * If no country IE has been received always enable active scan
index 58ea0e5fabfd495b7c1ffaa6d56ee84d84bd0d17..5f77cbe0b6aaeb5d6e121ad5e37b70a3b8596d62 100644 (file)
@@ -175,6 +175,7 @@ void b43_generate_plcp_hdr(struct b43_plcp_hdr4 *plcp,
        }
 }
 
+/* TODO: verify if needed for SSLPN or LCN  */
 static u16 b43_generate_tx_phy_ctl1(struct b43_wldev *dev, u8 bitrate)
 {
        const struct b43_phy *phy = &dev->phy;
@@ -256,6 +257,9 @@ int b43_generate_txhdr(struct b43_wldev *dev,
        unsigned int plcp_fragment_len;
        u32 mac_ctl = 0;
        u16 phy_ctl = 0;
+       bool fill_phy_ctl1 = (phy->type == B43_PHYTYPE_LP ||
+                             phy->type == B43_PHYTYPE_N ||
+                             phy->type == B43_PHYTYPE_HT);
        u8 extra_ft = 0;
        struct ieee80211_rate *txrate;
        struct ieee80211_tx_rate *rates;
@@ -531,7 +535,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                        extra_ft |= B43_TXH_EFT_RTSFB_CCK;
 
                if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS &&
-                   phy->type == B43_PHYTYPE_N) {
+                   fill_phy_ctl1) {
                        txhdr->phy_ctl1_rts = cpu_to_le16(
                                b43_generate_tx_phy_ctl1(dev, rts_rate));
                        txhdr->phy_ctl1_rts_fb = cpu_to_le16(
@@ -552,7 +556,7 @@ int b43_generate_txhdr(struct b43_wldev *dev,
                break;
        }
 
-       if (phy->type == B43_PHYTYPE_N) {
+       if (fill_phy_ctl1) {
                txhdr->phy_ctl1 =
                        cpu_to_le16(b43_generate_tx_phy_ctl1(dev, rate));
                txhdr->phy_ctl1_fb =
@@ -736,7 +740,14 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
 
        /* Link quality statistics */
        switch (chanstat & B43_RX_CHAN_PHYTYPE) {
+       case B43_PHYTYPE_HT:
+               /* TODO: is max the right choice? */
+               status.signal = max_t(__s8,
+                       max(rxhdr->phy_ht_power0, rxhdr->phy_ht_power1),
+                       rxhdr->phy_ht_power2);
+               break;
        case B43_PHYTYPE_N:
+               /* Broadcom has code for min and avg, but always uses max */
                if (rxhdr->power0 == 16 || rxhdr->power0 == 32)
                        status.signal = max(rxhdr->power1, rxhdr->power2);
                else
index 16c514d54afabb6be6f57c078e631e5a7d4c8647..98d90747836a482fa836f6e30c8fc173e1c935e5 100644 (file)
@@ -249,6 +249,12 @@ struct b43_rxhdr_fw4 {
                } __packed;
        } __packed;
        union {
+               /* HT-PHY */
+               struct {
+                       PAD_BYTES(1);
+                       __s8 phy_ht_power0;
+               } __packed;
+
                /* RSSI for N-PHYs */
                struct {
                        __s8 power2;
@@ -257,7 +263,15 @@ struct b43_rxhdr_fw4 {
 
                __le16 phy_status2;     /* PHY RX Status 2 */
        } __packed;
-       __le16 phy_status3;     /* PHY RX Status 3 */
+       union {
+               /* HT-PHY */
+               struct {
+                       __s8 phy_ht_power1;
+                       __s8 phy_ht_power2;
+               } __packed;
+
+               __le16 phy_status3;     /* PHY RX Status 3 */
+       } __packed;
        union {
                /* Tested with 598.314, 644.1001 and 666.2 */
                struct {
index b44e3094588afcac6abed088a7ba9c7eb5b9775f..d58aa1b0a932de0ed1b095d29c5ece1589492995 100644 (file)
@@ -26,7 +26,8 @@ DHDOFILES = \
        dhd_sdio.o      \
        dhd_linux.o \
        bcmsdh.o \
-       bcmsdh_sdmmc.o
+       bcmsdh_sdmmc.o \
+       sdio_chip.o
 
 obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += $(DHDOFILES)
index d7d3afd5a10fbb52bc14a2b8d1f2a26df121c3e2..cecb5e5f412ba2007938f7fdacddb160756e50e3 100644 (file)
 #define _bcmchip_h_
 
 /* bcm4329 */
-/* SDIO device core, ID 0x829 */
-#define BCM4329_CORE_BUS_BASE          0x18011000
-/* internal memory core, ID 0x80e */
-#define BCM4329_CORE_SOCRAM_BASE       0x18003000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM4329_CORE_ARM_BASE          0x18002000
-#define BCM4329_RAMSIZE                        0x48000
 /* firmware name */
 #define BCM4329_FW_NAME                        "brcm/bcm4329-fullmac-4.bin"
 #define BCM4329_NV_NAME                        "brcm/bcm4329-fullmac-4.txt"
index 4645766b40704c272254928385de8d9e404e69a9..6da519e7578f71a81b5f19d1d7411cb875d04ded 100644 (file)
@@ -87,7 +87,7 @@
 #define TOE_TX_CSUM_OL         0x00000001
 #define TOE_RX_CSUM_OL         0x00000002
 
-#define        BRCMF_BSS_INFO_VERSION  108 /* current ver of brcmf_bss_info struct */
+#define        BRCMF_BSS_INFO_VERSION  108 /* curr ver of brcmf_bss_info_le struct */
 
 /* size of brcmf_scan_params not including variable length array */
 #define BRCMF_SCAN_PARAMS_FIXED_SIZE 64
 
 /* For supporting multiple interfaces */
 #define BRCMF_MAX_IFS  16
-#define BRCMF_DEL_IF   -0xe
-#define BRCMF_BAD_IF   -0xf
 
 #define DOT11_BSSTYPE_ANY                      2
 #define DOT11_MAX_DEFAULT_KEYS 4
@@ -365,7 +363,7 @@ struct brcmf_pkt_filter_enable_le {
  * Applications MUST CHECK ie_offset field and length field to access IEs and
  * next bss_info structure in a vector (in struct brcmf_scan_results)
  */
-struct brcmf_bss_info {
+struct brcmf_bss_info_le {
        __le32 version;         /* version field */
        __le32 length;          /* byte length of data in this record,
                                 * starting at version and including IEs
@@ -466,14 +464,13 @@ struct brcmf_scan_results {
        u32 buflen;
        u32 version;
        u32 count;
-       struct brcmf_bss_info bss_info[1];
+       struct brcmf_bss_info_le bss_info_le[];
 };
 
 struct brcmf_scan_results_le {
        __le32 buflen;
        __le32 version;
        __le32 count;
-       struct brcmf_bss_info bss_info[1];
 };
 
 /* used for association with a specific BSSID and chanspec list */
@@ -493,10 +490,6 @@ struct brcmf_join_params {
        struct brcmf_assoc_params_le params_le;
 };
 
-/* size of brcmf_scan_results not including variable length array */
-#define BRCMF_SCAN_RESULTS_FIXED_SIZE \
-       (sizeof(struct brcmf_scan_results) - sizeof(struct brcmf_bss_info))
-
 /* incremental scan results struct */
 struct brcmf_iscan_results {
        union {
@@ -511,7 +504,7 @@ struct brcmf_iscan_results {
 
 /* size of brcmf_iscan_results not including variable length array */
 #define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
-       (BRCMF_SCAN_RESULTS_FIXED_SIZE + \
+       (sizeof(struct brcmf_scan_results) + \
         offsetof(struct brcmf_iscan_results, results))
 
 struct brcmf_wsec_key {
@@ -734,8 +727,7 @@ extern int brcmf_c_host_event(struct brcmf_info *drvr_priv, int *idx,
 extern void brcmf_c_init(void);
 
 extern int brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx,
-                       struct net_device *ndev, char *name, u8 *mac_addr,
-                       u32 flags, u8 bssidx);
+                       char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx);
 
 /* Send packet to dongle via data channel */
index 891826197f966bd9112c4cf32da8055fe9532682..40928e58b6a615f01463e05a78d2decee9a04ecb 100644 (file)
@@ -488,10 +488,9 @@ brcmf_c_host_event(struct brcmf_info *drvr_priv, int *ifidx, void *pktdata,
 
                if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
                        if (ifevent->action == BRCMF_E_IF_ADD)
-                               brcmf_add_if(drvr_priv, ifevent->ifidx, NULL,
+                               brcmf_add_if(drvr_priv, ifevent->ifidx,
                                             event->ifname,
-                                            pvt_data->eth.h_dest,
-                                            ifevent->flags, ifevent->bssidx);
+                                            pvt_data->eth.h_dest);
                        else
                                brcmf_del_if(drvr_priv, ifevent->ifidx);
                } else {
index 4acbac5a74c6ee41a44981cd886c89172408eb2c..719fd9397eb6f5dc405d8b04783871a50697acb6 100644 (file)
@@ -58,7 +58,6 @@ struct brcmf_if {
        struct net_device *ndev;
        struct net_device_stats stats;
        int idx;                /* iface idx in dongle */
-       int state;              /* interface state */
        u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
 };
 
@@ -80,20 +79,6 @@ struct brcmf_info {
 /* Error bits */
 module_param(brcmf_msg_level, int, 0);
 
-
-static int brcmf_net2idx(struct brcmf_info *drvr_priv, struct net_device *ndev)
-{
-       int i = 0;
-
-       while (i < BRCMF_MAX_IFS) {
-               if (drvr_priv->iflist[i] && drvr_priv->iflist[i]->ndev == ndev)
-                       return i;
-               i++;
-       }
-
-       return BRCMF_BAD_IF;
-}
-
 int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
 {
        int i = BRCMF_MAX_IFS;
@@ -285,14 +270,9 @@ _brcmf_set_mac_address(struct work_struct *work)
 
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        struct sockaddr *sa = (struct sockaddr *)addr;
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return -1;
 
        memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
        schedule_work(&drvr_priv->setmacaddr_work);
@@ -301,13 +281,8 @@ static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 
 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
-
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        schedule_work(&drvr_priv->multicast_work);
 }
@@ -341,9 +316,8 @@ int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 {
        int ret;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -355,9 +329,8 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                return -ENODEV;
        }
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF) {
-               brcmf_dbg(ERROR, "bad ifidx %d\n", ifidx);
+       if (!drvr_priv->iflist[ifp->idx]) {
+               brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
@@ -367,20 +340,20 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
                struct sk_buff *skb2;
 
                brcmf_dbg(INFO, "%s: insufficient headroom\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx));
+                         brcmf_ifname(&drvr_priv->pub, ifp->idx));
                drvr_priv->pub.tx_realloc++;
                skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
                dev_kfree_skb(skb);
                skb = skb2;
                if (skb == NULL) {
                        brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
-                                 brcmf_ifname(&drvr_priv->pub, ifidx));
+                                 brcmf_ifname(&drvr_priv->pub, ifp->idx));
                        ret = -ENOMEM;
                        goto done;
                }
        }
 
-       ret = brcmf_sendpkt(&drvr_priv->pub, ifidx, skb);
+       ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);
 
 done:
        if (ret)
@@ -482,12 +455,10 @@ void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx, struct sk_buff *skb,
                                          skb_mac_header(skb),
                                          &event, &data);
 
-               if (drvr_priv->iflist[ifidx] &&
-                   !drvr_priv->iflist[ifidx]->state)
+               if (drvr_priv->iflist[ifidx]) {
                        ifp = drvr_priv->iflist[ifidx];
-
-               if (ifp->ndev)
                        ifp->ndev->last_rx = jiffies;
+               }
 
                drvr->dstats.rx_bytes += skb->len;
                drvr->rx_packets++;     /* Local count */
@@ -524,19 +495,11 @@ void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       struct brcmf_if *ifp;
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       if (ifidx == BRCMF_BAD_IF)
-               return NULL;
-
-       ifp = drvr_priv->iflist[ifidx];
-
        if (drvr_priv->pub.up)
                /* Use the protocol to get dongle stats */
                brcmf_proto_dstats(&drvr_priv->pub);
@@ -637,8 +600,8 @@ static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
                                    struct ethtool_drvinfo *info)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        sprintf(info->driver, KBUILD_MODNAME);
        sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
@@ -765,14 +728,12 @@ static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
 static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
                                    int cmd)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifidx, cmd);
+       brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
 
-       if (ifidx == BRCMF_BAD_IF)
+       if (!drvr_priv->iflist[ifp->idx])
                return -1;
 
        if (cmd == SIOCETHTOOL)
@@ -788,17 +749,14 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        s32 err = 0;
        int buflen = 0;
        bool is_set_key_cmd;
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
-       int ifidx;
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
 
        memset(&dcmd, 0, sizeof(dcmd));
        dcmd.cmd = cmd;
        dcmd.buf = arg;
        dcmd.len = len;
 
-       ifidx = brcmf_net2idx(drvr_priv, ndev);
-
        if (dcmd.buf != NULL)
                buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
 
@@ -826,7 +784,7 @@ s32 brcmf_exec_dcmd(struct net_device *ndev, u32 cmd, void *arg, u32 len)
        if (is_set_key_cmd)
                brcmf_netdev_wait_pend8021x(ndev);
 
-       err = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, buflen);
+       err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);
 
 done:
        if (err > 0)
@@ -837,7 +795,8 @@ done:
 
 static int brcmf_netdev_stop(struct net_device *ndev)
 {
-       struct brcmf_pub *drvr = *(struct brcmf_pub **) netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_pub *drvr = &ifp->info->pub;
 
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_cfg80211_down(drvr->config);
@@ -853,16 +812,14 @@ static int brcmf_netdev_stop(struct net_device *ndev)
 
 static int brcmf_netdev_open(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)
-                                       netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        u32 toe_ol;
-       int ifidx = brcmf_net2idx(drvr_priv, ndev);
        s32 ret = 0;
 
-       brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
-
-       if (ifidx == 0) {       /* do it only for primary eth0 */
+       brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
+       if (ifp->idx == 0) {    /* do it only for primary eth0 */
                /* try to bring up bus */
                ret = brcmf_bus_start(&drvr_priv->pub);
                if (ret != 0) {
@@ -874,12 +831,12 @@ static int brcmf_netdev_open(struct net_device *ndev)
                memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
 
                /* Get current TOE mode from dongle */
-               if (brcmf_toe_get(drvr_priv, ifidx, &toe_ol) >= 0
+               if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0
                    && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr_priv->iflist[ifidx]->ndev->features |=
+                       drvr_priv->iflist[ifp->idx]->ndev->features |=
                                NETIF_F_IP_CSUM;
                else
-                       drvr_priv->iflist[ifidx]->ndev->features &=
+                       drvr_priv->iflist[ifp->idx]->ndev->features &=
                                ~NETIF_F_IP_CSUM;
        }
        /* Allow transmit calls */
@@ -893,75 +850,62 @@ static int brcmf_netdev_open(struct net_device *ndev)
        return ret;
 }
 
+static const struct net_device_ops brcmf_netdev_ops_pri = {
+       .ndo_open = brcmf_netdev_open,
+       .ndo_stop = brcmf_netdev_stop,
+       .ndo_get_stats = brcmf_netdev_get_stats,
+       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
+       .ndo_start_xmit = brcmf_netdev_start_xmit,
+       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
 int
-brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, struct net_device *ndev,
-            char *name, u8 *mac_addr, u32 flags, u8 bssidx)
+brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)
 {
        struct brcmf_if *ifp;
-       int ret = 0, err = 0;
+       struct net_device *ndev;
 
-       brcmf_dbg(TRACE, "idx %d, handle->%p\n", ifidx, ndev);
+       brcmf_dbg(TRACE, "idx %d\n", ifidx);
 
        ifp = drvr_priv->iflist[ifidx];
-       if (!ifp) {
-               ifp = kmalloc(sizeof(struct brcmf_if), GFP_ATOMIC);
-               if (!ifp)
-                       return -ENOMEM;
+       /*
+        * Delete the existing interface before overwriting it
+        * in case we missed the BRCMF_E_IF_DEL event.
+        */
+       if (ifp) {
+               brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+                         ifp->ndev->name);
+               netif_stop_queue(ifp->ndev);
+               unregister_netdev(ifp->ndev);
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+       }
+
+       /* Allocate netdev, including space for private structure */
+       ndev = alloc_netdev(sizeof(struct brcmf_if), name, ether_setup);
+       if (!ndev) {
+               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
+               return -ENOMEM;
        }
 
-       memset(ifp, 0, sizeof(struct brcmf_if));
+       ifp = netdev_priv(ndev);
+       ifp->ndev = ndev;
        ifp->info = drvr_priv;
        drvr_priv->iflist[ifidx] = ifp;
+       ifp->idx = ifidx;
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
-       if (ndev == NULL) {
-               ifp->state = BRCMF_E_IF_ADD;
-               ifp->idx = ifidx;
-               /*
-                * Delete the existing interface before overwriting it
-                * in case we missed the BRCMF_E_IF_DEL event.
-                */
-               if (ifp->ndev != NULL) {
-                       brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
-                                 ifp->ndev->name);
-                       netif_stop_queue(ifp->ndev);
-                       unregister_netdev(ifp->ndev);
-                       free_netdev(ifp->ndev);
-               }
-
-               /* Allocate netdev, including space for private structure */
-               ifp->ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d",
-                                        ether_setup);
-               if (!ifp->ndev) {
-                       brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-                       ret = -ENOMEM;
-               }
-
-               if (ret == 0) {
-                       memcpy(netdev_priv(ifp->ndev), &drvr_priv,
-                              sizeof(drvr_priv));
-                       err = brcmf_net_attach(&drvr_priv->pub, ifp->idx);
-                       if (err != 0) {
-                               brcmf_dbg(ERROR, "brcmf_net_attach failed, err %d\n",
-                                         err);
-                               ret = -EOPNOTSUPP;
-                       } else {
-                               brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
-                                         current->pid, ifp->ndev->name);
-                               ifp->state = 0;
-                       }
-               }
-
-               if (ret < 0) {
-                       if (ifp->ndev)
-                               free_netdev(ifp->ndev);
+       if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) {
+               brcmf_dbg(ERROR, "brcmf_net_attach failed");
+               free_netdev(ifp->ndev);
+               drvr_priv->iflist[ifidx] = NULL;
+               return -EOPNOTSUPP;
+       }
 
-                       drvr_priv->iflist[ifp->idx] = NULL;
-                       kfree(ifp);
-               }
-       } else
-               ifp->ndev = ndev;
+       brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
+                 current->pid, ifp->ndev->name);
 
        return 0;
 }
@@ -977,47 +921,36 @@ void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
                brcmf_dbg(ERROR, "Null interface\n");
                return;
        }
+       if (ifp->ndev) {
+               if (ifidx == 0) {
+                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
+                               rtnl_lock();
+                               brcmf_netdev_stop(ifp->ndev);
+                               rtnl_unlock();
+                       }
+               } else {
+                       netif_stop_queue(ifp->ndev);
+               }
 
-       ifp->state = BRCMF_E_IF_DEL;
-       ifp->idx = ifidx;
-       if (ifp->ndev != NULL) {
-               netif_stop_queue(ifp->ndev);
                unregister_netdev(ifp->ndev);
-               free_netdev(ifp->ndev);
                drvr_priv->iflist[ifidx] = NULL;
-               kfree(ifp);
+               if (ifidx == 0)
+                       brcmf_cfg80211_detach(drvr_priv->pub.config);
+               free_netdev(ifp->ndev);
        }
 }
 
 struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
 {
        struct brcmf_info *drvr_priv = NULL;
-       struct net_device *ndev;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Allocate netdev, including space for private structure */
-       ndev = alloc_netdev(sizeof(drvr_priv), "wlan%d", ether_setup);
-       if (!ndev) {
-               brcmf_dbg(ERROR, "OOM - alloc_netdev\n");
-               goto fail;
-       }
-
        /* Allocate primary brcmf_info */
        drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
        if (!drvr_priv)
                goto fail;
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
-       if (brcmf_add_if(drvr_priv, 0, ndev, ndev->name, NULL, 0, 0) ==
-           BRCMF_BAD_IF)
-               goto fail;
-
-       ndev->netdev_ops = NULL;
        mutex_init(&drvr_priv->proto_block);
 
        /* Link to info module */
@@ -1033,29 +966,12 @@ struct brcmf_pub *brcmf_attach(struct brcmf_bus *bus, uint bus_hdrlen)
                goto fail;
        }
 
-       /* Attach and link in the cfg80211 */
-       drvr_priv->pub.config =
-                       brcmf_cfg80211_attach(ndev,
-                                             brcmf_bus_get_device(bus),
-                                             &drvr_priv->pub);
-       if (drvr_priv->pub.config == NULL) {
-               brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
-               goto fail;
-       }
-
        INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
        INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
 
-       /*
-        * Save the brcmf_info into the priv
-        */
-       memcpy(netdev_priv(ndev), &drvr_priv, sizeof(drvr_priv));
-
        return &drvr_priv->pub;
 
 fail:
-       if (ndev)
-               free_netdev(ndev);
        if (drvr_priv)
                brcmf_detach(&drvr_priv->pub);
 
@@ -1123,16 +1039,6 @@ int brcmf_bus_start(struct brcmf_pub *drvr)
        return 0;
 }
 
-static struct net_device_ops brcmf_netdev_ops_pri = {
-       .ndo_open = brcmf_netdev_open,
-       .ndo_stop = brcmf_netdev_stop,
-       .ndo_get_stats = brcmf_netdev_get_stats,
-       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
-       .ndo_start_xmit = brcmf_netdev_start_xmit,
-       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
-       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
-};
-
 int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 {
        struct brcmf_info *drvr_priv = drvr->info;
@@ -1169,6 +1075,18 @@ int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
 
        memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
 
+       /* attach to cfg80211 for primary interface */
+       if (!ifidx) {
+               drvr->config =
+                       brcmf_cfg80211_attach(ndev,
+                                             brcmf_bus_get_device(drvr->bus),
+                                             drvr);
+               if (drvr->config == NULL) {
+                       brcmf_dbg(ERROR, "wl_cfg80211_attach failed\n");
+                       goto fail;
+               }
+       }
+
        if (register_netdev(ndev) != 0) {
                brcmf_dbg(ERROR, "couldn't register the net device\n");
                goto fail;
@@ -1210,21 +1128,13 @@ void brcmf_detach(struct brcmf_pub *drvr)
        if (drvr) {
                drvr_priv = drvr->info;
                if (drvr_priv) {
-                       struct brcmf_if *ifp;
                        int i;
 
-                       for (i = 1; i < BRCMF_MAX_IFS; i++)
+                       /* make sure primary interface removed last */
+                       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
                                if (drvr_priv->iflist[i])
                                        brcmf_del_if(drvr_priv, i);
 
-                       ifp = drvr_priv->iflist[0];
-                       if (ifp->ndev->netdev_ops == &brcmf_netdev_ops_pri) {
-                               rtnl_lock();
-                               brcmf_netdev_stop(ifp->ndev);
-                               rtnl_unlock();
-                               unregister_netdev(ifp->ndev);
-                       }
-
                        cancel_work_sync(&drvr_priv->setmacaddr_work);
                        cancel_work_sync(&drvr_priv->multicast_work);
 
@@ -1233,10 +1143,6 @@ void brcmf_detach(struct brcmf_pub *drvr)
                        if (drvr->prot)
                                brcmf_proto_detach(drvr);
 
-                       brcmf_cfg80211_detach(drvr->config);
-
-                       free_netdev(ifp->ndev);
-                       kfree(ifp);
                        kfree(drvr_priv);
                }
        }
@@ -1302,7 +1208,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
 
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
-       struct brcmf_info *drvr_priv = *(struct brcmf_info **)netdev_priv(ndev);
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_info *drvr_priv = ifp->info;
        int timeout = 10 * HZ / 1000;
        int ntimes = MAX_WAIT_FOR_8021X_TX;
        int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
index 313b8bf592d13782df7e3a6905cff60ed0b1be19..22913af26db85156e29418f85bb1e70e99d0a24e 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/semaphore.h>
 #include <linux/firmware.h>
 #include <linux/module.h>
+#include <linux/bcma/bcma.h>
 #include <asm/unaligned.h>
 #include <defs.h>
 #include <brcmu_wifi.h>
@@ -35,6 +36,7 @@
 #include <brcm_hw_ids.h>
 #include <soc.h>
 #include "sdio_host.h"
+#include "sdio_chip.h"
 
 #define DCMD_RESP_TIMEOUT  2000        /* In milli second */
 
@@ -134,33 +136,6 @@ struct rte_console {
 /*   Force no backplane reset */
 #define SBSDIO_DEVCTL_RST_NOBPRESET    0x20
 
-/* SBSDIO_FUNC1_CHIPCLKCSR */
-
-/* Force ALP request to backplane */
-#define SBSDIO_FORCE_ALP               0x01
-/* Force HT request to backplane */
-#define SBSDIO_FORCE_HT                        0x02
-/* Force ILP request to backplane */
-#define SBSDIO_FORCE_ILP               0x04
-/* Make ALP ready (power up xtal) */
-#define SBSDIO_ALP_AVAIL_REQ           0x08
-/* Make HT ready (power up PLL) */
-#define SBSDIO_HT_AVAIL_REQ            0x10
-/* Squelch clock requests from HW */
-#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
-/* Status: ALP is ready */
-#define SBSDIO_ALP_AVAIL               0x40
-/* Status: HT is ready */
-#define SBSDIO_HT_AVAIL                        0x80
-
-#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
-#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
-#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
-#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
-
-#define SBSDIO_CLKAV(regval, alponly) \
-       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
-
 /* direct(mapped) cis space */
 
 /* MAPPED common CIS address */
@@ -335,50 +310,6 @@ struct rte_console {
 /* Flags for SDH calls */
 #define F2SYNC (SDIO_REQ_4BYTE | SDIO_REQ_FIXED)
 
-/* sbimstate */
-#define        SBIM_IBE                0x20000 /* inbanderror */
-#define        SBIM_TO                 0x40000 /* timeout */
-#define        SBIM_BY                 0x01800000      /* busy (sonics >= 2.3) */
-#define        SBIM_RJ                 0x02000000      /* reject (sonics >= 2.3) */
-
-/* sbtmstatelow */
-
-/* reset */
-#define        SBTML_RESET             0x0001
-/* reject field */
-#define        SBTML_REJ_MASK          0x0006
-/* reject */
-#define        SBTML_REJ               0x0002
-/* temporary reject, for error recovery */
-#define        SBTML_TMPREJ            0x0004
-
-/* Shift to locate the SI control flags in sbtml */
-#define        SBTML_SICF_SHIFT        16
-
-/* sbtmstatehigh */
-#define        SBTMH_SERR              0x0001  /* serror */
-#define        SBTMH_INT               0x0002  /* interrupt */
-#define        SBTMH_BUSY              0x0004  /* busy */
-#define        SBTMH_TO                0x0020  /* timeout (sonics >= 2.3) */
-
-/* Shift to locate the SI status flags in sbtmh */
-#define        SBTMH_SISF_SHIFT        16
-
-/* sbidlow */
-#define        SBIDL_INIT              0x80    /* initiator */
-
-/* sbidhigh */
-#define        SBIDH_RC_MASK           0x000f  /* revision code */
-#define        SBIDH_RCE_MASK          0x7000  /* revision code extension field */
-#define        SBIDH_RCE_SHIFT         8
-#define        SBCOREREV(sbidh) \
-       ((((sbidh) & SBIDH_RCE_MASK) >> SBIDH_RCE_SHIFT) | \
-         ((sbidh) & SBIDH_RC_MASK))
-#define        SBIDH_CC_MASK           0x8ff0  /* core code */
-#define        SBIDH_CC_SHIFT          4
-#define        SBIDH_VC_MASK           0xffff0000      /* vendor code */
-#define        SBIDH_VC_SHIFT          16
-
 /*
  * Conversion of 802.1D priority to precedence level
  */
@@ -388,17 +319,6 @@ static uint prio2prec(u32 prio)
               (prio^2) : prio;
 }
 
-/*
- * Core reg address translation.
- * Both macro's returns a 32 bits byte address on the backplane bus.
- */
-#define CORE_CC_REG(base, field) \
-               (base + offsetof(struct chipcregs, field))
-#define CORE_BUS_REG(base, field) \
-               (base + offsetof(struct sdpcmd_regs, field))
-#define CORE_SB(base, field) \
-               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
-
 /* core registers */
 struct sdpcmd_regs {
        u32 corecontrol;                /* 0x00, rev8 */
@@ -524,21 +444,6 @@ struct sdpcm_shared_le {
 
 
 /* misc chip info needed by some of the routines */
-struct chip_info {
-       u32 chip;
-       u32 chiprev;
-       u32 cccorebase;
-       u32 ccrev;
-       u32 cccaps;
-       u32 buscorebase; /* 32 bits backplane bus address */
-       u32 buscorerev;
-       u32 buscoretype;
-       u32 ramcorebase;
-       u32 armcorebase;
-       u32 pmurev;
-       u32 ramsize;
-};
-
 /* Private data for SDIO bus interaction */
 struct brcmf_bus {
        struct brcmf_pub *drvr;
@@ -574,7 +479,7 @@ struct brcmf_bus {
        uint txminmax;
 
        struct sk_buff *glomd;  /* Packet containing glomming descriptor */
-       struct sk_buff *glom;   /* Packet chain for glommed superframe */
+       struct sk_buff_head glom; /* Packet list for glommed superframe */
        uint glomerr;           /* Glom packet read errors */
 
        u8 *rxbuf;              /* Buffer for receiving control packets */
@@ -663,46 +568,6 @@ struct brcmf_bus {
        u32 fw_ptr;
 };
 
-struct sbconfig {
-       u32 PAD[2];
-       u32 sbipsflag;  /* initiator port ocp slave flag */
-       u32 PAD[3];
-       u32 sbtpsflag;  /* target port ocp slave flag */
-       u32 PAD[11];
-       u32 sbtmerrloga;        /* (sonics >= 2.3) */
-       u32 PAD;
-       u32 sbtmerrlog; /* (sonics >= 2.3) */
-       u32 PAD[3];
-       u32 sbadmatch3; /* address match3 */
-       u32 PAD;
-       u32 sbadmatch2; /* address match2 */
-       u32 PAD;
-       u32 sbadmatch1; /* address match1 */
-       u32 PAD[7];
-       u32 sbimstate;  /* initiator agent state */
-       u32 sbintvec;   /* interrupt mask */
-       u32 sbtmstatelow;       /* target state */
-       u32 sbtmstatehigh;      /* target state */
-       u32 sbbwa0;             /* bandwidth allocation table0 */
-       u32 PAD;
-       u32 sbimconfiglow;      /* initiator configuration */
-       u32 sbimconfighigh;     /* initiator configuration */
-       u32 sbadmatch0; /* address match0 */
-       u32 PAD;
-       u32 sbtmconfiglow;      /* target configuration */
-       u32 sbtmconfighigh;     /* target configuration */
-       u32 sbbconfig;  /* broadcast configuration */
-       u32 PAD;
-       u32 sbbstate;   /* broadcast state */
-       u32 PAD[3];
-       u32 sbactcnfg;  /* activate configuration */
-       u32 PAD[3];
-       u32 sbflagst;   /* current sbflags */
-       u32 PAD[3];
-       u32 sbidlow;            /* identification */
-       u32 sbidhigh;   /* identification */
-};
-
 /* clkstate */
 #define CLK_NONE       0
 #define CLK_SDONLY     1
@@ -750,10 +615,12 @@ static bool data_ok(struct brcmf_bus *bus)
 static void
 r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                *regvar = brcmf_sdcard_reg_read(bus->sdiodev,
-                               bus->ci->buscorebase + reg_offset, sizeof(u32));
+                               bus->ci->c_inf[idx].base + reg_offset,
+                               sizeof(u32));
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
        if (*retryvar) {
@@ -768,10 +635,11 @@ r_sdreg32(struct brcmf_bus *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
 static void
 w_sdreg32(struct brcmf_bus *bus, u32 regval, u32 reg_offset, u32 *retryvar)
 {
+       u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
        *retryvar = 0;
        do {
                brcmf_sdcard_reg_write(bus->sdiodev,
-                                      bus->ci->buscorebase + reg_offset,
+                                      bus->ci->c_inf[idx].base + reg_offset,
                                       sizeof(u32), regval);
        } while (brcmf_sdcard_regfail(bus->sdiodev) &&
                 (++(*retryvar) <= retry_limit));
@@ -812,10 +680,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                clkreq =
                    bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
 
-               if ((bus->ci->chip == BCM4329_CHIP_ID)
-                   && (bus->ci->chiprev == 0))
-                       clkreq |= SBSDIO_FORCE_ALP;
-
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                                       SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
                if (err) {
@@ -823,14 +687,6 @@ static int brcmf_sdbrcm_htclk(struct brcmf_bus *bus, bool on, bool pendok)
                        return -EBADE;
                }
 
-               if (pendok && ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                              && (bus->ci->buscorerev == 9))) {
-                       u32 dummy, retries;
-                       r_sdreg32(bus, &dummy,
-                                 offsetof(struct sdpcmd_regs, clockctlstatus),
-                                 &retries);
-               }
-
                /* Check current status */
                clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
                                               SBSDIO_FUNC1_CHIPCLKCSR, &err);
@@ -1034,11 +890,9 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                        SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
 
                /* Isolate the bus */
-               if (bus->ci->chip != BCM4329_CHIP_ID) {
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL,
-                               SBSDIO_DEVCTL_PADS_ISO, NULL);
-               }
+               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
+                       SBSDIO_DEVICE_CTL,
+                       SBSDIO_DEVCTL_PADS_ISO, NULL);
 
                /* Change state */
                bus->sleeping = true;
@@ -1049,13 +903,6 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_bus *bus, bool sleep)
                brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
                        SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
-               /* Force pad isolation off if possible
-                        (in case power never toggled) */
-               if ((bus->ci->buscoretype == PCMCIA_CORE_ID)
-                   && (bus->ci->buscorerev >= 10))
-                       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_DEVICE_CTL, 0, NULL);
-
                /* Make sure the controller has the bus up */
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 
@@ -1222,6 +1069,51 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_bus *bus, bool abort, bool rtx)
                bus->drvr->busstate = BRCMF_BUS_DOWN;
 }
 
+/* copy a buffer into a pkt buffer chain */
+static uint brcmf_sdbrcm_glom_from_buf(struct brcmf_bus *bus, uint len)
+{
+       uint n, ret = 0;
+       struct sk_buff *p;
+       u8 *buf;
+
+       buf = bus->dataptr;
+
+       /* copy the data */
+       skb_queue_walk(&bus->glom, p) {
+               n = min_t(uint, p->len, len);
+               memcpy(p->data, buf, n);
+               buf += n;
+               len -= n;
+               ret += n;
+               if (!len)
+                       break;
+       }
+
+       return ret;
+}
+
+/* return total length of buffer chain */
+static uint brcmf_sdbrcm_glom_len(struct brcmf_bus *bus)
+{
+       struct sk_buff *p;
+       uint total;
+
+       total = 0;
+       skb_queue_walk(&bus->glom, p)
+               total += p->len;
+       return total;
+}
+
+static void brcmf_sdbrcm_free_glom(struct brcmf_bus *bus)
+{
+       struct sk_buff *cur, *next;
+
+       skb_queue_walk_safe(&bus->glom, cur, next) {
+               skb_unlink(cur, &bus->glom);
+               brcmu_pkt_buf_free_skb(cur);
+       }
+}
+
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 {
        u16 dlen, totlen;
@@ -1240,7 +1132,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
        /* If packets, issue read(s) and send up packet chain */
        /* Return sequence numbers consumed? */
 
-       brcmf_dbg(TRACE, "start: glomd %p glom %p\n", bus->glomd, bus->glom);
+       brcmf_dbg(TRACE, "start: glomd %p glom %p\n",
+                 bus->glomd, skb_peek(&bus->glom));
 
        /* If there's a descriptor, generate the packet chain */
        if (bus->glomd) {
@@ -1287,12 +1180,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                          num, sublen);
                                break;
                        }
-                       if (!pfirst) {
-                               pfirst = plast = pnext;
-                       } else {
-                               plast->next = pnext;
-                               plast = pnext;
-                       }
+                       skb_queue_tail(&bus->glom, pnext);
 
                        /* Adhere to start alignment requirements */
                        pkt_align(pnext, sublen, BRCMF_SDALIGN);
@@ -1308,12 +1196,9 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                brcmf_dbg(GLOM, "glomdesc mismatch: nextlen %d glomdesc %d rxseq %d\n",
                                          bus->nextlen, totlen, rxseq);
                        }
-                       bus->glom = pfirst;
                        pfirst = pnext = NULL;
                } else {
-                       if (pfirst)
-                               brcmu_pkt_buf_free_skb(pfirst);
-                       bus->glom = NULL;
+                       brcmf_sdbrcm_free_glom(bus);
                        num = 0;
                }
 
@@ -1325,18 +1210,18 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
        /* Ok -- either we just generated a packet chain,
                 or had one from before */
-       if (bus->glom) {
+       if (!skb_queue_empty(&bus->glom)) {
                if (BRCMF_GLOM_ON()) {
                        brcmf_dbg(GLOM, "try superframe read, packet chain:\n");
-                       for (pnext = bus->glom; pnext; pnext = pnext->next) {
+                       skb_queue_walk(&bus->glom, pnext) {
                                brcmf_dbg(GLOM, "    %p: %p len 0x%04x (%d)\n",
                                          pnext, (u8 *) (pnext->data),
                                          pnext->len, pnext->len);
                        }
                }
 
-               pfirst = bus->glom;
-               dlen = (u16) brcmu_pkttotlen(pfirst);
+               pfirst = skb_peek(&bus->glom);
+               dlen = (u16) brcmf_sdbrcm_glom_len(bus);
 
                /* Do an SDIO read for the superframe.  Configurable iovar to
                 * read directly into the chained packet, or allocate a large
@@ -1354,8 +1239,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                                        SDIO_FUNC_2,
                                        F2SYNC, bus->dataptr, dlen,
                                        NULL);
-                       sublen = (u16) brcmu_pktfrombuf(pfirst, 0, dlen,
-                                               bus->dataptr);
+                       sublen = (u16) brcmf_sdbrcm_glom_from_buf(bus, dlen);
                        if (sublen != dlen) {
                                brcmf_dbg(ERROR, "FAILED TO COPY, dlen %d sublen %d\n",
                                          dlen, sublen);
@@ -1380,9 +1264,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        return 0;
                }
@@ -1503,9 +1386,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
                        } else {
                                bus->glomerr = 0;
                                brcmf_sdbrcm_rxfail(bus, true, false);
-                               brcmu_pkt_buf_free_skb(bus->glom);
                                bus->rxglomfail++;
-                               bus->glom = NULL;
+                               brcmf_sdbrcm_free_glom(bus);
                        }
                        bus->nextlen = 0;
                        return 0;
@@ -1513,7 +1395,6 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_bus *bus, u8 rxseq)
 
                /* Basic SD framing looks ok - process each packet (header) */
                save_pfirst = pfirst;
-               bus->glom = NULL;
                plast = NULL;
 
                for (num = 0; pfirst; rxseq++, pfirst = pnext) {
@@ -1850,10 +1731,10 @@ brcmf_sdbrcm_readframes(struct brcmf_bus *bus, uint maxframes, bool *finished)
             rxseq++, rxleft--) {
 
                /* Handle glomming separately */
-               if (bus->glom || bus->glomd) {
+               if (bus->glomd || !skb_queue_empty(&bus->glom)) {
                        u8 cnt;
                        brcmf_dbg(GLOM, "calling rxglom: glomd %p, glom %p\n",
-                                 bus->glomd, bus->glom);
+                                 bus->glomd, skb_peek(&bus->glom));
                        cnt = brcmf_sdbrcm_rxglom(bus, rxseq);
                        brcmf_dbg(GLOM, "rxglom returned %d\n", cnt);
                        rxseq += cnt - 1;
@@ -3210,135 +3091,11 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_bus *bus)
        return bcmerror;
 }
 
-static void
-brcmf_sdbrcm_chip_disablecore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if (regdata & SBTML_RESET)
-               return;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(corebase, sbtmstatelow), 4);
-       if ((regdata & (SICF_CLOCK_EN << SBTML_SICF_SHIFT)) != 0) {
-               /*
-                * set target reject and spin until busy is clear
-                * (preserve core-specific bits)
-                */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow),
-                                      4, regdata | SBTML_REJ);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(1);
-               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4) &
-                       SBTMH_BUSY), 100000);
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatehigh), 4);
-               if (regdata & SBTMH_BUSY)
-                       brcmf_dbg(ERROR, "ARM core still busy\n");
-
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) |
-                               SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4);
-                       udelay(1);
-                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               SBIM_BY), 100000);
-               }
-
-               /* set reset and reject while enabling the clocks */
-               brcmf_sdcard_reg_write(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4,
-                       (((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-                       SBTML_REJ | SBTML_RESET));
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbtmstatelow), 4);
-               udelay(10);
-
-               /* clear the initiator reject bit */
-               regdata = brcmf_sdcard_reg_read(sdiodev,
-                       CORE_SB(corebase, sbidlow), 4);
-               if (regdata & SBIDL_INIT) {
-                       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4) &
-                               ~SBIM_RJ;
-                       brcmf_sdcard_reg_write(sdiodev,
-                               CORE_SB(corebase, sbimstate), 4,
-                               regdata);
-               }
-       }
-
-       /* leave reset and reject asserted */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SBTML_REJ | SBTML_RESET));
-       udelay(1);
-}
-
-static void
-brcmf_sdbrcm_chip_resetcore(struct brcmf_sdio_dev *sdiodev, u32 corebase)
-{
-       u32 regdata;
-
-       /*
-        * Must do the disable sequence first to work for
-        * arbitrary current core state.
-        */
-       brcmf_sdbrcm_chip_disablecore(sdiodev, corebase);
-
-       /*
-        * Now do the initialization sequence.
-        * set reset while enabling the clock and
-        * forcing them on throughout the core
-        */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               ((SICF_FGC | SICF_CLOCK_EN) << SBTML_SICF_SHIFT) |
-               SBTML_RESET);
-       udelay(1);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbtmstatehigh), 4);
-       if (regdata & SBTMH_SERR)
-               brcmf_sdcard_reg_write(sdiodev,
-                                      CORE_SB(corebase, sbtmstatehigh), 4, 0);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(corebase, sbimstate), 4);
-       if (regdata & (SBIM_IBE | SBIM_TO))
-               brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbimstate), 4,
-                       regdata & ~(SBIM_IBE | SBIM_TO));
-
-       /* clear reset and allow it to propagate throughout the core */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_FGC << SBTML_SICF_SHIFT) |
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-
-       /* leave clock enabled */
-       brcmf_sdcard_reg_write(sdiodev, CORE_SB(corebase, sbtmstatelow), 4,
-               (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-       udelay(1);
-}
-
 static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
 {
        uint retries;
-       u32 regdata;
        int bcmerror = 0;
+       struct chip_info *ci = bus->ci;
 
        /* To enter download state, disable ARM and reset SOCRAM.
         * To exit download state, simply reset ARM (default is RAM boot).
@@ -3346,10 +3103,9 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
        if (enter) {
                bus->alp_only = true;
 
-               brcmf_sdbrcm_chip_disablecore(bus->sdiodev,
-                                             bus->ci->armcorebase);
+               ci->coredisable(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->ramcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM);
 
                /* Clear the top bit of memory */
                if (bus->ramsize) {
@@ -3358,11 +3114,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                                         (u8 *)&zeros, 4);
                }
        } else {
-               regdata = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_SB(bus->ci->ramcorebase, sbtmstatelow), 4);
-               regdata &= (SBTML_RESET | SBTML_REJ_MASK |
-                       (SICF_CLOCK_EN << SBTML_SICF_SHIFT));
-               if ((SICF_CLOCK_EN << SBTML_SICF_SHIFT) != regdata) {
+               if (!ci->iscoreup(bus->sdiodev, ci, BCMA_CORE_INTERNAL_MEM)) {
                        brcmf_dbg(ERROR, "SOCRAM core is down after reset?\n");
                        bcmerror = -EBADE;
                        goto fail;
@@ -3377,7 +3129,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_bus *bus, bool enter)
                w_sdreg32(bus, 0xFFFFFFFF,
                          offsetof(struct sdpcmd_regs, intstatus), &retries);
 
-               brcmf_sdbrcm_chip_resetcore(bus->sdiodev, bus->ci->armcorebase);
+               ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
 
                /* Allow HT Clock now that the ARM is running. */
                bus->alp_only = false;
@@ -3661,11 +3413,7 @@ void brcmf_sdbrcm_bus_stop(struct brcmf_bus *bus)
        /* Clear any held glomming stuff */
        if (bus->glomd)
                brcmu_pkt_buf_free_skb(bus->glomd);
-
-       if (bus->glom)
-               brcmu_pkt_buf_free_skb(bus->glom);
-
-       bus->glom = bus->glomd = NULL;
+       brcmf_sdbrcm_free_glom(bus);
 
        /* Clear rx control and wake any waiters */
        bus->rxlen = 0;
@@ -3950,269 +3698,6 @@ fail:
        return false;
 }
 
-/* SDIO Pad drive strength to select value mappings */
-struct sdiod_drive_str {
-       u8 strength;    /* Pad Drive Strength in mA */
-       u8 sel;         /* Chip-specific select value */
-};
-
-/* SDIO Drive Strength to sel value table for PMU Rev 1 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
-       {
-       4, 0x2}, {
-       2, 0x3}, {
-       1, 0x0}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
-static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
-       {
-       12, 0x7}, {
-       10, 0x6}, {
-       8, 0x5}, {
-       6, 0x4}, {
-       4, 0x2}, {
-       2, 0x1}, {
-       0, 0x0}
-       };
-
-/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
-static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
-       {
-       32, 0x7}, {
-       26, 0x6}, {
-       22, 0x5}, {
-       16, 0x4}, {
-       12, 0x3}, {
-       8, 0x2}, {
-       4, 0x1}, {
-       0, 0x0}
-       };
-
-#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
-
-static char *brcmf_chipname(uint chipid, char *buf, uint len)
-{
-       const char *fmt;
-
-       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
-       snprintf(buf, len, fmt, chipid);
-       return buf;
-}
-
-static void brcmf_sdbrcm_sdiod_drive_strength_init(struct brcmf_bus *bus,
-                                                  u32 drivestrength) {
-       struct sdiod_drive_str *str_tab = NULL;
-       u32 str_mask = 0;
-       u32 str_shift = 0;
-       char chn[8];
-
-       if (!(bus->ci->cccaps & CC_CAP_PMU))
-               return;
-
-       switch (SDIOD_DRVSTR_KEY(bus->ci->chip, bus->ci->pmurev)) {
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
-               str_mask = 0x30000000;
-               str_shift = 28;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
-       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
-               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
-               str_mask = 0x00003800;
-               str_shift = 11;
-               break;
-       default:
-               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
-                         brcmf_chipname(bus->ci->chip, chn, 8),
-                         bus->ci->chiprev, bus->ci->pmurev);
-               break;
-       }
-
-       if (str_tab != NULL) {
-               u32 drivestrength_sel = 0;
-               u32 cc_data_temp;
-               int i;
-
-               for (i = 0; str_tab[i].strength != 0; i++) {
-                       if (drivestrength >= str_tab[i].strength) {
-                               drivestrength_sel = str_tab[i].sel;
-                               break;
-                       }
-               }
-
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, 1);
-               cc_data_temp = brcmf_sdcard_reg_read(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr), 4);
-               cc_data_temp &= ~str_mask;
-               drivestrength_sel <<= str_shift;
-               cc_data_temp |= drivestrength_sel;
-               brcmf_sdcard_reg_write(bus->sdiodev,
-                       CORE_CC_REG(bus->ci->cccorebase, chipcontrol_addr),
-                       4, cc_data_temp);
-
-               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
-                         drivestrength, cc_data_temp);
-       }
-}
-
-static int
-brcmf_sdbrcm_chip_recognition(struct brcmf_sdio_dev *sdiodev,
-                             struct chip_info *ci, u32 regs)
-{
-       u32 regdata;
-
-       /*
-        * Get CC core rev
-        * Chipid is assume to be at offset 0 from regs arg
-        * For different chiptypes or old sdio hosts w/o chipcommon,
-        * other ways of recognition should be added here.
-        */
-       ci->cccorebase = regs;
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                               CORE_CC_REG(ci->cccorebase, chipid), 4);
-       ci->chip = regdata & CID_ID_MASK;
-       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
-
-       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
-
-       /* Address of cores for new chips should be added here */
-       switch (ci->chip) {
-       case BCM4329_CHIP_ID:
-               ci->buscorebase = BCM4329_CORE_BUS_BASE;
-               ci->ramcorebase = BCM4329_CORE_SOCRAM_BASE;
-               ci->armcorebase = BCM4329_CORE_ARM_BASE;
-               ci->ramsize = BCM4329_RAMSIZE;
-               break;
-       default:
-               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
-               return -ENODEV;
-       }
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_SB(ci->cccorebase, sbidhigh), 4);
-       ci->ccrev = SBCOREREV(regdata);
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, pmucapabilities), 4);
-       ci->pmurev = regdata & PCAP_REV_MASK;
-
-       regdata = brcmf_sdcard_reg_read(sdiodev,
-                                       CORE_SB(ci->buscorebase, sbidhigh), 4);
-       ci->buscorerev = SBCOREREV(regdata);
-       ci->buscoretype = (regdata & SBIDH_CC_MASK) >> SBIDH_CC_SHIFT;
-
-       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
-                 ci->ccrev, ci->pmurev, ci->buscorerev, ci->buscoretype);
-
-       /* get chipcommon capabilites */
-       ci->cccaps = brcmf_sdcard_reg_read(sdiodev,
-               CORE_CC_REG(ci->cccorebase, capabilities), 4);
-
-       return 0;
-}
-
-static int
-brcmf_sdbrcm_chip_attach(struct brcmf_bus *bus, u32 regs)
-{
-       struct chip_info *ci;
-       int err;
-       u8 clkval, clkset;
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       /* alloc chip_info_t */
-       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
-       if (NULL == ci)
-               return -ENOMEM;
-
-       /* bus/core/clk setup for register access */
-       /* Try forcing SDIO core to do ALPAvail request only */
-       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
-       if (err) {
-               brcmf_dbg(ERROR, "error writing for HT off\n");
-               goto fail;
-       }
-
-       /* If register supported, wait for ALPAvail and then force ALP */
-       /* This may take up to 15 milliseconds */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       SBSDIO_FUNC1_CHIPCLKCSR, NULL);
-       if ((clkval & ~SBSDIO_AVBITS) == clkset) {
-               SPINWAIT(((clkval =
-                               brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                                               SBSDIO_FUNC1_CHIPCLKCSR,
-                                               NULL)),
-                               !SBSDIO_ALPAV(clkval)),
-                               PMU_MAX_TRANSITION_DLY);
-               if (!SBSDIO_ALPAV(clkval)) {
-                       brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
-                                 clkval);
-                       err = -EBUSY;
-                       goto fail;
-               }
-               clkset = SBSDIO_FORCE_HW_CLKREQ_OFF |
-                               SBSDIO_FORCE_ALP;
-               brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                               SBSDIO_FUNC1_CHIPCLKCSR,
-                               clkset, &err);
-               udelay(65);
-       } else {
-               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
-                         clkset, clkval);
-               err = -EACCES;
-               goto fail;
-       }
-
-       /* Also, disable the extra SDIO pull-ups */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
-
-       err = brcmf_sdbrcm_chip_recognition(bus->sdiodev, ci, regs);
-       if (err)
-               goto fail;
-
-       /*
-        * Make sure any on-chip ARM is off (in case strapping is wrong),
-        * or downloaded code was already running.
-        */
-       brcmf_sdbrcm_chip_disablecore(bus->sdiodev, ci->armcorebase);
-
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopullup), 4, 0);
-       brcmf_sdcard_reg_write(bus->sdiodev,
-               CORE_CC_REG(ci->cccorebase, gpiopulldown), 4, 0);
-
-       /* Disable F2 to clear any intermediate frame state on the dongle */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
-               SDIO_FUNC_ENABLE_1, NULL);
-
-       /* WAR: cmd52 backplane read so core HW will drop ALPReq */
-       clkval = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
-                       0, NULL);
-
-       /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
-                              SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
-       bus->ci = ci;
-       return 0;
-fail:
-       bus->ci = NULL;
-       kfree(ci);
-       return err;
-}
-
 static bool
 brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 {
@@ -4220,6 +3705,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        int err = 0;
        int reg_addr;
        u32 reg_val;
+       u8 idx;
 
        bus->alp_only = true;
 
@@ -4234,7 +3720,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
 #endif                         /* BCMDBG */
 
        /*
-        * Force PLL off until brcmf_sdbrcm_chip_attach()
+        * Force PLL off until brcmf_sdio_chip_attach()
         * programs PLL control regs
         */
 
@@ -4252,8 +3738,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       if (brcmf_sdbrcm_chip_attach(bus, regsva)) {
-               brcmf_dbg(ERROR, "brcmf_sdbrcm_chip_attach failed!\n");
+       if (brcmf_sdio_chip_attach(bus->sdiodev, &bus->ci, regsva)) {
+               brcmf_dbg(ERROR, "brcmf_sdio_chip_attach failed!\n");
                goto fail;
        }
 
@@ -4262,11 +3748,10 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
                goto fail;
        }
 
-       brcmf_sdbrcm_sdiod_drive_strength_init(bus, SDIO_DRIVE_STRENGTH);
+       brcmf_sdio_chip_drivestrengthinit(bus->sdiodev, bus->ci,
+                                         SDIO_DRIVE_STRENGTH);
 
-       /* Get info on the ARM and SOCRAM cores... */
-       brcmf_sdcard_reg_read(bus->sdiodev,
-                 CORE_SB(bus->ci->armcorebase, sbidhigh), 4);
+       /* Get info on the SOCRAM cores... */
        bus->ramsize = bus->ci->ramsize;
        if (!(bus->ramsize)) {
                brcmf_dbg(ERROR, "failed to find SOCRAM memory!\n");
@@ -4274,7 +3759,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_bus *bus, u32 regsva)
        }
 
        /* Set core control so an SDIO reset does a backplane reset */
-       reg_addr = bus->ci->buscorebase +
+       idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
+       reg_addr = bus->ci->c_inf[idx].base +
                   offsetof(struct sdpcmd_regs, corecontrol);
        reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
        brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
@@ -4364,15 +3850,6 @@ brcmf_sdbrcm_watchdog(unsigned long data)
        }
 }
 
-static void
-brcmf_sdbrcm_chip_detach(struct brcmf_bus *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       kfree(bus->ci);
-       bus->ci = NULL;
-}
-
 static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
@@ -4380,7 +3857,7 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_bus *bus)
        if (bus->ci) {
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
-               brcmf_sdbrcm_chip_detach(bus);
+               brcmf_sdio_chip_detach(&bus->ci);
                if (bus->vars && bus->varsz)
                        kfree(bus->vars);
                bus->vars = NULL;
@@ -4440,6 +3917,7 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
 
        bus->sdiodev = sdiodev;
        sdiodev->bus = bus;
+       skb_queue_head_init(&bus->glom);
        bus->txbound = BRCMF_TXBOUND;
        bus->rxbound = BRCMF_RXBOUND;
        bus->txminmax = BRCMF_TXMINMAX;
@@ -4521,9 +3999,10 @@ void *brcmf_sdbrcm_probe(u16 bus_no, u16 slot, u16 func, uint bustype,
                        goto fail;
                }
        }
-       /* Ok, have the per-port tell the stack we're open for business */
-       if (brcmf_net_attach(bus->drvr, 0) != 0) {
-               brcmf_dbg(ERROR, "Net attach failed!!\n");
+
+       /* add interface and open for business */
+       if (brcmf_add_if((struct brcmf_info *)bus->drvr, 0, "wlan%d", NULL)) {
+               brcmf_dbg(ERROR, "Add primary net device interface failed!!\n");
                goto fail;
        }
 
@@ -4554,10 +4033,6 @@ struct device *brcmf_bus_get_device(struct brcmf_bus *bus)
 void
 brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
 {
-       /* don't start the wd until fw is loaded */
-       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
-               return;
-
        /* Totally stop the timer */
        if (!wdtick && bus->wd_timer_valid == true) {
                del_timer_sync(&bus->timer);
@@ -4566,6 +4041,10 @@ brcmf_sdbrcm_wd_timer(struct brcmf_bus *bus, uint wdtick)
                return;
        }
 
+       /* don't start the wd until fw is loaded */
+       if (bus->drvr->busstate == BRCMF_BUS_DOWN)
+               return;
+
        if (wdtick) {
                if (bus->save_ms != BRCMF_WD_POLL_MS) {
                        if (bus->wd_timer_valid == true)
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
new file mode 100644 (file)
index 0000000..f6b1822
--- /dev/null
@@ -0,0 +1,622 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/* ***** SDIO interface chip backplane handle functions ***** */
+
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/mmc/card.h>
+#include <linux/ssb/ssb_regs.h>
+#include <linux/bcma/bcma.h>
+
+#include <chipcommon.h>
+#include <brcm_hw_ids.h>
+#include <brcmu_wifi.h>
+#include <brcmu_utils.h>
+#include <soc.h>
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "sdio_host.h"
+#include "sdio_chip.h"
+
+/* chip core base & ramsize */
+/* bcm4329 */
+/* SDIO device core, ID 0x829 */
+#define BCM4329_CORE_BUS_BASE          0x18011000
+/* internal memory core, ID 0x80e */
+#define BCM4329_CORE_SOCRAM_BASE       0x18003000
+/* ARM Cortex M3 core, ID 0x82a */
+#define BCM4329_CORE_ARM_BASE          0x18002000
+#define BCM4329_RAMSIZE                        0x48000
+
+#define        SBCOREREV(sbidh) \
+       ((((sbidh) & SSB_IDHIGH_RCHI) >> SSB_IDHIGH_RCHI_SHIFT) | \
+         ((sbidh) & SSB_IDHIGH_RCLO))
+
+/* SOC Interconnect types (aka chip types) */
+#define SOCI_SB                0
+#define SOCI_AI                1
+
+/* EROM CompIdentB */
+#define CIB_REV_MASK           0xff000000
+#define CIB_REV_SHIFT          24
+
+#define SDIOD_DRVSTR_KEY(chip, pmu)     (((chip) << 16) | (pmu))
+/* SDIO Pad drive strength to select value mappings */
+struct sdiod_drive_str {
+       u8 strength;    /* Pad Drive Strength in mA */
+       u8 sel;         /* Chip-specific select value */
+};
+/* SDIO Drive Strength to sel value table for PMU Rev 1 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab1[] = {
+       {
+       4, 0x2}, {
+       2, 0x3}, {
+       1, 0x0}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 2, 3 */
+static const struct sdiod_drive_str sdiod_drive_strength_tab2[] = {
+       {
+       12, 0x7}, {
+       10, 0x6}, {
+       8, 0x5}, {
+       6, 0x4}, {
+       4, 0x2}, {
+       2, 0x1}, {
+       0, 0x0}
+       };
+/* SDIO Drive Strength to sel value table for PMU Rev 8 (1.8V) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab3[] = {
+       {
+       32, 0x7}, {
+       26, 0x6}, {
+       22, 0x5}, {
+       16, 0x4}, {
+       12, 0x3}, {
+       8, 0x2}, {
+       4, 0x1}, {
+       0, 0x0}
+       };
+
+u8
+brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       for (idx = 0; idx < BRCMF_MAX_CORENUM; idx++)
+               if (coreid == ci->c_inf[idx].id)
+                       return idx;
+
+       return BRCMF_MAX_CORENUM;
+}
+
+static u32
+brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
+       return SBCOREREV(regdata);
+}
+
+static u32
+brcmf_sdio_ai_corerev(struct brcmf_sdio_dev *sdiodev,
+                     struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       return (ci->c_inf[idx].cib & CIB_REV_MASK) >> CIB_REV_SHIFT;
+}
+
+static bool
+brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
+                   SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
+       return (SSB_TMSLOW_CLOCK == regdata);
+}
+
+static bool
+brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
+                      struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+       bool ret;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
+
+       return ret;
+}
+
+static void
+brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if (regdata & SSB_TMSLOW_RESET)
+               return;
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
+               /*
+                * set target reject and spin until busy is clear
+                * (preserve core-specific bits)
+                */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                               4, regdata | SSB_TMSLOW_REJECT);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(1);
+               SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
+                       SSB_TMSHIGH_BUSY), 100000);
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+               if (regdata & SSB_TMSHIGH_BUSY)
+                       brcmf_dbg(ERROR, "core state still busy\n");
+
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
+                               SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+                       udelay(1);
+                       SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               SSB_IMSTATE_BUSY), 100000);
+               }
+
+               /* set reset and reject while enabling the clocks */
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       (SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
+                       SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+               udelay(10);
+
+               /* clear the initiator reject bit */
+               regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
+               if (regdata & SSB_IDLOW_INITIATOR) {
+                       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
+                               ~SSB_IMSTATE_REJECT;
+                       brcmf_sdcard_reg_write(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                               regdata);
+               }
+       }
+
+       /* leave reset and reject asserted */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               (SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
+                         struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* if core is already in reset, just return */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                                       4);
+       if ((regdata & BCMA_RESET_CTL_RESET) != 0)
+               return;
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, 0);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(10);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, BCMA_RESET_CTL_RESET);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u32 regdata;
+       u8 idx;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /*
+        * Must do the disable sequence first to work for
+        * arbitrary current core state.
+        */
+       brcmf_sdio_sb_coredisable(sdiodev, ci, coreid);
+
+       /*
+        * Now do the initialization sequence.
+        * set reset while enabling the clock and
+        * forcing them on throughout the core
+        */
+       brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+                       SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* clear any serror */
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
+       if (regdata & SSB_TMSHIGH_SERR)
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
+
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
+       if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
+                       regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
+
+       /* clear reset and allow it to propagate throughout the core */
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
+               SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+
+       /* leave clock enabled */
+       brcmf_sdcard_reg_write(sdiodev,
+                              CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
+                              4, SSB_TMSLOW_CLOCK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                               CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
+       udelay(1);
+}
+
+static void
+brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid)
+{
+       u8 idx;
+       u32 regdata;
+
+       idx = brcmf_sdio_chip_getinfidx(ci, coreid);
+
+       /* must disable first to work for arbitrary current core state */
+       brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
+
+       /* now do initialization sequence */
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
+                              4, 0);
+       udelay(1);
+
+       brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
+                              4, BCMA_IOCTL_CLK);
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                                       ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
+       udelay(1);
+}
+
+static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
+                                      struct chip_info *ci, u32 regs)
+{
+       u32 regdata;
+
+       /*
+        * Get CC core rev
+        * Chipid is assume to be at offset 0 from regs arg
+        * For different chiptypes or old sdio hosts w/o chipcommon,
+        * other ways of recognition should be added here.
+        */
+       ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
+       ci->c_inf[0].base = regs;
+       regdata = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
+       ci->chip = regdata & CID_ID_MASK;
+       ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
+       ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
+
+       brcmf_dbg(INFO, "chipid=0x%x chiprev=%d\n", ci->chip, ci->chiprev);
+
+       /* Address of cores for new chips should be added here */
+       switch (ci->chip) {
+       case BCM4329_CHIP_ID:
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = BCM4329_CORE_BUS_BASE;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = BCM4329_CORE_SOCRAM_BASE;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = BCM4329_CORE_ARM_BASE;
+               ci->ramsize = BCM4329_RAMSIZE;
+               break;
+       default:
+               brcmf_dbg(ERROR, "chipid 0x%x is not supported\n", ci->chip);
+               return -ENODEV;
+       }
+
+       switch (ci->socitype) {
+       case SOCI_SB:
+               ci->iscoreup = brcmf_sdio_sb_iscoreup;
+               ci->corerev = brcmf_sdio_sb_corerev;
+               ci->coredisable = brcmf_sdio_sb_coredisable;
+               ci->resetcore = brcmf_sdio_sb_resetcore;
+               break;
+       case SOCI_AI:
+               ci->iscoreup = brcmf_sdio_ai_iscoreup;
+               ci->corerev = brcmf_sdio_ai_corerev;
+               ci->coredisable = brcmf_sdio_ai_coredisable;
+               ci->resetcore = brcmf_sdio_ai_resetcore;
+               break;
+       default:
+               brcmf_dbg(ERROR, "socitype %u not supported\n", ci->socitype);
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int
+brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
+{
+       int err = 0;
+       u8 clkval, clkset;
+
+       /* Try forcing SDIO core to do ALPAvail request only */
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       if (err) {
+               brcmf_dbg(ERROR, "error writing for HT off\n");
+               return err;
+       }
+
+       /* If register supported, wait for ALPAvail and then force ALP */
+       /* This may take up to 15 milliseconds */
+       clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                                      SBSDIO_FUNC1_CHIPCLKCSR, NULL);
+
+       if ((clkval & ~SBSDIO_AVBITS) != clkset) {
+               brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
+                         clkset, clkval);
+               return -EACCES;
+       }
+
+       SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
+                               SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
+                       !SBSDIO_ALPAV(clkval)),
+                       PMU_MAX_TRANSITION_DLY);
+       if (!SBSDIO_ALPAV(clkval)) {
+               brcmf_dbg(ERROR, "timeout on ALPAV wait, clkval 0x%02x\n",
+                         clkval);
+               return -EBUSY;
+       }
+
+       clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
+       udelay(65);
+
+       /* Also, disable the extra SDIO pull-ups */
+       brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
+                              SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
+
+       return 0;
+}
+
+static void
+brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
+                            struct chip_info *ci)
+{
+       /* get chipcommon rev */
+       ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
+
+       /* get chipcommon capabilites */
+       ci->c_inf[0].caps =
+               brcmf_sdcard_reg_read(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
+
+       /* get pmu caps & rev */
+       if (ci->c_inf[0].caps & CC_CAP_PMU) {
+               ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
+               ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
+       }
+
+       ci->c_inf[1].rev = ci->corerev(sdiodev, ci, ci->c_inf[1].id);
+
+       brcmf_dbg(INFO, "ccrev=%d, pmurev=%d, buscore rev/type=%d/0x%x\n",
+                 ci->c_inf[0].rev, ci->pmurev,
+                 ci->c_inf[1].rev, ci->c_inf[1].id);
+
+       /*
+        * Make sure any on-chip ARM is off (in case strapping is wrong),
+        * or downloaded code was already running.
+        */
+       ci->coredisable(sdiodev, ci, BCMA_CORE_ARM_CM3);
+}
+
+int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                          struct chip_info **ci_ptr, u32 regs)
+{
+       int ret;
+       struct chip_info *ci;
+
+       brcmf_dbg(TRACE, "Enter\n");
+
+       /* alloc chip_info_t */
+       ci = kzalloc(sizeof(struct chip_info), GFP_ATOMIC);
+       if (!ci)
+               return -ENOMEM;
+
+       ret = brcmf_sdio_chip_buscoreprep(sdiodev);
+       if (ret != 0)
+               goto err;
+
+       ret = brcmf_sdio_chip_recognition(sdiodev, ci, regs);
+       if (ret != 0)
+               goto err;
+
+       brcmf_sdio_chip_buscoresetup(sdiodev, ci);
+
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
+       brcmf_sdcard_reg_write(sdiodev,
+               CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
+
+       *ci_ptr = ci;
+       return 0;
+
+err:
+       kfree(ci);
+       return ret;
+}
+
+void
+brcmf_sdio_chip_detach(struct chip_info **ci_ptr)
+{
+       brcmf_dbg(TRACE, "Enter\n");
+
+       kfree(*ci_ptr);
+       *ci_ptr = NULL;
+}
+
+static char *brcmf_sdio_chip_name(uint chipid, char *buf, uint len)
+{
+       const char *fmt;
+
+       fmt = ((chipid > 0xa000) || (chipid < 0x4000)) ? "%d" : "%x";
+       snprintf(buf, len, fmt, chipid);
+       return buf;
+}
+
+void
+brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info *ci, u32 drivestrength)
+{
+       struct sdiod_drive_str *str_tab = NULL;
+       u32 str_mask = 0;
+       u32 str_shift = 0;
+       char chn[8];
+
+       if (!(ci->c_inf[0].caps & CC_CAP_PMU))
+               return;
+
+       switch (SDIOD_DRVSTR_KEY(ci->chip, ci->pmurev)) {
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 1):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab1;
+               str_mask = 0x30000000;
+               str_shift = 28;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 2):
+       case SDIOD_DRVSTR_KEY(BCM4325_CHIP_ID, 3):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab2;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       case SDIOD_DRVSTR_KEY(BCM4336_CHIP_ID, 8):
+               str_tab = (struct sdiod_drive_str *)&sdiod_drive_strength_tab3;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
+       default:
+               brcmf_dbg(ERROR, "No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
+                         brcmf_sdio_chip_name(ci->chip, chn, 8),
+                         ci->chiprev, ci->pmurev);
+               break;
+       }
+
+       if (str_tab != NULL) {
+               u32 drivestrength_sel = 0;
+               u32 cc_data_temp;
+               int i;
+
+               for (i = 0; str_tab[i].strength != 0; i++) {
+                       if (drivestrength >= str_tab[i].strength) {
+                               drivestrength_sel = str_tab[i].sel;
+                               break;
+                       }
+               }
+
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, 1);
+               cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
+               cc_data_temp &= ~str_mask;
+               drivestrength_sel <<= str_shift;
+               cc_data_temp |= drivestrength_sel;
+               brcmf_sdcard_reg_write(sdiodev,
+                       CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
+                       4, cc_data_temp);
+
+               brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
+                         drivestrength, cc_data_temp);
+       }
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
new file mode 100644 (file)
index 0000000..ce974d7
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _BRCMFMAC_SDIO_CHIP_H_
+#define _BRCMFMAC_SDIO_CHIP_H_
+
+/*
+ * Core reg address translation.
+ * Both macro's returns a 32 bits byte address on the backplane bus.
+ */
+#define CORE_CC_REG(base, field) \
+               (base + offsetof(struct chipcregs, field))
+#define CORE_BUS_REG(base, field) \
+               (base + offsetof(struct sdpcmd_regs, field))
+#define CORE_SB(base, field) \
+               (base + SBCONFIGOFF + offsetof(struct sbconfig, field))
+
+/* SDIO function 1 register CHIPCLKCSR */
+/* Force ALP request to backplane */
+#define SBSDIO_FORCE_ALP               0x01
+/* Force HT request to backplane */
+#define SBSDIO_FORCE_HT                        0x02
+/* Force ILP request to backplane */
+#define SBSDIO_FORCE_ILP               0x04
+/* Make ALP ready (power up xtal) */
+#define SBSDIO_ALP_AVAIL_REQ           0x08
+/* Make HT ready (power up PLL) */
+#define SBSDIO_HT_AVAIL_REQ            0x10
+/* Squelch clock requests from HW */
+#define SBSDIO_FORCE_HW_CLKREQ_OFF     0x20
+/* Status: ALP is ready */
+#define SBSDIO_ALP_AVAIL               0x40
+/* Status: HT is ready */
+#define SBSDIO_HT_AVAIL                        0x80
+#define SBSDIO_AVBITS          (SBSDIO_HT_AVAIL | SBSDIO_ALP_AVAIL)
+#define SBSDIO_ALPAV(regval)   ((regval) & SBSDIO_AVBITS)
+#define SBSDIO_HTAV(regval)    (((regval) & SBSDIO_AVBITS) == SBSDIO_AVBITS)
+#define SBSDIO_ALPONLY(regval) (SBSDIO_ALPAV(regval) && !SBSDIO_HTAV(regval))
+#define SBSDIO_CLKAV(regval, alponly) \
+       (SBSDIO_ALPAV(regval) && (alponly ? 1 : SBSDIO_HTAV(regval)))
+
+#define BRCMF_MAX_CORENUM      6
+
+struct chip_core_info {
+       u16 id;
+       u16 rev;
+       u32 base;
+       u32 wrapbase;
+       u32 caps;
+       u32 cib;
+};
+
+struct chip_info {
+       u32 chip;
+       u32 chiprev;
+       u32 socitype;
+       /* core info */
+       /* always put chipcommon core at 0, bus core at 1 */
+       struct chip_core_info c_inf[BRCMF_MAX_CORENUM];
+       u32 pmurev;
+       u32 pmucaps;
+       u32 ramsize;
+
+       bool (*iscoreup)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       u32 (*corerev)(struct brcmf_sdio_dev *sdiodev, struct chip_info *ci,
+                        u16 coreid);
+       void (*coredisable)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+       void (*resetcore)(struct brcmf_sdio_dev *sdiodev,
+                       struct chip_info *ci, u16 coreid);
+};
+
+struct sbconfig {
+       u32 PAD[2];
+       u32 sbipsflag;  /* initiator port ocp slave flag */
+       u32 PAD[3];
+       u32 sbtpsflag;  /* target port ocp slave flag */
+       u32 PAD[11];
+       u32 sbtmerrloga;        /* (sonics >= 2.3) */
+       u32 PAD;
+       u32 sbtmerrlog; /* (sonics >= 2.3) */
+       u32 PAD[3];
+       u32 sbadmatch3; /* address match3 */
+       u32 PAD;
+       u32 sbadmatch2; /* address match2 */
+       u32 PAD;
+       u32 sbadmatch1; /* address match1 */
+       u32 PAD[7];
+       u32 sbimstate;  /* initiator agent state */
+       u32 sbintvec;   /* interrupt mask */
+       u32 sbtmstatelow;       /* target state */
+       u32 sbtmstatehigh;      /* target state */
+       u32 sbbwa0;             /* bandwidth allocation table0 */
+       u32 PAD;
+       u32 sbimconfiglow;      /* initiator configuration */
+       u32 sbimconfighigh;     /* initiator configuration */
+       u32 sbadmatch0; /* address match0 */
+       u32 PAD;
+       u32 sbtmconfiglow;      /* target configuration */
+       u32 sbtmconfighigh;     /* target configuration */
+       u32 sbbconfig;  /* broadcast configuration */
+       u32 PAD;
+       u32 sbbstate;   /* broadcast state */
+       u32 PAD[3];
+       u32 sbactcnfg;  /* activate configuration */
+       u32 PAD[3];
+       u32 sbflagst;   /* current sbflags */
+       u32 PAD[3];
+       u32 sbidlow;            /* identification */
+       u32 sbidhigh;   /* identification */
+};
+
+extern int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
+                                 struct chip_info **ci_ptr, u32 regs);
+extern void brcmf_sdio_chip_detach(struct chip_info **ci_ptr);
+extern void brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
+                                             struct chip_info *ci,
+                                             u32 drivestrength);
+extern u8 brcmf_sdio_chip_getinfidx(struct chip_info *ci, u16 coreid);
+
+
+#endif         /* _BRCMFMAC_SDIO_CHIP_H_ */
index 5eddabe5228a9e7a3f1f00b737114f98dc34c2f0..cc19a733ac65f16b370a50a755e5495b764d83db 100644 (file)
@@ -1997,7 +1997,7 @@ done:
 }
 
 static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
-                                  struct brcmf_bss_info *bi)
+                                  struct brcmf_bss_info_le *bi)
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
@@ -2049,18 +2049,27 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_priv *cfg_priv,
                notify_timestamp, notify_capability, notify_interval, notify_ie,
                notify_ielen, notify_signal, GFP_KERNEL);
 
-       if (!bss) {
-               WL_ERR("cfg80211_inform_bss_frame error\n");
-               return -EINVAL;
-       }
+       if (!bss)
+               return -ENOMEM;
+
+       cfg80211_put_bss(bss);
 
        return err;
 }
 
+static struct brcmf_bss_info_le *
+next_bss_le(struct brcmf_scan_results *list, struct brcmf_bss_info_le *bss)
+{
+       if (bss == NULL)
+               return list->bss_info_le;
+       return (struct brcmf_bss_info_le *)((unsigned long)bss +
+                                           le32_to_cpu(bss->length));
+}
+
 static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
 {
        struct brcmf_scan_results *bss_list;
-       struct brcmf_bss_info *bi = NULL;       /* must be initialized */
+       struct brcmf_bss_info_le *bi = NULL;    /* must be initialized */
        s32 err = 0;
        int i;
 
@@ -2072,7 +2081,7 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_priv *cfg_priv)
        }
        WL_SCAN("scanned AP count (%d)\n", bss_list->count);
        for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
-               bi = next_bss(bss_list, bi);
+               bi = next_bss_le(bss_list, bi);
                err = brcmf_inform_single_bss(cfg_priv, bi);
                if (err)
                        break;
@@ -2085,8 +2094,9 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
 {
        struct wiphy *wiphy = cfg_to_wiphy(cfg_priv);
        struct ieee80211_channel *notify_channel;
-       struct brcmf_bss_info *bi = NULL;
+       struct brcmf_bss_info_le *bi = NULL;
        struct ieee80211_supported_band *band;
+       struct cfg80211_bss *bss;
        u8 *buf = NULL;
        s32 err = 0;
        u16 channel;
@@ -2114,7 +2124,7 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
                goto CleanUp;
        }
 
-       bi = (struct brcmf_bss_info *)(buf + 4);
+       bi = (struct brcmf_bss_info_le *)(buf + 4);
 
        channel = bi->ctl_ch ? bi->ctl_ch :
                                CHSPEC_CHANNEL(le16_to_cpu(bi->chanspec));
@@ -2140,10 +2150,17 @@ static s32 wl_inform_ibss(struct brcmf_cfg80211_priv *cfg_priv,
        WL_CONN("signal: %d\n", notify_signal);
        WL_CONN("notify_timestamp: %#018llx\n", notify_timestamp);
 
-       cfg80211_inform_bss(wiphy, notify_channel, bssid,
+       bss = cfg80211_inform_bss(wiphy, notify_channel, bssid,
                notify_timestamp, notify_capability, notify_interval,
                notify_ie, notify_ielen, notify_signal, GFP_KERNEL);
 
+       if (!bss) {
+               err = -ENOMEM;
+               goto CleanUp;
+       }
+
+       cfg80211_put_bss(bss);
+
 CleanUp:
 
        kfree(buf);
@@ -2188,7 +2205,7 @@ static struct brcmf_tlv *brcmf_parse_tlvs(void *buf, int buflen, uint key)
 
 static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
 {
-       struct brcmf_bss_info *bi;
+       struct brcmf_bss_info_le *bi;
        struct brcmf_ssid *ssid;
        struct brcmf_tlv *tim;
        u16 beacon_interval;
@@ -2211,7 +2228,7 @@ static s32 brcmf_update_bss_info(struct brcmf_cfg80211_priv *cfg_priv)
                goto update_bss_info_out;
        }
 
-       bi = (struct brcmf_bss_info *)(cfg_priv->extra_buf + 4);
+       bi = (struct brcmf_bss_info_le *)(cfg_priv->extra_buf + 4);
        err = brcmf_inform_single_bss(cfg_priv, bi);
        if (err)
                goto update_bss_info_out;
index 62dc46144ede5935de0a8a8d8cf16bdba8b0f003..a613b49cb13f543e66363f5749ac09473a64b4b5 100644 (file)
@@ -352,15 +352,6 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_priv *cfg)
        return &cfg->conn_info;
 }
 
-static inline struct brcmf_bss_info *next_bss(struct brcmf_scan_results *list,
-                                          struct brcmf_bss_info *bss)
-{
-       return bss = bss ?
-               (struct brcmf_bss_info *)((unsigned long)bss +
-                                      le32_to_cpu(bss->length)) :
-               list->bss_info;
-}
-
 extern struct brcmf_cfg80211_dev *brcmf_cfg80211_attach(struct net_device *ndev,
                                                        struct device *busdev,
                                                        void *data);
index 106a7424a7cd4d60ee098d691db77e21067ba77c..b51d1e421e244ca0e92b2326d20c2c6b13fca5dd 100644 (file)
 /* PCIE Client Mode sb2pcitranslation2 (2 ZettaBytes), high 32 bits */
 #define SI_PCIE_DMA_H32                0x80000000
 
-/* core codes */
-#define        NODEV_CORE_ID           0x700   /* Invalid coreid */
-#define        CC_CORE_ID              0x800   /* chipcommon core */
-#define        ILINE20_CORE_ID         0x801   /* iline20 core */
-#define        SRAM_CORE_ID            0x802   /* sram core */
-#define        SDRAM_CORE_ID           0x803   /* sdram core */
-#define        PCI_CORE_ID             0x804   /* pci core */
-#define        MIPS_CORE_ID            0x805   /* mips core */
-#define        ENET_CORE_ID            0x806   /* enet mac core */
-#define        CODEC_CORE_ID           0x807   /* v90 codec core */
-#define        USB_CORE_ID             0x808   /* usb 1.1 host/device core */
-#define        ADSL_CORE_ID            0x809   /* ADSL core */
-#define        ILINE100_CORE_ID        0x80a   /* iline100 core */
-#define        IPSEC_CORE_ID           0x80b   /* ipsec core */
-#define        UTOPIA_CORE_ID          0x80c   /* utopia core */
-#define        PCMCIA_CORE_ID          0x80d   /* pcmcia core */
-#define        SOCRAM_CORE_ID          0x80e   /* internal memory core */
-#define        MEMC_CORE_ID            0x80f   /* memc sdram core */
-#define        OFDM_CORE_ID            0x810   /* OFDM phy core */
-#define        EXTIF_CORE_ID           0x811   /* external interface core */
-#define        D11_CORE_ID             0x812   /* 802.11 MAC core */
-#define        APHY_CORE_ID            0x813   /* 802.11a phy core */
-#define        BPHY_CORE_ID            0x814   /* 802.11b phy core */
-#define        GPHY_CORE_ID            0x815   /* 802.11g phy core */
-#define        MIPS33_CORE_ID          0x816   /* mips3302 core */
-#define        USB11H_CORE_ID          0x817   /* usb 1.1 host core */
-#define        USB11D_CORE_ID          0x818   /* usb 1.1 device core */
-#define        USB20H_CORE_ID          0x819   /* usb 2.0 host core */
-#define        USB20D_CORE_ID          0x81a   /* usb 2.0 device core */
-#define        SDIOH_CORE_ID           0x81b   /* sdio host core */
-#define        ROBO_CORE_ID            0x81c   /* roboswitch core */
-#define        ATA100_CORE_ID          0x81d   /* parallel ATA core */
-#define        SATAXOR_CORE_ID         0x81e   /* serial ATA & XOR DMA core */
-#define        GIGETH_CORE_ID          0x81f   /* gigabit ethernet core */
-#define        PCIE_CORE_ID            0x820   /* pci express core */
-#define        NPHY_CORE_ID            0x821   /* 802.11n 2x2 phy core */
-#define        SRAMC_CORE_ID           0x822   /* SRAM controller core */
-#define        MINIMAC_CORE_ID         0x823   /* MINI MAC/phy core */
-#define        ARM11_CORE_ID           0x824   /* ARM 1176 core */
-#define        ARM7S_CORE_ID           0x825   /* ARM7tdmi-s core */
-#define        LPPHY_CORE_ID           0x826   /* 802.11a/b/g phy core */
-#define        PMU_CORE_ID             0x827   /* PMU core */
-#define        SSNPHY_CORE_ID          0x828   /* 802.11n single-stream phy core */
-#define        SDIOD_CORE_ID           0x829   /* SDIO device core */
-#define        ARMCM3_CORE_ID          0x82a   /* ARM Cortex M3 core */
-#define        HTPHY_CORE_ID           0x82b   /* 802.11n 4x4 phy core */
-#define        MIPS74K_CORE_ID         0x82c   /* mips 74k core */
-#define        GMAC_CORE_ID            0x82d   /* Gigabit MAC core */
-#define        DMEMC_CORE_ID           0x82e   /* DDR1/2 memory controller core */
-#define        PCIERC_CORE_ID          0x82f   /* PCIE Root Complex core */
-#define        OCP_CORE_ID             0x830   /* OCP2OCP bridge core */
-#define        SC_CORE_ID              0x831   /* shared common core */
-#define        AHB_CORE_ID             0x832   /* OCP2AHB bridge core */
-#define        SPIH_CORE_ID            0x833   /* SPI host core */
-#define        I2S_CORE_ID             0x834   /* I2S core */
-#define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
-#define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
-#define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
-                                        * maps all unused address ranges
-                                        */
-
 /* chipcommon being the first core: */
 #define        SI_CC_IDX               0
 
 /* SOC Interconnect types (aka chip types) */
 #define        SOCI_AI                 1
 
-/* Common core control flags */
-#define        SICF_BIST_EN            0x8000
-#define        SICF_PME_EN             0x4000
-#define        SICF_CORE_BITS          0x3ffc
-#define        SICF_FGC                0x0002
-#define        SICF_CLOCK_EN           0x0001
-
-/* Common core status flags */
-#define        SISF_BIST_DONE          0x8000
-#define        SISF_BIST_ERROR         0x4000
-#define        SISF_GATED_CLK          0x2000
-#define        SISF_DMA64              0x1000
-#define        SISF_CORE_BITS          0x0fff
-
 /* A register that is common to all cores to
  * communicate w/PMU regarding clock control.
  */
index 7f27dbdb6b60943ae058d5f758330032280f237e..43f7a724dda812f1a6c27ba21e3f0184e70b30ce 100644 (file)
@@ -649,7 +649,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                len = roundup(len, 4);
                ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
 
-               dma_len += (u16) brcmu_pkttotlen(p);
+               dma_len += (u16) p->len;
 
                BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
                        " seg_cnt %d null delim %d\n",
@@ -741,9 +741,7 @@ brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
                if (p) {
                        if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
                            ((u8) (p->priority) == tid)) {
-
-                               plen = brcmu_pkttotlen(p) +
-                                      AMPDU_MAX_MPDU_OVERHEAD;
+                               plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
                                plen = max(scb_ampdu->min_len, plen);
 
                                if ((plen + ampdu_len) > max_ampdu_bytes) {
index 89ad1b7dab8fdd69a60822b80585cef29814af44..55e9f45fce22ec82315bd7559e346d8b02615f33 100644 (file)
@@ -1153,121 +1153,6 @@ brcms_c_channel_set_chanspec(struct brcms_cm_info *wlc_cm, u16 chanspec,
                              &txpwr);
 }
 
-#ifdef POWER_DBG
-static void wlc_phy_txpower_limits_dump(struct txpwr_limits *txpwr)
-{
-       int i;
-       char buf[80];
-       char fraction[4][4] = { "   ", ".25", ".5 ", ".75" };
-
-       sprintf(buf, "CCK                ");
-       for (i = 0; i < BRCMS_NUM_RATES_CCK; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->cck[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->cck[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_cdd[i] % BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM SISO   ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz OFDM CDD    ");
-       for (i = 0; i < BRCMS_NUM_RATES_OFDM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->ofdm_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->ofdm_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "20 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_20_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_20_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 SISO ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_siso[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_siso[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 CDD  ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_cdd[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_cdd[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS0-7 STBC ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_1_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_stbc[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_stbc[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       printk(KERN_DEBUG "%s\n", buf);
-
-       sprintf(buf, "40 MHz MCS8-15 SDM ");
-       for (i = 0; i < BRCMS_NUM_RATES_MCS_2_STREAM; i++)
-               sprintf(buf[strlen(buf)], " %2d%s",
-                       txpwr->mcs_40_mimo[i] / BRCMS_TXPWR_DB_FACTOR,
-                       fraction[txpwr->mcs_40_mimo[i] %
-                                                       BRCMS_TXPWR_DB_FACTOR]);
-       }
-       printk(KERN_DEBUG "%s\n", buf);
-
-       printk(KERN_DEBUG "MCS32               %2d%s\n",
-              txpwr->mcs32 / BRCMS_TXPWR_DB_FACTOR,
-              fraction[txpwr->mcs32 % BRCMS_TXPWR_DB_FACTOR]);
-}
-#endif                         /* POWER_DBG */
-
 void
 brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                       struct txpwr_limits *txpwr)
@@ -1478,9 +1363,6 @@ brcms_c_channel_reg_limits(struct brcms_cm_info *wlc_cm, u16 chanspec,
                        txpwr->mcs_40_stbc[i] = txpwr->mcs_40_cdd[i];
        }
 
-#ifdef POWER_DBG
-       wlc_phy_txpower_limits_dump(txpwr);
-#endif
        return;
 }
 
index b56a30297c269712840a8696f77d1d84daab358a..e286fb4d48135eab824546b420be9439c232d5a9 100644 (file)
@@ -14,7 +14,6 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/slab.h>
-#include <linux/skbuff.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
 
@@ -22,6 +21,7 @@
 #include <aiutils.h>
 #include "types.h"
 #include "dma.h"
+#include "soc.h"
 
 /*
  * DMA hardware requires each descriptor ring to be 8kB aligned, and fit within
@@ -358,13 +358,14 @@ static uint nrxdactive(struct dma_info *di, uint h, uint t)
 
 static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
 {
-       uint dmactrlflags = di->dma.dmactrlflags;
+       uint dmactrlflags;
 
        if (di == NULL) {
-               DMA_ERROR(("%s: _dma_ctrlflags: NULL dma handle\n", di->name));
+               DMA_ERROR(("_dma_ctrlflags: NULL dma handle\n"));
                return 0;
        }
 
+       dmactrlflags = di->dma.dmactrlflags;
        dmactrlflags &= ~mask;
        dmactrlflags |= flags;
 
@@ -900,7 +901,7 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
 
 /*
  * !! rx entry routine
- * returns a pointer to the next frame received, or NULL if there are no more
+ * returns the number packages in the next frame, or 0 if there are no more
  *   if DMA_CTRL_RXMULTI is defined, DMA scattering(multiple buffers) is
  *   supported with pkts chain
  *   otherwise, it's treated as giant pkt and will be tossed.
@@ -908,38 +909,40 @@ static struct sk_buff *_dma_getnextrxp(struct dma_info *di, bool forceall)
  *   buffer data. After it reaches the max size of buffer, the data continues
  *   in next DMA descriptor buffer WITHOUT DMA header
  */
-struct sk_buff *dma_rx(struct dma_pub *pub)
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
 {
        struct dma_info *di = (struct dma_info *)pub;
-       struct sk_buff *p, *head, *tail;
+       struct sk_buff_head dma_frames;
+       struct sk_buff *p, *next;
        uint len;
        uint pkt_len;
        int resid = 0;
+       int pktcnt = 1;
 
+       skb_queue_head_init(&dma_frames);
  next_frame:
-       head = _dma_getnextrxp(di, false);
-       if (head == NULL)
-               return NULL;
+       p = _dma_getnextrxp(di, false);
+       if (p == NULL)
+               return 0;
 
-       len = le16_to_cpu(*(__le16 *) (head->data));
+       len = le16_to_cpu(*(__le16 *) (p->data));
        DMA_TRACE(("%s: dma_rx len %d\n", di->name, len));
-       dma_spin_for_len(len, head);
+       dma_spin_for_len(len, p);
 
        /* set actual length */
        pkt_len = min((di->rxoffset + len), di->rxbufsize);
-       __skb_trim(head, pkt_len);
+       __skb_trim(p, pkt_len);
+       skb_queue_tail(&dma_frames, p);
        resid = len - (di->rxbufsize - di->rxoffset);
 
        /* check for single or multi-buffer rx */
        if (resid > 0) {
-               tail = head;
                while ((resid > 0) && (p = _dma_getnextrxp(di, false))) {
-                       tail->next = p;
                        pkt_len = min_t(uint, resid, di->rxbufsize);
                        __skb_trim(p, pkt_len);
-
-                       tail = p;
+                       skb_queue_tail(&dma_frames, p);
                        resid -= di->rxbufsize;
+                       pktcnt++;
                }
 
 #ifdef BCMDBG
@@ -958,13 +961,18 @@ struct sk_buff *dma_rx(struct dma_pub *pub)
                if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
                        DMA_ERROR(("%s: dma_rx: bad frame length (%d)\n",
                                   di->name, len));
-                       brcmu_pkt_buf_free_skb(head);
+                       skb_queue_walk_safe(&dma_frames, p, next) {
+                               skb_unlink(p, &dma_frames);
+                               brcmu_pkt_buf_free_skb(p);
+                       }
                        di->dma.rxgiants++;
+                       pktcnt = 1;
                        goto next_frame;
                }
        }
 
-       return head;
+       skb_queue_splice_tail(&dma_frames, skb_list);
+       return pktcnt;
 }
 
 static bool dma64_rxidle(struct dma_info *di)
index ebc5bc546f3b8bdd1c42e493554c9ad2c4d6d6e5..d317c7c12f9181738e64681dfb60ba5292e94fa0 100644 (file)
@@ -18,6 +18,7 @@
 #define        _BRCM_DMA_H_
 
 #include <linux/delay.h>
+#include <linux/skbuff.h>
 #include "types.h"             /* forward structure declarations */
 
 /* map/unmap direction */
@@ -80,7 +81,7 @@ extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
                            uint nrxpost, uint rxoffset, uint *msg_level);
 
 void dma_rxinit(struct dma_pub *pub);
-struct sk_buff *dma_rx(struct dma_pub *pub);
+int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list);
 bool dma_rxfill(struct dma_pub *pub);
 bool dma_rxreset(struct dma_pub *pub);
 bool dma_txreset(struct dma_pub *pub);
index 0d8a9cdf897afe3569ea412256a17cf301ffb8b4..8457e969eb4fe418178362ac5f0556772f8b5d2b 100644 (file)
@@ -216,8 +216,7 @@ static const struct ieee80211_supported_band brcms_band_2GHz_nphy_template = {
        .ht_cap = {
                   /* from include/linux/ieee80211.h */
                   .cap = IEEE80211_HT_CAP_GRN_FLD |
-                  IEEE80211_HT_CAP_SGI_20 |
-                  IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT,
+                         IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -238,8 +237,7 @@ static const struct ieee80211_supported_band brcms_band_5GHz_nphy_template = {
                        BRCMS_LEGACY_5G_RATE_OFFSET,
        .ht_cap = {
                   .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 |
-                         IEEE80211_HT_CAP_SGI_40 |
-                         IEEE80211_HT_CAP_40MHZ_INTOLERANT, /* No 40 mhz yet */
+                         IEEE80211_HT_CAP_SGI_40,
                   .ht_supported = true,
                   .ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K,
                   .ampdu_density = AMPDU_DEF_MPDU_DENSITY,
@@ -287,6 +285,7 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
 {
        struct brcms_info *wl = hw->priv;
        bool blocked;
+       int err;
 
        ieee80211_wake_queues(hw);
        spin_lock_bh(&wl->lock);
@@ -295,57 +294,69 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        if (!blocked)
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
 
-       return 0;
+       spin_lock_bh(&wl->lock);
+       /* avoid acknowledging frames before a non-monitor device is added */
+       wl->mute_tx = true;
+
+       if (!wl->pub->up)
+               err = brcms_up(wl);
+       else
+               err = -ENODEV;
+       spin_unlock_bh(&wl->lock);
+
+       if (err != 0)
+               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
+                         err);
+       return err;
 }
 
 static void brcms_ops_stop(struct ieee80211_hw *hw)
 {
+       struct brcms_info *wl = hw->priv;
+       int status;
+
        ieee80211_stop_queues(hw);
+
+       if (wl->wlc == NULL)
+               return;
+
+       spin_lock_bh(&wl->lock);
+       status = brcms_c_chipmatch(wl->wlc->hw->vendorid,
+                                  wl->wlc->hw->deviceid);
+       spin_unlock_bh(&wl->lock);
+       if (!status) {
+               wiphy_err(wl->wiphy,
+                         "wl: brcms_ops_stop: chipmatch failed\n");
+               return;
+       }
+
+       /* put driver in down state */
+       spin_lock_bh(&wl->lock);
+       brcms_down(wl);
+       spin_unlock_bh(&wl->lock);
 }
 
 static int
 brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-       int err;
+       struct brcms_info *wl = hw->priv;
 
        /* Just STA for now */
-       if (vif->type != NL80211_IFTYPE_AP &&
-           vif->type != NL80211_IFTYPE_MESH_POINT &&
-           vif->type != NL80211_IFTYPE_STATION &&
-           vif->type != NL80211_IFTYPE_WDS &&
-           vif->type != NL80211_IFTYPE_ADHOC) {
+       if (vif->type != NL80211_IFTYPE_STATION) {
                wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
                          " STA for now\n", __func__, vif->type);
                return -EOPNOTSUPP;
        }
 
-       wl = hw->priv;
-       spin_lock_bh(&wl->lock);
-       if (!wl->pub->up)
-               err = brcms_up(wl);
-       else
-               err = -ENODEV;
-       spin_unlock_bh(&wl->lock);
-
-       if (err != 0)
-               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
-                         err);
+       wl->mute_tx = false;
+       brcms_c_mute(wl->wlc, false);
 
-       return err;
+       return 0;
 }
 
 static void
 brcms_ops_remove_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
-       struct brcms_info *wl;
-
-       wl = hw->priv;
-
-       /* put driver in down state */
-       spin_lock_bh(&wl->lock);
-       brcms_down(wl);
-       spin_unlock_bh(&wl->lock);
 }
 
 static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
@@ -609,13 +620,6 @@ brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        wl->pub->global_ampdu->scb = scb;
        wl->pub->global_ampdu->max_pdu = 16;
 
-       sta->ht_cap.ht_supported = true;
-       sta->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
-       sta->ht_cap.ampdu_density = AMPDU_DEF_MPDU_DENSITY;
-       sta->ht_cap.cap = IEEE80211_HT_CAP_GRN_FLD |
-           IEEE80211_HT_CAP_SGI_20 |
-           IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_40MHZ_INTOLERANT;
-
        /*
         * minstrel_ht initiates addBA on our behalf by calling
         * ieee80211_start_tx_ba_session()
@@ -877,37 +881,18 @@ static void brcms_free(struct brcms_info *wl)
 }
 
 /*
-* called from both kernel as from this kernel module.
+* called from both kernel as from this kernel module (error flow on attach)
 * precondition: perimeter lock is not acquired.
 */
 static void brcms_remove(struct pci_dev *pdev)
 {
-       struct brcms_info *wl;
-       struct ieee80211_hw *hw;
-       int status;
-
-       hw = pci_get_drvdata(pdev);
-       wl = hw->priv;
-       if (!wl) {
-               pr_err("wl: brcms_remove: pci_get_drvdata failed\n");
-               return;
-       }
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct brcms_info *wl = hw->priv;
 
-       spin_lock_bh(&wl->lock);
-       status = brcms_c_chipmatch(pdev->vendor, pdev->device);
-       spin_unlock_bh(&wl->lock);
-       if (!status) {
-               wiphy_err(wl->wiphy, "wl: brcms_remove: chipmatch "
-                                    "failed\n");
-               return;
-       }
        if (wl->wlc) {
                wiphy_rfkill_set_hw_state(wl->pub->ieee_hw->wiphy, false);
                wiphy_rfkill_stop_polling(wl->pub->ieee_hw->wiphy);
                ieee80211_unregister_hw(hw);
-               spin_lock_bh(&wl->lock);
-               brcms_down(wl);
-               spin_unlock_bh(&wl->lock);
        }
        pci_disable_device(pdev);
 
@@ -1081,9 +1066,6 @@ static struct brcms_info *brcms_attach(u16 vendor, u16 device,
 
        wl->pub->ieee_hw = hw;
 
-       /* disable mpc */
-       brcms_c_set_radio_mpc(wl->wlc, false);
-
        /* register our interrupt handler */
        if (request_irq(irq, brcms_isr, IRQF_SHARED, KBUILD_MODNAME, wl)) {
                wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
@@ -1319,8 +1301,7 @@ void brcms_init(struct brcms_info *wl)
 {
        BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
        brcms_reset(wl);
-
-       brcms_c_init(wl->wlc);
+       brcms_c_init(wl->wlc, wl->mute_tx);
 }
 
 /*
@@ -1337,6 +1318,14 @@ uint brcms_reset(struct brcms_info *wl)
        return 0;
 }
 
+void brcms_fatal_error(struct brcms_info *wl)
+{
+       wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+                 wl->wlc->pub->unit);
+       brcms_reset(wl);
+       ieee80211_restart_hw(wl->pub->ieee_hw);
+}
+
 /*
  * These are interrupt on/off entry points. Disable interrupts
  * during interrupt state transition.
index 177f0e44e4b60c12c4384f893c80067e592cbd3c..6242f188b717d4e6c7a1cf3d7f30043a00fc1c29 100644 (file)
@@ -80,6 +80,7 @@ struct brcms_info {
        struct brcms_firmware fw;
        struct wiphy *wiphy;
        struct brcms_ucode ucode;
+       bool mute_tx;
 };
 
 /* misc callbacks */
@@ -104,5 +105,6 @@ extern bool brcms_del_timer(struct brcms_timer *timer);
 extern void brcms_msleep(struct brcms_info *wl, uint ms);
 extern void brcms_dpc(unsigned long data);
 extern void brcms_timer(struct brcms_timer *t);
+extern void brcms_fatal_error(struct brcms_info *wl);
 
 #endif                         /* _BRCM_MAC80211_IF_H_ */
index 510e9bb5228795c2d453d9eb641cc7084aa63b2b..36e3e06383000fc665a985bac23667e901dccf17 100644 (file)
 #include "mac80211_if.h"
 #include "ucode_loader.h"
 #include "main.h"
+#include "soc.h"
 
 /*
  * Indication for txflowcontrol that all priority bits in
  * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
  */
-#define ALLPRIO                -1
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+#define ALLPRIO                                -1
 
 /* watchdog timer, in unit of ms */
-#define        TIMER_INTERVAL_WATCHDOG 1000
+#define TIMER_INTERVAL_WATCHDOG                1000
 /* radio monitor timer, in unit of ms */
-#define        TIMER_INTERVAL_RADIOCHK 800
-
-/* Max MPC timeout, in unit of watchdog */
-#ifndef BRCMS_MPC_MAX_DELAYCNT
-#define        BRCMS_MPC_MAX_DELAYCNT  10
-#endif
-
-/* Min MPC timeout, in unit of watchdog */
-#define        BRCMS_MPC_MIN_DELAYCNT  1
-#define        BRCMS_MPC_THRESHOLD     3       /* MPC count threshold level */
+#define TIMER_INTERVAL_RADIOCHK                800
 
 /* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEFAULT 100
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEFAULT   3
-
-/* Scale down delays to accommodate QT slow speed */
-/* beacon interval, in unit of 1024TU */
-#define        BEACON_INTERVAL_DEF_QT  20
-/* DTIM interval, in unit of beacon interval */
-#define        DTIM_INTERVAL_DEF_QT    1
-
-#define        TBTT_ALIGN_LEEWAY_US    100     /* min leeway before first TBTT in us */
+#define BEACON_INTERVAL_DEFAULT                100
 
 /* n-mode support capability */
 /* 2x2 includes both 1x1 & 2x2 devices
 #define WL_11N_3x3                     3
 #define WL_11N_4x4                     4
 
-/* define 11n feature disable flags */
-#define WLFEATURE_DISABLE_11N          0x00000001
-#define WLFEATURE_DISABLE_11N_STBC_TX  0x00000002
-#define WLFEATURE_DISABLE_11N_STBC_RX  0x00000004
-#define WLFEATURE_DISABLE_11N_SGI_TX   0x00000008
-#define WLFEATURE_DISABLE_11N_SGI_RX   0x00000010
-#define WLFEATURE_DISABLE_11N_AMPDU_TX 0x00000020
-#define WLFEATURE_DISABLE_11N_AMPDU_RX 0x00000040
-#define WLFEATURE_DISABLE_11N_GF       0x00000080
-
-#define EDCF_ACI_MASK                0x60
-#define EDCF_ACI_SHIFT               5
-#define EDCF_ECWMIN_MASK             0x0f
-#define EDCF_ECWMAX_SHIFT            4
-#define EDCF_AIFSN_MASK              0x0f
-#define EDCF_AIFSN_MAX               15
-#define EDCF_ECWMAX_MASK             0xf0
-
-#define EDCF_AC_BE_TXOP_STA          0x0000
-#define EDCF_AC_BK_TXOP_STA          0x0000
-#define EDCF_AC_VO_ACI_STA           0x62
-#define EDCF_AC_VO_ECW_STA           0x32
-#define EDCF_AC_VI_ACI_STA           0x42
-#define EDCF_AC_VI_ECW_STA           0x43
-#define EDCF_AC_BK_ECW_STA           0xA4
-#define EDCF_AC_VI_TXOP_STA          0x005e
-#define EDCF_AC_VO_TXOP_STA          0x002f
-#define EDCF_AC_BE_ACI_STA           0x03
-#define EDCF_AC_BE_ECW_STA           0xA4
-#define EDCF_AC_BK_ACI_STA           0x27
-#define EDCF_AC_VO_TXOP_AP           0x002f
-
-#define EDCF_TXOP2USEC(txop)         ((txop) << 5)
-#define EDCF_ECW2CW(exp)             ((1 << (exp)) - 1)
-
-#define APHY_SYMBOL_TIME       4
-#define APHY_PREAMBLE_TIME     16
-#define APHY_SIGNAL_TIME       4
-#define APHY_SIFS_TIME         16
-#define APHY_SERVICE_NBITS     16
-#define APHY_TAIL_NBITS                6
-#define BPHY_SIFS_TIME         10
-#define BPHY_PLCP_SHORT_TIME   96
-
-#define PREN_PREAMBLE          24
-#define PREN_MM_EXT            12
-#define PREN_PREAMBLE_EXT      4
+#define EDCF_ACI_MASK                  0x60
+#define EDCF_ACI_SHIFT                 5
+#define EDCF_ECWMIN_MASK               0x0f
+#define EDCF_ECWMAX_SHIFT              4
+#define EDCF_AIFSN_MASK                        0x0f
+#define EDCF_AIFSN_MAX                 15
+#define EDCF_ECWMAX_MASK               0xf0
+
+#define EDCF_AC_BE_TXOP_STA            0x0000
+#define EDCF_AC_BK_TXOP_STA            0x0000
+#define EDCF_AC_VO_ACI_STA             0x62
+#define EDCF_AC_VO_ECW_STA             0x32
+#define EDCF_AC_VI_ACI_STA             0x42
+#define EDCF_AC_VI_ECW_STA             0x43
+#define EDCF_AC_BK_ECW_STA             0xA4
+#define EDCF_AC_VI_TXOP_STA            0x005e
+#define EDCF_AC_VO_TXOP_STA            0x002f
+#define EDCF_AC_BE_ACI_STA             0x03
+#define EDCF_AC_BE_ECW_STA             0xA4
+#define EDCF_AC_BK_ACI_STA             0x27
+#define EDCF_AC_VO_TXOP_AP             0x002f
+
+#define EDCF_TXOP2USEC(txop)           ((txop) << 5)
+#define EDCF_ECW2CW(exp)               ((1 << (exp)) - 1)
+
+#define APHY_SYMBOL_TIME               4
+#define APHY_PREAMBLE_TIME             16
+#define APHY_SIGNAL_TIME               4
+#define APHY_SIFS_TIME                 16
+#define APHY_SERVICE_NBITS             16
+#define APHY_TAIL_NBITS                        6
+#define BPHY_SIFS_TIME                 10
+#define BPHY_PLCP_SHORT_TIME           96
+
+#define PREN_PREAMBLE                  24
+#define PREN_MM_EXT                    12
+#define PREN_PREAMBLE_EXT              4
 
 #define DOT11_MAC_HDR_LEN              24
-#define        DOT11_ACK_LEN           10
-#define DOT11_BA_LEN           4
+#define DOT11_ACK_LEN                  10
+#define DOT11_BA_LEN                   4
 #define DOT11_OFDM_SIGNAL_EXTENSION    6
 #define DOT11_MIN_FRAG_LEN             256
-#define        DOT11_RTS_LEN           16
-#define        DOT11_CTS_LEN           10
+#define DOT11_RTS_LEN                  16
+#define DOT11_CTS_LEN                  10
 #define DOT11_BA_BITMAP_LEN            128
 #define DOT11_MIN_BEACON_PERIOD                1
 #define DOT11_MAX_BEACON_PERIOD                0xFFFF
-#define        DOT11_MAXNUMFRAGS       16
+#define DOT11_MAXNUMFRAGS              16
 #define DOT11_MAX_FRAG_LEN             2346
 
-#define BPHY_PLCP_TIME         192
-#define RIFS_11N_TIME          2
-
-#define WME_VER                        1
-#define WME_SUBTYPE_PARAM_IE   1
-#define WME_TYPE               2
-#define WME_OUI                        "\x00\x50\xf2"
-
-#define AC_BE                  0
-#define AC_BK                  1
-#define AC_VI                  2
-#define AC_VO                  3
+#define BPHY_PLCP_TIME                 192
+#define RIFS_11N_TIME                  2
 
-#define        BCN_TMPL_LEN            512     /* length of the BCN template area */
+/* length of the BCN template area */
+#define BCN_TMPL_LEN                   512
 
 /* brcms_bss_info flag bit values */
-#define BRCMS_BSS_HT           0x0020  /* BSS is HT (MIMO) capable */
+#define BRCMS_BSS_HT                   0x0020  /* BSS is HT (MIMO) capable */
 
-/* Flags used in brcms_c_txq_info.stopped */
-/* per prio flow control bits */
-#define TXQ_STOP_FOR_PRIOFC_MASK       0x000000FF
-/* stop txq enqueue for packet drain */
-#define TXQ_STOP_FOR_PKT_DRAIN         0x00000100
-/* stop txq enqueue for ampdu flow control */
-#define TXQ_STOP_FOR_AMPDU_FLOW_CNTRL  0x00000200
-
-#define        BRCMS_HWRXOFF           38      /* chip rx buffer offset */
-
-/* Find basic rate for a given rate */
-static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
-{
-       if (is_mcs_rate(rspec))
-               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
-                      .leg_ofdm];
-       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
-}
-
-static u16 frametype(u32 rspec, u8 mimoframe)
-{
-       if (is_mcs_rate(rspec))
-               return mimoframe;
-       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
-}
+/* chip rx buffer offset */
+#define BRCMS_HWRXOFF                  38
 
 /* rfdisable delay timer 500 ms, runs of ALP clock */
-#define RFDISABLE_DEFAULT      10000000
+#define RFDISABLE_DEFAULT              10000000
 
 #define BRCMS_TEMPSENSE_PERIOD         10      /* 10 second timeout */
 
@@ -194,87 +129,83 @@ static u16 frametype(u32 rspec, u8 mimoframe)
  * These constants are used ONLY by wlc_prio2prec_map.  Do not use them
  * elsewhere.
  */
-#define        _BRCMS_PREC_NONE                0       /* None = - */
-#define        _BRCMS_PREC_BK          2       /* BK - Background */
-#define        _BRCMS_PREC_BE          4       /* BE - Best-effort */
-#define        _BRCMS_PREC_EE          6       /* EE - Excellent-effort */
-#define        _BRCMS_PREC_CL          8       /* CL - Controlled Load */
-#define        _BRCMS_PREC_VI          10      /* Vi - Video */
-#define        _BRCMS_PREC_VO          12      /* Vo - Voice */
-#define        _BRCMS_PREC_NC          14      /* NC - Network Control */
-
-/* The BSS is generating beacons in HW */
-#define BRCMS_BSSCFG_HW_BCN    0x20
-
-#define        SYNTHPU_DLY_APHY_US     3700    /* a phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_BPHY_US     1050    /* b/g phy synthpu_dly time in us */
-#define        SYNTHPU_DLY_NPHY_US     2048    /* n phy REV3 synthpu_dly time in us */
-#define        SYNTHPU_DLY_LPPHY_US    300     /* lpphy synthpu_dly time in us */
-
-#define        SYNTHPU_DLY_PHY_US_QT   100     /* QT synthpu_dly time in us */
-
-#define        ANTCNT                  10      /* vanilla M_MAX_ANTCNT value */
+#define _BRCMS_PREC_NONE               0       /* None = - */
+#define _BRCMS_PREC_BK                 2       /* BK - Background */
+#define _BRCMS_PREC_BE                 4       /* BE - Best-effort */
+#define _BRCMS_PREC_EE                 6       /* EE - Excellent-effort */
+#define _BRCMS_PREC_CL                 8       /* CL - Controlled Load */
+#define _BRCMS_PREC_VI                 10      /* Vi - Video */
+#define _BRCMS_PREC_VO                 12      /* Vo - Voice */
+#define _BRCMS_PREC_NC                 14      /* NC - Network Control */
+
+/* synthpu_dly times in us */
+#define SYNTHPU_DLY_APHY_US            3700
+#define SYNTHPU_DLY_BPHY_US            1050
+#define SYNTHPU_DLY_NPHY_US            2048
+#define SYNTHPU_DLY_LPPHY_US           300
+
+#define ANTCNT                         10      /* vanilla M_MAX_ANTCNT val */
 
 /* Per-AC retry limit register definitions; uses defs.h bitfield macros */
-#define EDCF_SHORT_S            0
-#define EDCF_SFB_S              4
-#define EDCF_LONG_S             8
-#define EDCF_LFB_S              12
-#define EDCF_SHORT_M            BITFIELD_MASK(4)
-#define EDCF_SFB_M              BITFIELD_MASK(4)
-#define EDCF_LONG_M             BITFIELD_MASK(4)
-#define EDCF_LFB_M              BITFIELD_MASK(4)
+#define EDCF_SHORT_S                   0
+#define EDCF_SFB_S                     4
+#define EDCF_LONG_S                    8
+#define EDCF_LFB_S                     12
+#define EDCF_SHORT_M                   BITFIELD_MASK(4)
+#define EDCF_SFB_M                     BITFIELD_MASK(4)
+#define EDCF_LONG_M                    BITFIELD_MASK(4)
+#define EDCF_LFB_M                     BITFIELD_MASK(4)
 
-#define        RETRY_SHORT_DEF                 7       /* Default Short retry Limit */
-#define        RETRY_SHORT_MAX                 255     /* Maximum Short retry Limit */
-#define        RETRY_LONG_DEF                  4       /* Default Long retry count */
-#define        RETRY_SHORT_FB                  3 /* Short count for fallback rate */
-#define        RETRY_LONG_FB                   2 /* Long count for fallback rate */
+#define RETRY_SHORT_DEF                        7       /* Default Short retry Limit */
+#define RETRY_SHORT_MAX                        255     /* Maximum Short retry Limit */
+#define RETRY_LONG_DEF                 4       /* Default Long retry count */
+#define RETRY_SHORT_FB                 3       /* Short count for fb rate */
+#define RETRY_LONG_FB                  2       /* Long count for fb rate */
 
-#define        APHY_CWMIN              15
-#define PHY_CWMAX              1023
+#define APHY_CWMIN                     15
+#define PHY_CWMAX                      1023
 
-#define EDCF_AIFSN_MIN               1
+#define EDCF_AIFSN_MIN                 1
 
-#define FRAGNUM_MASK           0xF
+#define FRAGNUM_MASK                   0xF
 
-#define APHY_SLOT_TIME         9
-#define BPHY_SLOT_TIME         20
+#define APHY_SLOT_TIME                 9
+#define BPHY_SLOT_TIME                 20
 
-#define        WL_SPURAVOID_OFF        0
-#define        WL_SPURAVOID_ON1        1
-#define        WL_SPURAVOID_ON2        2
+#define WL_SPURAVOID_OFF               0
+#define WL_SPURAVOID_ON1               1
+#define WL_SPURAVOID_ON2               2
 
 /* invalid core flags, use the saved coreflags */
-#define BRCMS_USE_COREFLAGS    0xffffffff
+#define BRCMS_USE_COREFLAGS            0xffffffff
 
 /* values for PLCPHdr_override */
-#define BRCMS_PLCP_AUTO        -1
-#define BRCMS_PLCP_SHORT       0
-#define BRCMS_PLCP_LONG        1
+#define BRCMS_PLCP_AUTO                        -1
+#define BRCMS_PLCP_SHORT               0
+#define BRCMS_PLCP_LONG                        1
 
 /* values for g_protection_override and n_protection_override */
 #define BRCMS_PROTECTION_AUTO          -1
 #define BRCMS_PROTECTION_OFF           0
 #define BRCMS_PROTECTION_ON            1
 #define BRCMS_PROTECTION_MMHDR_ONLY    2
-#define BRCMS_PROTECTION_CTS_ONLY              3
+#define BRCMS_PROTECTION_CTS_ONLY      3
 
 /* values for g_protection_control and n_protection_control */
-#define BRCMS_PROTECTION_CTL_OFF               0
+#define BRCMS_PROTECTION_CTL_OFF       0
 #define BRCMS_PROTECTION_CTL_LOCAL     1
 #define BRCMS_PROTECTION_CTL_OVERLAP   2
 
 /* values for n_protection */
 #define BRCMS_N_PROTECTION_OFF         0
 #define BRCMS_N_PROTECTION_OPTIONAL    1
-#define BRCMS_N_PROTECTION_20IN40              2
+#define BRCMS_N_PROTECTION_20IN40      2
 #define BRCMS_N_PROTECTION_MIXEDMODE   3
 
 /* values for band specific 40MHz capabilities */
-#define BRCMS_N_BW_20ALL                       0
-#define BRCMS_N_BW_40ALL                       1
-#define BRCMS_N_BW_20IN2G_40IN5G               2
+#define BRCMS_N_BW_20ALL               0
+#define BRCMS_N_BW_40ALL               1
+#define BRCMS_N_BW_20IN2G_40IN5G       2
 
 /* bitflags for SGI support (sgi_rx iovar) */
 #define BRCMS_N_SGI_20                 0x01
@@ -282,48 +213,42 @@ static u16 frametype(u32 rspec, u8 mimoframe)
 
 /* defines used by the nrate iovar */
 /* MSC in use,indicates b0-6 holds an mcs */
-#define NRATE_MCS_INUSE        0x00000080
+#define NRATE_MCS_INUSE                        0x00000080
 /* rate/mcs value */
-#define NRATE_RATE_MASK 0x0000007f
+#define NRATE_RATE_MASK                        0x0000007f
 /* stf mode mask: siso, cdd, stbc, sdm */
-#define NRATE_STF_MASK 0x0000ff00
+#define NRATE_STF_MASK                 0x0000ff00
 /* stf mode shift */
-#define NRATE_STF_SHIFT        8
-/* bit indicates override both rate & mode */
-#define NRATE_OVERRIDE 0x80000000
+#define NRATE_STF_SHIFT                        8
 /* bit indicate to override mcs only */
-#define NRATE_OVERRIDE_MCS_ONLY 0x40000000
-#define NRATE_SGI_MASK  0x00800000     /* sgi mode */
-#define NRATE_SGI_SHIFT 23     /* sgi mode */
-#define NRATE_LDPC_CODING 0x00400000   /* bit indicates adv coding in use */
-#define NRATE_LDPC_SHIFT 22    /* ldpc shift */
+#define NRATE_OVERRIDE_MCS_ONLY                0x40000000
+#define NRATE_SGI_MASK                 0x00800000      /* sgi mode */
+#define NRATE_SGI_SHIFT                        23              /* sgi mode */
+#define NRATE_LDPC_CODING              0x00400000      /* adv coding in use */
+#define NRATE_LDPC_SHIFT               22              /* ldpc shift */
 
-#define NRATE_STF_SISO 0       /* stf mode SISO */
-#define NRATE_STF_CDD  1       /* stf mode CDD */
-#define NRATE_STF_STBC 2       /* stf mode STBC */
-#define NRATE_STF_SDM  3       /* stf mode SDM */
+#define NRATE_STF_SISO                 0               /* stf mode SISO */
+#define NRATE_STF_CDD                  1               /* stf mode CDD */
+#define NRATE_STF_STBC                 2               /* stf mode STBC */
+#define NRATE_STF_SDM                  3               /* stf mode SDM */
 
-#define MAX_DMA_SEGS 4
+#define MAX_DMA_SEGS                   4
 
 /* Max # of entries in Tx FIFO based on 4kb page size */
-#define NTXD           256
+#define NTXD                           256
 /* Max # of entries in Rx FIFO based on 4kb page size */
-#define NRXD           256
+#define NRXD                           256
 
 /* try to keep this # rbufs posted to the chip */
-#define        NRXBUFPOST      32
+#define NRXBUFPOST                     32
 
 /* data msg txq hiwat mark */
-#define BRCMS_DATAHIWAT                50
+#define BRCMS_DATAHIWAT                        50
 
-/* bounded rx loops */
-#define RXBND          8 /* max # frames to process in brcms_c_recv() */
-#define TXSBND         8 /* max # tx status to process in wlc_txstatus() */
-
-/*
- * 32 SSID chars, max of 4 chars for each SSID char "\xFF", plus NULL.
- */
-#define SSID_FMT_BUF_LEN       ((4 * IEEE80211_MAX_SSID_LEN) + 1)
+/* max # frames to process in brcms_c_recv() */
+#define RXBND                          8
+/* max # tx status to process in wlc_txstatus() */
+#define TXSBND                         8
 
 /* brcmu_format_flags() bit description structure */
 struct brcms_c_bit_desc {
@@ -375,10 +300,22 @@ uint brcm_msg_level =
 #endif                         /* BCMDBG */
 
 /* TX FIFO number to WME/802.1E Access Category */
-static const u8 wme_fifo2ac[] = { AC_BK, AC_BE, AC_VI, AC_VO, AC_BE, AC_BE };
+static const u8 wme_fifo2ac[] = {
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BE
+};
 
-/* WME/802.1E Access Category to TX FIFO number */
-static const u8 wme_ac2fifo[] = { 1, 0, 2, 3 };
+/* ieee80211 Access Category to TX FIFO number */
+static const u8 wme_ac2fifo[] = {
+       TX_AC_VO_FIFO,
+       TX_AC_VI_FIFO,
+       TX_AC_BE_FIFO,
+       TX_AC_BK_FIFO
+};
 
 /* 802.1D Priority to precedence queue mapping */
 const u8 wlc_prio2prec_map[] = {
@@ -405,13 +342,6 @@ static const u16 xmtfifo_sz[][NFIFO] = {
        {9, 58, 22, 14, 14, 5},
 };
 
-static const u8 acbitmap2maxprio[] = {
-       PRIO_8021D_BE, PRIO_8021D_BE, PRIO_8021D_BK, PRIO_8021D_BK,
-       PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI, PRIO_8021D_VI,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO,
-       PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO, PRIO_8021D_VO
-};
-
 #ifdef BCMDBG
 static const char * const fifo_names[] = {
        "AC_BK", "AC_BE", "AC_VI", "AC_VO", "BCMC", "ATIM" };
@@ -424,6 +354,22 @@ static const char fifo_names[6][0];
 static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
 #endif
 
+/* Find basic rate for a given rate */
+static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
+{
+       if (is_mcs_rate(rspec))
+               return wlc->band->basic_rate[mcs_table[rspec & RSPEC_RATE_MASK]
+                      .leg_ofdm];
+       return wlc->band->basic_rate[rspec & RSPEC_RATE_MASK];
+}
+
+static u16 frametype(u32 rspec, u8 mimoframe)
+{
+       if (is_mcs_rate(rspec))
+               return mimoframe;
+       return is_cck_rate(rspec) ? FT_CCK : FT_OFDM;
+}
+
 /* currently the best mechanism for determining SIFS is the band in use */
 static u16 get_sifs(struct brcms_band *band)
 {
@@ -470,20 +416,6 @@ static int brcms_chspec_bw(u16 chanspec)
        return BRCMS_10_MHZ;
 }
 
-/*
- * return true if Minimum Power Consumption should
- * be entered, false otherwise
- */
-static bool brcms_c_is_non_delay_mpc(struct brcms_c_info *wlc)
-{
-       return false;
-}
-
-static bool brcms_c_ismpc(struct brcms_c_info *wlc)
-{
-       return (wlc->mpc_delay_off == 0) && (brcms_c_is_non_delay_mpc(wlc));
-}
-
 static void brcms_c_bsscfg_mfree(struct brcms_bss_cfg *cfg)
 {
        if (cfg == NULL)
@@ -669,9 +601,8 @@ static void brcms_b_update_slot_timing(struct brcms_hardware *wlc_hw,
  * calculate frame duration of a given rate and length, return
  * time in usec unit
  */
-uint
-brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
-                       u8 preamble_type, uint mac_len)
+static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
+                                   u8 preamble_type, uint mac_len)
 {
        uint nsyms, dur = 0, Ndps, kNdps;
        uint rate = rspec2rate(ratespec);
@@ -969,7 +900,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                    lfbl,       /* Long Frame Rate Fallback Limit */
                    fbl;
 
-               if (queue < AC_COUNT) {
+               if (queue < IEEE80211_NUM_ACS) {
                        sfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
                                      EDCF_SFB);
                        lfbl = GFIELD(wlc->wme_retries[wme_fifo2ac[queue]],
@@ -1018,7 +949,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
                        tx_info->flags |= IEEE80211_TX_STAT_ACK;
        }
 
-       totlen = brcmu_pkttotlen(p);
+       totlen = p->len;
        free_pdu = true;
 
        brcms_c_txfifo_complete(wlc, queue, 1);
@@ -2352,13 +2283,6 @@ void brcms_b_antsel_type_set(struct brcms_hardware *wlc_hw, u8 antsel_type)
        wlc_phy_antsel_type_set(wlc_hw->band->pi, antsel_type);
 }
 
-static void brcms_c_fatal_error(struct brcms_c_info *wlc)
-{
-       wiphy_err(wlc->wiphy, "wl%d: fatal error, reinitializing\n",
-                 wlc->pub->unit);
-       brcms_init(wlc->wl);
-}
-
 static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
 {
        bool fatal = false;
@@ -2414,7 +2338,7 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
                }
 
                if (fatal) {
-                       brcms_c_fatal_error(wlc_hw->wlc);       /* big hammer */
+                       brcms_fatal_error(wlc_hw->wlc->wl); /* big hammer */
                        break;
                } else
                        W_REG(&regs->intctrlregs[idx].intstatus,
@@ -2479,6 +2403,7 @@ void brcms_c_intrsrestore(struct brcms_c_info *wlc, u32 macintmask)
        W_REG(&wlc_hw->regs->macintmask, wlc->macintmask);
 }
 
+/* assumes that the d11 MAC is enabled */
 static void brcms_b_tx_fifo_suspend(struct brcms_hardware *wlc_hw,
                                    uint tx_fifo)
 {
@@ -2535,11 +2460,12 @@ static void brcms_b_tx_fifo_resume(struct brcms_hardware *wlc_hw,
        }
 }
 
-static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
+/* precondition: requires the mac core to be enabled */
+static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool mute_tx)
 {
        static const u8 null_ether_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0};
 
-       if (on) {
+       if (mute_tx) {
                /* suspend tx fifos */
                brcms_b_tx_fifo_suspend(wlc_hw, TX_DATA_FIFO);
                brcms_b_tx_fifo_suspend(wlc_hw, TX_CTL_FIFO);
@@ -2561,14 +2487,20 @@ static void brcms_b_mute(struct brcms_hardware *wlc_hw, bool on, u32 flags)
                                       wlc_hw->etheraddr);
        }
 
-       wlc_phy_mute_upd(wlc_hw->band->pi, on, flags);
+       wlc_phy_mute_upd(wlc_hw->band->pi, mute_tx, 0);
 
-       if (on)
+       if (mute_tx)
                brcms_c_ucode_mute_override_set(wlc_hw);
        else
                brcms_c_ucode_mute_override_clear(wlc_hw);
 }
 
+void
+brcms_c_mute(struct brcms_c_info *wlc, bool mute_tx)
+{
+       brcms_b_mute(wlc->hw, mute_tx);
+}
+
 /*
  * Read and clear macintmask and macintstatus and intstatus registers.
  * This routine should be called with interrupts off
@@ -3437,8 +3369,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
 }
 
 void
-static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
-                         bool mute) {
+static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
        u32 macintmask;
        bool fastclk;
        struct brcms_c_info *wlc = wlc_hw->wlc;
@@ -3463,10 +3394,6 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec,
        /* core-specific initialization */
        brcms_b_coreinit(wlc);
 
-       /* suspend the tx fifos and mute the phy for preism cac time */
-       if (mute)
-               brcms_b_mute(wlc_hw, ON, PHY_MUTE_FOR_PREISM);
-
        /* band-specific inits */
        brcms_b_bsinit(wlc, chanspec);
 
@@ -3656,42 +3583,30 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
        brcms_c_set_phy_chanspec(wlc, chanspec);
 }
 
-static void brcms_c_mac_bcn_promisc(struct brcms_c_info *wlc)
-{
-       if (wlc->bcnmisc_monitor)
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, MCTL_BCNS_PROMISC);
-       else
-               brcms_b_mctrl(wlc->hw, MCTL_BCNS_PROMISC, 0);
-}
-
-void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
-{
-       wlc->bcnmisc_monitor = promisc;
-       brcms_c_mac_bcn_promisc(wlc);
-}
-
-/* set or clear maccontrol bits MCTL_PROMISC and MCTL_KEEPCONTROL */
+/*
+ * Set or clear maccontrol bits MCTL_PROMISC, MCTL_BCNS_PROMISC and
+ * MCTL_KEEPCONTROL
+ */
 static void brcms_c_mac_promisc(struct brcms_c_info *wlc)
 {
        u32 promisc_bits = 0;
 
-       /*
-        * promiscuous mode just sets MCTL_PROMISC
-        * Note: APs get all BSS traffic without the need to set
-        * the MCTL_PROMISC bit since all BSS data traffic is
-        * directed at the AP
-        */
-       if (wlc->pub->promisc)
-               promisc_bits |= MCTL_PROMISC;
+       if (wlc->bcnmisc_monitor)
+               promisc_bits |= MCTL_BCNS_PROMISC;
 
-       /* monitor mode needs both MCTL_PROMISC and MCTL_KEEPCONTROL
-        * Note: monitor mode also needs MCTL_BCNS_PROMISC, but that is
-        * handled in brcms_c_mac_bcn_promisc()
-        */
        if (wlc->monitor)
-               promisc_bits |= MCTL_PROMISC | MCTL_KEEPCONTROL;
+               promisc_bits |=
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL;
 
-       brcms_b_mctrl(wlc->hw, MCTL_PROMISC | MCTL_KEEPCONTROL, promisc_bits);
+       brcms_b_mctrl(wlc->hw,
+                       MCTL_PROMISC | MCTL_BCNS_PROMISC | MCTL_KEEPCONTROL,
+                       promisc_bits);
+}
+
+void brcms_c_mac_bcn_promisc_change(struct brcms_c_info *wlc, bool promisc)
+{
+       wlc->bcnmisc_monitor = promisc;
+       brcms_c_mac_promisc(wlc);
 }
 
 /*
@@ -3723,7 +3638,6 @@ static void brcms_c_ucode_mac_upd(struct brcms_c_info *wlc)
        }
 
        /* update the various promisc bits */
-       brcms_c_mac_bcn_promisc(wlc);
        brcms_c_mac_promisc(wlc);
 }
 
@@ -3979,7 +3893,7 @@ static void brcms_c_set_home_chanspec(struct brcms_c_info *wlc, u16 chanspec)
 
 void
 brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
-                     bool mute, struct txpwr_limits *txpwr)
+                     bool mute_tx, struct txpwr_limits *txpwr)
 {
        uint bandunit;
 
@@ -4005,7 +3919,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                }
        }
 
-       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute);
+       wlc_phy_initcal_enable(wlc_hw->band->pi, !mute_tx);
 
        if (!wlc_hw->up) {
                if (wlc_hw->clk)
@@ -4017,7 +3931,7 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
                wlc_phy_txpower_limit_set(wlc_hw->band->pi, txpwr, chanspec);
 
                /* Update muting of the channel */
-               brcms_b_mute(wlc_hw, mute, 0);
+               brcms_b_mute(wlc_hw, mute_tx);
        }
 }
 
@@ -4205,7 +4119,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
            EDCF_TXOP2USEC(acp_shm.txop);
        acp_shm.aifs = (params->aifs & EDCF_AIFSN_MASK);
 
-       if (aci == AC_VI && acp_shm.txop == 0
+       if (aci == IEEE80211_AC_VI && acp_shm.txop == 0
            && acp_shm.aifs < EDCF_AIFSN_MAX)
                acp_shm.aifs++;
 
@@ -4242,7 +4156,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
        }
 }
 
-void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
+static void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
 {
        u16 aci;
        int i_ac;
@@ -4255,7 +4169,7 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }; /* ucode needs these parameters during its initialization */
        const struct edcf_acparam *edcf_acp = &default_edcf_acparams[0];
 
-       for (i_ac = 0; i_ac < AC_COUNT; i_ac++, edcf_acp++) {
+       for (i_ac = 0; i_ac < IEEE80211_NUM_ACS; i_ac++, edcf_acp++) {
                /* find out which ac this set of params applies to */
                aci = (edcf_acp->ACI & EDCF_ACI_MASK) >> EDCF_ACI_SHIFT;
 
@@ -4277,17 +4191,6 @@ void brcms_c_edcf_setparams(struct brcms_c_info *wlc, bool suspend)
        }
 }
 
-/* maintain LED behavior in down state */
-static void brcms_c_down_led_upd(struct brcms_c_info *wlc)
-{
-       /*
-        * maintain LEDs while in down state, turn on sbclk if
-        * not available yet. Turn on sbclk if necessary
-        */
-       brcms_b_pllreq(wlc->hw, true, BRCMS_PLLREQ_FLIP);
-       brcms_b_pllreq(wlc->hw, false, BRCMS_PLLREQ_FLIP);
-}
-
 static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
 {
        /* Don't start the timer if HWRADIO feature is disabled */
@@ -4299,28 +4202,6 @@ static void brcms_c_radio_monitor_start(struct brcms_c_info *wlc)
        brcms_add_timer(wlc->radio_timer, TIMER_INTERVAL_RADIOCHK, true);
 }
 
-static void brcms_c_radio_disable(struct brcms_c_info *wlc)
-{
-       if (!wlc->pub->up) {
-               brcms_c_down_led_upd(wlc);
-               return;
-       }
-
-       brcms_c_radio_monitor_start(wlc);
-       brcms_down(wlc->wl);
-}
-
-static void brcms_c_radio_enable(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->up)
-               return;
-
-       if (brcms_deviceremoved(wlc))
-               return;
-
-       brcms_up(wlc->wl);
-}
-
 static bool brcms_c_radio_monitor_stop(struct brcms_c_info *wlc)
 {
        if (!wlc->radio_monitor)
@@ -4343,18 +4224,6 @@ static void brcms_c_radio_hwdisable_upd(struct brcms_c_info *wlc)
                mboolclr(wlc->pub->radio_disabled, WL_RADIO_HW_DISABLE);
 }
 
-/*
- * centralized radio disable/enable function,
- * invoke radio enable/disable after updating hwradio status
- */
-static void brcms_c_radio_upd(struct brcms_c_info *wlc)
-{
-       if (wlc->pub->radio_disabled)
-               brcms_c_radio_disable(wlc);
-       else
-               brcms_c_radio_enable(wlc);
-}
-
 /* update hwradio status and return it */
 bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc)
 {
@@ -4376,12 +4245,7 @@ static void brcms_c_radio_timer(void *arg)
                return;
        }
 
-       /* cap mpc off count */
-       if (wlc->mpc_offcnt < BRCMS_MPC_MAX_DELAYCNT)
-               wlc->mpc_offcnt++;
-
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
 }
 
 /* common low-level watchdog code */
@@ -4407,60 +4271,6 @@ static void brcms_b_watchdog(void *arg)
        wlc_phy_watchdog(wlc_hw->band->pi);
 }
 
-static void brcms_c_radio_mpc_upd(struct brcms_c_info *wlc)
-{
-       bool mpc_radio, radio_state;
-
-       /*
-        * Clear the WL_RADIO_MPC_DISABLE bit when mpc feature is disabled
-        * in case the WL_RADIO_MPC_DISABLE bit was set. Stop the radio
-        * monitor also when WL_RADIO_MPC_DISABLE is the only reason that
-        * the radio is going down.
-        */
-       if (!wlc->mpc) {
-               if (!wlc->pub->radio_disabled)
-                       return;
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (!wlc->pub->radio_disabled)
-                       brcms_c_radio_monitor_stop(wlc);
-               return;
-       }
-
-       /*
-        * sync ismpc logic with WL_RADIO_MPC_DISABLE bit in
-        * wlc->pub->radio_disabled to go ON, always call radio_upd
-        * synchronously to go OFF, postpone radio_upd to later when
-        * context is safe(e.g. watchdog)
-        */
-       radio_state =
-           (mboolisset(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE) ? OFF :
-            ON);
-       mpc_radio = (brcms_c_ismpc(wlc) == true) ? OFF : ON;
-
-       if (radio_state == ON && mpc_radio == OFF)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-       else if (radio_state == OFF && mpc_radio == ON) {
-               mboolclr(wlc->pub->radio_disabled, WL_RADIO_MPC_DISABLE);
-               brcms_c_radio_upd(wlc);
-               if (wlc->mpc_offcnt < BRCMS_MPC_THRESHOLD)
-                       wlc->mpc_dlycnt = BRCMS_MPC_MAX_DELAYCNT;
-               else
-                       wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-       }
-       /*
-        * Below logic is meant to capture the transition from mpc off
-        * to mpc on for reasons other than wlc->mpc_delay_off keeping
-        * the mpc off. In that case reset wlc->mpc_delay_off to
-        * wlc->mpc_dlycnt, so that we restart the countdown of mpc_delay_off
-        */
-       if ((wlc->prev_non_delay_mpc == false) &&
-           (brcms_c_is_non_delay_mpc(wlc) == true) && wlc->mpc_delay_off)
-               wlc->mpc_delay_off = wlc->mpc_dlycnt;
-
-       wlc->prev_non_delay_mpc = brcms_c_is_non_delay_mpc(wlc);
-}
-
 /* common watchdog code */
 static void brcms_c_watchdog(void *arg)
 {
@@ -4481,21 +4291,7 @@ static void brcms_c_watchdog(void *arg)
        /* increment second count */
        wlc->pub->now++;
 
-       /* delay radio disable */
-       if (wlc->mpc_delay_off) {
-               if (--wlc->mpc_delay_off == 0) {
-                       mboolset(wlc->pub->radio_disabled,
-                                WL_RADIO_MPC_DISABLE);
-                       if (wlc->mpc && brcms_c_ismpc(wlc))
-                               wlc->mpc_offcnt = 0;
-               }
-       }
-
-       /* mpc sync */
-       brcms_c_radio_mpc_upd(wlc);
-       /* radio sync: sw/hw/mpc --> radio_disable/radio_enable */
        brcms_c_radio_hwdisable_upd(wlc);
-       brcms_c_radio_upd(wlc);
        /* if radio is disable, driver may be down, quit here */
        if (wlc->pub->radio_disabled)
                return;
@@ -4599,9 +4395,6 @@ static void brcms_c_info_init(struct brcms_c_info *wlc, int unit)
        /* WME QoS mode is Auto by default */
        wlc->pub->_ampdu = AMPDU_AGG_HOST;
        wlc->pub->bcmerror = 0;
-
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
 }
 
 static uint brcms_c_attach_module(struct brcms_c_info *wlc)
@@ -5259,9 +5052,6 @@ static void brcms_c_ap_upd(struct brcms_c_info *wlc)
 {
        /* STA-BSS; short capable */
        wlc->PLCPHdr_override = BRCMS_PLCP_SHORT;
-
-       /* fixup mpc */
-       wlc->mpc = true;
 }
 
 /* Initialize just the hardware when coming out of POR or S3/S5 system states */
@@ -5376,7 +5166,7 @@ static void brcms_c_wme_retries_write(struct brcms_c_info *wlc)
        if (!wlc->clk)
                return;
 
-       for (ac = 0; ac < AC_COUNT; ac++)
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                brcms_b_write_shm(wlc->hw, M_AC_TXLMT_ADDR(ac),
                                  wlc->wme_retries[ac]);
 }
@@ -5575,7 +5365,6 @@ uint brcms_c_down(struct brcms_c_info *wlc)
        if (!wlc->pub->up)
                return callbacks;
 
-       /* in between, mpc could try to bring down again.. */
        wlc->going_down = true;
 
        callbacks += brcms_b_bmac_down_prep(wlc->hw);
@@ -5852,7 +5641,7 @@ int brcms_c_set_rate_limit(struct brcms_c_info *wlc, u16 srl, u16 lrl)
 
        brcms_b_retrylimit_upd(wlc->hw, wlc->SRL, wlc->LRL);
 
-       for (ac = 0; ac < AC_COUNT; ac++) {
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
                                               EDCF_SHORT,  wlc->SRL);
                wlc->wme_retries[ac] =  SFIELD(wlc->wme_retries[ac],
@@ -6103,7 +5892,6 @@ void brcms_c_print_txdesc(struct d11txh *txh)
 
        u8 *rtsph = txh->RTSPhyHeader;
        struct ieee80211_rts rts = txh->rts_frame;
-       char hexbuf[256];
 
        /* add plcp header along with txh descriptor */
        printk(KERN_DEBUG "Raw TxDesc + plcp header:\n");
@@ -6124,17 +5912,16 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "XtraFrameTypes: %04x ", xtraft);
        printk(KERN_DEBUG "\n");
 
-       brcmu_format_hex(hexbuf, iv, sizeof(txh->IV));
-       printk(KERN_DEBUG "SecIV:       %s\n", hexbuf);
-       brcmu_format_hex(hexbuf, ra, sizeof(txh->TxFrameRA));
-       printk(KERN_DEBUG "RA:          %s\n", hexbuf);
+       print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV));
+       print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET,
+                            ra, sizeof(txh->TxFrameRA));
 
        printk(KERN_DEBUG "Fb FES Time: %04x ", tfestfb);
-       brcmu_format_hex(hexbuf, rtspfb, sizeof(txh->RTSPLCPFallback));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtspfb, sizeof(txh->RTSPLCPFallback));
        printk(KERN_DEBUG "RTS DUR: %04x ", rtsdfb);
-       brcmu_format_hex(hexbuf, fragpfb, sizeof(txh->FragPLCPFallback));
-       printk(KERN_DEBUG "PLCP: %s ", hexbuf);
+       print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET,
+                            fragpfb, sizeof(txh->FragPLCPFallback));
        printk(KERN_DEBUG "DUR: %04x", fragdfb);
        printk(KERN_DEBUG "\n");
 
@@ -6149,18 +5936,18 @@ void brcms_c_print_txdesc(struct d11txh *txh)
        printk(KERN_DEBUG "MaxAggbyte_fb:  %04x\n", mabyte_f);
        printk(KERN_DEBUG "MinByte:     %04x\n", mmbyte);
 
-       brcmu_format_hex(hexbuf, rtsph, sizeof(txh->RTSPhyHeader));
-       printk(KERN_DEBUG "RTS PLCP: %s ", hexbuf);
-       brcmu_format_hex(hexbuf, (u8 *) &rts, sizeof(txh->rts_frame));
-       printk(KERN_DEBUG "RTS Frame: %s", hexbuf);
+       print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET,
+                            rtsph, sizeof(txh->RTSPhyHeader));
+       print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET,
+                            (u8 *)&rts, sizeof(txh->rts_frame));
        printk(KERN_DEBUG "\n");
 }
 #endif                         /* defined(BCMDBG) */
 
 #if defined(BCMDBG)
-int
+static int
 brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
-                  int len)
+                    int len)
 {
        int i;
        char *p = buf;
@@ -6916,7 +6703,7 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        qos = ieee80211_is_data_qos(h->frame_control);
 
        /* compute length of frame in bytes for use in PLCP computations */
-       len = brcmu_pkttotlen(p);
+       len = p->len;
        phylen = len + FCS_LEN;
 
        /* Get tx_info */
@@ -8253,12 +8040,6 @@ int brcms_c_get_tx_power(struct brcms_c_info *wlc)
        return (int)(qdbm / BRCMS_TXPWR_DB_FACTOR);
 }
 
-void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc)
-{
-       wlc->mpc = mpc;
-       brcms_c_radio_mpc_upd(wlc);
-}
-
 /* Process received frames */
 /*
  * Return true if more frames need to be processed. false otherwise.
@@ -8328,21 +8109,17 @@ static bool
 brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
 {
        struct sk_buff *p;
-       struct sk_buff *head = NULL;
-       struct sk_buff *tail = NULL;
+       struct sk_buff *next = NULL;
+       struct sk_buff_head recv_frames;
+
        uint n = 0;
        uint bound_limit = bound ? RXBND : -1;
 
        BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-       /* gather received frames */
-       while ((p = dma_rx(wlc_hw->di[fifo]))) {
+       skb_queue_head_init(&recv_frames);
 
-               if (!tail)
-                       head = tail = p;
-               else {
-                       tail->prev = p;
-                       tail = p;
-               }
+       /* gather received frames */
+       while (dma_rx(wlc_hw->di[fifo], &recv_frames)) {
 
                /* !give others some time to run! */
                if (++n >= bound_limit)
@@ -8353,12 +8130,11 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
        dma_rxfill(wlc_hw->di[fifo]);
 
        /* process each frame */
-       while ((p = head) != NULL) {
+       skb_queue_walk_safe(&recv_frames, p, next) {
                struct d11rxhdr_le *rxh_le;
                struct d11rxhdr *rxh;
-               head = head->prev;
-               p->prev = NULL;
 
+               skb_unlink(p, &recv_frames);
                rxh_le = (struct d11rxhdr_le *)p->data;
                rxh = (struct d11rxhdr *)p->data;
 
@@ -8448,8 +8224,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
                                        __func__, wlc_hw->sih->chip,
                                        wlc_hw->sih->chiprev);
-               /* big hammer */
-               brcms_init(wlc->wl);
+               brcms_fatal_error(wlc_hw->wlc->wl);
        }
 
        /* gptimer timeout */
@@ -8470,15 +8245,14 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
        return wlc->macintstatus != 0;
 
  fatal:
-       brcms_init(wlc->wl);
+       brcms_fatal_error(wlc_hw->wlc->wl);
        return wlc->macintstatus != 0;
 }
 
-void brcms_c_init(struct brcms_c_info *wlc)
+void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
 {
        struct d11regs __iomem *regs;
        u16 chanspec;
-       bool mute = false;
 
        BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
 
@@ -8494,7 +8268,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
        else
                chanspec = brcms_c_init_chanspec(wlc);
 
-       brcms_b_init(wlc->hw, chanspec, mute);
+       brcms_b_init(wlc->hw, chanspec);
 
        /* update beacon listen interval */
        brcms_c_bcn_li_upd(wlc);
@@ -8560,15 +8334,16 @@ void brcms_c_init(struct brcms_c_info *wlc)
        /* ..now really unleash hell (allow the MAC out of suspend) */
        brcms_c_enable_mac(wlc);
 
+       /* suspend the tx fifos and mute the phy for preism cac time */
+       if (mute_tx)
+               brcms_b_mute(wlc->hw, true);
+
        /* clear tx flow control */
        brcms_c_txflowcontrol_reset(wlc);
 
        /* enable the RF Disable Delay timer */
        W_REG(&wlc->regs->rfdisabledly, RFDISABLE_DEFAULT);
 
-       /* initialize mpc delay */
-       wlc->mpc_delay_off = wlc->mpc_dlycnt = BRCMS_MPC_MIN_DELAYCNT;
-
        /*
         * Initialize WME parameters; if they haven't been set by some other
         * mechanism (IOVar, etc) then read them from the hardware.
@@ -8577,7 +8352,7 @@ void brcms_c_init(struct brcms_c_info *wlc)
                /* Uninitialized; read from HW */
                int ac;
 
-               for (ac = 0; ac < AC_COUNT; ac++)
+               for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
                        wlc->wme_retries[ac] =
                            brcms_b_read_shm(wlc->hw, M_AC_TXLMT_ADDR(ac));
        }
@@ -8754,8 +8529,6 @@ brcms_c_attach(struct brcms_info *wl, u16 vendor, u16 device, uint unit,
                brcms_c_ht_update_sgi_rx(wlc, 0);
        }
 
-       /* initialize radio_mpc_disable according to wlc->mpc */
-       brcms_c_radio_mpc_upd(wlc);
        brcms_b_antsel_set(wlc->hw, wlc->asi->antsel_avail);
 
        if (perr)
index c0e0fcfdfaf8e7988e5ec6d22919df019218f08e..251c350b3164567fdc979aee8a22dd53217c274e 100644 (file)
@@ -44,8 +44,6 @@
 /* transmit buffer max headroom for protocol headers */
 #define TXOFF (D11_TXH_LEN + D11_PHY_HDR_LEN)
 
-#define AC_COUNT               4
-
 /* Macros for doing definition and get/set of bitfields
  * Usage example, e.g. a three-bit field (bits 4-6):
  *    #define <NAME>_M BITFIELD_MASK(3)
@@ -427,11 +425,6 @@ struct brcms_txq_info {
  * bandinit_pending: track band init in auto band.
  * radio_monitor: radio timer is running.
  * going_down: down path intermediate variable.
- * mpc: enable minimum power consumption.
- * mpc_dlycnt: # of watchdog cnt before turn disable radio.
- * mpc_offcnt: # of watchdog cnt that radio is disabled.
- * mpc_delay_off: delay radio disable by # of watchdog cnt.
- * prev_non_delay_mpc: prev state brcms_c_is_non_delay_mpc.
  * wdtimer: timer for watchdog routine.
  * radio_timer: timer for hw radio button monitor routine.
  * monitor: monitor (MPDU sniffing) mode.
@@ -441,7 +434,7 @@ struct brcms_txq_info {
  * bcn_li_dtim: beacon listen interval in # dtims.
  * WDarmed: watchdog timer is armed.
  * WDlast: last time wlc_watchdog() was called.
- * edcf_txop[AC_COUNT]: current txop for each ac.
+ * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac.
  * wme_retries: per-AC retry limits.
  * tx_prec_map: Precedence map based on HW FIFO space.
  * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
@@ -522,12 +515,6 @@ struct brcms_c_info {
        bool radio_monitor;
        bool going_down;
 
-       bool mpc;
-       u8 mpc_dlycnt;
-       u8 mpc_offcnt;
-       u8 mpc_delay_off;
-       u8 prev_non_delay_mpc;
-
        struct brcms_timer *wdtimer;
        struct brcms_timer *radio_timer;
 
@@ -546,9 +533,9 @@ struct brcms_c_info {
        u32 WDlast;
 
        /* WME */
-       u16 edcf_txop[AC_COUNT];
+       u16 edcf_txop[IEEE80211_NUM_ACS];
 
-       u16 wme_retries[AC_COUNT];
+       u16 wme_retries[IEEE80211_NUM_ACS];
        u16 tx_prec_map;
        u16 fifo2prec_map[NFIFO];
 
index a3149254cbcdadc9bdae753ec4300cf7904199c4..e17edf7e68335396d3de606681e61681d4ae0192 100644 (file)
@@ -112,7 +112,7 @@ static const struct chan_info_basic chan_info_all[] = {
        {216, 50800}
 };
 
-const u8 ofdm_rate_lookup[] = {
+static const u8 ofdm_rate_lookup[] = {
 
        BRCM_RATE_48M,
        BRCM_RATE_24M,
@@ -190,15 +190,7 @@ u16 read_radio_reg(struct brcms_phy *pi, u16 addr)
                data = R_REG(&pi->regs->radioregdata);
        } else {
                W_REG_FLUSH(&pi->regs->phy4waddr, addr);
-
-#ifdef __ARM_ARCH_4T__
-               __asm__(" .align 4 ");
-               __asm__(" nop ");
-               data = R_REG(&pi->regs->phy4wdatalo);
-#else
                data = R_REG(&pi->regs->phy4wdatalo);
-#endif
-
        }
        pi->phy_wreg = 0;
 
index bea85241a244630cc8be4baf9693ea5cb0a91676..5f9478b1c9937be8e0ea94061a390d409b4814a8 100644 (file)
@@ -774,11 +774,6 @@ struct brcms_phy {
        s16 nphy_noise_win[PHY_CORE_MAX][PHY_NOISE_WINDOW_SZ];
        u8 nphy_noise_index;
 
-       u8 nphy_txpid2g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5g[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gl[PHY_CORE_NUM_2];
-       u8 nphy_txpid5gh[PHY_CORE_NUM_2];
-
        bool nphy_gain_boost;
        bool nphy_elna_gain_config;
        u16 old_bphy_test;
index cd19c2f7a34776bc96ee29cf9070bb0cfe524933..ec9b56639d544fed3c60d46fc0ed4a021407a96d 100644 (file)
@@ -29,6 +29,7 @@
 #include "phy_radio.h"
 #include "phyreg_n.h"
 #include "phytbl_n.h"
+#include "soc.h"
 
 #define READ_RADIO_REG2(pi, radio_type, jspace, core, reg_name)        \
        read_radio_reg(pi, radio_type##_##jspace##_##reg_name | \
@@ -14417,12 +14418,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                switch (band_num) {
                case 0:
 
-                       pi->nphy_txpid2g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA0);
-                       pi->nphy_txpid2g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID2GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP2GA0);
@@ -14486,12 +14481,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 1:
 
-                       pi->nphy_txpid5g[PHY_CORE_0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA0);
-                       pi->nphy_txpid5g[PHY_CORE_1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GA1);
                        pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
                                (s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
                        pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
@@ -14551,12 +14540,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 2:
 
-                       pi->nphy_txpid5gl[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA0);
-                       pi->nphy_txpid5gl[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GLA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gl =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GLA0);
@@ -14615,12 +14598,6 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
                        break;
                case 3:
 
-                       pi->nphy_txpid5gh[0] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA0);
-                       pi->nphy_txpid5gh[1] =
-                               (u8) wlapi_getintvar(shim,
-                                                    BRCMS_SROM_TXPID5GHA1);
                        pi->nphy_pwrctrl_info[0].max_pwr_5gh =
                                (s8) wlapi_getintvar(shim,
                                                     BRCMS_SROM_MAXP5GHA0);
@@ -27994,20 +27971,11 @@ void wlc_phy_txpwr_fixpower_nphy(struct brcms_phy *pi)
                chan_freq_range = wlc_phy_get_chan_freq_range_nphy(pi, 0);
                switch (chan_freq_range) {
                case WL_CHAN_FREQ_RANGE_2G:
-                       txpi[0] = pi->nphy_txpid2g[0];
-                       txpi[1] = pi->nphy_txpid2g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GL:
-                       txpi[0] = pi->nphy_txpid5gl[0];
-                       txpi[1] = pi->nphy_txpid5gl[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GM:
-                       txpi[0] = pi->nphy_txpid5g[0];
-                       txpi[1] = pi->nphy_txpid5g[1];
-                       break;
                case WL_CHAN_FREQ_RANGE_5GH:
-                       txpi[0] = pi->nphy_txpid5gh[0];
-                       txpi[1] = pi->nphy_txpid5gh[1];
+                       txpi[0] = 0;
+                       txpi[1] = 0;
                        break;
                default:
                        txpi[0] = txpi[1] = 91;
index 3b36e3acfd74cb77672af14596dcb8c4c2edc7fa..12ba575f578559031226a91a7555c44ee33d6698 100644 (file)
@@ -23,6 +23,7 @@
 #include "pub.h"
 #include "aiutils.h"
 #include "pmu.h"
+#include "soc.h"
 
 /*
  * external LPO crystal frequency
index 37bb2dcc113f179d990d7d9007d779d26e95540e..21ccf3a039873cf777595e0e5a71ff8eb93a94a1 100644 (file)
@@ -170,22 +170,6 @@ enum brcms_srom_id {
        BRCMS_SROM_TSSIPOS2G,
        BRCMS_SROM_TSSIPOS5G,
        BRCMS_SROM_TXCHAIN,
-       BRCMS_SROM_TXPID2GA0,
-       BRCMS_SROM_TXPID2GA1,
-       BRCMS_SROM_TXPID2GA2,
-       BRCMS_SROM_TXPID2GA3,
-       BRCMS_SROM_TXPID5GA0,
-       BRCMS_SROM_TXPID5GA1,
-       BRCMS_SROM_TXPID5GA2,
-       BRCMS_SROM_TXPID5GA3,
-       BRCMS_SROM_TXPID5GHA0,
-       BRCMS_SROM_TXPID5GHA1,
-       BRCMS_SROM_TXPID5GHA2,
-       BRCMS_SROM_TXPID5GHA3,
-       BRCMS_SROM_TXPID5GLA0,
-       BRCMS_SROM_TXPID5GLA1,
-       BRCMS_SROM_TXPID5GLA2,
-       BRCMS_SROM_TXPID5GLA3,
        /*
         * per-path identifiers (see srom.c)
         */
@@ -225,10 +209,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA2GW2A1,
        BRCMS_SROM_PA2GW2A2,
        BRCMS_SROM_PA2GW2A3,
-       BRCMS_SROM_PA2GW3A0,
-       BRCMS_SROM_PA2GW3A1,
-       BRCMS_SROM_PA2GW3A2,
-       BRCMS_SROM_PA2GW3A3,
        BRCMS_SROM_PA5GHW0A0,
        BRCMS_SROM_PA5GHW0A1,
        BRCMS_SROM_PA5GHW0A2,
@@ -241,10 +221,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GHW2A1,
        BRCMS_SROM_PA5GHW2A2,
        BRCMS_SROM_PA5GHW2A3,
-       BRCMS_SROM_PA5GHW3A0,
-       BRCMS_SROM_PA5GHW3A1,
-       BRCMS_SROM_PA5GHW3A2,
-       BRCMS_SROM_PA5GHW3A3,
        BRCMS_SROM_PA5GLW0A0,
        BRCMS_SROM_PA5GLW0A1,
        BRCMS_SROM_PA5GLW0A2,
@@ -257,10 +233,6 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GLW2A1,
        BRCMS_SROM_PA5GLW2A2,
        BRCMS_SROM_PA5GLW2A3,
-       BRCMS_SROM_PA5GLW3A0,
-       BRCMS_SROM_PA5GLW3A1,
-       BRCMS_SROM_PA5GLW3A2,
-       BRCMS_SROM_PA5GLW3A3,
        BRCMS_SROM_PA5GW0A0,
        BRCMS_SROM_PA5GW0A1,
        BRCMS_SROM_PA5GW0A2,
@@ -273,14 +245,9 @@ enum brcms_srom_id {
        BRCMS_SROM_PA5GW2A1,
        BRCMS_SROM_PA5GW2A2,
        BRCMS_SROM_PA5GW2A3,
-       BRCMS_SROM_PA5GW3A0,
-       BRCMS_SROM_PA5GW3A1,
-       BRCMS_SROM_PA5GW3A2,
-       BRCMS_SROM_PA5GW3A3,
 };
 
 #define        BRCMS_NUMRATES  16      /* max # of rates in a rateset */
-#define        D11_PHY_HDR_LEN 6       /* Phy header length - 6 bytes */
 
 /* phy types */
 #define        PHY_TYPE_A      0       /* Phy type A */
@@ -414,7 +381,6 @@ struct brcms_pub {
        uint _nbands;           /* # bands supported */
        uint now;               /* # elapsed seconds */
 
-       bool promisc;           /* promiscuous destination address */
        bool delayed_down;      /* down delayed */
        bool associated;        /* true:part of [I]BSS, false: not */
        /* (union of stas_associated, aps_associated) */
@@ -572,7 +538,7 @@ extern int brcms_c_up(struct brcms_c_info *wlc);
 extern uint brcms_c_down(struct brcms_c_info *wlc);
 
 extern bool brcms_c_chipmatch(u16 vendor, u16 device);
-extern void brcms_c_init(struct brcms_c_info *wlc);
+extern void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx);
 extern void brcms_c_reset(struct brcms_c_info *wlc);
 
 extern void brcms_c_intrson(struct brcms_c_info *wlc);
@@ -628,7 +594,7 @@ extern void brcms_c_set_beacon_listen_interval(struct brcms_c_info *wlc,
                                        u8 interval);
 extern int brcms_c_set_tx_power(struct brcms_c_info *wlc, int txpwr);
 extern int brcms_c_get_tx_power(struct brcms_c_info *wlc);
-extern void brcms_c_set_radio_mpc(struct brcms_c_info *wlc, bool mpc);
 extern bool brcms_c_check_radio_disabled(struct brcms_c_info *wlc);
+extern void brcms_c_mute(struct brcms_c_info *wlc, bool on);
 
 #endif                         /* _BRCM_PUB_H_ */
index e7b9dc2f27315a17e7776efe43080ed3098afe93..980d578825cc0b3b131995bfcf6926bbab0bbbf1 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "types.h"
 #include "d11.h"
+#include "phy_hal.h"
 
 extern const u8 rate_info[];
 extern const struct brcms_c_rateset cck_ofdm_mimo_rates;
@@ -198,11 +199,9 @@ static inline u8 cck_rspec(u8 cck)
 
 /* Convert encoded rate value in plcp header to numerical rates in 500 KHz
  * increments */
-extern const u8 ofdm_rate_lookup[];
-
 static inline u8 ofdm_phy2mac_rate(u8 rlpt)
 {
-       return ofdm_rate_lookup[rlpt & 0x7];
+       return wlc_phy_get_ofdm_rate_lookup()[rlpt & 0x7];
 }
 
 static inline u8 cck_phy2mac_rate(u8 signal)
index 99f791048e841b7295a9fb8abf8c4f172c267029..b6987ea9fc689b6b4351ab83cf3af9f67aa32e3a 100644 (file)
@@ -28,6 +28,7 @@
 #include "aiutils.h"
 #include "otp.h"
 #include "srom.h"
+#include "soc.h"
 
 /*
  * SROM CRC8 polynomial value:
@@ -62,9 +63,6 @@
 #define        SROM_MACHI_ET1          42
 #define        SROM_MACMID_ET1         43
 #define        SROM_MACLO_ET1          44
-#define        SROM3_MACHI             37
-#define        SROM3_MACMID            38
-#define        SROM3_MACLO             39
 
 #define        SROM_BXARSSI2G          40
 #define        SROM_BXARSSI5G          41
 
 #define        SROM_BFL                57
 #define        SROM_BFL2               28
-#define        SROM3_BFL2              61
 
 #define        SROM_AG10               58
 
 
 #define        SROM_OPO                60
 
-#define        SROM3_LEDDC             62
-
 #define        SROM_CRCREV             63
 
-/* SROM Rev 4: Reallocate the software part of the srom to accommodate
- * MIMO features. It assumes up to two PCIE functions and 440 bytes
- * of usable srom i.e. the usable storage in chips with OTP that
- * implements hardware redundancy.
- */
-
 #define        SROM4_WORDS             220
 
-#define        SROM4_SIGN              32
-#define        SROM4_SIGNATURE         0x5372
-
-#define        SROM4_BREV              33
-
-#define        SROM4_BFL0              34
-#define        SROM4_BFL1              35
-#define        SROM4_BFL2              36
-#define        SROM4_BFL3              37
-#define        SROM5_BFL0              37
-#define        SROM5_BFL1              38
-#define        SROM5_BFL2              39
-#define        SROM5_BFL3              40
-
-#define        SROM4_MACHI             38
-#define        SROM4_MACMID            39
-#define        SROM4_MACLO             40
-#define        SROM5_MACHI             41
-#define        SROM5_MACMID            42
-#define        SROM5_MACLO             43
-
-#define        SROM4_CCODE             41
-#define        SROM4_REGREV            42
-#define        SROM5_CCODE             34
-#define        SROM5_REGREV            35
-
-#define        SROM4_LEDBH10           43
-#define        SROM4_LEDBH32           44
-#define        SROM5_LEDBH10           59
-#define        SROM5_LEDBH32           60
-
-#define        SROM4_LEDDC             45
-#define        SROM5_LEDDC             45
-
-#define        SROM4_AA                46
-
-#define        SROM4_AG10              47
-#define        SROM4_AG32              48
-
-#define        SROM4_TXPID2G           49
-#define        SROM4_TXPID5G           51
-#define        SROM4_TXPID5GL          53
-#define        SROM4_TXPID5GH          55
-
-#define SROM4_TXRXC            61
 #define SROM4_TXCHAIN_MASK     0x000f
-#define SROM4_TXCHAIN_SHIFT    0
 #define SROM4_RXCHAIN_MASK     0x00f0
-#define SROM4_RXCHAIN_SHIFT    4
 #define SROM4_SWITCH_MASK      0xff00
-#define SROM4_SWITCH_SHIFT     8
 
 /* Per-path fields */
 #define        MAX_PATH_SROM           4
-#define        SROM4_PATH0             64
-#define        SROM4_PATH1             87
-#define        SROM4_PATH2             110
-#define        SROM4_PATH3             133
-
-#define        SROM4_2G_ITT_MAXP       0
-#define        SROM4_2G_PA             1
-#define        SROM4_5G_ITT_MAXP       5
-#define        SROM4_5GLH_MAXP         6
-#define        SROM4_5G_PA             7
-#define        SROM4_5GL_PA            11
-#define        SROM4_5GH_PA            15
-
-/* All the miriad power offsets */
-#define        SROM4_2G_CCKPO          156
-#define        SROM4_2G_OFDMPO         157
-#define        SROM4_5G_OFDMPO         159
-#define        SROM4_5GL_OFDMPO        161
-#define        SROM4_5GH_OFDMPO        163
-#define        SROM4_2G_MCSPO          165
-#define        SROM4_5G_MCSPO          173
-#define        SROM4_5GL_MCSPO         181
-#define        SROM4_5GH_MCSPO         189
-#define        SROM4_CDDPO             197
-#define        SROM4_STBCPO            198
-#define        SROM4_BW40PO            199
-#define        SROM4_BWDUPPO           200
 
 #define        SROM4_CRCREV            219
 
@@ -424,103 +338,32 @@ struct brcms_varbuf {
 static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
         0xffff},
-       {BRCMS_SROM_BOARDREV, 0x0000000e, SRFL_PRHEX, SROM_AABREV,
-        SROM_BR_MASK},
-       {BRCMS_SROM_BOARDREV, 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
        {BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM3_BFL2, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL1, 0xffff},
        {BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_BFL3, 0xffff},
-       {BRCMS_SROM_BOARDFLAGS2, 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2,
-        0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM5_BFL3, 0xffff},
        {BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
         0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
        {BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000008, 0, SROM3_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x00000010, 0, SROM4_MACLO, 0xffff},
-       {BRCMS_SROM_BOARDNUM, 0x000000e0, 0, SROM5_MACLO, 0xffff},
        {BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
-       {BRCMS_SROM_CC, 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
-       {BRCMS_SROM_REGREV, 0x00000008, 0, SROM_OPO, 0xff00},
-       {BRCMS_SROM_REGREV, 0x00000010, 0, SROM4_REGREV, 0x00ff},
-       {BRCMS_SROM_REGREV, 0x000000e0, 0, SROM5_REGREV, 0x00ff},
        {BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
-       {BRCMS_SROM_LEDBH0, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
-       {BRCMS_SROM_LEDBH0, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
-       {BRCMS_SROM_LEDBH1, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
-       {BRCMS_SROM_LEDBH2, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
-       {BRCMS_SROM_LEDBH3, 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
        {BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
        {BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
        {BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
        {BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
-       {BRCMS_SROM_PA0B0, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
-       {BRCMS_SROM_PA0B1, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
-       {BRCMS_SROM_PA0B2, 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
-       {BRCMS_SROM_PA0ITSSIT, 0x0000000e, 0, SROM_ITT, 0x00ff},
-       {BRCMS_SROM_PA0MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
        {BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
        {BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
        {BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
        {BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
        {BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
-       {BRCMS_SROM_OPO, 0x0000000c, 0, SROM_OPO, 0x00ff},
        {BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
-       {BRCMS_SROM_AA2G, 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
-       {BRCMS_SROM_AA2G, 0x000000f0, 0, SROM4_AA, 0x00ff},
        {BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
-       {BRCMS_SROM_AA5G, 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
-       {BRCMS_SROM_AA5G, 0x000000f0, 0, SROM4_AA, 0xff00},
        {BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
-       {BRCMS_SROM_AG0, 0x0000000e, 0, SROM_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x0000000e, 0, SROM_AG10, 0xff00},
-       {BRCMS_SROM_AG0, 0x000000f0, 0, SROM4_AG10, 0x00ff},
-       {BRCMS_SROM_AG1, 0x000000f0, 0, SROM4_AG10, 0xff00},
-       {BRCMS_SROM_AG2, 0x000000f0, 0, SROM4_AG32, 0x00ff},
-       {BRCMS_SROM_AG3, 0x000000f0, 0, SROM4_AG32, 0xff00},
        {BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
        {BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
        {BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
        {BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
-       {BRCMS_SROM_PA1B0, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
-       {BRCMS_SROM_PA1B1, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
-       {BRCMS_SROM_PA1B2, 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
-       {BRCMS_SROM_PA1LOB0, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
-       {BRCMS_SROM_PA1LOB1, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
-       {BRCMS_SROM_PA1LOB2, 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
-       {BRCMS_SROM_PA1HIB0, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
-       {BRCMS_SROM_PA1HIB1, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
-       {BRCMS_SROM_PA1HIB2, 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
-       {BRCMS_SROM_PA1ITSSIT, 0x0000000e, 0, SROM_ITT, 0xff00},
-       {BRCMS_SROM_PA1MAXPWR, 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
-       {BRCMS_SROM_PA1LOMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
-       {BRCMS_SROM_PA1HIMAXPWR, 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
        {BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
        {BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
        {BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
@@ -534,40 +377,20 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
        {BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
        {BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
-       {BRCMS_SROM_BXA2G, 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
-       {BRCMS_SROM_RSSISAV2G, 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
-       {BRCMS_SROM_RSSISMC2G, 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
-       {BRCMS_SROM_RSSISMF2G, 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
        {BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
        {BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
        {BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
        {BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
-       {BRCMS_SROM_BXA5G, 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
-       {BRCMS_SROM_RSSISAV5G, 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
-       {BRCMS_SROM_RSSISMC5G, 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
-       {BRCMS_SROM_RSSISMF5G, 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
        {BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
        {BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
        {BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
        {BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
-       {BRCMS_SROM_TRI2G, 0x00000008, 0, SROM_TRI52G, 0x00ff},
-       {BRCMS_SROM_TRI5G, 0x00000008, 0, SROM_TRI52G, 0xff00},
-       {BRCMS_SROM_TRI5GL, 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
-       {BRCMS_SROM_TRI5GH, 0x00000008, 0, SROM_TRI5GHL, 0xff00},
        {BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
        {BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
        {BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
        {BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
-       {BRCMS_SROM_RXPO2G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
-       {BRCMS_SROM_RXPO5G, 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
        {BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
        {BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
-       {BRCMS_SROM_TXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_TXCHAIN_MASK},
-       {BRCMS_SROM_RXCHAIN, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_RXCHAIN_MASK},
-       {BRCMS_SROM_ANTSWITCH, 0x000000f0, SRFL_NOFFS, SROM4_TXRXC,
-        SROM4_SWITCH_MASK},
        {BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
         SROM4_TXCHAIN_MASK},
        {BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
@@ -594,43 +417,11 @@ static const struct brcms_sromvar pci_sromvars[] = {
         SROM8_FEM_ANTSWLUT_MASK},
        {BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
        {BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
-       {BRCMS_SROM_TXPID2GA0, 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
-       {BRCMS_SROM_TXPID2GA1, 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
-       {BRCMS_SROM_TXPID2GA2, 0x000000f0, 0, SROM4_TXPID2G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID2GA3, 0x000000f0, 0, SROM4_TXPID2G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GA0, 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
-       {BRCMS_SROM_TXPID5GA1, 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
-       {BRCMS_SROM_TXPID5GA2, 0x000000f0, 0, SROM4_TXPID5G + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GA3, 0x000000f0, 0, SROM4_TXPID5G + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GLA0, 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA1, 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
-       {BRCMS_SROM_TXPID5GLA2, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GLA3, 0x000000f0, 0, SROM4_TXPID5GL + 1, 0xff00},
-       {BRCMS_SROM_TXPID5GHA0, 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA1, 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
-       {BRCMS_SROM_TXPID5GHA2, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0x00ff},
-       {BRCMS_SROM_TXPID5GHA3, 0x000000f0, 0, SROM4_TXPID5GH + 1, 0xff00},
-
-       {BRCMS_SROM_CCODE, 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
-       {BRCMS_SROM_CCODE, 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
+
        {BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
        {BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
-       {BRCMS_SROM_MACADDR, 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
-       {BRCMS_SROM_IL0MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0,
-        0xffff},
-       {BRCMS_SROM_ET1MACADDR, 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1,
-        0xffff},
        {BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
         0xffff},
-       {BRCMS_SROM_LEDDC, 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC,
-        0xffff},
-       {BRCMS_SROM_LEDDC, 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC,
-        0xffff},
        {BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
         0x01ff},
        {BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
@@ -650,16 +441,7 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
         0x00ff},
 
-       {BRCMS_SROM_CCK2GPO, 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
        {BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
-       {BRCMS_SROM_OFDM2GPO, 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_2G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GPO, 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5G_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GLPO, 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GL_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_OFDM5GHPO, 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
-       {BRCMS_SROM_CONT, 0, 0, SROM4_5GH_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
@@ -668,38 +450,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
        {BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
        {BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO0, 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS2GPO1, 0x000000f0, 0, SROM4_2G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS2GPO2, 0x000000f0, 0, SROM4_2G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS2GPO3, 0x000000f0, 0, SROM4_2G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS2GPO4, 0x000000f0, 0, SROM4_2G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS2GPO5, 0x000000f0, 0, SROM4_2G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS2GPO6, 0x000000f0, 0, SROM4_2G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS2GPO7, 0x000000f0, 0, SROM4_2G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GPO0, 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GPO1, 0x000000f0, 0, SROM4_5G_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GPO2, 0x000000f0, 0, SROM4_5G_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GPO3, 0x000000f0, 0, SROM4_5G_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GPO4, 0x000000f0, 0, SROM4_5G_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GPO5, 0x000000f0, 0, SROM4_5G_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GPO6, 0x000000f0, 0, SROM4_5G_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GPO7, 0x000000f0, 0, SROM4_5G_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GLPO0, 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GLPO1, 0x000000f0, 0, SROM4_5GL_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GLPO2, 0x000000f0, 0, SROM4_5GL_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GLPO3, 0x000000f0, 0, SROM4_5GL_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GLPO4, 0x000000f0, 0, SROM4_5GL_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GLPO5, 0x000000f0, 0, SROM4_5GL_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GLPO6, 0x000000f0, 0, SROM4_5GL_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GLPO7, 0x000000f0, 0, SROM4_5GL_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_MCS5GHPO0, 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
-       {BRCMS_SROM_MCS5GHPO1, 0x000000f0, 0, SROM4_5GH_MCSPO + 1, 0xffff},
-       {BRCMS_SROM_MCS5GHPO2, 0x000000f0, 0, SROM4_5GH_MCSPO + 2, 0xffff},
-       {BRCMS_SROM_MCS5GHPO3, 0x000000f0, 0, SROM4_5GH_MCSPO + 3, 0xffff},
-       {BRCMS_SROM_MCS5GHPO4, 0x000000f0, 0, SROM4_5GH_MCSPO + 4, 0xffff},
-       {BRCMS_SROM_MCS5GHPO5, 0x000000f0, 0, SROM4_5GH_MCSPO + 5, 0xffff},
-       {BRCMS_SROM_MCS5GHPO6, 0x000000f0, 0, SROM4_5GH_MCSPO + 6, 0xffff},
-       {BRCMS_SROM_MCS5GHPO7, 0x000000f0, 0, SROM4_5GH_MCSPO + 7, 0xffff},
        {BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
        {BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
        {BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
@@ -732,10 +482,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
        {BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
        {BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
        {BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
-       {BRCMS_SROM_CDDPO, 0x000000f0, 0, SROM4_CDDPO, 0xffff},
-       {BRCMS_SROM_STBCPO, 0x000000f0, 0, SROM4_STBCPO, 0xffff},
-       {BRCMS_SROM_BW40PO, 0x000000f0, 0, SROM4_BW40PO, 0xffff},
-       {BRCMS_SROM_BWDUPPO, 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
        {BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
        {BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
        {BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
@@ -811,34 +557,6 @@ static const struct brcms_sromvar pci_sromvars[] = {
 };
 
 static const struct brcms_sromvar perpath_pci_sromvars[] = {
-       {BRCMS_SROM_MAXP2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_ITT2GA0, 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_ITT5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
-       {BRCMS_SROM_PA2GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
-       {BRCMS_SROM_PA2GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA2GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA2GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_2G_PA + 3, 0xffff},
-       {BRCMS_SROM_MAXP5GA0, 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GHA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
-       {BRCMS_SROM_MAXP5GLA0, 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
-       {BRCMS_SROM_PA5GW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
-       {BRCMS_SROM_PA5GW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 1, 0xffff},
-       {BRCMS_SROM_PA5GW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 2, 0xffff},
-       {BRCMS_SROM_PA5GW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5G_PA + 3, 0xffff},
-       {BRCMS_SROM_PA5GLW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
-       {BRCMS_SROM_PA5GLW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GLW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GLW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA + 3,
-        0xffff},
-       {BRCMS_SROM_PA5GHW0A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
-       {BRCMS_SROM_PA5GHW1A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 1,
-        0xffff},
-       {BRCMS_SROM_PA5GHW2A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 2,
-        0xffff},
-       {BRCMS_SROM_PA5GHW3A0, 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA + 3,
-        0xffff},
        {BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
        {BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
        {BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
@@ -868,24 +586,17 @@ static const struct brcms_sromvar perpath_pci_sromvars[] = {
  * shared between devices. */
 static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
 
-static u16 __iomem *
+static u8 __iomem *
 srom_window_address(struct si_pub *sih, u8 __iomem *curmap)
 {
        if (sih->ccrev < 32)
-               return (u16 __iomem *)(curmap + PCI_BAR0_SPROM_OFFSET);
+               return curmap + PCI_BAR0_SPROM_OFFSET;
        if (sih->cccaps & CC_CAP_SROM)
-               return (u16 __iomem *)
-                      (curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP);
+               return curmap + PCI_16KB0_CCREGS_OFFSET + CC_SROM_OTP;
 
        return NULL;
 }
 
-/* Parse SROM and create name=value pairs. 'srom' points to
- * the SROM word array. 'off' specifies the offset of the
- * first word 'srom' points to, which should be either 0 or
- * SROM3_SWRG_OFF (full SROM or software region).
- */
-
 static uint mask_shift(u16 mask)
 {
        uint i;
@@ -906,18 +617,16 @@ static uint mask_width(u16 mask)
        return 0;
 }
 
-static inline void ltoh16_buf(u16 *buf, unsigned int size)
+static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(buf + size) = le16_to_cpu(*(__le16 *)(buf + size));
+       while (nwords--)
+               *(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
 }
 
-static inline void htol16_buf(u16 *buf, unsigned int size)
+static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
 {
-       size /= 2;
-       while (size--)
-               *(__le16 *)(buf + size) = cpu_to_le16(*(buf + size));
+       while (nwords--)
+               *(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
 }
 
 /*
@@ -929,11 +638,14 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
        struct brcms_srom_list_head *entry;
        enum brcms_srom_id id;
        u16 w;
-       u32 val;
+       u32 val = 0;
        const struct brcms_sromvar *srv;
        uint width;
        uint flags;
        u32 sr = (1 << sromrev);
+       uint p;
+       uint pb =  SROM8_PATH0;
+       const uint psz = SROM8_PATH1 - SROM8_PATH0;
 
        /* first store the srom revision */
        entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
@@ -1031,47 +743,34 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
                list_add(&entry->var_list, var_list);
        }
 
-       if (sromrev >= 4) {
-               /* Do per-path variables */
-               uint p, pb, psz;
-
-               if (sromrev >= 8) {
-                       pb = SROM8_PATH0;
-                       psz = SROM8_PATH1 - SROM8_PATH0;
-               } else {
-                       pb = SROM4_PATH0;
-                       psz = SROM4_PATH1 - SROM4_PATH0;
-               }
-
-               for (p = 0; p < MAX_PATH_SROM; p++) {
-                       for (srv = perpath_pci_sromvars;
-                            srv->varid != BRCMS_SROM_NULL; srv++) {
-                               if ((srv->revmask & sr) == 0)
-                                       continue;
+       for (p = 0; p < MAX_PATH_SROM; p++) {
+               for (srv = perpath_pci_sromvars;
+                    srv->varid != BRCMS_SROM_NULL; srv++) {
+                       if ((srv->revmask & sr) == 0)
+                               continue;
 
-                               if (srv->flags & SRFL_NOVAR)
-                                       continue;
+                       if (srv->flags & SRFL_NOVAR)
+                               continue;
 
-                               w = srom[pb + srv->off];
-                               val = (w & srv->mask) >> mask_shift(srv->mask);
-                               width = mask_width(srv->mask);
+                       w = srom[pb + srv->off];
+                       val = (w & srv->mask) >> mask_shift(srv->mask);
+                       width = mask_width(srv->mask);
 
-                               /* Cheating: no per-path var is more than
-                                * 1 word */
-                               if ((srv->flags & SRFL_NOFFS)
-                                   && ((int)val == (1 << width) - 1))
-                                       continue;
+                       /* Cheating: no per-path var is more than
+                        * 1 word */
+                       if ((srv->flags & SRFL_NOFFS)
+                           && ((int)val == (1 << width) - 1))
+                               continue;
 
-                               entry =
-                                   kzalloc(sizeof(struct brcms_srom_list_head),
-                                           GFP_KERNEL);
-                               entry->varid = srv->varid+p;
-                               entry->var_type = BRCMS_SROM_UNUMBER;
-                               entry->uval = val;
-                               list_add(&entry->var_list, var_list);
-                       }
-                       pb += psz;
+                       entry =
+                           kzalloc(sizeof(struct brcms_srom_list_head),
+                                   GFP_KERNEL);
+                       entry->varid = srv->varid+p;
+                       entry->var_type = BRCMS_SROM_UNUMBER;
+                       entry->uval = val;
+                       list_add(&entry->var_list, var_list);
                }
+               pb += psz;
        }
 }
 
@@ -1080,41 +779,38 @@ _initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
  * Return 0 on success, nonzero on error.
  */
 static int
-sprom_read_pci(struct si_pub *sih, u16 __iomem *sprom, uint wordoff,
+sprom_read_pci(struct si_pub *sih, u8 __iomem *sprom, uint wordoff,
               u16 *buf, uint nwords, bool check_crc)
 {
        int err = 0;
        uint i;
+       u8 *bbuf = (u8 *)buf; /* byte buffer */
+       uint nbytes = nwords << 1;
 
-       /* read the sprom */
-       for (i = 0; i < nwords; i++)
-               buf[i] = R_REG(&sprom[wordoff + i]);
-
-       if (check_crc) {
+       /* read the sprom in bytes */
+       for (i = 0; i < nbytes; i++)
+               bbuf[i] = readb(sprom+i);
 
-               if (buf[0] == 0xffff)
-                       /*
-                        * The hardware thinks that an srom that starts with
-                        * 0xffff is blank, regardless of the rest of the
-                        * content, so declare it bad.
-                        */
-                       return -ENODATA;
-
-               /* fixup the endianness so crc8 will pass */
-               htol16_buf(buf, nwords * 2);
-               if (crc8(brcms_srom_crc8_table, (u8 *) buf, nwords * 2,
-                        CRC8_INIT_VALUE) !=
-                        CRC8_GOOD_VALUE(brcms_srom_crc8_table))
-                       /* DBG only pci always read srom4 first, then srom8/9 */
-                       err = -EIO;
+       if (buf[0] == 0xffff)
+               /*
+                * The hardware thinks that an srom that starts with
+                * 0xffff is blank, regardless of the rest of the
+                * content, so declare it bad.
+                */
+               return -ENODATA;
 
+       if (check_crc &&
+           crc8(brcms_srom_crc8_table, bbuf, nbytes, CRC8_INIT_VALUE) !=
+                CRC8_GOOD_VALUE(brcms_srom_crc8_table))
+               err = -EIO;
+       else
                /* now correct the endianness of the byte array */
-               ltoh16_buf(buf, nwords * 2);
-       }
+               le16_to_cpu_buf(buf, nwords);
+
        return err;
 }
 
-static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
+static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
 {
        u8 *otp;
        uint sz = OTP_SZ_MAX / 2;       /* size in words */
@@ -1126,7 +822,8 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 
        err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
 
-       memcpy(buf, otp, bufsz);
+       sz = min_t(uint, sz, nwords);
+       memcpy(buf, otp, sz * 2);
 
        kfree(otp);
 
@@ -1139,13 +836,13 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
                return -ENODATA;
 
        /* fixup the endianness so crc8 will pass */
-       htol16_buf(buf, bufsz);
-       if (crc8(brcms_srom_crc8_table, (u8 *) buf, SROM4_WORDS * 2,
+       cpu_to_le16_buf(buf, sz);
+       if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
                 CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
                err = -EIO;
-
-       /* now correct the endianness of the byte array */
-       ltoh16_buf(buf, bufsz);
+       else
+               /* now correct the endianness of the byte array */
+               le16_to_cpu_buf(buf, sz);
 
        return err;
 }
@@ -1157,7 +854,7 @@ static int otp_read_pci(struct si_pub *sih, u16 *buf, uint bufsz)
 static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 {
        u16 *srom;
-       u16 __iomem *sromwindow;
+       u8 __iomem *sromwindow;
        u8 sromrev = 0;
        u32 sr;
        int err = 0;
@@ -1173,29 +870,16 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
 
        crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
        if (ai_is_sprom_available(sih)) {
-               err = sprom_read_pci(sih, sromwindow, 0, srom, SROM_WORDS,
-                                    true);
-
-               if ((srom[SROM4_SIGN] == SROM4_SIGNATURE) ||
-                   (((sih->buscoretype == PCIE_CORE_ID)
-                     && (sih->buscorerev >= 6))
-                    || ((sih->buscoretype == PCI_CORE_ID)
-                        && (sih->buscorerev >= 0xe)))) {
-                       /* sromrev >= 4, read more */
-                       err = sprom_read_pci(sih, sromwindow, 0, srom,
-                                            SROM4_WORDS, true);
-                       sromrev = srom[SROM4_CRCREV] & 0xff;
-               } else if (err == 0) {
-                       /* srom is good and is rev < 4 */
+               err = sprom_read_pci(sih, sromwindow, 0, srom,
+                                    SROM4_WORDS, true);
+
+               if (err == 0)
+                       /* srom read and passed crc */
                        /* top word of sprom contains version and crc8 */
-                       sromrev = srom[SROM_CRCREV] & 0xff;
-                       /* bcm4401 sroms misprogrammed */
-                       if (sromrev == 0x10)
-                               sromrev = 1;
-               }
+                       sromrev = srom[SROM4_CRCREV] & 0xff;
        } else {
                /* Use OTP if SPROM not available */
-               err = otp_read_pci(sih, srom, SROM_MAX);
+               err = otp_read_pci(sih, srom, SROM4_WORDS);
                if (err == 0)
                        /* OTP only contain SROM rev8/rev9 for now */
                        sromrev = srom[SROM4_CRCREV] & 0xff;
@@ -1208,10 +892,9 @@ static int initvars_srom_pci(struct si_pub *sih, void __iomem *curmap)
                sr = 1 << sromrev;
 
                /*
-                * srom version check: Current valid versions: 1, 2, 3, 4, 5, 8,
-                * 9
+                * srom version check: Current valid versions: 8, 9
                 */
-               if ((sr & 0x33e) == 0) {
+               if ((sr & 0x300) == 0) {
                        err = -EINVAL;
                        goto errout;
                }
index 708c43ff51ccf44286c25ce0e18500f1f6799fc7..c81df9798e50ac606dc4c9e15122f8ba58d28354 100644 (file)
@@ -26,9 +26,4 @@ extern void srom_free_vars(struct si_pub *sih);
 extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
                     uint byteoff, uint nbytes, u16 *buf, bool check_crc);
 
-/* parse standard PCMCIA cis, normally used by SB/PCMCIA/SDIO/SPI/OTP
- *   and extract from it into name=value pairs
- */
-extern int srom_parsecis(u8 **pcis, uint ciscnt,
-                        char **vars, uint *count);
 #endif                         /* _BRCM_SROM_H_ */
index f27c489108273281f96f5d2c3be8bd1c9ee70bf4..b7537f70a79538fab66fd48183179c4b78a2f78a 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/netdevice.h>
 #include <linux/module.h>
+
 #include <brcmu_utils.h>
 
 MODULE_AUTHOR("Broadcom Corporation");
@@ -40,74 +41,20 @@ EXPORT_SYMBOL(brcmu_pkt_buf_get_skb);
 /* Free the driver packet. Free the tag if present */
 void brcmu_pkt_buf_free_skb(struct sk_buff *skb)
 {
-       struct sk_buff *nskb;
-       int nest = 0;
-
-       /* perversion: we use skb->next to chain multi-skb packets */
-       while (skb) {
-               nskb = skb->next;
-               skb->next = NULL;
-
-               if (skb->destructor)
-                       /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
-                        * destructor exists
-                        */
-                       dev_kfree_skb_any(skb);
-               else
-                       /* can free immediately (even in_irq()) if destructor
-                        * does not exist
-                        */
-                       dev_kfree_skb(skb);
-
-               nest++;
-               skb = nskb;
-       }
+       WARN_ON(skb->next);
+       if (skb->destructor)
+               /* cannot kfree_skb() on hard IRQ (net/core/skbuff.c) if
+                * destructor exists
+                */
+               dev_kfree_skb_any(skb);
+       else
+               /* can free immediately (even in_irq()) if destructor
+                * does not exist
+                */
+               dev_kfree_skb(skb);
 }
 EXPORT_SYMBOL(brcmu_pkt_buf_free_skb);
 
-
-/* copy a buffer into a pkt buffer chain */
-uint brcmu_pktfrombuf(struct sk_buff *p, uint offset, int len,
-               unsigned char *buf)
-{
-       uint n, ret = 0;
-
-       /* skip 'offset' bytes */
-       for (; p && offset; p = p->next) {
-               if (offset < (uint) (p->len))
-                       break;
-               offset -= p->len;
-       }
-
-       if (!p)
-               return 0;
-
-       /* copy the data */
-       for (; p && len; p = p->next) {
-               n = min((uint) (p->len) - offset, (uint) len);
-               memcpy(p->data + offset, buf, n);
-               buf += n;
-               len -= n;
-               ret += n;
-               offset = 0;
-       }
-
-       return ret;
-}
-EXPORT_SYMBOL(brcmu_pktfrombuf);
-
-/* return total length of buffer chain */
-uint brcmu_pkttotlen(struct sk_buff *p)
-{
-       uint total;
-
-       total = 0;
-       for (; p; p = p->next)
-               total += p->len;
-       return total;
-}
-EXPORT_SYMBOL(brcmu_pkttotlen);
-
 /*
  * osl multiple-precedence packet queue
  * hi_prec is always >= the number of the highest non-empty precedence
@@ -115,21 +62,13 @@ EXPORT_SYMBOL(brcmu_pkttotlen);
 struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
                                      struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head)
-               q->tail->prev = p;
-       else
-               q->head = p;
-
-       q->tail = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_tail(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -142,20 +81,13 @@ EXPORT_SYMBOL(brcmu_pktq_penq);
 struct sk_buff *brcmu_pktq_penq_head(struct pktq *pq, int prec,
                                           struct sk_buff *p)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
 
        if (pktq_full(pq) || pktq_pfull(pq, prec))
                return NULL;
 
-       q = &pq->q[prec];
-
-       if (q->head == NULL)
-               q->tail = p;
-
-       p->prev = q->head;
-       q->head = p;
-       q->len++;
-
+       q = &pq->q[prec].skblist;
+       skb_queue_head(q, p);
        pq->len++;
 
        if (pq->hi_prec < prec)
@@ -167,53 +99,30 @@ EXPORT_SYMBOL(brcmu_pktq_penq_head);
 
 struct sk_buff *brcmu_pktq_pdeq(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
-
        pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq);
 
 struct sk_buff *brcmu_pktq_pdeq_tail(struct pktq *pq, int prec)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev;
-
-       q = &pq->q[prec];
+       struct sk_buff_head *q;
+       struct sk_buff *p;
 
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue_tail(q);
        if (p == NULL)
                return NULL;
 
-       for (prev = NULL; p != q->tail; p = p->prev)
-               prev = p;
-
-       if (prev)
-               prev->prev = NULL;
-       else
-               q->head = NULL;
-
-       q->tail = prev;
-       q->len--;
-
        pq->len--;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_pdeq_tail);
@@ -222,31 +131,17 @@ void
 brcmu_pktq_pflush(struct pktq *pq, int prec, bool dir,
                  bool (*fn)(struct sk_buff *, void *), void *arg)
 {
-       struct pktq_prec *q;
-       struct sk_buff *p, *prev = NULL;
+       struct sk_buff_head *q;
+       struct sk_buff *p, *next;
 
-       q = &pq->q[prec];
-       p = q->head;
-       while (p) {
+       q = &pq->q[prec].skblist;
+       skb_queue_walk_safe(q, p, next) {
                if (fn == NULL || (*fn) (p, arg)) {
-                       bool head = (p == q->head);
-                       if (head)
-                               q->head = p->prev;
-                       else
-                               prev->prev = p->prev;
-                       p->prev = NULL;
+                       skb_unlink(p, q);
                        brcmu_pkt_buf_free_skb(p);
-                       q->len--;
                        pq->len--;
-                       p = (head ? q->head : prev->prev);
-               } else {
-                       prev = p;
-                       p = p->prev;
                }
        }
-
-       if (q->head == NULL)
-               q->tail = NULL;
 }
 EXPORT_SYMBOL(brcmu_pktq_pflush);
 
@@ -271,8 +166,10 @@ void brcmu_pktq_init(struct pktq *pq, int num_prec, int max_len)
 
        pq->max = (u16) max_len;
 
-       for (prec = 0; prec < num_prec; prec++)
+       for (prec = 0; prec < num_prec; prec++) {
                pq->q[prec].max = pq->max;
+               skb_queue_head_init(&pq->q[prec].skblist);
+       }
 }
 EXPORT_SYMBOL(brcmu_pktq_init);
 
@@ -284,13 +181,13 @@ struct sk_buff *brcmu_pktq_peek_tail(struct pktq *pq, int *prec_out)
                return NULL;
 
        for (prec = 0; prec < pq->hi_prec; prec++)
-               if (pq->q[prec].head)
+               if (!skb_queue_empty(&pq->q[prec].skblist))
                        break;
 
        if (prec_out)
                *prec_out = prec;
 
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 EXPORT_SYMBOL(brcmu_pktq_peek_tail);
 
@@ -303,7 +200,7 @@ int brcmu_pktq_mlen(struct pktq *pq, uint prec_bmp)
 
        for (prec = 0; prec <= pq->hi_prec; prec++)
                if (prec_bmp & (1 << prec))
-                       len += pq->q[prec].len;
+                       len += pq->q[prec].skblist.qlen;
 
        return len;
 }
@@ -313,39 +210,32 @@ EXPORT_SYMBOL(brcmu_pktq_mlen);
 struct sk_buff *brcmu_pktq_mdeq(struct pktq *pq, uint prec_bmp,
                                      int *prec_out)
 {
-       struct pktq_prec *q;
+       struct sk_buff_head *q;
        struct sk_buff *p;
        int prec;
 
        if (pq->len == 0)
                return NULL;
 
-       while ((prec = pq->hi_prec) > 0 && pq->q[prec].head == NULL)
+       while ((prec = pq->hi_prec) > 0 &&
+              skb_queue_empty(&pq->q[prec].skblist))
                pq->hi_prec--;
 
-       while ((prec_bmp & (1 << prec)) == 0 || pq->q[prec].head == NULL)
+       while ((prec_bmp & (1 << prec)) == 0 ||
+              skb_queue_empty(&pq->q[prec].skblist))
                if (prec-- == 0)
                        return NULL;
 
-       q = &pq->q[prec];
-
-       p = q->head;
+       q = &pq->q[prec].skblist;
+       p = skb_dequeue(q);
        if (p == NULL)
                return NULL;
 
-       q->head = p->prev;
-       if (q->head == NULL)
-               q->tail = NULL;
-
-       q->len--;
+       pq->len--;
 
        if (prec_out)
                *prec_out = prec;
 
-       pq->len--;
-
-       p->prev = NULL;
-
        return p;
 }
 EXPORT_SYMBOL(brcmu_pktq_mdeq);
@@ -364,23 +254,3 @@ void brcmu_prpkt(const char *msg, struct sk_buff *p0)
 }
 EXPORT_SYMBOL(brcmu_prpkt);
 #endif                         /* defined(BCMDBG) */
-
-#if defined(BCMDBG)
-/*
- * print bytes formatted as hex to a string. return the resulting
- * string length
- */
-int brcmu_format_hex(char *str, const void *bytes, int len)
-{
-       int i;
-       char *p = str;
-       const u8 *src = (const u8 *)bytes;
-
-       for (i = 0; i < len; i++) {
-               p += snprintf(p, 3, "%02X", *src);
-               src++;
-       }
-       return (int)(p - str);
-}
-EXPORT_SYMBOL(brcmu_format_hex);
-#endif                         /* defined(BCMDBG) */
index 7d0f46e0eb95a071d4f40ab16fefcb6cfb7c2570..ad249a0b4730ebea6eec5cd2f2bdfbb355fe232a 100644 (file)
@@ -65,9 +65,7 @@
 #define ETHER_ADDR_STR_LEN     18
 
 struct pktq_prec {
-       struct sk_buff *head;   /* first packet to dequeue */
-       struct sk_buff *tail;   /* last packet to dequeue */
-       u16 len;                /* number of queued packets */
+       struct sk_buff_head skblist;
        u16 max;                /* maximum number of queued packets */
 };
 
@@ -88,32 +86,32 @@ struct pktq {
 
 static inline int pktq_plen(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len;
+       return pq->q[prec].skblist.qlen;
 }
 
 static inline int pktq_pavail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].max - pq->q[prec].len;
+       return pq->q[prec].max - pq->q[prec].skblist.qlen;
 }
 
 static inline bool pktq_pfull(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len >= pq->q[prec].max;
+       return pq->q[prec].skblist.qlen >= pq->q[prec].max;
 }
 
 static inline bool pktq_pempty(struct pktq *pq, int prec)
 {
-       return pq->q[prec].len == 0;
+       return skb_queue_empty(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek(struct pktq *pq, int prec)
 {
-       return pq->q[prec].head;
+       return skb_peek(&pq->q[prec].skblist);
 }
 
 static inline struct sk_buff *pktq_ppeek_tail(struct pktq *pq, int prec)
 {
-       return pq->q[prec].tail;
+       return skb_peek_tail(&pq->q[prec].skblist);
 }
 
 extern struct sk_buff *brcmu_pktq_penq(struct pktq *pq, int prec,
@@ -172,24 +170,16 @@ extern void brcmu_pktq_flush(struct pktq *pq, bool dir,
                bool (*fn)(struct sk_buff *, void *), void *arg);
 
 /* externs */
-/* packet */
-extern uint brcmu_pktfrombuf(struct sk_buff *p,
-       uint offset, int len, unsigned char *buf);
-extern uint brcmu_pkttotlen(struct sk_buff *p);
-
 /* ip address */
 struct ipv4_addr;
 
+
+/* externs */
+/* format/print */
 #ifdef BCMDBG
 extern void brcmu_prpkt(const char *msg, struct sk_buff *p0);
 #else
 #define brcmu_prpkt(a, b)
 #endif                         /* BCMDBG */
 
-/* externs */
-/* format/print */
-#if defined(BCMDBG)
-extern int brcmu_format_hex(char *str, const void *bytes, int len);
-#endif
-
 #endif                         /* _BRCMU_UTILS_H_ */
index 1e5f310af1e77e10e341e8fe26872f4bd6db592a..f0d8c04a9c8cd13b03962b8855acdc69f8913b35 100644 (file)
@@ -62,7 +62,6 @@
 
 #define WL_RADIO_SW_DISABLE            (1<<0)
 #define WL_RADIO_HW_DISABLE            (1<<1)
-#define WL_RADIO_MPC_DISABLE           (1<<2)
 /* some countries don't support any channel */
 #define WL_RADIO_COUNTRY_DISABLE       (1<<3)
 
index 4fcb956ad9e03633ed01589e4adade6f05919eb0..4e9b7e4827ea88c845a7869835763849cd2db57e 100644 (file)
@@ -77,8 +77,9 @@
 #define        DMEMS_CORE_ID           0x835   /* SDR/DDR1 memory controller core */
 #define        DEF_SHIM_COMP           0x837   /* SHIM component in ubus/6362 */
 #define OOB_ROUTER_CORE_ID     0x367   /* OOB router core ID */
-/* Default component, in ai chips it maps all unused address ranges */
-#define        DEF_AI_COMP             0xfff
+#define        DEF_AI_COMP             0xfff   /* Default component, in ai chips it
+                                        * maps all unused address ranges
+                                        */
 
 /* Common core control flags */
 #define        SICF_BIST_EN            0x8000
 #define        SICF_FGC                0x0002
 #define        SICF_CLOCK_EN           0x0001
 
+/* Common core status flags */
+#define        SISF_BIST_DONE          0x8000
+#define        SISF_BIST_ERROR         0x4000
+#define        SISF_GATED_CLK          0x2000
+#define        SISF_DMA64              0x1000
+#define        SISF_CORE_BITS          0x0fff
+
 #endif                         /* _BRCM_SOC_H */
index 99a710dfe77106d83a61d795aebe90a68297a4ea..99575884ff525af70d69186ad625b55fb7d6dbdf 100644 (file)
@@ -131,6 +131,14 @@ static struct ieee80211_rate ipw2200_rates[] = {
 #define ipw2200_bg_rates       (ipw2200_rates + 0)
 #define ipw2200_num_bg_rates   12
 
+/* Ugly macro to convert literal channel numbers into their mhz equivalents
+ * There are certianly some conditions that will break this (like feeding it '30')
+ * but they shouldn't arise since nothing talks on channel 30. */
+#define ieee80211chan2mhz(x) \
+       (((x) <= 14) ? \
+       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
+       ((x) + 1000) * 5)
+
 #ifdef CONFIG_IPW2200_QOS
 static int qos_enable = 0;
 static int qos_burst_enable = 0;
index 70f5586d96bdeb060195763d8409fb4f64c27458..3d5821eeb05491327bda8a8a74c583722ca375cb 100644 (file)
@@ -66,16 +66,8 @@ extern u32 libipw_debug_level;
 do { if (libipw_debug_level & (level)) \
   printk(KERN_DEBUG "libipw: %c %s " fmt, \
          in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return (libipw_debug_level & level) && net_ratelimit();
-}
 #else
 #define LIBIPW_DEBUG(level, fmt, args...) do {} while (0)
-static inline bool libipw_ratelimit_debug(u32 level)
-{
-       return false;
-}
 #endif                         /* CONFIG_LIBIPW_DEBUG */
 
 /*
index c73e5ed8db5e6994651358ac13f8da9b4d84f6d9..a7ab280994c8105e74aa61f0cec84a99449aa4eb 100644 (file)
@@ -1,6 +1,6 @@
 # WIFI
 obj-$(CONFIG_IWLWIFI)  += iwlwifi.o
-iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o
+iwlwifi-objs           := iwl-agn.o iwl-agn-rs.o iwl-mac80211.o
 iwlwifi-objs           += iwl-agn-ucode.o iwl-agn-tx.o
 iwlwifi-objs           += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
 iwlwifi-objs           += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-rx.o
index 79431977a968583d8fb155fcc3c8fd5ea76bd6c7..b3193571ed07b3797f9e05783956a57384a63d06 100644 (file)
@@ -270,11 +270,6 @@ struct iwl_cfg iwl2000_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2000_2bg_cfg = {
-       .name = "2000 Series 2x2 BG",
-       IWL_DEVICE_2000,
-};
-
 struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .name = "2000D Series 2x2 BGN",
        IWL_DEVICE_2000,
@@ -304,11 +299,6 @@ struct iwl_cfg iwl2030_2bgn_cfg = {
        .ht_params = &iwl2000_ht_params,
 };
 
-struct iwl_cfg iwl2030_2bg_cfg = {
-       .name = "2000 Series 2x2 BG/BT",
-       IWL_DEVICE_2030,
-};
-
 #define IWL_DEVICE_105                                         \
        .fw_name_pre = IWL105_FW_PRE,                           \
        .ucode_api_max = IWL105_UCODE_API_MAX,                  \
@@ -326,11 +316,6 @@ struct iwl_cfg iwl2030_2bg_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl105_bg_cfg = {
-       .name = "105 Series 1x1 BG",
-       IWL_DEVICE_105,
-};
-
 struct iwl_cfg iwl105_bgn_cfg = {
        .name = "105 Series 1x1 BGN",
        IWL_DEVICE_105,
@@ -361,11 +346,6 @@ struct iwl_cfg iwl105_bgn_d_cfg = {
        .rx_with_siso_diversity = true,                         \
        .iq_invert = true                                       \
 
-struct iwl_cfg iwl135_bg_cfg = {
-       .name = "135 Series 1x1 BG/BT",
-       IWL_DEVICE_135,
-};
-
 struct iwl_cfg iwl135_bgn_cfg = {
        .name = "135 Series 1x1 BGN/BT",
        IWL_DEVICE_135,
index c840c78278db89e977854c16756a129db4a97f94..ee3363fdf309d8881d47849154a2a567720ec271 100644 (file)
@@ -439,16 +439,6 @@ struct iwl_cfg iwl6035_2agn_cfg = {
        .ht_params = &iwl6000_ht_params,
 };
 
-struct iwl_cfg iwl6035_2abg_cfg = {
-       .name = "6035 Series 2x2 ABG/BT",
-       IWL_DEVICE_6030,
-};
-
-struct iwl_cfg iwl6035_2bg_cfg = {
-       .name = "6035 Series 2x2 BG/BT",
-       IWL_DEVICE_6030,
-};
-
 struct iwl_cfg iwl1030_bgn_cfg = {
        .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        IWL_DEVICE_6030,
index 1a52ed29f2d64e4425552e603534dc0f1f16a54f..0bc9622173510580b27892737b4ca03fad74ab52 100644 (file)
@@ -827,6 +827,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt)
        case IEEE80211_SMPS_STATIC:
        case IEEE80211_SMPS_DYNAMIC:
                return IWL_NUM_IDLE_CHAINS_SINGLE;
+       case IEEE80211_SMPS_AUTOMATIC:
        case IEEE80211_SMPS_OFF:
                return active_cnt;
        default:
@@ -983,3 +984,360 @@ void iwlagn_remove_notification(struct iwl_priv *priv,
        list_del(&wait_entry->list);
        spin_unlock_bh(&priv->notif_wait_lock);
 }
+
+#ifdef CONFIG_PM_SLEEP
+static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
+{
+       int i;
+
+       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
+               out[i] = cpu_to_le16(p1k[i]);
+}
+
+struct wowlan_key_data {
+       struct iwl_rxon_context *ctx;
+       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
+       struct iwlagn_wowlan_tkip_params_cmd *tkip;
+       const u8 *bssid;
+       bool error, use_rsc_tsc, use_tkip;
+};
+
+
+static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif,
+                              struct ieee80211_sta *sta,
+                              struct ieee80211_key_conf *key,
+                              void *_data)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct wowlan_key_data *data = _data;
+       struct iwl_rxon_context *ctx = data->ctx;
+       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
+       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
+       struct iwlagn_p1k_cache *rx_p1ks;
+       u8 *rx_mic_key;
+       struct ieee80211_key_seq seq;
+       u32 cur_rx_iv32 = 0;
+       u16 p1k[IWLAGN_P1K_SIZE];
+       int ret, i;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
+            !sta && !ctx->key_mapping_keys)
+               ret = iwl_set_default_wep_key(priv, ctx, key);
+       else
+               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+
+       if (ret) {
+               IWL_ERR(priv, "Error setting key during suspend!\n");
+               data->error = true;
+       }
+
+       switch (key->cipher) {
+       case WLAN_CIPHER_SUITE_TKIP:
+               if (sta) {
+                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
+                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
+
+                       rx_p1ks = data->tkip->rx_uni;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+
+                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
+                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
+
+                       memcpy(data->tkip->mic_keys.tx,
+                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
+                              IWLAGN_MIC_KEY_SIZE);
+
+                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
+               } else {
+                       tkip_sc =
+                               data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
+                       rx_p1ks = data->tkip->rx_multi;
+                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
+               }
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 (as they need to to avoid replay attacks)
+                * for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
+                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
+                       /* wrapping isn't allowed, AP must rekey */
+                       if (seq.tkip.iv32 > cur_rx_iv32)
+                               cur_rx_iv32 = seq.tkip.iv32;
+               }
+
+               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
+               ieee80211_get_tkip_rx_p1k(key, data->bssid,
+                                         cur_rx_iv32 + 1, p1k);
+               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
+
+               memcpy(rx_mic_key,
+                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
+                      IWLAGN_MIC_KEY_SIZE);
+
+               data->use_tkip = true;
+               data->use_rsc_tsc = true;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               if (sta) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
+                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
+
+                       ieee80211_get_key_tx_seq(key, &seq);
+                       aes_tx_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               } else
+                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
+
+               /*
+                * For non-QoS this relies on the fact that both the uCode and
+                * mac80211 use TID 0 for checking the IV in the frames.
+                */
+               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
+                       u8 *pn = seq.ccmp.pn;
+
+                       ieee80211_get_key_rx_seq(key, i, &seq);
+                       aes_sc->pn = cpu_to_le64(
+                                       (u64)pn[5] |
+                                       ((u64)pn[4] << 8) |
+                                       ((u64)pn[3] << 16) |
+                                       ((u64)pn[2] << 24) |
+                                       ((u64)pn[1] << 32) |
+                                       ((u64)pn[0] << 40));
+               }
+               data->use_rsc_tsc = true;
+               break;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+}
+
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                       struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_WOWLAN_PATTERNS,
+               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+               .flags = CMD_SYNC,
+       };
+       int i, err;
+
+       if (!wowlan->n_patterns)
+               return 0;
+
+       cmd.len[0] = sizeof(*pattern_cmd) +
+               wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+
+       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
+       if (!pattern_cmd)
+               return -ENOMEM;
+
+       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+
+       for (i = 0; i < wowlan->n_patterns; i++) {
+               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+
+               memcpy(&pattern_cmd->patterns[i].mask,
+                       wowlan->patterns[i].mask, mask_len);
+               memcpy(&pattern_cmd->patterns[i].pattern,
+                       wowlan->patterns[i].pattern,
+                       wowlan->patterns[i].pattern_len);
+               pattern_cmd->patterns[i].mask_size = mask_len;
+               pattern_cmd->patterns[i].pattern_size =
+                       wowlan->patterns[i].pattern_len;
+       }
+
+       cmd.data[0] = pattern_cmd;
+       err = iwl_trans_send_cmd(trans(priv), &cmd);
+       kfree(pattern_cmd);
+       return err;
+}
+
+int iwlagn_suspend(struct iwl_priv *priv,
+               struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
+{
+       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
+       struct iwl_rxon_cmd rxon;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
+       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
+       struct iwlagn_d3_config_cmd d3_cfg_cmd = {};
+       struct wowlan_key_data key_data = {
+               .ctx = ctx,
+               .bssid = ctx->active.bssid_addr,
+               .use_rsc_tsc = false,
+               .tkip = &tkip_cmd,
+               .use_tkip = false,
+       };
+       int ret, i;
+       u16 seq;
+
+       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
+       if (!key_data.rsc_tsc)
+               return -ENOMEM;
+
+       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
+
+       /*
+        * We know the last used seqno, and the uCode expects to know that
+        * one, it will increment before TX.
+        */
+       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
+       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
+
+       /*
+        * For QoS counters, we store the one to use next, so subtract 0x10
+        * since the uCode will add 0x10 before using the value.
+        */
+       for (i = 0; i < 8; i++) {
+               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
+               seq -= 0x10;
+               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
+       }
+
+       if (wowlan->disconnect)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
+                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
+       if (wowlan->magic_pkt)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
+       if (wowlan->gtk_rekey_failure)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
+       if (wowlan->eap_identity_req)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
+       if (wowlan->four_way_handshake)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
+       if (wowlan->n_patterns)
+               wakeup_filter_cmd.enabled |=
+                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
+
+       if (wowlan->rfkill_release)
+               d3_cfg_cmd.wakeup_flags |=
+                       cpu_to_le32(IWLAGN_D3_WAKEUP_RFKILL);
+
+       iwl_scan_cancel_timeout(priv, 200);
+
+       memcpy(&rxon, &ctx->active, sizeof(rxon));
+
+       iwl_trans_stop_device(trans(priv));
+
+       priv->shrd->wowlan = true;
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_WOWLAN);
+       if (ret)
+               goto out;
+
+       /* now configure WoWLAN ucode */
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto out;
+
+       memcpy(&ctx->staging, &rxon, sizeof(rxon));
+       ret = iwlagn_commit_rxon(priv, ctx);
+       if (ret)
+               goto out;
+
+       ret = iwl_power_update_mode(priv, true);
+       if (ret)
+               goto out;
+
+       if (!iwlagn_mod_params.sw_crypto) {
+               /* mark all keys clear */
+               priv->ucode_key_table = 0;
+               ctx->key_mapping_keys = 0;
+
+               /*
+                * This needs to be unlocked due to lock ordering
+                * constraints. Since we're in the suspend path
+                * that isn't really a problem though.
+                */
+               mutex_unlock(&priv->shrd->mutex);
+               ieee80211_iter_keys(priv->hw, ctx->vif,
+                                   iwlagn_wowlan_program_keys,
+                                   &key_data);
+               mutex_lock(&priv->shrd->mutex);
+               if (key_data.error) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               if (key_data.use_rsc_tsc) {
+                       struct iwl_host_cmd rsc_tsc_cmd = {
+                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
+                               .flags = CMD_SYNC,
+                               .data[0] = key_data.rsc_tsc,
+                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
+                               .len[0] = sizeof(key_data.rsc_tsc),
+                       };
+
+                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (key_data.use_tkip) {
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_TKIP_PARAMS,
+                                                CMD_SYNC, sizeof(tkip_cmd),
+                                                &tkip_cmd);
+                       if (ret)
+                               goto out;
+               }
+
+               if (priv->have_rekey_data) {
+                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
+                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
+                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
+                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
+                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
+                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
+
+                       ret = iwl_trans_send_cmd_pdu(trans(priv),
+                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
+                                                CMD_SYNC, sizeof(kek_kck_cmd),
+                                                &kek_kck_cmd);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_D3_CONFIG, CMD_SYNC,
+                                    sizeof(d3_cfg_cmd), &d3_cfg_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
+                                CMD_SYNC, sizeof(wakeup_filter_cmd),
+                                &wakeup_filter_cmd);
+       if (ret)
+               goto out;
+
+       ret = iwlagn_send_patterns(priv, wowlan);
+ out:
+       kfree(key_data.rsc_tsc);
+       return ret;
+}
+#endif
index 66118cea2af343d3f97a0b4fe52cfc7c7e093769..359c47a4fcea457841c57e702910d4400797a22d 100644 (file)
@@ -1458,10 +1458,8 @@ static int rs_move_legacy_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_LEGACY_SWITCH_ANTENNA2)
-                       tbl->action = IWL_LEGACY_SWITCH_ANTENNA1;
+                       tbl->action = IWL_LEGACY_SWITCH_SISO;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
@@ -1636,10 +1634,8 @@ static int rs_move_siso_to_other(struct iwl_priv *priv,
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_LOW:
                /* avoid antenna B unless MIMO */
-               valid_tx_ant =
-                       first_antenna(hw_params(priv).valid_tx_ant);
                if (tbl->action == IWL_SISO_SWITCH_ANTENNA2)
-                       tbl->action = IWL_SISO_SWITCH_ANTENNA1;
+                       tbl->action = IWL_SISO_SWITCH_MIMO2_AB;
                break;
        case IWL_BT_COEX_TRAFFIC_LOAD_HIGH:
        case IWL_BT_COEX_TRAFFIC_LOAD_CONTINUOUS:
index 5af9e6258a16a07ab21e42480b17199991ffd88e..fdb4c3786114d799dd890ca24c3b883a241a8c7e 100644 (file)
@@ -800,7 +800,8 @@ static void iwlagn_pass_packet_to_mac80211(struct iwl_priv *priv,
                                               ctx->active.bssid_addr))
                                continue;
                        ctx->last_tx_rejected = false;
-                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid);
+                       iwl_trans_wake_any_queue(trans(priv), ctx->ctxid,
+                               "channel got active");
                }
        }
 
@@ -1032,6 +1033,50 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
        return 0;
 }
 
+static int iwlagn_rx_noa_notification(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
+{
+       struct iwl_wipan_noa_data *new_data, *old_data;
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       struct iwl_wipan_noa_notification *noa_notif = (void *)pkt->u.raw;
+
+       /* no condition -- we're in softirq */
+       old_data = rcu_dereference_protected(priv->noa_data, true);
+
+       if (noa_notif->noa_active) {
+               u32 len = le16_to_cpu(noa_notif->noa_attribute.length);
+               u32 copylen = len;
+
+               /* EID, len, OUI, subtype */
+               len += 1 + 1 + 3 + 1;
+               /* P2P id, P2P length */
+               len += 1 + 2;
+               copylen += 1 + 2;
+
+               new_data = kmalloc(sizeof(*new_data) + len, GFP_ATOMIC);
+               if (new_data) {
+                       new_data->length = len;
+                       new_data->data[0] = WLAN_EID_VENDOR_SPECIFIC;
+                       new_data->data[1] = len - 2; /* not counting EID, len */
+                       new_data->data[2] = (WLAN_OUI_WFA >> 16) & 0xff;
+                       new_data->data[3] = (WLAN_OUI_WFA >> 8) & 0xff;
+                       new_data->data[4] = (WLAN_OUI_WFA >> 0) & 0xff;
+                       new_data->data[5] = WLAN_OUI_TYPE_WFA_P2P;
+                       memcpy(&new_data->data[6], &noa_notif->noa_attribute,
+                              copylen);
+               }
+       } else
+               new_data = NULL;
+
+       rcu_assign_pointer(priv->noa_data, new_data);
+
+       if (old_data)
+               kfree_rcu(old_data, rcu_head);
+
+       return 0;
+}
+
 /**
  * iwl_setup_rx_handlers - Initialize Rx handler callbacks
  *
@@ -1055,6 +1100,8 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        handlers[BEACON_NOTIFICATION]           = iwlagn_rx_beacon_notif;
        handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
 
+       handlers[REPLY_WIPAN_NOA_NOTIFICATION]  = iwlagn_rx_noa_notification;
+
        /*
         * The same handler is used for both the REPLY to a discrete
         * statistics request from the host as well as for the periodic
index 58a381c01c89c9a367c7b592d65a49eb02457be0..8de97f5a1825f2f5818041f1f9bf6c7e3dc0a54a 100644 (file)
@@ -45,7 +45,8 @@ static int iwlagn_disable_bss(struct iwl_priv *priv,
        send->filter_flags = old_filter;
 
        if (ret)
-               IWL_ERR(priv, "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
+               IWL_DEBUG_QUIET_RFKILL(priv,
+                       "Error clearing ASSOC_MSK on BSS (%d)\n", ret);
 
        return ret;
 }
@@ -116,7 +117,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
        if (ctx->ht.enabled)
                ctx->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
 
-       IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+       IWL_DEBUG_INFO(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
                      ctx->qos_data.qos_active,
                      ctx->qos_data.def_qos_parm.qos_flags);
 
@@ -124,7 +125,7 @@ static void iwlagn_update_qos(struct iwl_priv *priv,
                               sizeof(struct iwl_qosparam_cmd),
                               &ctx->qos_data.def_qos_parm);
        if (ret)
-               IWL_ERR(priv, "Failed to update QoS\n");
+               IWL_DEBUG_QUIET_RFKILL(priv, "Failed to update QoS\n");
 }
 
 static int iwlagn_update_beacon(struct iwl_priv *priv,
@@ -541,6 +542,9 @@ int iwlagn_mac_config(struct ieee80211_hw *hw, u32 changed)
 
        mutex_lock(&priv->shrd->mutex);
 
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+               goto out;
+
        if (unlikely(test_bit(STATUS_SCANNING, &priv->shrd->status))) {
                IWL_DEBUG_MAC80211(priv, "leave - scanning\n");
                goto out;
@@ -840,7 +844,8 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                        if (ctx->last_tx_rejected) {
                                ctx->last_tx_rejected = false;
                                iwl_trans_wake_any_queue(trans(priv),
-                                                        ctx->ctxid);
+                                                        ctx->ctxid,
+                                                        "Disassoc: flush queue");
                        }
                        ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
index ed6283623932e2436ddc364d8429ee085df28249..901fd9485d757b216fd959b1aaa20849494a27a5 100644 (file)
@@ -647,7 +647,7 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        int ret;
        struct iwl_addsta_cmd sta_cmd;
        struct iwl_link_quality_cmd lq;
-       bool active;
+       bool active, have_lq = false;
 
        spin_lock_irqsave(&priv->shrd->sta_lock, flags);
        if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) {
@@ -657,7 +657,10 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
 
        memcpy(&sta_cmd, &priv->stations[sta_id].sta, sizeof(sta_cmd));
        sta_cmd.mode = 0;
-       memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+       if (priv->stations[sta_id].lq) {
+               memcpy(&lq, priv->stations[sta_id].lq, sizeof(lq));
+               have_lq = true;
+       }
 
        active = priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE;
        priv->stations[sta_id].used &= ~IWL_STA_DRIVER_ACTIVE;
@@ -679,7 +682,8 @@ void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (ret)
                IWL_ERR(priv, "failed to re-add STA %pM (%d)\n",
                        priv->stations[sta_id].sta.sta.addr, ret);
-       iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
+       if (have_lq)
+               iwl_send_lq_cmd(priv, ctx, &lq, CMD_SYNC, true);
 }
 
 int iwl_get_free_ucode_key_offset(struct iwl_priv *priv)
@@ -825,28 +829,6 @@ int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        return ret;
 }
 
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
-                      struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
-                          "station %pM\n", sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
-                       sta->addr);
-       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
-       if (ret)
-               IWL_ERR(priv, "Error removing station %pM\n",
-                       sta->addr);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
 
 void iwl_sta_fill_lq(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                     u8 sta_id, struct iwl_link_quality_cmd *link_cmd)
@@ -1464,20 +1446,7 @@ int iwl_sta_rx_agg_stop(struct iwl_priv *priv, struct ieee80211_sta *sta,
        return iwl_send_add_sta(priv, &sta_cmd, CMD_SYNC);
 }
 
-static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
-{
-       unsigned long flags;
 
-       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
-       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
-       priv->stations[sta_id].sta.sta.modify_mask = 0;
-       priv->stations[sta_id].sta.sleep_tx_count = 0;
-       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
-       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
-       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-
-}
 
 void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
 {
@@ -1494,36 +1463,3 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt)
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
 
 }
-
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       int sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       switch (cmd) {
-       case STA_NOTIFY_SLEEP:
-               WARN_ON(!sta_priv->client);
-               sta_priv->asleep = true;
-               if (atomic_read(&sta_priv->pending_frames) > 0)
-                       ieee80211_sta_block_awake(hw, sta, true);
-               break;
-       case STA_NOTIFY_AWAKE:
-               WARN_ON(!sta_priv->client);
-               if (!sta_priv->asleep)
-                       break;
-               sta_priv->asleep = false;
-               sta_id = iwl_sta_id(sta);
-               if (sta_id != IWL_INVALID_STATION)
-                       iwl_sta_modify_ps_wake(priv, sta_id);
-               break;
-       default:
-               break;
-       }
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
index 35a6b71f358ce7a563f6507b58f0743eb6ded16a..e6a02e09ee18e1115ef83986e3bfaa998ec6d383 100644 (file)
@@ -283,6 +283,19 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                IWL_DEBUG_TX(priv, "Sending REASSOC frame\n");
 #endif
 
+       if (unlikely(ieee80211_is_probe_resp(fc))) {
+               struct iwl_wipan_noa_data *noa_data =
+                       rcu_dereference(priv->noa_data);
+
+               if (noa_data &&
+                   pskb_expand_head(skb, 0, noa_data->length,
+                                    GFP_ATOMIC) == 0) {
+                       memcpy(skb_put(skb, noa_data->length),
+                              noa_data->data, noa_data->length);
+                       hdr = (struct ieee80211_hdr *)skb->data;
+               }
+       }
+
        hdr_len = ieee80211_hdrlen(fc);
 
        /* For management frames use broadcast id to do not break aggregation */
@@ -800,7 +813,8 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
                            iwl_is_associated_ctx(ctx) && ctx->vif &&
                            ctx->vif->type == NL80211_IFTYPE_STATION) {
                                ctx->last_tx_rejected = true;
-                               iwl_trans_stop_queue(trans(priv), txq_id);
+                               iwl_trans_stop_queue(trans(priv), txq_id,
+                                       "Tx on passive channel");
 
                                IWL_DEBUG_TX_REPLY(priv,
                                           "TXQ %d status %s (0x%08x) "
index 8ba0dd54e37d4faee68bb900a1e99fb5de6543d6..9ec315b31d453cb0b9d71531ba060b9a23ff27d8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/sched.h>
+#include <linux/dma-mapping.h>
 
 #include "iwl-dev.h"
 #include "iwl-core.h"
@@ -72,51 +73,98 @@ static struct iwl_wimax_coex_event_entry cu_priorities[COEX_NUM_OF_EVENTS] = {
        {COEX_CU_RSRVD2_RP, COEX_CU_RSRVD2_WP, 0, COEX_RSRVD2_FLAGS}
 };
 
+/******************************************************************************
+ *
+ * uCode download functions
+ *
+ ******************************************************************************/
+
+static void iwl_free_fw_desc(struct iwl_bus *bus, struct fw_desc *desc)
+{
+       if (desc->v_addr)
+               dma_free_coherent(bus->dev, desc->len,
+                                 desc->v_addr, desc->p_addr);
+       desc->v_addr = NULL;
+       desc->len = 0;
+}
+
+static void iwl_free_fw_img(struct iwl_bus *bus, struct fw_img *img)
+{
+       iwl_free_fw_desc(bus, &img->code);
+       iwl_free_fw_desc(bus, &img->data);
+}
+
+void iwl_dealloc_ucode(struct iwl_trans *trans)
+{
+       iwl_free_fw_img(bus(trans), &trans->ucode_rt);
+       iwl_free_fw_img(bus(trans), &trans->ucode_init);
+       iwl_free_fw_img(bus(trans), &trans->ucode_wowlan);
+}
+
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len)
+{
+       if (!len) {
+               desc->v_addr = NULL;
+               return -EINVAL;
+       }
+
+       desc->v_addr = dma_alloc_coherent(bus->dev, len,
+                                         &desc->p_addr, GFP_KERNEL);
+       if (!desc->v_addr)
+               return -ENOMEM;
+
+       desc->len = len;
+       memcpy(desc->v_addr, data, len);
+       return 0;
+}
+
 /*
  * ucode
  */
-static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
+static int iwlagn_load_section(struct iwl_trans *trans, const char *name,
                                struct fw_desc *image, u32 dst_addr)
 {
+       struct iwl_bus *bus = bus(trans);
        dma_addr_t phy_addr = image->p_addr;
        u32 byte_cnt = image->len;
        int ret;
 
-       priv->ucode_write_complete = 0;
+       trans->ucode_write_complete = 0;
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_SRVC_CHNL_SRAM_ADDR_REG(FH_SRVC_CHNL), dst_addr);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL0_REG(FH_SRVC_CHNL),
                phy_addr & FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL),
                (iwl_get_dma_hi_addr(phy_addr)
                        << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_BUF_STS_REG(FH_SRVC_CHNL),
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM |
                1 << FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX |
                FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID);
 
-       iwl_write_direct32(bus(priv),
+       iwl_write_direct32(bus,
                FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL),
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE       |
                FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE    |
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
-       IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_timeout(priv->shrd->wait_command_queue,
-                                priv->ucode_write_complete, 5 * HZ);
+       IWL_DEBUG_FW(bus, "%s uCode section being loaded...\n", name);
+       ret = wait_event_timeout(trans->shrd->wait_command_queue,
+                                trans->ucode_write_complete, 5 * HZ);
        if (!ret) {
-               IWL_ERR(priv, "Could not load the %s uCode section\n",
+               IWL_ERR(trans, "Could not load the %s uCode section\n",
                        name);
                return -ETIMEDOUT;
        }
@@ -124,17 +172,41 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
        return 0;
 }
 
-static int iwlagn_load_given_ucode(struct iwl_priv *priv,
-                                  struct fw_img *image)
+static inline struct fw_img *iwl_get_ucode_image(struct iwl_trans *trans,
+                                       enum iwl_ucode_type ucode_type)
+{
+       switch (ucode_type) {
+       case IWL_UCODE_INIT:
+               return &trans->ucode_init;
+       case IWL_UCODE_WOWLAN:
+               return &trans->ucode_wowlan;
+       case IWL_UCODE_REGULAR:
+               return &trans->ucode_rt;
+       case IWL_UCODE_NONE:
+               break;
+       }
+       return NULL;
+}
+
+static int iwlagn_load_given_ucode(struct iwl_trans *trans,
+                                  enum iwl_ucode_type ucode_type)
 {
        int ret = 0;
+       struct fw_img *image = iwl_get_ucode_image(trans, ucode_type);
+
+
+       if (!image) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n",
+                       ucode_type);
+               return -EINVAL;
+       }
 
-       ret = iwlagn_load_section(priv, "INST", &image->code,
+       ret = iwlagn_load_section(trans, "INST", &image->code,
                                   IWLAGN_RTC_INST_LOWER_BOUND);
        if (ret)
                return ret;
 
-       return iwlagn_load_section(priv, "DATA", &image->data,
+       return iwlagn_load_section(trans, "DATA", &image->data,
                                    IWLAGN_RTC_DATA_LOWER_BOUND);
 }
 
@@ -418,7 +490,7 @@ static int iwlagn_alive_notify(struct iwl_priv *priv)
  *   using sample data 100 bytes apart.  If these sample points are good,
  *   it's a pretty good bet that everything between them is good, too.
  */
-static int iwl_verify_inst_sparse(struct iwl_priv *priv,
+static int iwl_verify_inst_sparse(struct iwl_bus *bus,
                                      struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -426,15 +498,15 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        u32 val;
        u32 i;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
        for (i = 0; i < len; i += 100, image += 100/sizeof(u32)) {
                /* read data comes through single port, auto-incr addr */
                /* NOTE: Use the debugless read so we don't flood kernel log
                 * if IWL_DL_IO is set */
-               iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+               iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                        i + IWLAGN_RTC_INST_LOWER_BOUND);
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image))
                        return -EIO;
        }
@@ -442,7 +514,7 @@ static int iwl_verify_inst_sparse(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwl_print_mismatch_inst(struct iwl_priv *priv,
+static void iwl_print_mismatch_inst(struct iwl_bus *bus,
                                    struct fw_desc *fw_desc)
 {
        __le32 *image = (__le32 *)fw_desc->v_addr;
@@ -451,18 +523,18 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
        u32 offs;
        int errors = 0;
 
-       IWL_DEBUG_FW(priv, "ucode inst image size is %u\n", len);
+       IWL_DEBUG_FW(bus, "ucode inst image size is %u\n", len);
 
-       iwl_write_direct32(bus(priv), HBUS_TARG_MEM_RADDR,
+       iwl_write_direct32(bus, HBUS_TARG_MEM_RADDR,
                           IWLAGN_RTC_INST_LOWER_BOUND);
 
        for (offs = 0;
             offs < len && errors < 20;
             offs += sizeof(u32), image++) {
                /* read data comes through single port, auto-incr addr */
-               val = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+               val = iwl_read32(bus, HBUS_TARG_MEM_RDAT);
                if (val != le32_to_cpu(*image)) {
-                       IWL_ERR(priv, "uCode INST section at "
+                       IWL_ERR(bus, "uCode INST section at "
                                "offset 0x%x, is 0x%x, s/b 0x%x\n",
                                offs, val, le32_to_cpu(*image));
                        errors++;
@@ -474,16 +546,24 @@ static void iwl_print_mismatch_inst(struct iwl_priv *priv,
  * iwl_verify_ucode - determine which instruction image is in SRAM,
  *    and verify its contents
  */
-static int iwl_verify_ucode(struct iwl_priv *priv, struct fw_img *img)
+static int iwl_verify_ucode(struct iwl_trans *trans,
+                           enum iwl_ucode_type ucode_type)
 {
-       if (!iwl_verify_inst_sparse(priv, &img->code)) {
-               IWL_DEBUG_FW(priv, "uCode is good in inst SRAM\n");
+       struct fw_img *img = iwl_get_ucode_image(trans, ucode_type);
+
+       if (!img) {
+               IWL_ERR(trans, "Invalid ucode requested (%d)\n", ucode_type);
+               return -EINVAL;
+       }
+
+       if (!iwl_verify_inst_sparse(bus(trans), &img->code)) {
+               IWL_DEBUG_FW(trans, "uCode is good in inst SRAM\n");
                return 0;
        }
 
-       IWL_ERR(priv, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
+       IWL_ERR(trans, "UCODE IMAGE IN INSTRUCTION SRAM NOT VALID!!\n");
 
-       iwl_print_mismatch_inst(priv, &img->code);
+       iwl_print_mismatch_inst(bus(trans), &img->code);
        return -EIO;
 }
 
@@ -519,13 +599,12 @@ static void iwlagn_alive_fn(struct iwl_priv *priv,
 #define UCODE_CALIB_TIMEOUT    (2*HZ)
 
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type)
+                                enum iwl_ucode_type ucode_type)
 {
        struct iwl_notification_wait alive_wait;
        struct iwlagn_alive_data alive_data;
        int ret;
-       enum iwlagn_ucode_type old_type;
+       enum iwl_ucode_type old_type;
 
        ret = iwl_trans_start_device(trans(priv));
        if (ret)
@@ -537,7 +616,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
        old_type = priv->ucode_type;
        priv->ucode_type = ucode_type;
 
-       ret = iwlagn_load_given_ucode(priv, image);
+       ret = iwlagn_load_given_ucode(trans(priv), ucode_type);
        if (ret) {
                priv->ucode_type = old_type;
                iwlagn_remove_notification(priv, &alive_wait);
@@ -568,7 +647,7 @@ int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
         * skip it for WoWLAN.
         */
        if (ucode_type != IWL_UCODE_WOWLAN) {
-               ret = iwl_verify_ucode(priv, image);
+               ret = iwl_verify_ucode(trans(priv), ucode_type);
                if (ret) {
                        priv->ucode_type = old_type;
                        return ret;
@@ -597,7 +676,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
        lockdep_assert_held(&priv->shrd->mutex);
 
        /* No init ucode required? Curious, but maybe ok */
-       if (!priv->ucode_init.code.len)
+       if (!trans(priv)->ucode_init.code.len)
                return 0;
 
        if (priv->ucode_type != IWL_UCODE_NONE)
@@ -608,8 +687,7 @@ int iwlagn_run_init_ucode(struct iwl_priv *priv)
                                      NULL, NULL);
 
        /* Will also start the device */
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                          IWL_UCODE_INIT);
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
        if (ret)
                goto error;
 
index ccba69b7f8a78f9b54635328bee5c3e3d4d4553a..e235e84de8b4a5c678a2f5ad479899e9ac662901 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/dma-mapping.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/skbuff.h>
@@ -452,52 +451,6 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-/******************************************************************************
- *
- * uCode download functions
- *
- ******************************************************************************/
-
-static void iwl_free_fw_desc(struct iwl_priv *priv, struct fw_desc *desc)
-{
-       if (desc->v_addr)
-               dma_free_coherent(bus(priv)->dev, desc->len,
-                                 desc->v_addr, desc->p_addr);
-       desc->v_addr = NULL;
-       desc->len = 0;
-}
-
-static void iwl_free_fw_img(struct iwl_priv *priv, struct fw_img *img)
-{
-       iwl_free_fw_desc(priv, &img->code);
-       iwl_free_fw_desc(priv, &img->data);
-}
-
-static void iwl_dealloc_ucode(struct iwl_priv *priv)
-{
-       iwl_free_fw_img(priv, &priv->ucode_rt);
-       iwl_free_fw_img(priv, &priv->ucode_init);
-       iwl_free_fw_img(priv, &priv->ucode_wowlan);
-}
-
-static int iwl_alloc_fw_desc(struct iwl_priv *priv, struct fw_desc *desc,
-                            const void *data, size_t len)
-{
-       if (!len) {
-               desc->v_addr = NULL;
-               return -EINVAL;
-       }
-
-       desc->v_addr = dma_alloc_coherent(bus(priv)->dev, len,
-                                         &desc->p_addr, GFP_KERNEL);
-       if (!desc->v_addr)
-               return -ENOMEM;
-
-       desc->len = len;
-       memcpy(desc->v_addr, data, len);
-       return 0;
-}
-
 static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
 {
        int i;
@@ -555,16 +508,7 @@ static void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
        BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
 }
 
-
-struct iwlagn_ucode_capabilities {
-       u32 max_probe_length;
-       u32 standard_phy_calibration_size;
-       u32 flags;
-};
-
 static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context);
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa);
 
 #define UCODE_EXPERIMENTAL_INDEX       100
 #define UCODE_EXPERIMENTAL_TAG         "exp"
@@ -1040,30 +984,32 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        /* Runtime instructions and 2 copies of data:
         * 1) unmodified from disk
         * 2) backup cache for save/restore during power-downs */
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.code,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.code,
                              pieces.inst, pieces.inst_size))
                goto err_pci_alloc;
-       if (iwl_alloc_fw_desc(priv, &priv->ucode_rt.data,
+       if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_rt.data,
                              pieces.data, pieces.data_size))
                goto err_pci_alloc;
 
        /* Initialization instructions and data */
        if (pieces.init_size && pieces.init_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.code,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.code,
                                      pieces.init, pieces.init_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_init.data,
+               if (iwl_alloc_fw_desc(bus(priv), &trans(priv)->ucode_init.data,
                                      pieces.init_data, pieces.init_data_size))
                        goto err_pci_alloc;
        }
 
        /* WoWLAN instructions and data */
        if (pieces.wowlan_inst_size && pieces.wowlan_data_size) {
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.code,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.code,
                                      pieces.wowlan_inst,
                                      pieces.wowlan_inst_size))
                        goto err_pci_alloc;
-               if (iwl_alloc_fw_desc(priv, &priv->ucode_wowlan.data,
+               if (iwl_alloc_fw_desc(bus(priv),
+                                     &trans(priv)->ucode_wowlan.data,
                                      pieces.wowlan_data,
                                      pieces.wowlan_data_size))
                        goto err_pci_alloc;
@@ -1156,7 +1102,7 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
 
  err_pci_alloc:
        IWL_ERR(priv, "failed to allocate pci memory\n");
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
  out_unbind:
        complete(&priv->firmware_loading_complete);
        device_release_driver(bus(priv)->dev);
@@ -1352,7 +1298,7 @@ int iwl_alive_start(struct iwl_priv *priv)
 
 static void iwl_cancel_deferred_work(struct iwl_priv *priv);
 
-static void __iwl_down(struct iwl_priv *priv)
+void __iwl_down(struct iwl_priv *priv)
 {
        int exit_pending;
 
@@ -1415,7 +1361,7 @@ static void __iwl_down(struct iwl_priv *priv)
        priv->beacon_skb = NULL;
 }
 
-static void iwl_down(struct iwl_priv *priv)
+void iwl_down(struct iwl_priv *priv)
 {
        mutex_lock(&priv->shrd->mutex);
        __iwl_down(priv);
@@ -1424,57 +1370,6 @@ static void iwl_down(struct iwl_priv *priv)
        iwl_cancel_deferred_work(priv);
 }
 
-#define MAX_HW_RESTARTS 5
-
-static int __iwl_up(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx;
-       int ret;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
-               return -EIO;
-       }
-
-       for_each_context(priv, ctx) {
-               ret = iwlagn_alloc_bcast_station(priv, ctx);
-               if (ret) {
-                       iwl_dealloc_bcast_stations(priv);
-                       return ret;
-               }
-       }
-
-       ret = iwlagn_run_init_ucode(priv);
-       if (ret) {
-               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
-       if (ret) {
-               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
-               goto error;
-       }
-
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-       return 0;
-
- error:
-       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-       __iwl_down(priv);
-       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
-
-       IWL_ERR(priv, "Unable to initialize device.\n");
-       return ret;
-}
-
-
 /*****************************************************************************
  *
  * Workqueue callbacks
@@ -1502,7 +1397,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work)
        mutex_unlock(&priv->shrd->mutex);
 }
 
-static void iwlagn_prepare_restart(struct iwl_priv *priv)
+void iwlagn_prepare_restart(struct iwl_priv *priv)
 {
        struct iwl_rxon_context *ctx;
        bool bt_full_concurrent;
@@ -1559,1499 +1454,180 @@ static void iwl_bg_restart(struct work_struct *data)
        }
 }
 
-/*****************************************************************************
- *
- * mac80211 entry point functions
- *
- *****************************************************************************/
-
-static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_GO) |
-                        BIT(NL80211_IFTYPE_AP),
-       },
-};
-
-static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
-       {
-               .max = 2,
-               .types = BIT(NL80211_IFTYPE_STATION),
-       },
-       {
-               .max = 1,
-               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_dualmode[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_sta_ap_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
-       },
-};
 
-static const struct ieee80211_iface_combination
-iwlagn_iface_combinations_p2p[] = {
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .beacon_int_infra_match = true,
-         .limits = iwlagn_p2p_sta_go_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
-       },
-       { .num_different_channels = 1,
-         .max_interfaces = 2,
-         .limits = iwlagn_p2p_2sta_limits,
-         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
-       },
-};
 
-/*
- * Not a mac80211 entry point function, but it fits in with all the
- * other mac80211 functions grouped here.
- */
-static int iwlagn_mac_setup_register(struct iwl_priv *priv,
-                                 struct iwlagn_ucode_capabilities *capa)
+void iwlagn_disable_roc(struct iwl_priv *priv)
 {
-       int ret;
-       struct ieee80211_hw *hw = priv->hw;
-       struct iwl_rxon_context *ctx;
-
-       hw->rate_control_algorithm = "iwl-agn-rs";
-
-       /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_AMPDU_AGGREGATION |
-                   IEEE80211_HW_NEED_DTIM_PERIOD |
-                   IEEE80211_HW_SPECTRUM_MGMT |
-                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
-
-       /*
-        * Including the following line will crash some AP's.  This
-        * workaround removes the stimulus which causes the crash until
-        * the AP software can be fixed.
-       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-        */
-
-       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
-                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
-
-       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
-               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
-                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
-
-       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
-
-       hw->sta_data_size = sizeof(struct iwl_station_priv);
-       hw->vif_data_size = sizeof(struct iwl_vif_priv);
-
-       for_each_context(priv, ctx) {
-               hw->wiphy->interface_modes |= ctx->interface_modes;
-               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
-       }
-
-       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-
-       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
-       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
-               hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode;
-               hw->wiphy->n_iface_combinations =
-                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
-       }
-
-       hw->wiphy->max_remain_on_channel_duration = 1000;
-
-       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
-                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
-                           WIPHY_FLAG_IBSS_RSN;
-
-       if (priv->ucode_wowlan.code.len && device_can_wakeup(bus(priv)->dev)) {
-               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
-                                         WIPHY_WOWLAN_DISCONNECT |
-                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
-                                         WIPHY_WOWLAN_RFKILL_RELEASE;
-               if (!iwlagn_mod_params.sw_crypto)
-                       hw->wiphy->wowlan.flags |=
-                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
-                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
-
-               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
-               hw->wiphy->wowlan.pattern_min_len =
-                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
-               hw->wiphy->wowlan.pattern_max_len =
-                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
-       }
-
-       if (iwlagn_mod_params.power_save)
-               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
-       else
-               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
 
-       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
-       /* we create the 802.11 header and a zero-length SSID element */
-       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+       lockdep_assert_held(&priv->shrd->mutex);
 
-       /* Default value; 4 EDCA QOS priorities */
-       hw->queues = 4;
+       if (!priv->hw_roc_setup)
+               return;
 
-       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
-       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
-                       &priv->bands[IEEE80211_BAND_2GHZ];
-       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
-               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &priv->bands[IEEE80211_BAND_5GHZ];
+       priv->hw_roc_channel = NULL;
 
-       iwl_leds_init(priv);
+       memset(ctx->staging.node_addr, 0, ETH_ALEN);
 
-       ret = ieee80211_register_hw(priv->hw);
-       if (ret) {
-               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
-               return ret;
-       }
-       priv->mac80211_registered = 1;
+       iwlagn_commit_rxon(priv, ctx);
 
-       return 0;
+       ctx->is_active = false;
+       priv->hw_roc_setup = false;
 }
 
-
-static int iwlagn_mac_start(struct ieee80211_hw *hw)
+static void iwlagn_disable_roc_work(struct work_struct *work)
 {
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       struct iwl_priv *priv = container_of(work, struct iwl_priv,
+                                            hw_roc_disable_work.work);
 
-       /* we should be verifying the device is ready to be opened */
        mutex_lock(&priv->shrd->mutex);
-       ret = __iwl_up(priv);
+       iwlagn_disable_roc(priv);
        mutex_unlock(&priv->shrd->mutex);
-       if (ret)
-               return ret;
-
-       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
-
-       /* Now we should be done, and the READY bit should be set. */
-       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
-               ret = -EIO;
-
-       iwlagn_led_enable(priv);
-
-       priv->is_open = 1;
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
 }
 
-static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+/*****************************************************************************
+ *
+ * driver setup and teardown
+ *
+ *****************************************************************************/
+
+static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
+       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
 
-       IWL_DEBUG_MAC80211(priv, "enter\n");
+       init_waitqueue_head(&priv->shrd->wait_command_queue);
 
-       if (!priv->is_open)
-               return;
+       INIT_WORK(&priv->restart, iwl_bg_restart);
+       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
+       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
+       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
+       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
+       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
+       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
+                         iwlagn_disable_roc_work);
 
-       priv->is_open = 0;
+       iwl_setup_scan_deferred_work(priv);
 
-       iwl_down(priv);
+       if (priv->cfg->lib->bt_setup_deferred_work)
+               priv->cfg->lib->bt_setup_deferred_work(priv);
 
-       flush_workqueue(priv->shrd->workqueue);
+       init_timer(&priv->statistics_periodic);
+       priv->statistics_periodic.data = (unsigned long)priv;
+       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
 
-       /* User space software may expect getting rfkill changes
-        * even if interface is down */
-       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
-       iwl_enable_rfkill_int(priv);
+       init_timer(&priv->ucode_trace);
+       priv->ucode_trace.data = (unsigned long)priv;
+       priv->ucode_trace.function = iwl_bg_ucode_trace;
 
-       IWL_DEBUG_MAC80211(priv, "leave\n");
+       init_timer(&priv->watchdog);
+       priv->watchdog.data = (unsigned long)priv;
+       priv->watchdog.function = iwl_bg_watchdog;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int iwlagn_send_patterns(struct iwl_priv *priv,
-                               struct cfg80211_wowlan *wowlan)
+static void iwl_cancel_deferred_work(struct iwl_priv *priv)
 {
-       struct iwlagn_wowlan_patterns_cmd *pattern_cmd;
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_WOWLAN_PATTERNS,
-               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-               .flags = CMD_SYNC,
-       };
-       int i, err;
+       if (priv->cfg->lib->cancel_deferred_work)
+               priv->cfg->lib->cancel_deferred_work(priv);
 
-       if (!wowlan->n_patterns)
-               return 0;
+       cancel_work_sync(&priv->run_time_calib_work);
+       cancel_work_sync(&priv->beacon_update);
 
-       cmd.len[0] = sizeof(*pattern_cmd) +
-                       wowlan->n_patterns * sizeof(struct iwlagn_wowlan_pattern);
+       iwl_cancel_scan_deferred_work(priv);
 
-       pattern_cmd = kmalloc(cmd.len[0], GFP_KERNEL);
-       if (!pattern_cmd)
-               return -ENOMEM;
+       cancel_work_sync(&priv->bt_full_concurrency);
+       cancel_work_sync(&priv->bt_runtime_config);
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
 
-       pattern_cmd->n_patterns = cpu_to_le32(wowlan->n_patterns);
+       del_timer_sync(&priv->statistics_periodic);
+       del_timer_sync(&priv->ucode_trace);
+}
 
-       for (i = 0; i < wowlan->n_patterns; i++) {
-               int mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
+static void iwl_init_hw_rates(struct iwl_priv *priv,
+                             struct ieee80211_rate *rates)
+{
+       int i;
 
-               memcpy(&pattern_cmd->patterns[i].mask,
-                       wowlan->patterns[i].mask, mask_len);
-               memcpy(&pattern_cmd->patterns[i].pattern,
-                       wowlan->patterns[i].pattern,
-                       wowlan->patterns[i].pattern_len);
-               pattern_cmd->patterns[i].mask_size = mask_len;
-               pattern_cmd->patterns[i].pattern_size =
-                       wowlan->patterns[i].pattern_len;
+       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
+               rates[i].bitrate = iwl_rates[i].ieee * 5;
+               rates[i].hw_value = i; /* Rate scaling will work on indexes */
+               rates[i].hw_value_short = i;
+               rates[i].flags = 0;
+               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
+                       /*
+                        * If CCK != 1M then set short preamble rate flag.
+                        */
+                       rates[i].flags |=
+                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
+                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
+               }
        }
-
-       cmd.data[0] = pattern_cmd;
-       err = iwl_trans_send_cmd(trans(priv), &cmd);
-       kfree(pattern_cmd);
-       return err;
 }
-#endif
 
-static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
-                                     struct ieee80211_vif *vif,
-                                     struct cfg80211_gtk_rekey_data *data)
+static int iwl_init_drv(struct iwl_priv *priv)
 {
-       struct iwl_priv *priv = hw->priv;
-
-       if (iwlagn_mod_params.sw_crypto)
-               return;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
+       int ret;
 
-       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
-               goto out;
+       spin_lock_init(&priv->shrd->sta_lock);
 
-       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
-       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
-       priv->replay_ctr = cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
-       priv->have_rekey_data = true;
+       mutex_init(&priv->shrd->mutex);
 
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
+       priv->ieee_channels = NULL;
+       priv->ieee_rates = NULL;
+       priv->band = IEEE80211_BAND_2GHZ;
 
-struct wowlan_key_data {
-       struct iwl_rxon_context *ctx;
-       struct iwlagn_wowlan_rsc_tsc_params_cmd *rsc_tsc;
-       struct iwlagn_wowlan_tkip_params_cmd *tkip;
-       const u8 *bssid;
-       bool error, use_rsc_tsc, use_tkip;
-};
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
+       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
+       priv->agg_tids_count = 0;
 
-#ifdef CONFIG_PM_SLEEP
-static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
-{
-       int i;
+       /* initialize force reset */
+       priv->force_reset[IWL_RF_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_RF_RESET;
+       priv->force_reset[IWL_FW_RESET].reset_duration =
+               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
 
-       for (i = 0; i < IWLAGN_P1K_SIZE; i++)
-               out[i] = cpu_to_le16(p1k[i]);
-}
+       priv->rx_statistics_jiffies = jiffies;
 
-static void iwlagn_wowlan_program_keys(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_sta *sta,
-                                      struct ieee80211_key_conf *key,
-                                      void *_data)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct wowlan_key_data *data = _data;
-       struct iwl_rxon_context *ctx = data->ctx;
-       struct aes_sc *aes_sc, *aes_tx_sc = NULL;
-       struct tkip_sc *tkip_sc, *tkip_tx_sc = NULL;
-       struct iwlagn_p1k_cache *rx_p1ks;
-       u8 *rx_mic_key;
-       struct ieee80211_key_seq seq;
-       u32 cur_rx_iv32 = 0;
-       u16 p1k[IWLAGN_P1K_SIZE];
-       int ret, i;
+       /* Choose which receivers/antennas to use */
+       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
 
-       mutex_lock(&priv->shrd->mutex);
+       iwl_init_scan_params(priv);
 
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) &&
-            !sta && !ctx->key_mapping_keys)
-               ret = iwl_set_default_wep_key(priv, ctx, key);
-       else
-               ret = iwl_set_dynamic_key(priv, ctx, key, sta);
+       /* init bt coex */
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
+               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
+               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
+               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
+               priv->bt_duration = BT_DURATION_LIMIT_DEF;
+               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
+       }
 
+       ret = iwl_init_channel_map(priv);
        if (ret) {
-               IWL_ERR(priv, "Error setting key during suspend!\n");
-               data->error = true;
+               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
+               goto err;
        }
 
-       switch (key->cipher) {
-       case WLAN_CIPHER_SUITE_TKIP:
-               if (sta) {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.unicast_rsc;
-                       tkip_tx_sc = &data->rsc_tsc->all_tsc_rsc.tkip.tsc;
-
-                       rx_p1ks = data->tkip->rx_uni;
+       ret = iwl_init_geos(priv);
+       if (ret) {
+               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
+               goto err_free_channel_map;
+       }
+       iwl_init_hw_rates(priv, priv->ieee_rates);
 
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       tkip_tx_sc->iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_tx_sc->iv32 = cpu_to_le32(seq.tkip.iv32);
+       return 0;
 
-                       ieee80211_get_tkip_p1k_iv(key, seq.tkip.iv32, p1k);
-                       iwlagn_convert_p1k(p1k, data->tkip->tx.p1k);
-
-                       memcpy(data->tkip->mic_keys.tx,
-                              &key->key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY],
-                              IWLAGN_MIC_KEY_SIZE);
-
-                       rx_mic_key = data->tkip->mic_keys.rx_unicast;
-               } else {
-                       tkip_sc = data->rsc_tsc->all_tsc_rsc.tkip.multicast_rsc;
-                       rx_p1ks = data->tkip->rx_multi;
-                       rx_mic_key = data->tkip->mic_keys.rx_mcast;
-               }
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 (as they need to to avoid replay attacks)
-                * for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       tkip_sc[i].iv16 = cpu_to_le16(seq.tkip.iv16);
-                       tkip_sc[i].iv32 = cpu_to_le32(seq.tkip.iv32);
-                       /* wrapping isn't allowed, AP must rekey */
-                       if (seq.tkip.iv32 > cur_rx_iv32)
-                               cur_rx_iv32 = seq.tkip.iv32;
-               }
-
-               ieee80211_get_tkip_rx_p1k(key, data->bssid, cur_rx_iv32, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[0].p1k);
-               ieee80211_get_tkip_rx_p1k(key, data->bssid,
-                                         cur_rx_iv32 + 1, p1k);
-               iwlagn_convert_p1k(p1k, rx_p1ks[1].p1k);
-
-               memcpy(rx_mic_key,
-                      &key->key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY],
-                      IWLAGN_MIC_KEY_SIZE);
-
-               data->use_tkip = true;
-               data->use_rsc_tsc = true;
-               break;
-       case WLAN_CIPHER_SUITE_CCMP:
-               if (sta) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.unicast_rsc;
-                       aes_tx_sc = &data->rsc_tsc->all_tsc_rsc.aes.tsc;
-
-                       ieee80211_get_key_tx_seq(key, &seq);
-                       aes_tx_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               } else
-                       aes_sc = data->rsc_tsc->all_tsc_rsc.aes.multicast_rsc;
-
-               /*
-                * For non-QoS this relies on the fact that both the uCode and
-                * mac80211 use TID 0 for checking the IV in the frames.
-                */
-               for (i = 0; i < IWLAGN_NUM_RSC; i++) {
-                       u8 *pn = seq.ccmp.pn;
-
-                       ieee80211_get_key_rx_seq(key, i, &seq);
-                       aes_sc->pn = cpu_to_le64(
-                                       (u64)pn[5] |
-                                       ((u64)pn[4] << 8) |
-                                       ((u64)pn[3] << 16) |
-                                       ((u64)pn[2] << 24) |
-                                       ((u64)pn[1] << 32) |
-                                       ((u64)pn[0] << 40));
-               }
-               data->use_rsc_tsc = true;
-               break;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
-                             struct cfg80211_wowlan *wowlan)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwlagn_wowlan_wakeup_filter_cmd wakeup_filter_cmd;
-       struct iwl_rxon_cmd rxon;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwlagn_wowlan_kek_kck_material_cmd kek_kck_cmd;
-       struct iwlagn_wowlan_tkip_params_cmd tkip_cmd = {};
-       struct wowlan_key_data key_data = {
-               .ctx = ctx,
-               .bssid = ctx->active.bssid_addr,
-               .use_rsc_tsc = false,
-               .tkip = &tkip_cmd,
-               .use_tkip = false,
-       };
-       int ret, i;
-       u16 seq;
-
-       if (WARN_ON(!wowlan))
-               return -EINVAL;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       /* Don't attempt WoWLAN when not associated, tear down instead. */
-       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
-           !iwl_is_associated_ctx(ctx)) {
-               ret = 1;
-               goto out;
-       }
-
-       key_data.rsc_tsc = kzalloc(sizeof(*key_data.rsc_tsc), GFP_KERNEL);
-       if (!key_data.rsc_tsc) {
-               ret = -ENOMEM;
-               goto out;
-       }
-
-       memset(&wakeup_filter_cmd, 0, sizeof(wakeup_filter_cmd));
-
-       /*
-        * We know the last used seqno, and the uCode expects to know that
-        * one, it will increment before TX.
-        */
-       seq = le16_to_cpu(priv->last_seq_ctl) & IEEE80211_SCTL_SEQ;
-       wakeup_filter_cmd.non_qos_seq = cpu_to_le16(seq);
-
-       /*
-        * For QoS counters, we store the one to use next, so subtract 0x10
-        * since the uCode will add 0x10 before using the value.
-        */
-       for (i = 0; i < 8; i++) {
-               seq = priv->shrd->tid_data[IWL_AP_ID][i].seq_number;
-               seq -= 0x10;
-               wakeup_filter_cmd.qos_seq[i] = cpu_to_le16(seq);
-       }
-
-       if (wowlan->disconnect)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_BEACON_MISS |
-                                   IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE);
-       if (wowlan->magic_pkt)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_MAGIC_PACKET);
-       if (wowlan->gtk_rekey_failure)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL);
-       if (wowlan->eap_identity_req)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ);
-       if (wowlan->four_way_handshake)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE);
-       if (wowlan->rfkill_release)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_RFKILL);
-       if (wowlan->n_patterns)
-               wakeup_filter_cmd.enabled |=
-                       cpu_to_le32(IWLAGN_WOWLAN_WAKEUP_PATTERN_MATCH);
-
-       iwl_scan_cancel_timeout(priv, 200);
-
-       memcpy(&rxon, &ctx->active, sizeof(rxon));
-
-       iwl_trans_stop_device(trans(priv));
-
-       priv->shrd->wowlan = true;
-
-       ret = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_wowlan,
-                                          IWL_UCODE_WOWLAN);
-       if (ret)
-               goto error;
-
-       /* now configure WoWLAN ucode */
-       ret = iwl_alive_start(priv);
-       if (ret)
-               goto error;
-
-       memcpy(&ctx->staging, &rxon, sizeof(rxon));
-       ret = iwlagn_commit_rxon(priv, ctx);
-       if (ret)
-               goto error;
-
-       ret = iwl_power_update_mode(priv, true);
-       if (ret)
-               goto error;
-
-       if (!iwlagn_mod_params.sw_crypto) {
-               /* mark all keys clear */
-               priv->ucode_key_table = 0;
-               ctx->key_mapping_keys = 0;
-
-               /*
-                * This needs to be unlocked due to lock ordering
-                * constraints. Since we're in the suspend path
-                * that isn't really a problem though.
-                */
-               mutex_unlock(&priv->shrd->mutex);
-               ieee80211_iter_keys(priv->hw, ctx->vif,
-                                   iwlagn_wowlan_program_keys,
-                                   &key_data);
-               mutex_lock(&priv->shrd->mutex);
-               if (key_data.error) {
-                       ret = -EIO;
-                       goto error;
-               }
-
-               if (key_data.use_rsc_tsc) {
-                       struct iwl_host_cmd rsc_tsc_cmd = {
-                               .id = REPLY_WOWLAN_TSC_RSC_PARAMS,
-                               .flags = CMD_SYNC,
-                               .data[0] = key_data.rsc_tsc,
-                               .dataflags[0] = IWL_HCMD_DFL_NOCOPY,
-                               .len[0] = sizeof(*key_data.rsc_tsc),
-                       };
-
-                       ret = iwl_trans_send_cmd(trans(priv), &rsc_tsc_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (key_data.use_tkip) {
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_TKIP_PARAMS,
-                                                CMD_SYNC, sizeof(tkip_cmd),
-                                                &tkip_cmd);
-                       if (ret)
-                               goto error;
-               }
-
-               if (priv->have_rekey_data) {
-                       memset(&kek_kck_cmd, 0, sizeof(kek_kck_cmd));
-                       memcpy(kek_kck_cmd.kck, priv->kck, NL80211_KCK_LEN);
-                       kek_kck_cmd.kck_len = cpu_to_le16(NL80211_KCK_LEN);
-                       memcpy(kek_kck_cmd.kek, priv->kek, NL80211_KEK_LEN);
-                       kek_kck_cmd.kek_len = cpu_to_le16(NL80211_KEK_LEN);
-                       kek_kck_cmd.replay_ctr = priv->replay_ctr;
-
-                       ret = iwl_trans_send_cmd_pdu(trans(priv),
-                                                REPLY_WOWLAN_KEK_KCK_MATERIAL,
-                                                CMD_SYNC, sizeof(kek_kck_cmd),
-                                                &kek_kck_cmd);
-                       if (ret)
-                               goto error;
-               }
-       }
-
-       ret = iwl_trans_send_cmd_pdu(trans(priv), REPLY_WOWLAN_WAKEUP_FILTER,
-                                CMD_SYNC, sizeof(wakeup_filter_cmd),
-                                &wakeup_filter_cmd);
-       if (ret)
-               goto error;
-
-       ret = iwlagn_send_patterns(priv, wowlan);
-       if (ret)
-               goto error;
-
-       device_set_wakeup_enable(bus(priv)->dev, true);
-
-       /* Now let the ucode operate on its own */
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       goto out;
-
- error:
-       priv->shrd->wowlan = false;
-       iwlagn_prepare_restart(priv);
-       ieee80211_restart_hw(priv->hw);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       kfree(key_data.rsc_tsc);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_resume(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct ieee80211_vif *vif;
-       unsigned long flags;
-       u32 base, status = 0xffffffff;
-       int ret = -EIO;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
-                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
-
-       base = priv->device_pointers.error_event_table;
-       if (iwlagn_hw_valid_rtc_data_addr(base)) {
-               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
-               ret = iwl_grab_nic_access_silent(bus(priv));
-               if (ret == 0) {
-                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
-                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
-                       iwl_release_nic_access(bus(priv));
-               }
-               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-               if (ret == 0) {
-                       if (!priv->wowlan_sram)
-                               priv->wowlan_sram =
-                                       kzalloc(priv->ucode_wowlan.data.len,
-                                               GFP_KERNEL);
-
-                       if (priv->wowlan_sram)
-                               _iwl_read_targ_mem_words(
-                                       bus(priv), 0x800000, priv->wowlan_sram,
-                                       priv->ucode_wowlan.data.len / 4);
-               }
-#endif
-       }
-
-       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
-       vif = ctx->vif;
-
-       priv->shrd->wowlan = false;
-
-       device_set_wakeup_enable(bus(priv)->dev, false);
-
-       iwlagn_prepare_restart(priv);
-
-       memset((void *)&ctx->active, 0, sizeof(ctx->active));
-       iwl_connection_init_rx_config(priv, ctx);
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       ieee80211_resume_disconnect(vif);
-
-       return 1;
-}
-#endif
-
-static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MACDUMP(priv, "enter\n");
-
-       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
-                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
-
-       if (iwlagn_tx_skb(priv, skb))
-               dev_kfree_skb_any(skb);
-
-       IWL_DEBUG_MACDUMP(priv, "leave\n");
-}
-
-static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif,
-                                      struct ieee80211_key_conf *keyconf,
-                                      struct ieee80211_sta *sta,
-                                      u32 iv32, u16 *phase1key)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
-}
-
-static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta,
-                             struct ieee80211_key_conf *key)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       bool is_default_wep_key = false;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (iwlagn_mod_params.sw_crypto) {
-               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
-               return -EOPNOTSUPP;
-       }
-
-       /*
-        * We could program these keys into the hardware as well, but we
-        * don't expect much multicast traffic in IBSS and having keys
-        * for more stations is probably more useful.
-        *
-        * Mark key TX-only and return 0.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC &&
-           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
-               key->hw_key_idx = WEP_INVALID_OFFSET;
-               return 0;
-       }
-
-       /* If they key was TX-only, accept deletion */
-       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
-               return 0;
-
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, 100);
-
-       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
-
-       /*
-        * If we are getting WEP group key and we didn't receive any key mapping
-        * so far, we are in legacy wep mode (group key only), otherwise we are
-        * in 1X mode.
-        * In legacy wep mode, we use another host command to the uCode.
-        */
-       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
-            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
-               if (cmd == SET_KEY)
-                       is_default_wep_key = !ctx->key_mapping_keys;
-               else
-                       is_default_wep_key =
-                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
-       }
-
-
-       switch (cmd) {
-       case SET_KEY:
-               if (is_default_wep_key) {
-                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
-                       break;
-               }
-               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
-               if (ret) {
-                       /*
-                        * can't add key for RX, but we don't need it
-                        * in the device for TX so still return 0
-                        */
-                       ret = 0;
-                       key->hw_key_idx = WEP_INVALID_OFFSET;
-               }
-
-               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
-               break;
-       case DISABLE_KEY:
-               if (is_default_wep_key)
-                       ret = iwl_remove_default_wep_key(priv, ctx, key);
-               else
-                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
-
-               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  enum ieee80211_ampdu_mlme_action action,
-                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
-                                  u8 buf_size)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret = -EINVAL;
-       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
-       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
-                    sta->addr, tid);
-
-       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
-               return -EACCES;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       switch (action) {
-       case IEEE80211_AMPDU_RX_START:
-               IWL_DEBUG_HT(priv, "start Rx\n");
-               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
-               break;
-       case IEEE80211_AMPDU_RX_STOP:
-               IWL_DEBUG_HT(priv, "stop Rx\n");
-               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               break;
-       case IEEE80211_AMPDU_TX_START:
-               IWL_DEBUG_HT(priv, "start Tx\n");
-               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
-               break;
-       case IEEE80211_AMPDU_TX_STOP:
-               IWL_DEBUG_HT(priv, "stop Tx\n");
-               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
-               if ((ret == 0) && (priv->agg_tids_count > 0)) {
-                       priv->agg_tids_count--;
-                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                                    priv->agg_tids_count);
-               }
-               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
-                       ret = 0;
-               if (!priv->agg_tids_count && priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch off RTS/CTS if it was previously enabled
-                        */
-                       sta_priv->lq_sta.lq.general_params.flags &=
-                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-               }
-               break;
-       case IEEE80211_AMPDU_TX_OPERATIONAL:
-               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
-
-               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
-                               tid, buf_size);
-
-               /*
-                * If the limit is 0, then it wasn't initialised yet,
-                * use the default. We can do that since we take the
-                * minimum below, and we don't want to go above our
-                * default due to hardware restrictions.
-                */
-               if (sta_priv->max_agg_bufsize == 0)
-                       sta_priv->max_agg_bufsize =
-                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
-
-               /*
-                * Even though in theory the peer could have different
-                * aggregation reorder buffer sizes for different sessions,
-                * our ucode doesn't allow for that and has a global limit
-                * for each station. Therefore, use the minimum of all the
-                * aggregation sessions and our default value.
-                */
-               sta_priv->max_agg_bufsize =
-                       min(sta_priv->max_agg_bufsize, buf_size);
-
-               if (priv->cfg->ht_params &&
-                   priv->cfg->ht_params->use_rts_for_aggregation) {
-                       /*
-                        * switch to RTS/CTS if it is the prefer protection
-                        * method for HT traffic
-                        */
-
-                       sta_priv->lq_sta.lq.general_params.flags |=
-                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
-               }
-               priv->agg_tids_count++;
-               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
-                            priv->agg_tids_count);
-
-               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
-                       sta_priv->max_agg_bufsize;
-
-               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
-                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
-
-               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
-                        sta->addr, tid);
-               ret = 0;
-               break;
-       }
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return ret;
-}
-
-static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             struct ieee80211_sta *sta)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
-       int ret = 0;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
-                       sta->addr);
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
-                       sta->addr);
-       sta_priv->sta_id = IWL_INVALID_STATION;
-
-       atomic_set(&sta_priv->pending_frames, 0);
-       if (vif->type == NL80211_IFTYPE_AP)
-               sta_priv->client = true;
-
-       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
-                                    is_ap, sta, &sta_id);
-       if (ret) {
-               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
-                       sta->addr, ret);
-               /* Should we return success if return code is EEXIST ? */
-               goto out;
-       }
-
-       sta_priv->sta_id = sta_id;
-
-       /* Initialize rate scaling */
-       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
-                      sta->addr);
-       iwl_rs_rate_init(priv, sta, sta_id);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
-                               struct ieee80211_channel_switch *ch_switch)
-{
-       struct iwl_priv *priv = hw->priv;
-       const struct iwl_channel_info *ch_info;
-       struct ieee80211_conf *conf = &hw->conf;
-       struct ieee80211_channel *channel = ch_switch->channel;
-       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
-       /*
-        * MULTI-FIXME
-        * When we add support for multiple interfaces, we need to
-        * revisit this. The channel switch command in the device
-        * only affects the BSS context, but what does that really
-        * mean? And what if we get a CSA on the second interface?
-        * This needs a lot of work.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u16 ch;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_rfkill(priv->shrd))
-               goto out;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
-           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
-           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
-               goto out;
-
-       if (!iwl_is_associated_ctx(ctx))
-               goto out;
-
-       if (!priv->cfg->lib->set_channel_switch)
-               goto out;
-
-       ch = channel->hw_value;
-       if (le16_to_cpu(ctx->active.channel) == ch)
-               goto out;
-
-       ch_info = iwl_get_channel_info(priv, channel->band, ch);
-       if (!is_channel_valid(ch_info)) {
-               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-               goto out;
-       }
-
-       spin_lock_irq(&priv->shrd->lock);
-
-       priv->current_ht_config.smps = conf->smps_mode;
-
-       /* Configure HT40 channels */
-       ctx->ht.enabled = conf_is_ht(conf);
-       if (ctx->ht.enabled) {
-               if (conf_is_ht40_minus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                       ctx->ht.is_40mhz = true;
-               } else if (conf_is_ht40_plus(conf)) {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                       ctx->ht.is_40mhz = true;
-               } else {
-                       ctx->ht.extension_chan_offset =
-                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                       ctx->ht.is_40mhz = false;
-               }
-       } else
-               ctx->ht.is_40mhz = false;
-
-       if ((le16_to_cpu(ctx->staging.channel) != ch))
-               ctx->staging.flags = 0;
-
-       iwl_set_rxon_channel(priv, channel, ctx);
-       iwl_set_rxon_ht(priv, ht_conf);
-       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
-
-       spin_unlock_irq(&priv->shrd->lock);
-
-       iwl_set_rate(priv);
-       /*
-        * at this point, staging_rxon has the
-        * configuration for channel switch
-        */
-       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-       priv->switch_channel = cpu_to_le16(ch);
-       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
-               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
-               priv->switch_channel = 0;
-               ieee80211_chswitch_done(ctx->vif, false);
-       }
-
-out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static void iwlagn_configure_filter(struct ieee80211_hw *hw,
-                                   unsigned int changed_flags,
-                                   unsigned int *total_flags,
-                                   u64 multicast)
-{
-       struct iwl_priv *priv = hw->priv;
-       __le32 filter_or = 0, filter_nand = 0;
-       struct iwl_rxon_context *ctx;
-
-#define CHK(test, flag)        do { \
-       if (*total_flags & (test))              \
-               filter_or |= (flag);            \
-       else                                    \
-               filter_nand |= (flag);          \
-       } while (0)
-
-       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
-                       changed_flags, *total_flags);
-
-       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
-       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
-       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
-       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
-
-#undef CHK
-
-       mutex_lock(&priv->shrd->mutex);
-
-       for_each_context(priv, ctx) {
-               ctx->staging.filter_flags &= ~filter_nand;
-               ctx->staging.filter_flags |= filter_or;
-
-               /*
-                * Not committing directly because hardware can perform a scan,
-                * but we'll eventually commit the filter flags change anyway.
-                */
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       /*
-        * Receiving all multicast frames is always enabled by the
-        * default flags setup in iwl_connection_init_rx_config()
-        * since we currently do not support programming multicast
-        * filters into the device.
-        */
-       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
-                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
-}
-
-static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       mutex_lock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
-               goto done;
-       }
-       if (iwl_is_rfkill(priv->shrd)) {
-               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
-               goto done;
-       }
-
-       /*
-        * mac80211 will not push any more frames for transmit
-        * until the flush is completed
-        */
-       if (drop) {
-               IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
-                       IWL_ERR(priv, "flush request fail\n");
-                       goto done;
-               }
-       }
-       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
-       iwl_trans_wait_tx_queue_empty(trans(priv));
-done:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-void iwlagn_disable_roc(struct iwl_priv *priv)
-{
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (!priv->hw_roc_setup)
-               return;
-
-       ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-       ctx->staging.filter_flags &= ~RXON_FILTER_ASSOC_MSK;
-
-       priv->hw_roc_channel = NULL;
-
-       memset(ctx->staging.node_addr, 0, ETH_ALEN);
-
-       iwlagn_commit_rxon(priv, ctx);
-
-       ctx->is_active = false;
-       priv->hw_roc_setup = false;
-}
-
-static void iwlagn_disable_roc_work(struct work_struct *work)
-{
-       struct iwl_priv *priv = container_of(work, struct iwl_priv,
-                                            hw_roc_disable_work.work);
-
-       mutex_lock(&priv->shrd->mutex);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-}
-
-static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
-                                    struct ieee80211_channel *channel,
-                                    enum nl80211_channel_type channel_type,
-                                    int duration)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
-       int err = 0;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       priv->hw_roc_channel = channel;
-       priv->hw_roc_chantype = channel_type;
-       priv->hw_roc_duration = duration;
-       priv->hw_roc_start_notified = false;
-       cancel_delayed_work(&priv->hw_roc_disable_work);
-
-       if (!ctx->is_active) {
-               ctx->is_active = true;
-               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
-               memcpy(ctx->staging.node_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               memcpy(ctx->staging.bssid_addr,
-                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
-                      ETH_ALEN);
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err)
-                       goto out;
-               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
-                                            RXON_FILTER_PROMISC_MSK |
-                                            RXON_FILTER_CTL2HOST_MSK;
-
-               err = iwlagn_commit_rxon(priv, ctx);
-               if (err) {
-                       iwlagn_disable_roc(priv);
-                       goto out;
-               }
-               priv->hw_roc_setup = true;
-       }
-
-       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
-       if (err)
-               iwlagn_disable_roc(priv);
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
-
-static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
-               return -EOPNOTSUPP;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
-       iwlagn_disable_roc(priv);
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return 0;
-}
-
-static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif,
-                             const u8 *bssid,
-                             enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-       int ret;
-       u8 sta_id;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx)) {
-               ret = 0;
-               goto out;
-       }
-
-       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
-               ret = -EBUSY;
-               goto out;
-       }
-
-       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
-       if (ret)
-               goto out;
-
-       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
-               ret = -EIO;
-               goto out_remove_sta;
-       }
-
-       memcpy(ctx->bssid, bssid, ETH_ALEN);
-       ctx->preauth_bssid = true;
-
-       ret = iwlagn_commit_rxon(priv, ctx);
-
-       if (ret == 0)
-               goto out;
-
- out_remove_sta:
-       iwl_remove_station(priv, sta_id, bssid);
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return ret;
-}
-
-static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
-                                  struct ieee80211_vif *vif,
-                                  const u8 *bssid,
-                                  enum ieee80211_tx_sync_type type)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *ctx = vif_priv->ctx;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (iwl_is_associated_ctx(ctx))
-               goto out;
-
-       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
-       ctx->preauth_bssid = false;
-       /* no need to commit */
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-/*****************************************************************************
- *
- * driver setup and teardown
- *
- *****************************************************************************/
-
-static void iwl_setup_deferred_work(struct iwl_priv *priv)
-{
-       priv->shrd->workqueue = create_singlethread_workqueue(DRV_NAME);
-
-       init_waitqueue_head(&priv->shrd->wait_command_queue);
-
-       INIT_WORK(&priv->restart, iwl_bg_restart);
-       INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update);
-       INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work);
-       INIT_WORK(&priv->tx_flush, iwl_bg_tx_flush);
-       INIT_WORK(&priv->bt_full_concurrency, iwl_bg_bt_full_concurrency);
-       INIT_WORK(&priv->bt_runtime_config, iwl_bg_bt_runtime_config);
-       INIT_DELAYED_WORK(&priv->hw_roc_disable_work,
-                         iwlagn_disable_roc_work);
-
-       iwl_setup_scan_deferred_work(priv);
-
-       if (priv->cfg->lib->bt_setup_deferred_work)
-               priv->cfg->lib->bt_setup_deferred_work(priv);
-
-       init_timer(&priv->statistics_periodic);
-       priv->statistics_periodic.data = (unsigned long)priv;
-       priv->statistics_periodic.function = iwl_bg_statistics_periodic;
-
-       init_timer(&priv->ucode_trace);
-       priv->ucode_trace.data = (unsigned long)priv;
-       priv->ucode_trace.function = iwl_bg_ucode_trace;
-
-       init_timer(&priv->watchdog);
-       priv->watchdog.data = (unsigned long)priv;
-       priv->watchdog.function = iwl_bg_watchdog;
-}
-
-static void iwl_cancel_deferred_work(struct iwl_priv *priv)
-{
-       if (priv->cfg->lib->cancel_deferred_work)
-               priv->cfg->lib->cancel_deferred_work(priv);
-
-       cancel_work_sync(&priv->run_time_calib_work);
-       cancel_work_sync(&priv->beacon_update);
-
-       iwl_cancel_scan_deferred_work(priv);
-
-       cancel_work_sync(&priv->bt_full_concurrency);
-       cancel_work_sync(&priv->bt_runtime_config);
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       del_timer_sync(&priv->statistics_periodic);
-       del_timer_sync(&priv->ucode_trace);
-}
-
-static void iwl_init_hw_rates(struct iwl_priv *priv,
-                             struct ieee80211_rate *rates)
-{
-       int i;
-
-       for (i = 0; i < IWL_RATE_COUNT_LEGACY; i++) {
-               rates[i].bitrate = iwl_rates[i].ieee * 5;
-               rates[i].hw_value = i; /* Rate scaling will work on indexes */
-               rates[i].hw_value_short = i;
-               rates[i].flags = 0;
-               if ((i >= IWL_FIRST_CCK_RATE) && (i <= IWL_LAST_CCK_RATE)) {
-                       /*
-                        * If CCK != 1M then set short preamble rate flag.
-                        */
-                       rates[i].flags |=
-                               (iwl_rates[i].plcp == IWL_RATE_1M_PLCP) ?
-                                       0 : IEEE80211_RATE_SHORT_PREAMBLE;
-               }
-       }
-}
-
-static int iwl_init_drv(struct iwl_priv *priv)
-{
-       int ret;
-
-       spin_lock_init(&priv->shrd->sta_lock);
-
-       mutex_init(&priv->shrd->mutex);
-
-       priv->ieee_channels = NULL;
-       priv->ieee_rates = NULL;
-       priv->band = IEEE80211_BAND_2GHZ;
-
-       priv->iw_mode = NL80211_IFTYPE_STATION;
-       priv->current_ht_config.smps = IEEE80211_SMPS_STATIC;
-       priv->missed_beacon_threshold = IWL_MISSED_BEACON_THRESHOLD_DEF;
-       priv->agg_tids_count = 0;
-
-       /* initialize force reset */
-       priv->force_reset[IWL_RF_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_RF_RESET;
-       priv->force_reset[IWL_FW_RESET].reset_duration =
-               IWL_DELAY_NEXT_FORCE_FW_RELOAD;
-
-       priv->rx_statistics_jiffies = jiffies;
-
-       /* Choose which receivers/antennas to use */
-       iwlagn_set_rxon_chain(priv, &priv->contexts[IWL_RXON_CTX_BSS]);
-
-       iwl_init_scan_params(priv);
-
-       /* init bt coex */
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               priv->kill_ack_mask = IWLAGN_BT_KILL_ACK_MASK_DEFAULT;
-               priv->kill_cts_mask = IWLAGN_BT_KILL_CTS_MASK_DEFAULT;
-               priv->bt_valid = IWLAGN_BT_ALL_VALID_MSK;
-               priv->bt_on_thresh = BT_ON_THRESHOLD_DEF;
-               priv->bt_duration = BT_DURATION_LIMIT_DEF;
-               priv->dynamic_frag_thresh = BT_FRAG_THRESHOLD_DEF;
-       }
-
-       ret = iwl_init_channel_map(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing regulatory failed: %d\n", ret);
-               goto err;
-       }
-
-       ret = iwl_init_geos(priv);
-       if (ret) {
-               IWL_ERR(priv, "initializing geos failed: %d\n", ret);
-               goto err_free_channel_map;
-       }
-       iwl_init_hw_rates(priv, priv->ieee_rates);
-
-       return 0;
-
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
-}
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
+       return ret;
+}
 
 static void iwl_uninit_drv(struct iwl_priv *priv)
 {
@@ -3062,81 +1638,13 @@ static void iwl_uninit_drv(struct iwl_priv *priv)
                kmem_cache_destroy(priv->tx_cmd_pool);
        kfree(priv->scan_cmd);
        kfree(priv->beacon_cmd);
+       kfree(rcu_dereference_raw(priv->noa_data));
 #ifdef CONFIG_IWLWIFI_DEBUGFS
        kfree(priv->wowlan_sram);
 #endif
 }
 
-static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
-                          enum ieee80211_rssi_event rssi_event)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-       mutex_lock(&priv->shrd->mutex);
-
-       if (priv->cfg->bt_params &&
-                       priv->cfg->bt_params->advanced_bt_coexist) {
-               if (rssi_event == RSSI_EVENT_LOW)
-                       priv->bt_enable_pspoll = true;
-               else if (rssi_event == RSSI_EVENT_HIGH)
-                       priv->bt_enable_pspoll = false;
-
-               iwlagn_send_advance_bt_config(priv);
-       } else {
-               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
-                               "ignoring RSSI callback\n");
-       }
-
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-}
-
-static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
-                          struct ieee80211_sta *sta, bool set)
-{
-       struct iwl_priv *priv = hw->priv;
 
-       queue_work(priv->shrd->workqueue, &priv->beacon_update);
-
-       return 0;
-}
-
-struct ieee80211_ops iwlagn_hw_ops = {
-       .tx = iwlagn_mac_tx,
-       .start = iwlagn_mac_start,
-       .stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM_SLEEP
-       .suspend = iwlagn_mac_suspend,
-       .resume = iwlagn_mac_resume,
-#endif
-       .add_interface = iwlagn_mac_add_interface,
-       .remove_interface = iwlagn_mac_remove_interface,
-       .change_interface = iwlagn_mac_change_interface,
-       .config = iwlagn_mac_config,
-       .configure_filter = iwlagn_configure_filter,
-       .set_key = iwlagn_mac_set_key,
-       .update_tkip_key = iwlagn_mac_update_tkip_key,
-       .set_rekey_data = iwlagn_mac_set_rekey_data,
-       .conf_tx = iwlagn_mac_conf_tx,
-       .bss_info_changed = iwlagn_bss_info_changed,
-       .ampdu_action = iwlagn_mac_ampdu_action,
-       .hw_scan = iwlagn_mac_hw_scan,
-       .sta_notify = iwlagn_mac_sta_notify,
-       .sta_add = iwlagn_mac_sta_add,
-       .sta_remove = iwlagn_mac_sta_remove,
-       .channel_switch = iwlagn_mac_channel_switch,
-       .flush = iwlagn_mac_flush,
-       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
-       .remain_on_channel = iwlagn_mac_remain_on_channel,
-       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
-       .rssi_callback = iwlagn_mac_rssi_callback,
-       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
-       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
-       .tx_sync = iwlagn_mac_tx_sync,
-       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
-       .set_tim = iwlagn_mac_set_tim,
-};
 
 static u32 iwl_hw_detect(struct iwl_priv *priv)
 {
@@ -3170,27 +1678,7 @@ static int iwl_set_hw_params(struct iwl_priv *priv)
        return priv->cfg->lib->set_hw_params(priv);
 }
 
-/* This function both allocates and initializes hw and priv. */
-static struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg)
-{
-       struct iwl_priv *priv;
-       /* mac80211 allocates memory for this device instance, including
-        *   space for this driver's private structure */
-       struct ieee80211_hw *hw;
-
-       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
-       if (hw == NULL) {
-               pr_err("%s: Can not allocate network device\n",
-                      cfg->name);
-               goto out;
-       }
-
-       priv = hw->priv;
-       priv->hw = hw;
 
-out:
-       return hw;
-}
 
 int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
                struct iwl_cfg *cfg)
@@ -3204,8 +1692,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        /************************
         * 1. Allocating HW data
         ************************/
-       hw = iwl_alloc_all(cfg);
+       hw = iwl_alloc_all();
        if (!hw) {
+               pr_err("%s: Cannot allocate network device\n", cfg->name);
                err = -ENOMEM;
                goto out;
        }
@@ -3397,7 +1886,7 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        /*This will stop the queues, move the device to low power state */
        iwl_trans_stop_device(trans(priv));
 
-       iwl_dealloc_ucode(priv);
+       iwl_dealloc_ucode(trans(priv));
 
        iwl_eeprom_free(priv);
 
index 5b936ec1a541ecc1ecd213771f7d4e75f7960136..5d8d2f445923f7c68a3c9dcd5547505c9b0b6bb6 100644 (file)
 
 #include "iwl-dev.h"
 
+struct iwlagn_ucode_capabilities {
+       u32 max_probe_length;
+       u32 standard_phy_calibration_size;
+       u32 flags;
+};
+
 extern struct ieee80211_ops iwlagn_hw_ops;
 
 int iwl_reset_ict(struct iwl_trans *trans);
@@ -77,6 +83,15 @@ static inline void iwl_set_calib_hdr(struct iwl_calib_hdr *hdr, u8 cmd)
        hdr->data_valid = 1;
 }
 
+void __iwl_down(struct iwl_priv *priv);
+void iwl_down(struct iwl_priv *priv);
+void iwlagn_prepare_restart(struct iwl_priv *priv);
+
+/* MAC80211 */
+struct ieee80211_hw *iwl_alloc_all(void);
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                             struct iwlagn_ucode_capabilities *capa);
+
 /* RXON */
 int iwlagn_set_pan_params(struct iwl_priv *priv);
 int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -95,8 +110,7 @@ int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
 int iwlagn_run_init_ucode(struct iwl_priv *priv);
 int iwlagn_load_ucode_wait_alive(struct iwl_priv *priv,
-                                struct fw_img *image,
-                                enum iwlagn_ucode_type ucode_type);
+                                enum iwl_ucode_type ucode_type);
 
 /* lib */
 int iwlagn_send_tx_power(struct iwl_priv *priv);
@@ -105,6 +119,12 @@ u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv);
 int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
+#ifdef CONFIG_PM_SLEEP
+int iwlagn_send_patterns(struct iwl_priv *priv,
+                        struct cfg80211_wowlan *wowlan);
+int iwlagn_suspend(struct iwl_priv *priv,
+                  struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
+#endif
 
 /* rx */
 int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band);
@@ -196,9 +216,6 @@ int iwl_add_station_common(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           struct ieee80211_sta *sta, u8 *sta_id_r);
 int iwl_remove_station(struct iwl_priv *priv, const u8 sta_id,
                       const u8 *addr);
-int iwlagn_mac_sta_remove(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
-                      struct ieee80211_sta *sta);
-
 u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    const u8 *addr, bool is_ap, struct ieee80211_sta *sta);
 
@@ -316,10 +333,6 @@ void iwl_sta_modify_sleep_tx_count(struct iwl_priv *priv, int sta_id, int cnt);
 int iwl_update_bcast_station(struct iwl_priv *priv,
                             struct iwl_rxon_context *ctx);
 int iwl_update_bcast_stations(struct iwl_priv *priv);
-void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
-                          struct ieee80211_vif *vif,
-                          enum sta_notify_cmd cmd,
-                          struct ieee80211_sta *sta);
 
 /* rate */
 static inline u32 iwl_ant_idx_to_flags(u8 ant_idx)
index 2a2dc4597ba187e46da6814d05af0f98cee3bc31..e1d78257e4a9426c0908a0b64acd7b31a1ca972b 100644 (file)
@@ -101,17 +101,11 @@ extern struct iwl_cfg iwl100_bg_cfg;
 extern struct iwl_cfg iwl130_bgn_cfg;
 extern struct iwl_cfg iwl130_bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_cfg;
-extern struct iwl_cfg iwl2000_2bg_cfg;
 extern struct iwl_cfg iwl2000_2bgn_d_cfg;
 extern struct iwl_cfg iwl2030_2bgn_cfg;
-extern struct iwl_cfg iwl2030_2bg_cfg;
 extern struct iwl_cfg iwl6035_2agn_cfg;
-extern struct iwl_cfg iwl6035_2abg_cfg;
-extern struct iwl_cfg iwl6035_2bg_cfg;
-extern struct iwl_cfg iwl105_bg_cfg;
 extern struct iwl_cfg iwl105_bgn_cfg;
 extern struct iwl_cfg iwl105_bgn_d_cfg;
-extern struct iwl_cfg iwl135_bg_cfg;
 extern struct iwl_cfg iwl135_bgn_cfg;
 
 #endif /* __iwl_pci_h__ */
index 69d5f85d11e2a10e53d02ac986e18288e614d972..f4eccf583775f0b4b806d6b3ab2de7d220dedd61 100644 (file)
@@ -198,6 +198,7 @@ enum {
        REPLY_WOWLAN_TKIP_PARAMS = 0xe3,
        REPLY_WOWLAN_KEK_KCK_MATERIAL = 0xe4,
        REPLY_WOWLAN_GET_STATUS = 0xe5,
+       REPLY_D3_CONFIG = 0xd3,
 
        REPLY_MAX = 0xff
 };
@@ -3800,6 +3801,19 @@ struct iwl_bt_coex_prot_env_cmd {
        u8 reserved[2];
 } __attribute__((packed));
 
+/*
+ * REPLY_D3_CONFIG
+ */
+enum iwlagn_d3_wakeup_filters {
+       IWLAGN_D3_WAKEUP_RFKILL         = BIT(0),
+       IWLAGN_D3_WAKEUP_SYSASSERT      = BIT(1),
+};
+
+struct iwlagn_d3_config_cmd {
+       __le32 min_sleep_time;
+       __le32 wakeup_flags;
+} __packed;
+
 /*
  * REPLY_WOWLAN_PATTERNS
  */
@@ -3830,19 +3844,16 @@ enum iwlagn_wowlan_wakeup_filters {
        IWLAGN_WOWLAN_WAKEUP_BEACON_MISS        = BIT(2),
        IWLAGN_WOWLAN_WAKEUP_LINK_CHANGE        = BIT(3),
        IWLAGN_WOWLAN_WAKEUP_GTK_REKEY_FAIL     = BIT(4),
-       IWLAGN_WOWLAN_WAKEUP_RFKILL             = BIT(5),
-       IWLAGN_WOWLAN_WAKEUP_UCODE_ERROR        = BIT(6),
-       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(7),
-       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(8),
-       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(9),
-       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(10),
+       IWLAGN_WOWLAN_WAKEUP_EAP_IDENT_REQ      = BIT(5),
+       IWLAGN_WOWLAN_WAKEUP_4WAY_HANDSHAKE     = BIT(6),
+       IWLAGN_WOWLAN_WAKEUP_ALWAYS             = BIT(7),
+       IWLAGN_WOWLAN_WAKEUP_ENABLE_NET_DETECT  = BIT(8),
 };
 
 struct iwlagn_wowlan_wakeup_filter_cmd {
        __le32 enabled;
        __le16 non_qos_seq;
-       u8 min_sleep_seconds;
-       u8 reserved;
+       __le16 reserved;
        __le16 qos_seq[8];
 };
 
index 001fdf140abbb72de6d12fe95dac3d8211158ff0..f9e9170e977a8ac053e3af8cd35281987c59493f 100644 (file)
@@ -1120,229 +1120,8 @@ int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags, bool clear)
                                        &statistics_cmd);
 }
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx;
-       unsigned long flags;
-       int q;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
-               return -EIO;
-       }
-
-       if (queue >= AC_NUM) {
-               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
-               return 0;
-       }
-
-       q = AC_NUM - 1 - queue;
-
-       spin_lock_irqsave(&priv->shrd->lock, flags);
-
-       /*
-        * MULTI-FIXME
-        * This may need to be done per interface in nl80211/cfg80211/mac80211.
-        */
-       for_each_context(priv, ctx) {
-               ctx->qos_data.def_qos_parm.ac[q].cw_min =
-                       cpu_to_le16(params->cw_min);
-               ctx->qos_data.def_qos_parm.ac[q].cw_max =
-                       cpu_to_le16(params->cw_max);
-               ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
-               ctx->qos_data.def_qos_parm.ac[q].edca_txop =
-                               cpu_to_le16((params->txop * 32));
-
-               ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
-       }
-
-       spin_unlock_irqrestore(&priv->shrd->lock, flags);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return 0;
-}
-
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
-{
-       struct iwl_priv *priv = hw->priv;
-
-       return priv->ibss_manager == IWL_IBSS_MANAGER;
-}
-
-static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
-{
-       iwl_connection_init_rx_config(priv, ctx);
-
-       iwlagn_set_rxon_chain(priv, ctx);
-
-       return iwlagn_commit_rxon(priv, ctx);
-}
-
-static int iwl_setup_interface(struct iwl_priv *priv,
-                              struct iwl_rxon_context *ctx)
-{
-       struct ieee80211_vif *vif = ctx->vif;
-       int err;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       /*
-        * This variable will be correct only when there's just
-        * a single context, but all code using it is for hardware
-        * that supports only one context.
-        */
-       priv->iw_mode = vif->type;
-
-       ctx->is_active = true;
-
-       err = iwl_set_mode(priv, ctx);
-       if (err) {
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-               return err;
-       }
-
-       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
-           vif->type == NL80211_IFTYPE_ADHOC) {
-               /*
-                * pretend to have high BT traffic as long as we
-                * are operating in IBSS mode, as this will cause
-                * the rate scaling etc. to behave as intended.
-                */
-               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
-       }
-
-       return 0;
-}
-
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
-       struct iwl_rxon_context *tmp, *ctx = NULL;
-       int err;
-       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
-                          viftype, vif->addr);
-
-       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       iwlagn_disable_roc(priv);
-
-       if (!iwl_is_ready_rf(priv->shrd)) {
-               IWL_WARN(priv, "Try to add interface when device not ready\n");
-               err = -EINVAL;
-               goto out;
-       }
-
-       for_each_context(priv, tmp) {
-               u32 possible_modes =
-                       tmp->interface_modes | tmp->exclusive_interface_modes;
-
-               if (tmp->vif) {
-                       /* check if this busy context is exclusive */
-                       if (tmp->exclusive_interface_modes &
-                                               BIT(tmp->vif->type)) {
-                               err = -EINVAL;
-                               goto out;
-                       }
-                       continue;
-               }
-
-               if (!(possible_modes & BIT(viftype)))
-                       continue;
 
-               /* have maybe usable context w/o interface */
-               ctx = tmp;
-               break;
-       }
-
-       if (!ctx) {
-               err = -EOPNOTSUPP;
-               goto out;
-       }
-
-       vif_priv->ctx = ctx;
-       ctx->vif = vif;
-
-       err = iwl_setup_interface(priv, ctx);
-       if (!err)
-               goto out;
 
-       ctx->vif = NULL;
-       priv->iw_mode = NL80211_IFTYPE_STATION;
- out:
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-       return err;
-}
-
-static void iwl_teardown_interface(struct iwl_priv *priv,
-                                  struct ieee80211_vif *vif,
-                                  bool mode_change)
-{
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (priv->scan_vif == vif) {
-               iwl_scan_cancel_timeout(priv, 200);
-               iwl_force_scan_end(priv);
-       }
-
-       if (!mode_change) {
-               iwl_set_mode(priv, ctx);
-               if (!ctx->always_active)
-                       ctx->is_active = false;
-       }
-
-       /*
-        * When removing the IBSS interface, overwrite the
-        * BT traffic load with the stored one from the last
-        * notification, if any. If this is a device that
-        * doesn't implement this, this has no effect since
-        * both values are the same and zero.
-        */
-       if (vif->type == NL80211_IFTYPE_ADHOC)
-               priv->bt_traffic_load = priv->last_bt_traffic_load;
-}
-
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (WARN_ON(ctx->vif != vif)) {
-               struct iwl_rxon_context *tmp;
-               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
-               for_each_context(priv, tmp)
-                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
-                               tmp->ctxid, tmp, tmp->vif);
-       }
-       ctx->vif = NULL;
-
-       iwl_teardown_interface(priv, vif, false);
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-}
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 
@@ -1649,97 +1428,13 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external)
        return 0;
 }
 
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               enum nl80211_iftype newtype, bool newp2p)
-{
-       struct iwl_priv *priv = hw->priv;
-       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
-       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl_rxon_context *tmp;
-       enum nl80211_iftype newviftype = newtype;
-       u32 interface_modes;
-       int err;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       newtype = ieee80211_iftype_p2p(newtype, newp2p);
-
-       mutex_lock(&priv->shrd->mutex);
-
-       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
-               /*
-                * Huh? But wait ... this can maybe happen when
-                * we're in the middle of a firmware restart!
-                */
-               err = -EBUSY;
-               goto out;
-       }
-
-       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
-
-       if (!(interface_modes & BIT(newtype))) {
-               err = -EBUSY;
-               goto out;
-       }
-
-       /*
-        * Refuse a change that should be done by moving from the PAN
-        * context to the BSS context instead, if the BSS context is
-        * available and can support the new interface type.
-        */
-       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
-           (bss_ctx->interface_modes & BIT(newtype) ||
-            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
-               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
-               err = -EBUSY;
-               goto out;
-       }
-
-       if (ctx->exclusive_interface_modes & BIT(newtype)) {
-               for_each_context(priv, tmp) {
-                       if (ctx == tmp)
-                               continue;
-
-                       if (!tmp->vif)
-                               continue;
-
-                       /*
-                        * The current mode switch would be exclusive, but
-                        * another context is active ... refuse the switch.
-                        */
-                       err = -EBUSY;
-                       goto out;
-               }
-       }
-
-       /* success */
-       iwl_teardown_interface(priv, vif, true);
-       vif->type = newviftype;
-       vif->p2p = newp2p;
-       err = iwl_setup_interface(priv, ctx);
-       WARN_ON(err);
-       /*
-        * We've switched internally, but submitting to the
-        * device may have failed for some reason. Mask this
-        * error, because otherwise mac80211 will not switch
-        * (and set the interface type back) and we'll be
-        * out of sync with it.
-        */
-       err = 0;
-
- out:
-       mutex_unlock(&priv->shrd->mutex);
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       return err;
-}
 
 int iwl_cmd_echo_test(struct iwl_priv *priv)
 {
        int ret;
        struct iwl_host_cmd cmd = {
                .id = REPLY_ECHO,
+               .len = { 0 },
                .flags = CMD_SYNC,
        };
 
index 137da33807044bedd162a501a65454037abce49f..fa47f75185dfe57745f5f3b38f3174a76e431155 100644 (file)
@@ -237,10 +237,6 @@ struct iwl_cfg {
  *   L i b                 *
  ***************************/
 
-int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif, u16 queue,
-                   const struct ieee80211_tx_queue_params *params);
-int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                           int hw_decrypt);
 int iwl_check_rxon_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
@@ -260,13 +256,6 @@ bool iwl_is_ht40_tx_allowed(struct iwl_priv *priv,
 void iwl_connection_init_rx_config(struct iwl_priv *priv,
                                   struct iwl_rxon_context *ctx);
 void iwl_set_rate(struct iwl_priv *priv);
-int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
-                         struct ieee80211_vif *vif);
-void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif);
-int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
-                            struct ieee80211_vif *vif,
-                            enum nl80211_iftype newtype, bool newp2p);
 int iwl_cmd_echo_test(struct iwl_priv *priv);
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 int iwl_alloc_traffic_mem(struct iwl_priv *priv);
@@ -323,9 +312,6 @@ void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req);
 void iwl_internal_short_hw_scan(struct iwl_priv *priv);
 int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
index b9f3267e720cb3c9b9d14b75fa6331555576823e..fbc3095c7b445b71f9ddf09bc15d3cf2fd308869 100644 (file)
 #define CSR_HW_REV_TYPE_6x35          CSR_HW_REV_TYPE_6x05
 #define CSR_HW_REV_TYPE_2x30          (0x00000C0)
 #define CSR_HW_REV_TYPE_2x00          (0x0000100)
-#define CSR_HW_REV_TYPE_200           (0x0000110)
-#define CSR_HW_REV_TYPE_230           (0x0000120)
+#define CSR_HW_REV_TYPE_105           (0x0000110)
+#define CSR_HW_REV_TYPE_135           (0x0000120)
 #define CSR_HW_REV_TYPE_NONE           (0x00001F0)
 
 /* EEPROM REG */
index 69a77e24d2293536dec710f80707c491d24e9b4c..40ef97bac1aa232139d8d4274ee46fd9e7f64398 100644 (file)
@@ -70,10 +70,25 @@ do {                                                                \
                               DUMP_PREFIX_OFFSET, 16, 1, p, len, 1);   \
 } while (0)
 
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)                        \
+do {                                                                   \
+       if (!iwl_is_rfkill(p->shrd))                            \
+               dev_printk(KERN_ERR, bus(p)->dev, "%c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+       else if (iwl_get_debug_level(p->shrd) & IWL_DL_RADIO)   \
+               dev_printk(KERN_ERR, bus(p)->dev, "(RFKILL) %c %s " fmt, \
+               (in_interrupt() ? 'I' : 'U'), __func__ , ##args);       \
+} while (0)
+
 #else
 #define IWL_DEBUG(m, level, fmt, args...)
 #define IWL_DEBUG_LIMIT(m, level, fmt, args...)
 #define iwl_print_hex_dump(m, level, p, len)
+#define IWL_DEBUG_QUIET_RFKILL(p, fmt, args...)        \
+do {                                                   \
+       if (!iwl_is_rfkill(p->shrd))                    \
+               IWL_ERR(p, fmt, ##args);                \
+} while (0)
 #endif                         /* CONFIG_IWLWIFI_DEBUG */
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -151,7 +166,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DL_11H             (1 << 28)
 #define IWL_DL_STATS           (1 << 29)
 #define IWL_DL_TX_REPLY                (1 << 30)
-#define IWL_DL_QOS             (1 << 31)
+#define IWL_DL_TX_QUEUES       (1 << 31)
 
 #define IWL_DEBUG_INFO(p, f, a...)     IWL_DEBUG(p, IWL_DL_INFO, f, ## a)
 #define IWL_DEBUG_MAC80211(p, f, a...) IWL_DEBUG(p, IWL_DL_MAC80211, f, ## a)
@@ -188,7 +203,7 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv)
 #define IWL_DEBUG_TX_REPLY(p, f, a...) IWL_DEBUG(p, IWL_DL_TX_REPLY, f, ## a)
 #define IWL_DEBUG_TX_REPLY_LIMIT(p, f, a...) \
                IWL_DEBUG_LIMIT(p, IWL_DL_TX_REPLY, f, ## a)
-#define IWL_DEBUG_QOS(p, f, a...)      IWL_DEBUG(p, IWL_DL_QOS, f, ## a)
+#define IWL_DEBUG_TX_QUEUES(p, f, a...)        IWL_DEBUG(p, IWL_DL_TX_QUEUES, f, ## a)
 #define IWL_DEBUG_RADIO(p, f, a...)    IWL_DEBUG(p, IWL_DL_RADIO, f, ## a)
 #define IWL_DEBUG_POWER(p, f, a...)    IWL_DEBUG(p, IWL_DL_POWER, f, ## a)
 #define IWL_DEBUG_11H(p, f, a...)      IWL_DEBUG(p, IWL_DL_11H, f, ## a)
index a1670e3f8bfaa48bc0f2bb1328e9ba6b59acfe92..68b04f5b10ceb31ba0ac2480e87103b67f016a58 100644 (file)
@@ -236,9 +236,9 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file,
        if (!priv->dbgfs_sram_offset && !priv->dbgfs_sram_len) {
                priv->dbgfs_sram_offset = 0x800000;
                if (priv->ucode_type == IWL_UCODE_INIT)
-                       priv->dbgfs_sram_len = priv->ucode_init.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_init.data.len;
                else
-                       priv->dbgfs_sram_len = priv->ucode_rt.data.len;
+                       priv->dbgfs_sram_len = trans(priv)->ucode_rt.data.len;
        }
        len = priv->dbgfs_sram_len;
 
@@ -341,7 +341,7 @@ static ssize_t iwl_dbgfs_wowlan_sram_read(struct file *file,
 
        return simple_read_from_buffer(user_buf, count, ppos,
                                       priv->wowlan_sram,
-                                      priv->ucode_wowlan.data.len);
+                                      trans(priv)->ucode_wowlan.data.len);
 }
 static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
                                        size_t count, loff_t *ppos)
@@ -430,7 +430,7 @@ static ssize_t iwl_dbgfs_nvm_read(struct file *file,
        eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
        pos += scnprintf(buf + pos, buf_size - pos, "NVM Type: %s, "
                        "version: 0x%x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                         ? "OTP" : "EEPROM", eeprom_ver);
        for (ofs = 0 ; ofs < eeprom_len ; ofs += 16) {
                pos += scnprintf(buf + pos, buf_size - pos, "0x%.4x ", ofs);
index 6c00a447963d7f5bec37ecd2921696a4517d8b22..556e4a2c19bceb0296cb90309f2d21bc534c82f8 100644 (file)
@@ -230,17 +230,6 @@ struct iwl_vif_priv {
        u8 ibss_bssid_sta_id;
 };
 
-/* one for each uCode image (inst/data, boot/init/runtime) */
-struct fw_desc {
-       void *v_addr;           /* access by driver */
-       dma_addr_t p_addr;      /* access by card's busmaster DMA */
-       u32 len;                /* bytes */
-};
-
-struct fw_img {
-       struct fw_desc code, data;
-};
-
 /* v1/v2 uCode file layout */
 struct iwl_ucode_header {
        __le32 ver;     /* major/minor/API/serial */
@@ -805,13 +794,6 @@ enum iwl_scan_type {
        IWL_SCAN_ROC,
 };
 
-enum iwlagn_ucode_type {
-       IWL_UCODE_NONE,
-       IWL_UCODE_REGULAR,
-       IWL_UCODE_INIT,
-       IWL_UCODE_WOWLAN,
-};
-
 #ifdef CONFIG_IWLWIFI_DEVICE_SVTOOL
 struct iwl_testmode_trace {
        u32 buff_size;
@@ -824,6 +806,12 @@ struct iwl_testmode_trace {
 };
 #endif
 
+struct iwl_wipan_noa_data {
+       struct rcu_head rcu_head;
+       u32 length;
+       u8 data[];
+};
+
 struct iwl_priv {
 
        /*data shared among all the driver's layers */
@@ -883,6 +871,8 @@ struct iwl_priv {
        /* init calibration results */
        struct iwl_calib_result calib_results[IWL_CALIB_MAX];
 
+       struct iwl_wipan_noa_data __rcu *noa_data;
+
        /* Scan related variables */
        unsigned long scan_start;
        unsigned long scan_start_tsf;
@@ -907,12 +897,7 @@ struct iwl_priv {
        u32 ucode_ver;                  /* version of ucode, copy of
                                           iwl_ucode.ver */
 
-       struct fw_img ucode_rt;
-       struct fw_img ucode_init;
-       struct fw_img ucode_wowlan;
-
-       enum iwlagn_ucode_type ucode_type;
-       u8 ucode_write_complete;        /* the image write is complete */
+       enum iwl_ucode_type ucode_type;
        char firmware_name[25];
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
@@ -959,7 +944,6 @@ struct iwl_priv {
 
        /* eeprom -- this is in the card's little endian byte order */
        u8 *eeprom;
-       int    nvm_device_type;
        struct iwl_eeprom_calib_info *calib_info;
 
        enum nl80211_iftype iw_mode;
index a635a7e754473220fa93c85fab9475654f0013c8..2a2c8de64a04d135052d2e8ec421f2aebbd8553d 100644 (file)
@@ -28,7 +28,7 @@
 
 /* sparse doesn't like tracepoint macros */
 #ifndef __CHECKER__
-#include "iwl-dev.h"
+#include "iwl-trans.h"
 
 #define CREATE_TRACE_POINTS
 #include "iwl-devtrace.h"
index 8a51c5ccda1ee50b81b734125cc9eb008647e1d6..f9d3319ecad5b9f6cb1c9f32bae83f59cc2f4a90 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/tracepoint.h>
 
-struct iwl_priv;
 
 #if !defined(CONFIG_IWLWIFI_DEVICE_TRACING) || defined(__CHECKER__)
 #undef TRACE_EVENT
@@ -37,14 +36,14 @@ struct iwl_priv;
 static inline void trace_ ## name(proto) {}
 #endif
 
-#define PRIV_ENTRY     __field(struct iwl_priv *, priv)
+#define PRIV_ENTRY     __field(void *, priv)
 #define PRIV_ASSIGN    __entry->priv = priv
 
 #undef TRACE_SYSTEM
 #define TRACE_SYSTEM iwlwifi_io
 
 TRACE_EVENT(iwlwifi_dev_ioread32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -60,7 +59,7 @@ TRACE_EVENT(iwlwifi_dev_ioread32,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite8,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u8 val),
+       TP_PROTO(void *priv, u32 offs, u8 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -76,7 +75,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite8,
 );
 
 TRACE_EVENT(iwlwifi_dev_iowrite32,
-       TP_PROTO(struct iwl_priv *priv, u32 offs, u32 val),
+       TP_PROTO(void *priv, u32 offs, u32 val),
        TP_ARGS(priv, offs, val),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -95,7 +94,7 @@ TRACE_EVENT(iwlwifi_dev_iowrite32,
 #define TRACE_SYSTEM iwlwifi_ucode
 
 TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -115,7 +114,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_cont_event,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
-       TP_PROTO(struct iwl_priv *priv, u32 wraps, u32 n_entry, u32 p_entry),
+       TP_PROTO(void *priv, u32 wraps, u32 n_entry, u32 p_entry),
        TP_ARGS(priv, wraps, n_entry, p_entry),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -139,7 +138,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_wrap_event,
 #define TRACE_SYSTEM iwlwifi
 
 TRACE_EVENT(iwlwifi_dev_hcmd,
-       TP_PROTO(struct iwl_priv *priv, u32 flags,
+       TP_PROTO(void *priv, u32 flags,
                 const void *hcmd0, size_t len0,
                 const void *hcmd1, size_t len1,
                 const void *hcmd2, size_t len2),
@@ -164,7 +163,7 @@ TRACE_EVENT(iwlwifi_dev_hcmd,
 );
 
 TRACE_EVENT(iwlwifi_dev_rx,
-       TP_PROTO(struct iwl_priv *priv, void *rxbuf, size_t len),
+       TP_PROTO(void *priv, void *rxbuf, size_t len),
        TP_ARGS(priv, rxbuf, len),
        TP_STRUCT__entry(
                PRIV_ENTRY
@@ -179,7 +178,7 @@ TRACE_EVENT(iwlwifi_dev_rx,
 );
 
 TRACE_EVENT(iwlwifi_dev_tx,
-       TP_PROTO(struct iwl_priv *priv, void *tfd, size_t tfdlen,
+       TP_PROTO(void *priv, void *tfd, size_t tfdlen,
                 void *buf0, size_t buf0_len,
                 void *buf1, size_t buf1_len),
        TP_ARGS(priv, tfd, tfdlen, buf0, buf0_len, buf1, buf1_len),
@@ -211,7 +210,7 @@ TRACE_EVENT(iwlwifi_dev_tx,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_error,
-       TP_PROTO(struct iwl_priv *priv, u32 desc, u32 tsf_low,
+       TP_PROTO(void *priv, u32 desc, u32 tsf_low,
                 u32 data1, u32 data2, u32 line, u32 blink1,
                 u32 blink2, u32 ilink1, u32 ilink2, u32 bcon_time,
                 u32 gp1, u32 gp2, u32 gp3, u32 ucode_ver, u32 hw_ver,
@@ -271,7 +270,7 @@ TRACE_EVENT(iwlwifi_dev_ucode_error,
 );
 
 TRACE_EVENT(iwlwifi_dev_ucode_event,
-       TP_PROTO(struct iwl_priv *priv, u32 time, u32 data, u32 ev),
+       TP_PROTO(void *priv, u32 time, u32 data, u32 ev),
        TP_ARGS(priv, time, data, ev),
        TP_STRUCT__entry(
                PRIV_ENTRY
index a4e43bd4a54763bfac47354088f027a4023ebc63..dcada0827ea43db482effeaa8966b62af51be67e 100644 (file)
@@ -149,23 +149,23 @@ static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
  * EEPROM chip, not a single event, so even reads could conflict if they
  * weren't arbitrated by the semaphore.
  */
-static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
+static int iwl_eeprom_acquire_semaphore(struct iwl_bus *bus)
 {
        u16 count;
        int ret;
 
        for (count = 0; count < EEPROM_SEM_RETRY_LIMIT; count++) {
                /* Request semaphore */
-               iwl_set_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               iwl_set_bit(bus, CSR_HW_IF_CONFIG_REG,
                            CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
                /* See if we got it */
-               ret = iwl_poll_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+               ret = iwl_poll_bit(bus, CSR_HW_IF_CONFIG_REG,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM,
                                EEPROM_SEM_TIMEOUT);
                if (ret >= 0) {
-                       IWL_DEBUG_EEPROM(priv,
+                       IWL_DEBUG_EEPROM(bus,
                                "Acquired semaphore after %d tries.\n",
                                count+1);
                        return ret;
@@ -175,39 +175,39 @@ static int iwl_eeprom_acquire_semaphore(struct iwl_priv *priv)
        return ret;
 }
 
-static void iwl_eeprom_release_semaphore(struct iwl_priv *priv)
+static void iwl_eeprom_release_semaphore(struct iwl_bus *bus)
 {
-       iwl_clear_bit(bus(priv), CSR_HW_IF_CONFIG_REG,
+       iwl_clear_bit(bus, CSR_HW_IF_CONFIG_REG,
                CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM);
 
 }
 
-static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
+static int iwl_eeprom_verify_signature(struct iwl_trans *trans)
 {
-       u32 gp = iwl_read32(bus(priv), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
+       u32 gp = iwl_read32(bus(trans), CSR_EEPROM_GP) & CSR_EEPROM_GP_VALID_MSK;
        int ret = 0;
 
-       IWL_DEBUG_EEPROM(priv, "EEPROM signature=0x%08x\n", gp);
+       IWL_DEBUG_EEPROM(trans, "EEPROM signature=0x%08x\n", gp);
        switch (gp) {
        case CSR_EEPROM_GP_BAD_SIG_EEP_GOOD_SIG_OTP:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
-                       IWL_ERR(priv, "EEPROM with bad signature: 0x%08x\n",
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_OTP) {
+                       IWL_ERR(trans, "EEPROM with bad signature: 0x%08x\n",
                                gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_GOOD_SIG_EEP_LESS_THAN_4K:
        case CSR_EEPROM_GP_GOOD_SIG_EEP_MORE_THAN_4K:
-               if (priv->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
-                       IWL_ERR(priv, "OTP with bad signature: 0x%08x\n", gp);
+               if (trans->nvm_device_type != NVM_DEVICE_TYPE_EEPROM) {
+                       IWL_ERR(trans, "OTP with bad signature: 0x%08x\n", gp);
                        ret = -ENOENT;
                }
                break;
        case CSR_EEPROM_GP_BAD_SIGNATURE_BOTH_EEP_AND_OTP:
        default:
-               IWL_ERR(priv, "bad EEPROM/OTP signature, type=%s, "
+               IWL_ERR(trans, "bad EEPROM/OTP signature, type=%s, "
                        "EEPROM_GP=0x%08x\n",
-                       (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                       (trans->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                        ? "OTP" : "EEPROM", gp);
                ret = -ENOENT;
                break;
@@ -302,19 +302,19 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
  *
 ******************************************************************************/
 
-static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
+static void iwl_set_otp_access(struct iwl_bus *bus, enum iwl_access_mode mode)
 {
-       iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       iwl_read32(bus, CSR_OTP_GP_REG);
 
        if (mode == IWL_OTP_ACCESS_ABSOLUTE)
-               iwl_clear_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_clear_bit(bus, CSR_OTP_GP_REG,
                              CSR_OTP_GP_REG_OTP_ACCESS_MODE);
        else
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                            CSR_OTP_GP_REG_OTP_ACCESS_MODE);
 }
 
-static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
+static int iwl_get_nvm_type(struct iwl_bus *bus, u32 hw_rev)
 {
        u32 otpgp;
        int nvm_type;
@@ -322,7 +322,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        /* OTP only valid for CP/PP and after */
        switch (hw_rev & CSR_HW_REV_TYPE_MSK) {
        case CSR_HW_REV_TYPE_NONE:
-               IWL_ERR(priv, "Unknown hardware type\n");
+               IWL_ERR(bus, "Unknown hardware type\n");
                return -ENOENT;
        case CSR_HW_REV_TYPE_5300:
        case CSR_HW_REV_TYPE_5350:
@@ -331,7 +331,7 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
                nvm_type = NVM_DEVICE_TYPE_EEPROM;
                break;
        default:
-               otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+               otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
                if (otpgp & CSR_OTP_GP_REG_DEVICE_SELECT)
                        nvm_type = NVM_DEVICE_TYPE_OTP;
                else
@@ -341,73 +341,73 @@ static int iwl_get_nvm_type(struct iwl_priv *priv, u32 hw_rev)
        return  nvm_type;
 }
 
-static int iwl_init_otp_access(struct iwl_priv *priv)
+static int iwl_init_otp_access(struct iwl_bus *bus)
 {
        int ret;
 
        /* Enable 40MHz radio clock */
-       iwl_write32(bus(priv), CSR_GP_CNTRL,
-                   iwl_read32(bus(priv), CSR_GP_CNTRL) |
+       iwl_write32(bus, CSR_GP_CNTRL,
+                   iwl_read32(bus, CSR_GP_CNTRL) |
                    CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
        /* wait for clock to be ready */
-       ret = iwl_poll_bit(bus(priv), CSR_GP_CNTRL,
+       ret = iwl_poll_bit(bus, CSR_GP_CNTRL,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY,
                                 25000);
        if (ret < 0)
-               IWL_ERR(priv, "Time out access OTP\n");
+               IWL_ERR(bus, "Time out access OTP\n");
        else {
-               iwl_set_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_set_bits_prph(bus, APMG_PS_CTRL_REG,
                                  APMG_PS_CTRL_VAL_RESET_REQ);
                udelay(5);
-               iwl_clear_bits_prph(bus(priv), APMG_PS_CTRL_REG,
+               iwl_clear_bits_prph(bus, APMG_PS_CTRL_REG,
                                    APMG_PS_CTRL_VAL_RESET_REQ);
 
                /*
                 * CSR auto clock gate disable bit -
                 * this is only applicable for HW with OTP shadow RAM
                 */
-               if (priv->cfg->base_params->shadow_ram_support)
-                       iwl_set_bit(bus(priv), CSR_DBG_LINK_PWR_MGMT_REG,
+               if (priv(bus)->cfg->base_params->shadow_ram_support)
+                       iwl_set_bit(bus, CSR_DBG_LINK_PWR_MGMT_REG,
                                CSR_RESET_LINK_PWR_MGMT_DISABLED);
        }
        return ret;
 }
 
-static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_data)
+static int iwl_read_otp_word(struct iwl_bus *bus, u16 addr, __le16 *eeprom_data)
 {
        int ret = 0;
        u32 r;
        u32 otpgp;
 
-       iwl_write32(bus(priv), CSR_EEPROM_REG,
+       iwl_write32(bus, CSR_EEPROM_REG,
                    CSR_EEPROM_REG_MSK_ADDR & (addr << 1));
-       ret = iwl_poll_bit(bus(priv), CSR_EEPROM_REG,
+       ret = iwl_poll_bit(bus, CSR_EEPROM_REG,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 CSR_EEPROM_REG_READ_VALID_MSK,
                                 IWL_EEPROM_ACCESS_TIMEOUT);
        if (ret < 0) {
-               IWL_ERR(priv, "Time out reading OTP[%d]\n", addr);
+               IWL_ERR(bus, "Time out reading OTP[%d]\n", addr);
                return ret;
        }
-       r = iwl_read32(bus(priv), CSR_EEPROM_REG);
+       r = iwl_read32(bus, CSR_EEPROM_REG);
        /* check for ECC errors: */
-       otpgp = iwl_read32(bus(priv), CSR_OTP_GP_REG);
+       otpgp = iwl_read32(bus, CSR_OTP_GP_REG);
        if (otpgp & CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK) {
                /* stop in this case */
                /* set the uncorrectable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                        CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
-               IWL_ERR(priv, "Uncorrectable OTP ECC error, abort OTP read\n");
+               IWL_ERR(bus, "Uncorrectable OTP ECC error, abort OTP read\n");
                return -EINVAL;
        }
        if (otpgp & CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK) {
                /* continue in this case */
                /* set the correctable OTP ECC bit for acknowledgement */
-               iwl_set_bit(bus(priv), CSR_OTP_GP_REG,
+               iwl_set_bit(bus, CSR_OTP_GP_REG,
                                CSR_OTP_GP_REG_ECC_CORR_STATUS_MSK);
-               IWL_ERR(priv, "Correctable OTP ECC error, continue read\n");
+               IWL_ERR(bus, "Correctable OTP ECC error, continue read\n");
        }
        *eeprom_data = cpu_to_le16(r >> 16);
        return 0;
@@ -416,20 +416,20 @@ static int iwl_read_otp_word(struct iwl_priv *priv, u16 addr, __le16 *eeprom_dat
 /*
  * iwl_is_otp_empty: check for empty OTP
  */
-static bool iwl_is_otp_empty(struct iwl_priv *priv)
+static bool iwl_is_otp_empty(struct iwl_bus *bus)
 {
        u16 next_link_addr = 0;
        __le16 link_value;
        bool is_empty = false;
 
        /* locate the beginning of OTP link list */
-       if (!iwl_read_otp_word(priv, next_link_addr, &link_value)) {
+       if (!iwl_read_otp_word(bus, next_link_addr, &link_value)) {
                if (!link_value) {
-                       IWL_ERR(priv, "OTP is empty\n");
+                       IWL_ERR(bus, "OTP is empty\n");
                        is_empty = true;
                }
        } else {
-               IWL_ERR(priv, "Unable to read first block of OTP list.\n");
+               IWL_ERR(bus, "Unable to read first block of OTP list.\n");
                is_empty = true;
        }
 
@@ -446,7 +446,7 @@ static bool iwl_is_otp_empty(struct iwl_priv *priv)
  *   we should read and used to configure the device.
  *   only perform this operation if shadow RAM is disabled
  */
-static int iwl_find_otp_image(struct iwl_priv *priv,
+static int iwl_find_otp_image(struct iwl_bus *bus,
                                        u16 *validblockaddr)
 {
        u16 next_link_addr = 0, valid_addr;
@@ -454,10 +454,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
        int usedblocks = 0;
 
        /* set addressing mode to absolute to traverse the link list */
-       iwl_set_otp_access(priv, IWL_OTP_ACCESS_ABSOLUTE);
+       iwl_set_otp_access(bus, IWL_OTP_ACCESS_ABSOLUTE);
 
        /* checking for empty OTP or error */
-       if (iwl_is_otp_empty(priv))
+       if (iwl_is_otp_empty(bus))
                return -EINVAL;
 
        /*
@@ -471,9 +471,9 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                 */
                valid_addr = next_link_addr;
                next_link_addr = le16_to_cpu(link_value) * sizeof(u16);
-               IWL_DEBUG_EEPROM(priv, "OTP blocks %d addr 0x%x\n",
+               IWL_DEBUG_EEPROM(bus, "OTP blocks %d addr 0x%x\n",
                               usedblocks, next_link_addr);
-               if (iwl_read_otp_word(priv, next_link_addr, &link_value))
+               if (iwl_read_otp_word(bus, next_link_addr, &link_value))
                        return -EINVAL;
                if (!link_value) {
                        /*
@@ -488,10 +488,10 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
                }
                /* more in the link list, continue */
                usedblocks++;
-       } while (usedblocks <= priv->cfg->base_params->max_ll_items);
+       } while (usedblocks <= priv(bus)->cfg->base_params->max_ll_items);
 
        /* OTP has no valid blocks */
-       IWL_DEBUG_EEPROM(priv, "OTP has no valid blocks\n");
+       IWL_DEBUG_EEPROM(bus, "OTP has no valid blocks\n");
        return -EINVAL;
 }
 
@@ -504,28 +504,28 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
  * iwl_get_max_txpower_avg - get the highest tx power from all chains.
  *     find the highest tx power from all chains for the channel
  */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+static s8 iwl_get_max_txpower_avg(struct iwl_cfg *cfg,
                struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
                int element, s8 *max_txpower_in_half_dbm)
 {
        s8 max_txpower_avg = 0; /* (dBm) */
 
        /* Take the highest tx power from any valid chains */
-       if ((priv->cfg->valid_tx_ant & ANT_A) &&
+       if ((cfg->valid_tx_ant & ANT_A) &&
            (enhanced_txpower[element].chain_a_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_a_max;
-       if ((priv->cfg->valid_tx_ant & ANT_B) &&
+       if ((cfg->valid_tx_ant & ANT_B) &&
            (enhanced_txpower[element].chain_b_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_b_max;
-       if ((priv->cfg->valid_tx_ant & ANT_C) &&
+       if ((cfg->valid_tx_ant & ANT_C) &&
            (enhanced_txpower[element].chain_c_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].chain_c_max;
-       if (((priv->cfg->valid_tx_ant == ANT_AB) |
-           (priv->cfg->valid_tx_ant == ANT_BC) |
-           (priv->cfg->valid_tx_ant == ANT_AC)) &&
+       if (((cfg->valid_tx_ant == ANT_AB) |
+           (cfg->valid_tx_ant == ANT_BC) |
+           (cfg->valid_tx_ant == ANT_AC)) &&
            (enhanced_txpower[element].mimo2_max > max_txpower_avg))
                max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-       if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+       if ((cfg->valid_tx_ant == ANT_ABC) &&
            (enhanced_txpower[element].mimo3_max > max_txpower_avg))
                max_txpower_avg = enhanced_txpower[element].mimo3_max;
 
@@ -627,7 +627,7 @@ void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
                                 ((txp->delta_20_in_40 & 0xf0) >> 4),
                                 (txp->delta_20_in_40 & 0x0f));
 
-               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+               max_txp_avg = iwl_get_max_txpower_avg(priv->cfg, txp_array, idx,
                                                      &max_txp_avg_halfdbm);
 
                /*
@@ -660,8 +660,8 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        u16 validblockaddr = 0;
        u16 cache_addr = 0;
 
-       priv->nvm_device_type = iwl_get_nvm_type(priv, hw_rev);
-       if (priv->nvm_device_type == -ENOENT)
+       trans(priv)->nvm_device_type = iwl_get_nvm_type(bus(priv), hw_rev);
+       if (trans(priv)->nvm_device_type == -ENOENT)
                return -ENOENT;
        /* allocate eeprom */
        sz = priv->cfg->base_params->eeprom_size;
@@ -675,7 +675,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
 
        iwl_apm_init(priv);
 
-       ret = iwl_eeprom_verify_signature(priv);
+       ret = iwl_eeprom_verify_signature(trans(priv));
        if (ret < 0) {
                IWL_ERR(priv, "EEPROM not found, EEPROM_GP=0x%08x\n", gp);
                ret = -ENOENT;
@@ -683,16 +683,16 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        /* Make sure driver (instead of uCode) is allowed to read EEPROM */
-       ret = iwl_eeprom_acquire_semaphore(priv);
+       ret = iwl_eeprom_acquire_semaphore(bus(priv));
        if (ret < 0) {
                IWL_ERR(priv, "Failed to acquire EEPROM semaphore.\n");
                ret = -ENOENT;
                goto err;
        }
 
-       if (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
+       if (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP) {
 
-               ret = iwl_init_otp_access(priv);
+               ret = iwl_init_otp_access(bus(priv));
                if (ret) {
                        IWL_ERR(priv, "Failed to initialize OTP access.\n");
                        ret = -ENOENT;
@@ -707,7 +707,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                             CSR_OTP_GP_REG_ECC_UNCORR_STATUS_MSK);
                /* traversing the linked list if no shadow ram supported */
                if (!priv->cfg->base_params->shadow_ram_support) {
-                       if (iwl_find_otp_image(priv, &validblockaddr)) {
+                       if (iwl_find_otp_image(bus(priv), &validblockaddr)) {
                                ret = -ENOENT;
                                goto done;
                        }
@@ -716,7 +716,7 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
                     addr += sizeof(u16)) {
                        __le16 eeprom_data;
 
-                       ret = iwl_read_otp_word(priv, addr, &eeprom_data);
+                       ret = iwl_read_otp_word(bus(priv), addr, &eeprom_data);
                        if (ret)
                                goto done;
                        e[cache_addr / 2] = eeprom_data;
@@ -744,13 +744,13 @@ int iwl_eeprom_init(struct iwl_priv *priv, u32 hw_rev)
        }
 
        IWL_DEBUG_EEPROM(priv, "NVM Type: %s, version: 0x%x\n",
-                      (priv->nvm_device_type == NVM_DEVICE_TYPE_OTP)
+                      (trans(priv)->nvm_device_type == NVM_DEVICE_TYPE_OTP)
                       ? "OTP" : "EEPROM",
                       iwl_eeprom_query16(priv, EEPROM_VERSION));
 
        ret = 0;
 done:
-       iwl_eeprom_release_semaphore(priv);
+       iwl_eeprom_release_semaphore(bus(priv));
 
 err:
        if (ret)
diff --git a/drivers/net/wireless/iwlwifi/iwl-mac80211.c b/drivers/net/wireless/iwlwifi/iwl-mac80211.c
new file mode 100644 (file)
index 0000000..05b1f0d
--- /dev/null
@@ -0,0 +1,1632 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2003 - 2011 Intel Corporation. All rights reserved.
+ *
+ * Portions of this file are derived from the ipw3945 project, as well
+ * as portions of the ieee80211 subsystem header files.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ *****************************************************************************/
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/firmware.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+
+#include <net/mac80211.h>
+
+#include <asm/div64.h>
+
+#include "iwl-eeprom.h"
+#include "iwl-dev.h"
+#include "iwl-core.h"
+#include "iwl-io.h"
+#include "iwl-agn-calib.h"
+#include "iwl-agn.h"
+#include "iwl-shared.h"
+#include "iwl-bus.h"
+#include "iwl-trans.h"
+
+/*****************************************************************************
+ *
+ * mac80211 entry point functions
+ *
+ *****************************************************************************/
+
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_sta_ap_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_p2p_sta_go_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_p2p_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+       },
+};
+
+/*
+ * Not a mac80211 entry point function, but it fits in with all the
+ * other mac80211 functions grouped here.
+ */
+int iwlagn_mac_setup_register(struct iwl_priv *priv,
+                                 struct iwlagn_ucode_capabilities *capa)
+{
+       int ret;
+       struct ieee80211_hw *hw = priv->hw;
+       struct iwl_rxon_context *ctx;
+
+       hw->rate_control_algorithm = "iwl-agn-rs";
+
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_AMPDU_AGGREGATION |
+                   IEEE80211_HW_NEED_DTIM_PERIOD |
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
+
+       /*
+        * Including the following line will crash some AP's.  This
+        * workaround removes the stimulus which causes the crash until
+        * the AP software can be fixed.
+       hw->max_tx_aggregation_subframes = LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+        */
+
+       hw->flags |= IEEE80211_HW_SUPPORTS_PS |
+                    IEEE80211_HW_SUPPORTS_DYNAMIC_PS;
+
+       if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE)
+               hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
+                            IEEE80211_HW_SUPPORTS_STATIC_SMPS;
+
+       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
+               hw->flags |= IEEE80211_HW_MFP_CAPABLE;
+
+       hw->sta_data_size = sizeof(struct iwl_station_priv);
+       hw->vif_data_size = sizeof(struct iwl_vif_priv);
+
+       for_each_context(priv, ctx) {
+               hw->wiphy->interface_modes |= ctx->interface_modes;
+               hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
+       }
+
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->iface_combinations =
+                       iwlagn_iface_combinations_dualmode;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+       }
+
+       hw->wiphy->max_remain_on_channel_duration = 1000;
+
+       hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
+                           WIPHY_FLAG_DISABLE_BEACON_HINTS |
+                           WIPHY_FLAG_IBSS_RSN;
+
+       if (trans(priv)->ucode_wowlan.code.len &&
+           device_can_wakeup(bus(priv)->dev)) {
+               hw->wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
+                                         WIPHY_WOWLAN_DISCONNECT |
+                                         WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+                                         WIPHY_WOWLAN_RFKILL_RELEASE;
+               if (!iwlagn_mod_params.sw_crypto)
+                       hw->wiphy->wowlan.flags |=
+                               WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
+                               WIPHY_WOWLAN_GTK_REKEY_FAILURE;
+
+               hw->wiphy->wowlan.n_patterns = IWLAGN_WOWLAN_MAX_PATTERNS;
+               hw->wiphy->wowlan.pattern_min_len =
+                                       IWLAGN_WOWLAN_MIN_PATTERN_LEN;
+               hw->wiphy->wowlan.pattern_max_len =
+                                       IWLAGN_WOWLAN_MAX_PATTERN_LEN;
+       }
+
+       if (iwlagn_mod_params.power_save)
+               hw->wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       else
+               hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+
+       hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
+       /* we create the 802.11 header and a zero-length SSID element */
+       hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
+
+       /* Default value; 4 EDCA QOS priorities */
+       hw->queues = 4;
+
+       hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+
+       if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+                       &priv->bands[IEEE80211_BAND_2GHZ];
+       if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
+               priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &priv->bands[IEEE80211_BAND_5GHZ];
+
+       iwl_leds_init(priv);
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
+
+       return 0;
+}
+
+static int __iwl_up(struct iwl_priv *priv)
+{
+       struct iwl_rxon_context *ctx;
+       int ret;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_WARN(priv, "Exit pending; will not bring the NIC up\n");
+               return -EIO;
+       }
+
+       for_each_context(priv, ctx) {
+               ret = iwlagn_alloc_bcast_station(priv, ctx);
+               if (ret) {
+                       iwl_dealloc_bcast_stations(priv);
+                       return ret;
+               }
+       }
+
+       ret = iwlagn_run_init_ucode(priv);
+       if (ret) {
+               IWL_ERR(priv, "Failed to run INIT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
+       if (ret) {
+               IWL_ERR(priv, "Failed to start RT ucode: %d\n", ret);
+               goto error;
+       }
+
+       ret = iwl_alive_start(priv);
+       if (ret)
+               goto error;
+       return 0;
+
+ error:
+       set_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+       __iwl_down(priv);
+       clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
+
+       IWL_ERR(priv, "Unable to initialize device.\n");
+       return ret;
+}
+
+static int iwlagn_mac_start(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       /* we should be verifying the device is ready to be opened */
+       mutex_lock(&priv->shrd->mutex);
+       ret = __iwl_up(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       if (ret)
+               return ret;
+
+       IWL_DEBUG_INFO(priv, "Start UP work done.\n");
+
+       /* Now we should be done, and the READY bit should be set. */
+       if (WARN_ON(!test_bit(STATUS_READY, &priv->shrd->status)))
+               ret = -EIO;
+
+       iwlagn_led_enable(priv);
+
+       priv->is_open = 1;
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static void iwlagn_mac_stop(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!priv->is_open)
+               return;
+
+       priv->is_open = 0;
+
+       iwl_down(priv);
+
+       flush_workqueue(priv->shrd->workqueue);
+
+       /* User space software may expect getting rfkill changes
+        * even if interface is down */
+       iwl_write32(bus(priv), CSR_INT, 0xFFFFFFFF);
+       iwl_enable_rfkill_int(priv);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_set_rekey_data(struct ieee80211_hw *hw,
+                                     struct ieee80211_vif *vif,
+                                     struct cfg80211_gtk_rekey_data *data)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (iwlagn_mod_params.sw_crypto)
+               return;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->contexts[IWL_RXON_CTX_BSS].vif != vif)
+               goto out;
+
+       memcpy(priv->kek, data->kek, NL80211_KEK_LEN);
+       memcpy(priv->kck, data->kck, NL80211_KCK_LEN);
+       priv->replay_ctr =
+               cpu_to_le64(be64_to_cpup((__be64 *)&data->replay_ctr));
+       priv->have_rekey_data = true;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int iwlagn_mac_suspend(struct ieee80211_hw *hw,
+                             struct cfg80211_wowlan *wowlan)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       int ret;
+
+       if (WARN_ON(!wowlan))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       /* Don't attempt WoWLAN when not associated, tear down instead. */
+       if (!ctx->vif || ctx->vif->type != NL80211_IFTYPE_STATION ||
+           !iwl_is_associated_ctx(ctx)) {
+               ret = 1;
+               goto out;
+       }
+
+       ret = iwlagn_suspend(priv, hw, wowlan);
+       if (ret)
+               goto error;
+
+       device_set_wakeup_enable(bus(priv)->dev, true);
+
+       /* Now let the ucode operate on its own */
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_SET,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       goto out;
+
+ error:
+       priv->shrd->wowlan = false;
+       iwlagn_prepare_restart(priv);
+       ieee80211_restart_hw(priv->hw);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_resume(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct ieee80211_vif *vif;
+       unsigned long flags;
+       u32 base, status = 0xffffffff;
+       int ret = -EIO;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       iwl_write32(bus(priv), CSR_UCODE_DRV_GP1_CLR,
+                         CSR_UCODE_DRV_GP1_BIT_D3_CFG_COMPLETE);
+
+       base = priv->device_pointers.error_event_table;
+       if (iwlagn_hw_valid_rtc_data_addr(base)) {
+               spin_lock_irqsave(&bus(priv)->reg_lock, flags);
+               ret = iwl_grab_nic_access_silent(bus(priv));
+               if (ret == 0) {
+                       iwl_write32(bus(priv), HBUS_TARG_MEM_RADDR, base);
+                       status = iwl_read32(bus(priv), HBUS_TARG_MEM_RDAT);
+                       iwl_release_nic_access(bus(priv));
+               }
+               spin_unlock_irqrestore(&bus(priv)->reg_lock, flags);
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+               if (ret == 0) {
+                       struct iwl_trans *trans = trans(priv);
+                       if (!priv->wowlan_sram)
+                               priv->wowlan_sram =
+                                       kzalloc(trans->ucode_wowlan.data.len,
+                                               GFP_KERNEL);
+
+                       if (priv->wowlan_sram)
+                               _iwl_read_targ_mem_words(
+                                       bus(priv), 0x800000, priv->wowlan_sram,
+                                       trans->ucode_wowlan.data.len / 4);
+               }
+#endif
+       }
+
+       /* we'll clear ctx->vif during iwlagn_prepare_restart() */
+       vif = ctx->vif;
+
+       priv->shrd->wowlan = false;
+
+       device_set_wakeup_enable(bus(priv)->dev, false);
+
+       iwlagn_prepare_restart(priv);
+
+       memset((void *)&ctx->active, 0, sizeof(ctx->active));
+       iwl_connection_init_rx_config(priv, ctx);
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       ieee80211_resume_disconnect(vif);
+
+       return 1;
+}
+
+#endif
+
+static void iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MACDUMP(priv, "enter\n");
+
+       IWL_DEBUG_TX(priv, "dev->xmit(%d bytes) at rate 0x%02x\n", skb->len,
+                    ieee80211_get_tx_rate(hw, IEEE80211_SKB_CB(skb))->bitrate);
+
+       if (iwlagn_tx_skb(priv, skb))
+               dev_kfree_skb_any(skb);
+
+       IWL_DEBUG_MACDUMP(priv, "leave\n");
+}
+
+static void iwlagn_mac_update_tkip_key(struct ieee80211_hw *hw,
+                                      struct ieee80211_vif *vif,
+                                      struct ieee80211_key_conf *keyconf,
+                                      struct ieee80211_sta *sta,
+                                      u32 iv32, u16 *phase1key)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       iwl_update_tkip_key(priv, vif, keyconf, sta, iv32, phase1key);
+}
+
+static int iwlagn_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta,
+                             struct ieee80211_key_conf *key)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       bool is_default_wep_key = false;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (iwlagn_mod_params.sw_crypto) {
+               IWL_DEBUG_MAC80211(priv, "leave - hwcrypto disabled\n");
+               return -EOPNOTSUPP;
+       }
+
+       /*
+        * We could program these keys into the hardware as well, but we
+        * don't expect much multicast traffic in IBSS and having keys
+        * for more stations is probably more useful.
+        *
+        * Mark key TX-only and return 0.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC &&
+           !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
+               key->hw_key_idx = WEP_INVALID_OFFSET;
+               return 0;
+       }
+
+       /* If they key was TX-only, accept deletion */
+       if (cmd == DISABLE_KEY && key->hw_key_idx == WEP_INVALID_OFFSET)
+               return 0;
+
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, 100);
+
+       BUILD_BUG_ON(WEP_INVALID_OFFSET == IWLAGN_HW_KEY_DEFAULT);
+
+       /*
+        * If we are getting WEP group key and we didn't receive any key mapping
+        * so far, we are in legacy wep mode (group key only), otherwise we are
+        * in 1X mode.
+        * In legacy wep mode, we use another host command to the uCode.
+        */
+       if ((key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
+            key->cipher == WLAN_CIPHER_SUITE_WEP104) && !sta) {
+               if (cmd == SET_KEY)
+                       is_default_wep_key = !ctx->key_mapping_keys;
+               else
+                       is_default_wep_key =
+                               key->hw_key_idx == IWLAGN_HW_KEY_DEFAULT;
+       }
+
+
+       switch (cmd) {
+       case SET_KEY:
+               if (is_default_wep_key) {
+                       ret = iwl_set_default_wep_key(priv, vif_priv->ctx, key);
+                       break;
+               }
+               ret = iwl_set_dynamic_key(priv, vif_priv->ctx, key, sta);
+               if (ret) {
+                       /*
+                        * can't add key for RX, but we don't need it
+                        * in the device for TX so still return 0
+                        */
+                       ret = 0;
+                       key->hw_key_idx = WEP_INVALID_OFFSET;
+               }
+
+               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
+               break;
+       case DISABLE_KEY:
+               if (is_default_wep_key)
+                       ret = iwl_remove_default_wep_key(priv, ctx, key);
+               else
+                       ret = iwl_remove_dynamic_key(priv, ctx, key, sta);
+
+               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  enum ieee80211_ampdu_mlme_action action,
+                                  struct ieee80211_sta *sta, u16 tid, u16 *ssn,
+                                  u8 buf_size)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret = -EINVAL;
+       struct iwl_station_priv *sta_priv = (void *) sta->drv_priv;
+       struct iwl_rxon_context *ctx =  iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_HT(priv, "A-MPDU action on addr %pM tid %d\n",
+                    sta->addr, tid);
+
+       if (!(priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE))
+               return -EACCES;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       switch (action) {
+       case IEEE80211_AMPDU_RX_START:
+               IWL_DEBUG_HT(priv, "start Rx\n");
+               ret = iwl_sta_rx_agg_start(priv, sta, tid, *ssn);
+               break;
+       case IEEE80211_AMPDU_RX_STOP:
+               IWL_DEBUG_HT(priv, "stop Rx\n");
+               ret = iwl_sta_rx_agg_stop(priv, sta, tid);
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               break;
+       case IEEE80211_AMPDU_TX_START:
+               IWL_DEBUG_HT(priv, "start Tx\n");
+               ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
+               break;
+       case IEEE80211_AMPDU_TX_STOP:
+               IWL_DEBUG_HT(priv, "stop Tx\n");
+               ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
+               if ((ret == 0) && (priv->agg_tids_count > 0)) {
+                       priv->agg_tids_count--;
+                       IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                                    priv->agg_tids_count);
+               }
+               if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
+                       ret = 0;
+               if (!priv->agg_tids_count && priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch off RTS/CTS if it was previously enabled
+                        */
+                       sta_priv->lq_sta.lq.general_params.flags &=
+                               ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+                       iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                                       &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+               }
+               break;
+       case IEEE80211_AMPDU_TX_OPERATIONAL:
+               buf_size = min_t(int, buf_size, LINK_QUAL_AGG_FRAME_LIMIT_DEF);
+
+               iwl_trans_tx_agg_setup(trans(priv), ctx->ctxid, iwl_sta_id(sta),
+                               tid, buf_size);
+
+               /*
+                * If the limit is 0, then it wasn't initialised yet,
+                * use the default. We can do that since we take the
+                * minimum below, and we don't want to go above our
+                * default due to hardware restrictions.
+                */
+               if (sta_priv->max_agg_bufsize == 0)
+                       sta_priv->max_agg_bufsize =
+                               LINK_QUAL_AGG_FRAME_LIMIT_DEF;
+
+               /*
+                * Even though in theory the peer could have different
+                * aggregation reorder buffer sizes for different sessions,
+                * our ucode doesn't allow for that and has a global limit
+                * for each station. Therefore, use the minimum of all the
+                * aggregation sessions and our default value.
+                */
+               sta_priv->max_agg_bufsize =
+                       min(sta_priv->max_agg_bufsize, buf_size);
+
+               if (priv->cfg->ht_params &&
+                   priv->cfg->ht_params->use_rts_for_aggregation) {
+                       /*
+                        * switch to RTS/CTS if it is the prefer protection
+                        * method for HT traffic
+                        */
+
+                       sta_priv->lq_sta.lq.general_params.flags |=
+                               LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
+               }
+               priv->agg_tids_count++;
+               IWL_DEBUG_HT(priv, "priv->agg_tids_count = %u\n",
+                            priv->agg_tids_count);
+
+               sta_priv->lq_sta.lq.agg_params.agg_frame_cnt_limit =
+                       sta_priv->max_agg_bufsize;
+
+               iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
+                               &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+
+               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+                        sta->addr, tid);
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return ret;
+}
+
+static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       bool is_ap = vif->type == NL80211_IFTYPE_STATION;
+       int ret = 0;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "received request to add station %pM\n",
+                       sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
+                       sta->addr);
+       sta_priv->sta_id = IWL_INVALID_STATION;
+
+       atomic_set(&sta_priv->pending_frames, 0);
+       if (vif->type == NL80211_IFTYPE_AP)
+               sta_priv->client = true;
+
+       ret = iwl_add_station_common(priv, vif_priv->ctx, sta->addr,
+                                    is_ap, sta, &sta_id);
+       if (ret) {
+               IWL_ERR(priv, "Unable to add station %pM (%d)\n",
+                       sta->addr, ret);
+               /* Should we return success if return code is EEXIST ? */
+               goto out;
+       }
+
+       sta_priv->sta_id = sta_id;
+
+       /* Initialize rate scaling */
+       IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
+                      sta->addr);
+       iwl_rs_rate_init(priv, sta, sta_id);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
+                               struct ieee80211_channel_switch *ch_switch)
+{
+       struct iwl_priv *priv = hw->priv;
+       const struct iwl_channel_info *ch_info;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct ieee80211_channel *channel = ch_switch->channel;
+       struct iwl_ht_config *ht_conf = &priv->current_ht_config;
+       /*
+        * MULTI-FIXME
+        * When we add support for multiple interfaces, we need to
+        * revisit this. The channel switch command in the device
+        * only affects the BSS context, but what does that really
+        * mean? And what if we get a CSA on the second interface?
+        * This needs a lot of work.
+        */
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u16 ch;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_rfkill(priv->shrd))
+               goto out;
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) ||
+           test_bit(STATUS_SCANNING, &priv->shrd->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
+               goto out;
+
+       if (!iwl_is_associated_ctx(ctx))
+               goto out;
+
+       if (!priv->cfg->lib->set_channel_switch)
+               goto out;
+
+       ch = channel->hw_value;
+       if (le16_to_cpu(ctx->active.channel) == ch)
+               goto out;
+
+       ch_info = iwl_get_channel_info(priv, channel->band, ch);
+       if (!is_channel_valid(ch_info)) {
+               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+               goto out;
+       }
+
+       spin_lock_irq(&priv->shrd->lock);
+
+       priv->current_ht_config.smps = conf->smps_mode;
+
+       /* Configure HT40 channels */
+       ctx->ht.enabled = conf_is_ht(conf);
+       if (ctx->ht.enabled) {
+               if (conf_is_ht40_minus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                       ctx->ht.is_40mhz = true;
+               } else if (conf_is_ht40_plus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                       ctx->ht.is_40mhz = true;
+               } else {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                       ctx->ht.is_40mhz = false;
+               }
+       } else
+               ctx->ht.is_40mhz = false;
+
+       if ((le16_to_cpu(ctx->staging.channel) != ch))
+               ctx->staging.flags = 0;
+
+       iwl_set_rxon_channel(priv, channel, ctx);
+       iwl_set_rxon_ht(priv, ht_conf);
+       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+       spin_unlock_irq(&priv->shrd->lock);
+
+       iwl_set_rate(priv);
+       /*
+        * at this point, staging_rxon has the
+        * configuration for channel switch
+        */
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+       priv->switch_channel = cpu_to_le16(ch);
+       if (priv->cfg->lib->set_channel_switch(priv, ch_switch)) {
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status);
+               priv->switch_channel = 0;
+               ieee80211_chswitch_done(ctx->vif, false);
+       }
+
+out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_configure_filter(struct ieee80211_hw *hw,
+                                   unsigned int changed_flags,
+                                   unsigned int *total_flags,
+                                   u64 multicast)
+{
+       struct iwl_priv *priv = hw->priv;
+       __le32 filter_or = 0, filter_nand = 0;
+       struct iwl_rxon_context *ctx;
+
+#define CHK(test, flag)        do { \
+       if (*total_flags & (test))              \
+               filter_or |= (flag);            \
+       else                                    \
+               filter_nand |= (flag);          \
+       } while (0)
+
+       IWL_DEBUG_MAC80211(priv, "Enter: changed: 0x%x, total: 0x%x\n",
+                       changed_flags, *total_flags);
+
+       CHK(FIF_OTHER_BSS | FIF_PROMISC_IN_BSS, RXON_FILTER_PROMISC_MSK);
+       /* Setting _just_ RXON_FILTER_CTL2HOST_MSK causes FH errors */
+       CHK(FIF_CONTROL, RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_PROMISC_MSK);
+       CHK(FIF_BCN_PRBRESP_PROMISC, RXON_FILTER_BCON_AWARE_MSK);
+
+#undef CHK
+
+       mutex_lock(&priv->shrd->mutex);
+
+       for_each_context(priv, ctx) {
+               ctx->staging.filter_flags &= ~filter_nand;
+               ctx->staging.filter_flags |= filter_or;
+
+               /*
+                * Not committing directly because hardware can perform a scan,
+                * but we'll eventually commit the filter flags change anyway.
+                */
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       /*
+        * Receiving all multicast frames is always enabled by the
+        * default flags setup in iwl_connection_init_rx_config()
+        * since we currently do not support programming multicast
+        * filters into the device.
+        */
+       *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS |
+                       FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL;
+}
+
+static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to device shutdown\n");
+               goto done;
+       }
+       if (iwl_is_rfkill(priv->shrd)) {
+               IWL_DEBUG_TX(priv, "Aborting flush due to RF Kill\n");
+               goto done;
+       }
+
+       /*
+        * mac80211 will not push any more frames for transmit
+        * until the flush is completed
+        */
+       if (drop) {
+               IWL_DEBUG_MAC80211(priv, "send flush command\n");
+               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+                       IWL_ERR(priv, "flush request fail\n");
+                       goto done;
+               }
+       }
+       IWL_DEBUG_MAC80211(priv, "wait transmit/flush all frames\n");
+       iwl_trans_wait_tx_queue_empty(trans(priv));
+done:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+                                    struct ieee80211_channel *channel,
+                                    enum nl80211_channel_type channel_type,
+                                    int duration)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_PAN];
+       int err = 0;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       if (!(ctx->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       priv->hw_roc_channel = channel;
+       priv->hw_roc_chantype = channel_type;
+       /* convert from ms to TU */
+       priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
+       priv->hw_roc_start_notified = false;
+       cancel_delayed_work(&priv->hw_roc_disable_work);
+
+       if (!ctx->is_active) {
+               static const struct iwl_qos_info default_qos_data = {
+                       .def_qos_parm = {
+                               .ac[0] = {
+                                       .cw_min = cpu_to_le16(3),
+                                       .cw_max = cpu_to_le16(7),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(1504),
+                               },
+                               .ac[1] = {
+                                       .cw_min = cpu_to_le16(7),
+                                       .cw_max = cpu_to_le16(15),
+                                       .aifsn = 2,
+                                       .edca_txop = cpu_to_le16(3008),
+                               },
+                               .ac[2] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 3,
+                               },
+                               .ac[3] = {
+                                       .cw_min = cpu_to_le16(15),
+                                       .cw_max = cpu_to_le16(1023),
+                                       .aifsn = 7,
+                               },
+                       },
+               };
+
+               ctx->is_active = true;
+               ctx->qos_data = default_qos_data;
+               ctx->staging.dev_type = RXON_DEV_TYPE_P2P;
+               memcpy(ctx->staging.node_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               memcpy(ctx->staging.bssid_addr,
+                      priv->contexts[IWL_RXON_CTX_BSS].staging.node_addr,
+                      ETH_ALEN);
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err)
+                       goto out;
+               ctx->staging.filter_flags |= RXON_FILTER_ASSOC_MSK |
+                                            RXON_FILTER_PROMISC_MSK |
+                                            RXON_FILTER_CTL2HOST_MSK;
+
+               err = iwlagn_commit_rxon(priv, ctx);
+               if (err) {
+                       iwlagn_disable_roc(priv);
+                       goto out;
+               }
+               priv->hw_roc_setup = true;
+       }
+
+       err = iwl_scan_initiate(priv, ctx->vif, IWL_SCAN_ROC, channel->band);
+       if (err)
+               iwlagn_disable_roc(priv);
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_cancel_remain_on_channel(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       if (!(priv->shrd->valid_contexts & BIT(IWL_RXON_CTX_PAN)))
+               return -EOPNOTSUPP;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+       iwl_scan_cancel_timeout(priv, priv->hw_roc_duration);
+       iwlagn_disable_roc(priv);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return 0;
+}
+
+static int iwlagn_mac_tx_sync(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             const u8 *bssid,
+                             enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       int ret;
+       u8 sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx)) {
+               ret = 0;
+               goto out;
+       }
+
+       if (ctx->preauth_bssid || test_bit(STATUS_SCAN_HW,
+           &priv->shrd->status)) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       ret = iwl_add_station_common(priv, ctx, bssid, true, NULL, &sta_id);
+       if (ret)
+               goto out;
+
+       if (WARN_ON(sta_id != ctx->ap_sta_id)) {
+               ret = -EIO;
+               goto out_remove_sta;
+       }
+
+       memcpy(ctx->bssid, bssid, ETH_ALEN);
+       ctx->preauth_bssid = true;
+
+       ret = iwlagn_commit_rxon(priv, ctx);
+
+       if (ret == 0)
+               goto out;
+
+ out_remove_sta:
+       iwl_remove_station(priv, sta_id, bssid);
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwlagn_mac_finish_tx_sync(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const u8 *bssid,
+                                  enum ieee80211_tx_sync_type type)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (iwl_is_associated_ctx(ctx))
+               goto out;
+
+       iwl_remove_station(priv, ctx->ap_sta_id, bssid);
+       ctx->preauth_bssid = false;
+       /* no need to commit */
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static void iwlagn_mac_rssi_callback(struct ieee80211_hw *hw,
+                          enum ieee80211_rssi_event rssi_event)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+       mutex_lock(&priv->shrd->mutex);
+
+       if (priv->cfg->bt_params &&
+                       priv->cfg->bt_params->advanced_bt_coexist) {
+               if (rssi_event == RSSI_EVENT_LOW)
+                       priv->bt_enable_pspoll = true;
+               else if (rssi_event == RSSI_EVENT_HIGH)
+                       priv->bt_enable_pspoll = false;
+
+               iwlagn_send_advance_bt_config(priv);
+       } else {
+               IWL_DEBUG_MAC80211(priv, "Advanced BT coex disabled,"
+                               "ignoring RSSI callback\n");
+       }
+
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+static int iwlagn_mac_set_tim(struct ieee80211_hw *hw,
+                          struct ieee80211_sta *sta, bool set)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       queue_work(priv->shrd->workqueue, &priv->beacon_update);
+
+       return 0;
+}
+
+static int iwlagn_mac_conf_tx(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif, u16 queue,
+                   const struct ieee80211_tx_queue_params *params)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *ctx = vif_priv->ctx;
+       unsigned long flags;
+       int q;
+
+       if (WARN_ON(!ctx))
+               return -EINVAL;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF not ready\n");
+               return -EIO;
+       }
+
+       if (queue >= AC_NUM) {
+               IWL_DEBUG_MAC80211(priv, "leave - queue >= AC_NUM %d\n", queue);
+               return 0;
+       }
+
+       q = AC_NUM - 1 - queue;
+
+       spin_lock_irqsave(&priv->shrd->lock, flags);
+
+       ctx->qos_data.def_qos_parm.ac[q].cw_min =
+               cpu_to_le16(params->cw_min);
+       ctx->qos_data.def_qos_parm.ac[q].cw_max =
+               cpu_to_le16(params->cw_max);
+       ctx->qos_data.def_qos_parm.ac[q].aifsn = params->aifs;
+       ctx->qos_data.def_qos_parm.ac[q].edca_txop =
+                       cpu_to_le16((params->txop * 32));
+
+       ctx->qos_data.def_qos_parm.ac[q].reserved1 = 0;
+
+       spin_unlock_irqrestore(&priv->shrd->lock, flags);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return 0;
+}
+
+static int iwlagn_mac_tx_last_beacon(struct ieee80211_hw *hw)
+{
+       struct iwl_priv *priv = hw->priv;
+
+       return priv->ibss_manager == IWL_IBSS_MANAGER;
+}
+
+static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
+{
+       iwl_connection_init_rx_config(priv, ctx);
+
+       iwlagn_set_rxon_chain(priv, ctx);
+
+       return iwlagn_commit_rxon(priv, ctx);
+}
+
+static int iwl_setup_interface(struct iwl_priv *priv,
+                              struct iwl_rxon_context *ctx)
+{
+       struct ieee80211_vif *vif = ctx->vif;
+       int err;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       /*
+        * This variable will be correct only when there's just
+        * a single context, but all code using it is for hardware
+        * that supports only one context.
+        */
+       priv->iw_mode = vif->type;
+
+       ctx->is_active = true;
+
+       err = iwl_set_mode(priv, ctx);
+       if (err) {
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+               return err;
+       }
+
+       if (priv->cfg->bt_params && priv->cfg->bt_params->advanced_bt_coexist &&
+           vif->type == NL80211_IFTYPE_ADHOC) {
+               /*
+                * pretend to have high BT traffic as long as we
+                * are operating in IBSS mode, as this will cause
+                * the rate scaling etc. to behave as intended.
+                */
+               priv->bt_traffic_load = IWL_BT_COEX_TRAFFIC_LOAD_HIGH;
+       }
+
+       return 0;
+}
+
+static int iwlagn_mac_add_interface(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_vif_priv *vif_priv = (void *)vif->drv_priv;
+       struct iwl_rxon_context *tmp, *ctx = NULL;
+       int err;
+       enum nl80211_iftype viftype = ieee80211_vif_type_p2p(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter: type %d, addr %pM\n",
+                          viftype, vif->addr);
+
+       cancel_delayed_work_sync(&priv->hw_roc_disable_work);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       iwlagn_disable_roc(priv);
+
+       if (!iwl_is_ready_rf(priv->shrd)) {
+               IWL_WARN(priv, "Try to add interface when device not ready\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       for_each_context(priv, tmp) {
+               u32 possible_modes =
+                       tmp->interface_modes | tmp->exclusive_interface_modes;
+
+               if (tmp->vif) {
+                       /* check if this busy context is exclusive */
+                       if (tmp->exclusive_interface_modes &
+                                               BIT(tmp->vif->type)) {
+                               err = -EINVAL;
+                               goto out;
+                       }
+                       continue;
+               }
+
+               if (!(possible_modes & BIT(viftype)))
+                       continue;
+
+               /* have maybe usable context w/o interface */
+               ctx = tmp;
+               break;
+       }
+
+       if (!ctx) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
+       vif_priv->ctx = ctx;
+       ctx->vif = vif;
+
+       err = iwl_setup_interface(priv, ctx);
+       if (!err)
+               goto out;
+
+       ctx->vif = NULL;
+       priv->iw_mode = NL80211_IFTYPE_STATION;
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+       return err;
+}
+
+static void iwl_teardown_interface(struct iwl_priv *priv,
+                                  struct ieee80211_vif *vif,
+                                  bool mode_change)
+{
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (priv->scan_vif == vif) {
+               iwl_scan_cancel_timeout(priv, 200);
+               iwl_force_scan_end(priv);
+       }
+
+       if (!mode_change) {
+               iwl_set_mode(priv, ctx);
+               if (!ctx->always_active)
+                       ctx->is_active = false;
+       }
+
+       /*
+        * When removing the IBSS interface, overwrite the
+        * BT traffic load with the stored one from the last
+        * notification, if any. If this is a device that
+        * doesn't implement this, this has no effect since
+        * both values are the same and zero.
+        */
+       if (vif->type == NL80211_IFTYPE_ADHOC)
+               priv->bt_traffic_load = priv->last_bt_traffic_load;
+}
+
+static void iwlagn_mac_remove_interface(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (WARN_ON(ctx->vif != vif)) {
+               struct iwl_rxon_context *tmp;
+               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+               for_each_context(priv, tmp)
+                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+                               tmp->ctxid, tmp, tmp->vif);
+       }
+       ctx->vif = NULL;
+
+       iwl_teardown_interface(priv, vif, false);
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+}
+
+static int iwlagn_mac_change_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               enum nl80211_iftype newtype, bool newp2p)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_rxon_context *ctx = iwl_rxon_ctx_from_vif(vif);
+       struct iwl_rxon_context *bss_ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       struct iwl_rxon_context *tmp;
+       enum nl80211_iftype newviftype = newtype;
+       u32 interface_modes;
+       int err;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       newtype = ieee80211_iftype_p2p(newtype, newp2p);
+
+       mutex_lock(&priv->shrd->mutex);
+
+       if (!ctx->vif || !iwl_is_ready_rf(priv->shrd)) {
+               /*
+                * Huh? But wait ... this can maybe happen when
+                * we're in the middle of a firmware restart!
+                */
+               err = -EBUSY;
+               goto out;
+       }
+
+       interface_modes = ctx->interface_modes | ctx->exclusive_interface_modes;
+
+       if (!(interface_modes & BIT(newtype))) {
+               err = -EBUSY;
+               goto out;
+       }
+
+       /*
+        * Refuse a change that should be done by moving from the PAN
+        * context to the BSS context instead, if the BSS context is
+        * available and can support the new interface type.
+        */
+       if (ctx->ctxid == IWL_RXON_CTX_PAN && !bss_ctx->vif &&
+           (bss_ctx->interface_modes & BIT(newtype) ||
+            bss_ctx->exclusive_interface_modes & BIT(newtype))) {
+               BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+               err = -EBUSY;
+               goto out;
+       }
+
+       if (ctx->exclusive_interface_modes & BIT(newtype)) {
+               for_each_context(priv, tmp) {
+                       if (ctx == tmp)
+                               continue;
+
+                       if (!tmp->vif)
+                               continue;
+
+                       /*
+                        * The current mode switch would be exclusive, but
+                        * another context is active ... refuse the switch.
+                        */
+                       err = -EBUSY;
+                       goto out;
+               }
+       }
+
+       /* success */
+       iwl_teardown_interface(priv, vif, true);
+       vif->type = newviftype;
+       vif->p2p = newp2p;
+       err = iwl_setup_interface(priv, ctx);
+       WARN_ON(err);
+       /*
+        * We've switched internally, but submitting to the
+        * device may have failed for some reason. Mask this
+        * error, because otherwise mac80211 will not switch
+        * (and set the interface type back) and we'll be
+        * out of sync with it.
+        */
+       err = 0;
+
+ out:
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return err;
+}
+
+static int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
+                   struct ieee80211_vif *vif,
+                   struct cfg80211_scan_request *req)
+{
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       if (req->n_channels == 0)
+               return -EINVAL;
+
+       mutex_lock(&priv->shrd->mutex);
+
+       /*
+        * If an internal scan is in progress, just set
+        * up the scan_request as per above.
+        */
+       if (priv->scan_type != IWL_SCAN_NORMAL) {
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               ret = 0;
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
+               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
+                                       req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       mutex_unlock(&priv->shrd->mutex);
+
+       return ret;
+}
+
+static int iwlagn_mac_sta_remove(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif,
+                      struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int ret;
+
+       IWL_DEBUG_MAC80211(priv, "enter: received request to remove "
+                          "station %pM\n", sta->addr);
+       mutex_lock(&priv->shrd->mutex);
+       IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
+                       sta->addr);
+       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
+       if (ret)
+               IWL_DEBUG_QUIET_RFKILL(priv, "Error removing station %pM\n",
+                       sta->addr);
+       mutex_unlock(&priv->shrd->mutex);
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+       return ret;
+}
+
+static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&priv->shrd->sta_lock, flags);
+       priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK;
+       priv->stations[sta_id].sta.sta.modify_mask = 0;
+       priv->stations[sta_id].sta.sleep_tx_count = 0;
+       priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
+       iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC);
+       spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+
+}
+
+static void iwlagn_mac_sta_notify(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif,
+                          enum sta_notify_cmd cmd,
+                          struct ieee80211_sta *sta)
+{
+       struct iwl_priv *priv = hw->priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
+       int sta_id;
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       switch (cmd) {
+       case STA_NOTIFY_SLEEP:
+               WARN_ON(!sta_priv->client);
+               sta_priv->asleep = true;
+               if (atomic_read(&sta_priv->pending_frames) > 0)
+                       ieee80211_sta_block_awake(hw, sta, true);
+               break;
+       case STA_NOTIFY_AWAKE:
+               WARN_ON(!sta_priv->client);
+               if (!sta_priv->asleep)
+                       break;
+               sta_priv->asleep = false;
+               sta_id = iwl_sta_id(sta);
+               if (sta_id != IWL_INVALID_STATION)
+                       iwl_sta_modify_ps_wake(priv, sta_id);
+               break;
+       default:
+               break;
+       }
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+}
+
+struct ieee80211_ops iwlagn_hw_ops = {
+       .tx = iwlagn_mac_tx,
+       .start = iwlagn_mac_start,
+       .stop = iwlagn_mac_stop,
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwlagn_mac_suspend,
+       .resume = iwlagn_mac_resume,
+#endif
+       .add_interface = iwlagn_mac_add_interface,
+       .remove_interface = iwlagn_mac_remove_interface,
+       .change_interface = iwlagn_mac_change_interface,
+       .config = iwlagn_mac_config,
+       .configure_filter = iwlagn_configure_filter,
+       .set_key = iwlagn_mac_set_key,
+       .update_tkip_key = iwlagn_mac_update_tkip_key,
+       .set_rekey_data = iwlagn_mac_set_rekey_data,
+       .conf_tx = iwlagn_mac_conf_tx,
+       .bss_info_changed = iwlagn_bss_info_changed,
+       .ampdu_action = iwlagn_mac_ampdu_action,
+       .hw_scan = iwlagn_mac_hw_scan,
+       .sta_notify = iwlagn_mac_sta_notify,
+       .sta_add = iwlagn_mac_sta_add,
+       .sta_remove = iwlagn_mac_sta_remove,
+       .channel_switch = iwlagn_mac_channel_switch,
+       .flush = iwlagn_mac_flush,
+       .tx_last_beacon = iwlagn_mac_tx_last_beacon,
+       .remain_on_channel = iwlagn_mac_remain_on_channel,
+       .cancel_remain_on_channel = iwlagn_mac_cancel_remain_on_channel,
+       .rssi_callback = iwlagn_mac_rssi_callback,
+       CFG80211_TESTMODE_CMD(iwlagn_mac_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(iwlagn_mac_testmode_dump)
+       .tx_sync = iwlagn_mac_tx_sync,
+       .finish_tx_sync = iwlagn_mac_finish_tx_sync,
+       .set_tim = iwlagn_mac_set_tim,
+};
+
+/* This function both allocates and initializes hw and priv. */
+struct ieee80211_hw *iwl_alloc_all(void)
+{
+       struct iwl_priv *priv;
+       /* mac80211 allocates memory for this device instance, including
+        *   space for this driver's private structure */
+       struct ieee80211_hw *hw;
+
+       hw = ieee80211_alloc_hw(sizeof(struct iwl_priv), &iwlagn_hw_ops);
+       if (!hw)
+               goto out;
+
+       priv = hw->priv;
+       priv->hw = hw;
+
+out:
+       return hw;
+}
index 1800029911adfa1e21dfc8d3c6b0d59614daf88f..850ec8e51b176738544b755bdbea8687e1f0b3be 100644 (file)
@@ -256,6 +256,8 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0x1341, iwl6005_2agn_d_cfg)},
+       {IWL_PCI_DEVICE(0x0082, 0x1304, iwl6005_2agn_cfg)},/* low 5GHz active */
+       {IWL_PCI_DEVICE(0x0082, 0x1305, iwl6005_2agn_cfg)},/* high 5GHz active */
 
 /* 6x30 Series */
        {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -325,46 +327,28 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0890, 0x4022, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0891, 0x4222, iwl2000_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4422, iwl2000_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4026, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0891, 0x4226, iwl2000_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0890, 0x4426, iwl2000_2bg_cfg)},
        {IWL_PCI_DEVICE(0x0890, 0x4822, iwl2000_2bgn_d_cfg)},
 
 /* 2x30 Series */
        {IWL_PCI_DEVICE(0x0887, 0x4062, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0888, 0x4262, iwl2030_2bgn_cfg)},
        {IWL_PCI_DEVICE(0x0887, 0x4462, iwl2030_2bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4066, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0888, 0x4266, iwl2030_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x0887, 0x4466, iwl2030_2bg_cfg)},
 
 /* 6x35 Series */
        {IWL_PCI_DEVICE(0x088E, 0x4060, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088F, 0x4260, iwl6035_2agn_cfg)},
        {IWL_PCI_DEVICE(0x088E, 0x4460, iwl6035_2agn_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4064, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4264, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4464, iwl6035_2abg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4066, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088F, 0x4266, iwl6035_2bg_cfg)},
-       {IWL_PCI_DEVICE(0x088E, 0x4466, iwl6035_2bg_cfg)},
 
 /* 105 Series */
        {IWL_PCI_DEVICE(0x0894, 0x0022, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0895, 0x0222, iwl105_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0422, iwl105_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0026, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0895, 0x0226, iwl105_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0894, 0x0426, iwl105_bg_cfg)},
        {IWL_PCI_DEVICE(0x0894, 0x0822, iwl105_bgn_d_cfg)},
 
 /* 135 Series */
        {IWL_PCI_DEVICE(0x0892, 0x0062, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0893, 0x0262, iwl135_bgn_cfg)},
        {IWL_PCI_DEVICE(0x0892, 0x0462, iwl135_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0066, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0893, 0x0266, iwl135_bg_cfg)},
-       {IWL_PCI_DEVICE(0x0892, 0x0466, iwl135_bg_cfg)},
 
        {0}
 };
index e5d727f537d08eb09080fa8170609771cb230b5b..359d2182757bbbb6c567b2fb9cb4d7291021df4c 100644 (file)
@@ -416,6 +416,8 @@ static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
 
                if (!iwl_is_associated_ctx(ctx))
                        continue;
+               if (ctx->staging.dev_type == RXON_DEV_TYPE_P2P)
+                       continue;
                value = ctx->beacon_int;
                if (!value)
                        value = IWL_PASSIVE_DWELL_BASE;
@@ -678,7 +680,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
                        priv->contexts[IWL_RXON_CTX_BSS].active.flags &
                                                RXON_FLG_CHANNEL_MODE_MSK)
                                       >> RXON_FLG_CHANNEL_MODE_POS;
-               if (chan_mod == CHANNEL_MODE_PURE_40) {
+               if ((priv->scan_request && priv->scan_request->no_cck) ||
+                   chan_mod == CHANNEL_MODE_PURE_40) {
                        rate = IWL_RATE_6M_PLCP;
                } else {
                        rate = IWL_RATE_1M_PLCP;
@@ -938,51 +941,6 @@ int __must_check iwl_scan_initiate(struct iwl_priv *priv,
        return 0;
 }
 
-int iwlagn_mac_hw_scan(struct ieee80211_hw *hw,
-                   struct ieee80211_vif *vif,
-                   struct cfg80211_scan_request *req)
-{
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (req->n_channels == 0)
-               return -EINVAL;
-
-       mutex_lock(&priv->shrd->mutex);
-
-       /*
-        * If an internal scan is in progress, just set
-        * up the scan_request as per above.
-        */
-       if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv,
-                              "SCAN request during internal scan - defer\n");
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               ret = 0;
-       } else {
-               priv->scan_request = req;
-               priv->scan_vif = vif;
-               /*
-                * mac80211 will only ask for one band at a time
-                * so using channels[0] here is ok
-                */
-               ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
-                                       req->channels[0]->band);
-               if (ret) {
-                       priv->scan_request = NULL;
-                       priv->scan_vif = NULL;
-               }
-       }
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-       mutex_unlock(&priv->shrd->mutex);
-
-       return ret;
-}
 
 /*
  * internal short scan, this function should only been called while associated.
index 5e50d88f302b761e565f8e4b24989a46639a14c0..e3882d0cfc85b9ce4c1bee214596a40c9ecfe2be 100644 (file)
@@ -396,8 +396,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_INIT_FW:
-               status = iwlagn_load_ucode_wait_alive(priv, &priv->ucode_init,
-                                                     IWL_UCODE_INIT);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_INIT);
                if (status)
                        IWL_DEBUG_INFO(priv,
                                "Error loading init ucode: %d\n", status);
@@ -409,9 +408,7 @@ static int iwl_testmode_driver(struct ieee80211_hw *hw, struct nlattr **tb)
                break;
 
        case IWL_TM_CMD_APP2DEV_LOAD_RUNTIME_FW:
-               status = iwlagn_load_ucode_wait_alive(priv,
-                                          &priv->ucode_rt,
-                                          IWL_UCODE_REGULAR);
+               status = iwlagn_load_ucode_wait_alive(priv, IWL_UCODE_REGULAR);
                if (status) {
                        IWL_DEBUG_INFO(priv,
                                "Error loading runtime ucode: %d\n", status);
index 2b6756e8b8f97578394bdfd2a473f8acd0bd95d6..afaaa2a51b966e0bb93477f03fabfbb5590f0d40 100644 (file)
@@ -355,7 +355,7 @@ static inline void iwl_set_swq_id(struct iwl_tx_queue *txq, u8 ac, u8 hwq)
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -363,13 +363,22 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0)
+       if (test_and_clear_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0) {
                        iwl_wake_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Wake hwq %d ac %d. %s",
+                                           hwq, ac, msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't wake hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       }
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_tx_queue *txq, const char *msg)
 {
        u8 queue = txq->swq_id;
        u8 ac = queue & 3;
@@ -377,9 +386,23 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped))
-               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0)
+       if (!test_and_set_bit(hwq, trans_pcie->queue_stopped)) {
+               if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0) {
                        iwl_stop_sw_queue(priv(trans), ac);
+                       IWL_DEBUG_TX_QUEUES(trans, "Stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               } else {
+                       IWL_DEBUG_TX_QUEUES(trans, "Don't stop hwq %d ac %d"
+                                           " stop count %d. %s",
+                                           hwq, ac, atomic_read(&trans_pcie->
+                                           queue_stop_count[ac]), msg);
+               }
+       } else {
+               IWL_DEBUG_TX_QUEUES(trans, "stop hwq %d, but it is stopped/ %s",
+                                   hwq, msg);
+       }
 }
 
 #ifdef ieee80211_stop_queue
index 374c68cc1d705dca84ed42d75714524f3e0569b1..ee126f844a5c412f8eafaf32ea0b5e7daecfbd55 100644 (file)
@@ -1108,7 +1108,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                isr_stats->tx++;
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
-               priv(trans)->ucode_write_complete = 1;
+               trans->ucode_write_complete = 1;
                wake_up(&trans->shrd->wait_command_queue);
        }
 
index 4a0c95302a7e89f08021257f76468dbf43dae0a4..6dba1515023c89efcc95330da663c34c336ea3fd 100644 (file)
@@ -430,7 +430,7 @@ void iwl_trans_tx_queue_set_status(struct iwl_trans *trans,
 
        txq->sched_retry = scd_retry;
 
-       IWL_DEBUG_INFO(trans, "%s %s Queue %d on FIFO %d\n",
+       IWL_DEBUG_TX_QUEUES(trans, "%s %s Queue %d on FIFO %d\n",
                       active ? "Activate" : "Deactivate",
                       scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
 }
@@ -561,12 +561,13 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
 
        tid_data = &trans->shrd->tid_data[sta_id][tid];
        if (tid_data->tfds_in_queue == 0) {
-               IWL_DEBUG_HT(trans, "HW queue is empty\n");
+               IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
                tid_data->agg.state = IWL_AGG_ON;
                iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
        } else {
-               IWL_DEBUG_HT(trans, "HW queue is NOT empty: %d packets in HW"
-                            "queue\n", tid_data->tfds_in_queue);
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "HW queue is NOT empty: %d packets in HW"
+                                   " queue\n", tid_data->tfds_in_queue);
                tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
        }
        spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
@@ -643,14 +644,15 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
 
        /* The queue is not empty */
        if (write_ptr != read_ptr) {
-               IWL_DEBUG_HT(trans, "Stopping a non empty AGG HW QUEUE\n");
+               IWL_DEBUG_TX_QUEUES(trans,
+                                   "Stopping a non empty AGG HW QUEUE\n");
                trans->shrd->tid_data[sta_id][tid].agg.state =
                        IWL_EMPTYING_HW_QUEUE_DELBA;
                spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
                return 0;
        }
 
-       IWL_DEBUG_HT(trans, "HW queue is empty\n");
+       IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n");
 turn_off:
        trans->shrd->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF;
 
@@ -982,7 +984,8 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        ret = iwl_enqueue_hcmd(trans, cmd);
        if (ret < 0) {
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1000,6 +1003,20 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
 
+       if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
+               return -EBUSY;
+
+
+       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
+                              get_cmd_string(cmd->id));
+               return -ECANCELED;
+       }
+       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
+               IWL_ERR(trans, "Command %s failed: FW Error\n",
+                              get_cmd_string(cmd->id));
+               return -EIO;
+       }
        set_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
                        get_cmd_string(cmd->id));
@@ -1008,7 +1025,8 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (cmd_idx < 0) {
                ret = cmd_idx;
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-               IWL_ERR(trans, "Error sending %s: enqueue_hcmd failed: %d\n",
+               IWL_DEBUG_QUIET_RFKILL(trans,
+                       "Error sending %s: enqueue_hcmd failed: %d\n",
                          get_cmd_string(cmd->id), ret);
                return ret;
        }
@@ -1022,12 +1040,12 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                                &trans_pcie->txq[trans->shrd->cmd_queue];
                        struct iwl_queue *q = &txq->q;
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Error sending %s: time out after %dms.\n",
                                get_cmd_string(cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
-                       IWL_ERR(trans,
+                       IWL_DEBUG_QUIET_RFKILL(trans,
                                "Current CMD queue read_ptr %d write_ptr %d\n",
                                q->read_ptr, q->write_ptr);
 
@@ -1039,18 +1057,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                }
        }
 
-       if (test_bit(STATUS_RF_KILL_HW, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s aborted: RF KILL Switch\n",
-                              get_cmd_string(cmd->id));
-               ret = -ECANCELED;
-               goto fail;
-       }
-       if (test_bit(STATUS_FW_ERROR, &trans->shrd->status)) {
-               IWL_ERR(trans, "Command %s failed: FW Error\n",
-                              get_cmd_string(cmd->id));
-               ret = -EIO;
-               goto fail;
-       }
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->reply_page) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
                          get_cmd_string(cmd->id));
@@ -1071,7 +1077,7 @@ cancel:
                trans_pcie->txq[trans->shrd->cmd_queue].meta[cmd_idx].flags &=
                                                        ~CMD_WANT_SKB;
        }
-fail:
+
        if (cmd->reply_page) {
                iwl_free_pages(trans->shrd, cmd->reply_page);
                cmd->reply_page = 0;
index da3411057afca2d9debd63bbe1f2523c650f337d..a1a58330273f71683364d4117b7a9cb13a9c58ae 100644 (file)
@@ -1231,7 +1231,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                        txq->need_update = 1;
                        iwl_txq_update_write_ptr(trans, txq);
                } else {
-                       iwl_stop_queue(trans, txq);
+                       iwl_stop_queue(trans, txq, "Queue is full");
                }
        }
        return 0;
@@ -1283,20 +1283,21 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
                /* aggregated HW queue */
                if ((txq_id  == tid_data->agg.txq_id) &&
                    (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue DELBA flow\n");
                        iwl_trans_pcie_txq_agg_disable(trans, txq_id);
                        tid_data->agg.state = IWL_AGG_OFF;
                        iwl_stop_tx_ba_trans_ready(priv(trans),
                                                   NUM_IWL_RXON_CTX,
                                                   sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id],
+                                      "DELBA flow complete");
                }
                break;
        case IWL_EMPTYING_HW_QUEUE_ADDBA:
                /* We are reclaiming the last packet of the queue */
                if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(trans,
+                       IWL_DEBUG_TX_QUEUES(trans,
                                "HW queue empty: continue ADDBA flow\n");
                        tid_data->agg.state = IWL_AGG_ON;
                        iwl_start_tx_ba_trans_ready(priv(trans),
@@ -1354,7 +1355,7 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                                ssn , tfd_num, txq_id, txq->swq_id);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
                if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
-                       iwl_wake_queue(trans, txq);
+                       iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
 
        iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
@@ -1418,7 +1419,8 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 #endif /* CONFIG_PM_SLEEP */
 
 static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         enum iwl_rxon_context_id ctx)
+                                         enum iwl_rxon_context_id ctx,
+                                         const char *msg)
 {
        u8 ac, txq_id;
        struct iwl_trans_pcie *trans_pcie =
@@ -1426,11 +1428,11 @@ static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
 
        for (ac = 0; ac < AC_NUM; ac++) {
                txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
+               IWL_DEBUG_TX_QUEUES(trans, "Queue Status: Q[%d] %s\n",
                        ac,
                        (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
                              ? "stopped" : "awake");
-               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+               iwl_wake_queue(trans, &trans_pcie->txq[txq_id], msg);
        }
 }
 
@@ -1453,11 +1455,12 @@ static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
        return iwl_trans;
 }
 
-static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id,
+                                     const char *msg)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+       iwl_stop_queue(trans, &trans_pcie->txq[txq_id], msg);
 }
 
 #define IWL_FLUSH_WAIT_MS      2000
index c5923125c3f96bb8fe7625e2b59e0ba1cde4b8d7..50227ebc0ee22243d9baffde3b8223663923c696 100644 (file)
@@ -171,7 +171,8 @@ struct iwl_trans_ops {
        void (*tx_start)(struct iwl_trans *trans);
 
        void (*wake_any_queue)(struct iwl_trans *trans,
-                              enum iwl_rxon_context_id ctx);
+                              enum iwl_rxon_context_id ctx,
+                              const char *msg);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
@@ -196,7 +197,7 @@ struct iwl_trans_ops {
 
        void (*free)(struct iwl_trans *trans);
 
-       void (*stop_queue)(struct iwl_trans *trans, int q);
+       void (*stop_queue)(struct iwl_trans *trans, int q, const char *msg);
 
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*check_stuck_queue)(struct iwl_trans *trans, int q);
@@ -207,17 +208,48 @@ struct iwl_trans_ops {
 #endif
 };
 
+/* one for each uCode image (inst/data, boot/init/runtime) */
+struct fw_desc {
+       dma_addr_t p_addr;      /* hardware address */
+       void *v_addr;           /* software address */
+       u32 len;                /* size in bytes */
+};
+
+struct fw_img {
+       struct fw_desc code;    /* firmware code image */
+       struct fw_desc data;    /* firmware data image */
+};
+
+enum iwl_ucode_type {
+       IWL_UCODE_NONE,
+       IWL_UCODE_REGULAR,
+       IWL_UCODE_INIT,
+       IWL_UCODE_WOWLAN,
+};
+
 /**
  * struct iwl_trans - transport common data
  * @ops - pointer to iwl_trans_ops
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
  * @hcmd_lock: protects HCMD
+ * @ucode_write_complete: indicates that the ucode has been copied.
+ * @ucode_rt: run time ucode image
+ * @ucode_init: init ucode image
+ * @ucode_wowlan: wake on wireless ucode image (optional)
  */
 struct iwl_trans {
        const struct iwl_trans_ops *ops;
        struct iwl_shared *shrd;
        spinlock_t hcmd_lock;
 
+       u8 ucode_write_complete;        /* the image write is complete */
+       struct fw_img ucode_rt;
+       struct fw_img ucode_init;
+       struct fw_img ucode_wowlan;
+
+       /* eeprom related variables */
+       int    nvm_device_type;
+
        /* pointer to trans specific struct */
        /*Ensure that this pointer will always be aligned to sizeof pointer */
        char trans_specific[0] __attribute__((__aligned__(sizeof(void *))));
@@ -249,9 +281,10 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans)
 }
 
 static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
-                                           enum iwl_rxon_context_id ctx)
+                                           enum iwl_rxon_context_id ctx,
+                                           const char *msg)
 {
-       trans->ops->wake_any_queue(trans, ctx);
+       trans->ops->wake_any_queue(trans, ctx, msg);
 }
 
 
@@ -311,9 +344,10 @@ static inline void iwl_trans_free(struct iwl_trans *trans)
        trans->ops->free(trans);
 }
 
-static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q)
+static inline void iwl_trans_stop_queue(struct iwl_trans *trans, int q,
+                                       const char *msg)
 {
-       trans->ops->stop_queue(trans, q);
+       trans->ops->stop_queue(trans, q, msg);
 }
 
 static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans)
@@ -348,4 +382,8 @@ static inline int iwl_trans_resume(struct iwl_trans *trans)
 ******************************************************/
 extern const struct iwl_trans_ops trans_ops_pcie;
 
+int iwl_alloc_fw_desc(struct iwl_bus *bus, struct fw_desc *desc,
+                     const void *data, size_t len);
+void iwl_dealloc_ucode(struct iwl_trans *trans);
+
 #endif /* __iwl_trans_h__ */
index c42be81e979ebd700742154922acce4fcb6acde7..48e8218fd23bc32ad79f56c007b10fbb49109ff9 100644 (file)
@@ -165,11 +165,15 @@ static int iwm_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
                                struct key_params *params)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
        int ret;
 
        IWM_DBG_WEXT(iwm, DBG, "Adding key for %pM\n", mac_addr);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       key = &iwm->keys[key_index];
        memset(key, 0, sizeof(struct iwm_key));
        ret = iwm_key_init(key, key_index, mac_addr, params);
        if (ret < 0) {
@@ -214,8 +218,12 @@ static int iwm_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
                                u8 key_index, bool pairwise, const u8 *mac_addr)
 {
        struct iwm_priv *iwm = ndev_to_iwm(ndev);
-       struct iwm_key *key = &iwm->keys[key_index];
+       struct iwm_key *key;
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
+       key = &iwm->keys[key_index];
        if (!iwm->keys[key_index].key_len) {
                IWM_DBG_WEXT(iwm, DBG, "Key %d not used\n", key_index);
                return 0;
@@ -236,6 +244,9 @@ static int iwm_cfg80211_set_default_key(struct wiphy *wiphy,
 
        IWM_DBG_WEXT(iwm, DBG, "Default key index is: %d\n", key_index);
 
+       if (key_index >= IWM_NUM_KEYS)
+               return -ENOENT;
+
        if (!iwm->keys[key_index].key_len) {
                IWM_ERR(iwm, "Key %d not used\n", key_index);
                return -EINVAL;
index 4fcd653bddc4a6fafee3da28188d76fe3c279173..89f34ad8d34acd1f01ba34644339bdffa228fdb1 100644 (file)
@@ -485,6 +485,7 @@ static int lbs_cfg_set_channel(struct wiphy *wiphy,
 static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
        struct cmd_header *resp)
 {
+       struct cfg80211_bss *bss;
        struct cmd_ds_802_11_scan_rsp *scanresp = (void *)resp;
        int bsssize;
        const u8 *pos;
@@ -632,12 +633,14 @@ static int lbs_ret_scan(struct lbs_private *priv, unsigned long dummy,
                                     LBS_SCAN_RSSI_TO_MBM(rssi)/100);
 
                        if (channel &&
-                           !(channel->flags & IEEE80211_CHAN_DISABLED))
-                               cfg80211_inform_bss(wiphy, channel,
+                           !(channel->flags & IEEE80211_CHAN_DISABLED)) {
+                               bss = cfg80211_inform_bss(wiphy, channel,
                                        bssid, le64_to_cpu(*(__le64 *)tsfdesc),
                                        capa, intvl, ie, ielen,
                                        LBS_SCAN_RSSI_TO_MBM(rssi),
                                        GFP_KERNEL);
+                               cfg80211_put_bss(bss);
+                       }
                } else
                        lbs_deb_scan("scan response: missing BSS channel IE\n");
 
@@ -1720,6 +1723,7 @@ static void lbs_join_post(struct lbs_private *priv,
                   2 + 2 +                      /* atim */
                   2 + 8];                      /* extended rates */
        u8 *fake = fake_ie;
+       struct cfg80211_bss *bss;
 
        lbs_deb_enter(LBS_DEB_CFG80211);
 
@@ -1763,14 +1767,15 @@ static void lbs_join_post(struct lbs_private *priv,
        *fake++ = 0x6c;
        lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
 
-       cfg80211_inform_bss(priv->wdev->wiphy,
-                           params->channel,
-                           bssid,
-                           0,
-                           capability,
-                           params->beacon_interval,
-                           fake_ie, fake - fake_ie,
-                           0, GFP_KERNEL);
+       bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                 params->channel,
+                                 bssid,
+                                 0,
+                                 capability,
+                                 params->beacon_interval,
+                                 fake_ie, fake - fake_ie,
+                                 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 
        memcpy(priv->wdev->ssid, params->ssid, params->ssid_len);
        priv->wdev->ssid_len = params->ssid_len;
index 523ad55a288501af3931b03ae56eef98756bbeb7..6cf6d6d25e217bd1718fe3cb98f40b5078ad60a6 100644 (file)
@@ -1748,6 +1748,8 @@ static int __init init_mac80211_hwsim(void)
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION;
 
+               hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS;
+
                /* ask mac80211 to reserve space for magic */
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
                hw->sta_data_size = sizeof(struct hwsim_sta_priv);
index 7aa9aa0ac958eba09e8661d05b16a512ccec49d2..681d3f2a4c2885b82b0e76256403bca2c060f782 100644 (file)
@@ -33,7 +33,7 @@
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
                                         struct mwifiex_rx_reorder_tbl
                                         *rx_reor_tbl_ptr, int start_win)
@@ -71,8 +71,6 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
 
        rx_reor_tbl_ptr->start_win = start_win;
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-
-       return 0;
 }
 
 /*
@@ -83,7 +81,7 @@ mwifiex_11n_dispatch_pkt_until_start_win(struct mwifiex_private *priv,
  * Since the buffer is linear, the function uses rotation to simulate
  * circular buffer.
  */
-static int
+static void
 mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
                              struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr)
 {
@@ -119,7 +117,6 @@ mwifiex_11n_scan_and_dispatch(struct mwifiex_private *priv,
        rx_reor_tbl_ptr->start_win = (rx_reor_tbl_ptr->start_win + i)
                &(MAX_TID_VALUE - 1);
        spin_unlock_irqrestore(&priv->rx_pkt_lock, flags);
-       return 0;
 }
 
 /*
@@ -405,7 +402,7 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                                u8 *ta, u8 pkt_type, void *payload)
 {
        struct mwifiex_rx_reorder_tbl *rx_reor_tbl_ptr;
-       int start_win, end_win, win_size, ret;
+       int start_win, end_win, win_size;
        u16 pkt_index;
 
        rx_reor_tbl_ptr =
@@ -452,11 +449,8 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
                        start_win = (end_win - win_size) + 1;
                else
                        start_win = (MAX_TID_VALUE - (win_size - seq_num)) + 1;
-               ret = mwifiex_11n_dispatch_pkt_until_start_win(priv,
+               mwifiex_11n_dispatch_pkt_until_start_win(priv,
                                                rx_reor_tbl_ptr, start_win);
-
-               if (ret)
-                       return ret;
        }
 
        if (pkt_type != PKT_TYPE_BAR) {
@@ -475,9 +469,9 @@ int mwifiex_11n_rx_reorder_pkt(struct mwifiex_private *priv,
         * Dispatch all packets sequentially from start_win until a
         * hole is found and adjust the start_win appropriately
         */
-       ret = mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
+       mwifiex_11n_scan_and_dispatch(priv, rx_reor_tbl_ptr);
 
-       return ret;
+       return 0;
 }
 
 /*
index 462c71067bfb83d6d445946e6137991dbc3ab617..e9ab9a3fbe9c2cb70ac2da2c0dbf3e1226c21bad 100644 (file)
@@ -780,6 +780,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
 {
        struct ieee80211_channel *chan;
        struct mwifiex_bss_info bss_info;
+       struct cfg80211_bss *bss;
        int ie_len;
        u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
        enum ieee80211_band band;
@@ -800,9 +801,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                        ieee80211_channel_to_frequency(bss_info.bss_chan,
                                                       band));
 
-       cfg80211_inform_bss(priv->wdev->wiphy, chan,
+       bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
                bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
                0, ie_buf, ie_len, 0, GFP_KERNEL);
+       cfg80211_put_bss(bss);
        memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
 
        return 0;
index 0cc5d73cb0c1e99730b4ebcbd882bc765ac187f0..35cb29cbd96e5d083b438fa62c22e85493dec45d 100644 (file)
@@ -673,7 +673,7 @@ struct host_cmd_ds_802_11_ad_hoc_start {
        union ieee_types_phy_param_set phy_param_set;
        u16 reserved1;
        __le16 cap_info_bitmap;
-       u8 DataRate[HOSTCMD_SUPPORTED_RATES];
+       u8 data_rate[HOSTCMD_SUPPORTED_RATES];
 } __packed;
 
 struct host_cmd_ds_802_11_ad_hoc_result {
index d792b3fb7c16ec407984288772eaa1e17a21c6b6..26940455255ba4637fdd31ec19a3407640f71e87 100644 (file)
@@ -187,8 +187,6 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        struct mwifiex_opt_sleep_confirm *sleep_cfm_buf = NULL;
 
        skb_put(adapter->sleep_cfm, sizeof(struct mwifiex_opt_sleep_confirm));
-       sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
-                                               (adapter->sleep_cfm->data);
 
        adapter->cmd_sent = false;
 
@@ -254,6 +252,8 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
        mwifiex_wmm_init(adapter);
 
        if (adapter->sleep_cfm) {
+               sleep_cfm_buf = (struct mwifiex_opt_sleep_confirm *)
+                                               adapter->sleep_cfm->data;
                memset(sleep_cfm_buf, 0, adapter->sleep_cfm->len);
                sleep_cfm_buf->command =
                                cpu_to_le16(HostCmd_CMD_802_11_PS_MODE_ENH);
index 62b4c2938608d67873d66afb8be9e288247820b9..1c4981367e508fbaa45fd6e5648452e75da5ee7c 100644 (file)
@@ -724,8 +724,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        u32 cmd_append_size = 0;
        u32 i;
        u16 tmp_cap;
-       uint16_t ht_cap_info;
        struct mwifiex_ie_types_chan_list_param_set *chan_tlv;
+       u8 radio_type;
 
        struct mwifiex_ie_types_htcap *ht_cap;
        struct mwifiex_ie_types_htinfo *ht_info;
@@ -837,8 +837,8 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_ACCEPT_ALL;
        }
 
-       memset(adhoc_start->DataRate, 0, sizeof(adhoc_start->DataRate));
-       mwifiex_get_active_data_rates(priv, adhoc_start->DataRate);
+       memset(adhoc_start->data_rate, 0, sizeof(adhoc_start->data_rate));
+       mwifiex_get_active_data_rates(priv, adhoc_start->data_rate);
        if ((adapter->adhoc_start_band & BAND_G) &&
            (priv->curr_pkt_filter & HostCmd_ACT_MAC_ADHOC_G_PROTECTION_ON)) {
                if (mwifiex_send_cmd_async(priv, HostCmd_CMD_MAC_CONTROL,
@@ -850,20 +850,19 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
                }
        }
        /* Find the last non zero */
-       for (i = 0; i < sizeof(adhoc_start->DataRate) &&
-                       adhoc_start->DataRate[i];
-                       i++)
-                       ;
+       for (i = 0; i < sizeof(adhoc_start->data_rate); i++)
+               if (!adhoc_start->data_rate[i])
+                       break;
 
        priv->curr_bss_params.num_of_rates = i;
 
        /* Copy the ad-hoc creating rates into Current BSS rate structure */
        memcpy(&priv->curr_bss_params.data_rates,
-              &adhoc_start->DataRate, priv->curr_bss_params.num_of_rates);
+              &adhoc_start->data_rate, priv->curr_bss_params.num_of_rates);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: rates=%02x %02x %02x %02x\n",
-              adhoc_start->DataRate[0], adhoc_start->DataRate[1],
-              adhoc_start->DataRate[2], adhoc_start->DataRate[3]);
+              adhoc_start->data_rate[0], adhoc_start->data_rate[1],
+              adhoc_start->data_rate[2], adhoc_start->data_rate[3]);
 
        dev_dbg(adapter->dev, "info: ADHOC_S_CMD: AD-HOC Start command is ready\n");
 
@@ -914,55 +913,40 @@ mwifiex_cmd_802_11_ad_hoc_start(struct mwifiex_private *priv,
        }
 
        if (adapter->adhoc_11n_enabled) {
-               {
-                       ht_cap = (struct mwifiex_ie_types_htcap *) pos;
-                       memset(ht_cap, 0,
-                              sizeof(struct mwifiex_ie_types_htcap));
-                       ht_cap->header.type =
-                               cpu_to_le16(WLAN_EID_HT_CAPABILITY);
-                       ht_cap->header.len =
-                              cpu_to_le16(sizeof(struct ieee80211_ht_cap));
-                       ht_cap_info = le16_to_cpu(ht_cap->ht_cap.cap_info);
-
-                       ht_cap_info |= IEEE80211_HT_CAP_SGI_20;
-                       if (adapter->chan_offset) {
-                               ht_cap_info |= IEEE80211_HT_CAP_SGI_40;
-                               ht_cap_info |= IEEE80211_HT_CAP_DSSSCCK40;
-                               ht_cap_info |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-                               SETHT_MCS32(ht_cap->ht_cap.mcs.rx_mask);
-                       }
+               /* Fill HT CAPABILITY */
+               ht_cap = (struct mwifiex_ie_types_htcap *) pos;
+               memset(ht_cap, 0, sizeof(struct mwifiex_ie_types_htcap));
+               ht_cap->header.type = cpu_to_le16(WLAN_EID_HT_CAPABILITY);
+               ht_cap->header.len =
+                      cpu_to_le16(sizeof(struct ieee80211_ht_cap));
+               radio_type = mwifiex_band_to_radio_type(
+                                       priv->adapter->config_bands);
+               mwifiex_fill_cap_info(priv, radio_type, ht_cap);
+
+               pos += sizeof(struct mwifiex_ie_types_htcap);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htcap);
 
-                       ht_cap->ht_cap.ampdu_params_info
-                                       = IEEE80211_HT_MAX_AMPDU_64K;
-                       ht_cap->ht_cap.mcs.rx_mask[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htcap);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htcap);
-               }
-               {
-                       ht_info = (struct mwifiex_ie_types_htinfo *) pos;
-                       memset(ht_info, 0,
-                              sizeof(struct mwifiex_ie_types_htinfo));
-                       ht_info->header.type =
-                               cpu_to_le16(WLAN_EID_HT_INFORMATION);
-                       ht_info->header.len =
-                               cpu_to_le16(sizeof(struct ieee80211_ht_info));
-                       ht_info->ht_info.control_chan =
-                               (u8) priv->curr_bss_params.bss_descriptor.
-                               channel;
-                       if (adapter->chan_offset) {
-                               ht_info->ht_info.ht_param =
-                                       adapter->chan_offset;
-                               ht_info->ht_info.ht_param |=
+               /* Fill HT INFORMATION */
+               ht_info = (struct mwifiex_ie_types_htinfo *) pos;
+               memset(ht_info, 0, sizeof(struct mwifiex_ie_types_htinfo));
+               ht_info->header.type = cpu_to_le16(WLAN_EID_HT_INFORMATION);
+               ht_info->header.len =
+                       cpu_to_le16(sizeof(struct ieee80211_ht_info));
+
+               ht_info->ht_info.control_chan =
+                       (u8) priv->curr_bss_params.bss_descriptor.channel;
+               if (adapter->chan_offset) {
+                       ht_info->ht_info.ht_param = adapter->chan_offset;
+                       ht_info->ht_info.ht_param |=
                                        IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
-                       }
-                       ht_info->ht_info.operation_mode =
-                            cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
-                       ht_info->ht_info.basic_set[0] = 0xff;
-                       pos += sizeof(struct mwifiex_ie_types_htinfo);
-                       cmd_append_size +=
-                               sizeof(struct mwifiex_ie_types_htinfo);
                }
+               ht_info->ht_info.operation_mode =
+                    cpu_to_le16(IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT);
+               ht_info->ht_info.basic_set[0] = 0xff;
+               pos += sizeof(struct mwifiex_ie_types_htinfo);
+               cmd_append_size +=
+                       sizeof(struct mwifiex_ie_types_htinfo);
        }
 
        cmd->size = cpu_to_le16((u16)
index d34acf082d3ae03fdc0b35b58f19a924415915a0..a2f32008f9a80810355c8c4cc145ada8199d9516 100644 (file)
@@ -386,7 +386,6 @@ static int mwifiex_pcie_create_txbd_ring(struct mwifiex_adapter *adapter)
        card->txbd_ring_vbase = kzalloc(card->txbd_ring_size, GFP_KERNEL);
        if (!card->txbd_ring_vbase) {
                dev_err(adapter->dev, "Unable to allocate buffer for txbd ring.\n");
-               kfree(card->txbd_ring_vbase);
                return -1;
        }
        card->txbd_ring_pbase = virt_to_phys(card->txbd_ring_vbase);
@@ -1229,9 +1228,12 @@ static int mwifiex_pcie_event_complete(struct mwifiex_adapter *adapter,
        if (!skb)
                return 0;
 
-       if (rdptr >= MWIFIEX_MAX_EVT_BD)
+       if (rdptr >= MWIFIEX_MAX_EVT_BD) {
                dev_err(adapter->dev, "event_complete: Invalid rdptr 0x%x\n",
                                        rdptr);
+               ret = -EINVAL;
+               goto done;
+       }
 
        /* Read the event ring write pointer set by firmware */
        if (mwifiex_read_reg(adapter, REG_EVTBD_WRPTR, &wrptr)) {
@@ -1672,9 +1674,8 @@ static int mwifiex_pcie_host_to_card(struct mwifiex_adapter *adapter, u8 type,
                                     struct sk_buff *skb,
                                     struct mwifiex_tx_param *tx_param)
 {
-       if (!adapter || !skb) {
-               dev_err(adapter->dev, "Invalid parameter in %s <%p, %p>\n",
-                               __func__, adapter, skb);
+       if (!skb) {
+               dev_err(adapter->dev, "Passed NULL skb to %s\n", __func__);
                return -1;
        }
 
index dae8dbb24a03e83352742b20c3320c9819019889..8a18bcc23b26106fd993f33f3d057fa6e4eefe6b 100644 (file)
@@ -1469,7 +1469,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
                               s32 rssi, const u8 *ie_buf, size_t ie_len,
                               u16 beacon_period, u16 cap_info_bitmap, u8 band)
 {
-       struct mwifiex_bssdescriptor *bss_desc = NULL;
+       struct mwifiex_bssdescriptor *bss_desc;
        int ret;
        unsigned long flags;
        u8 *beacon_ie;
@@ -1484,6 +1484,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
 
        beacon_ie = kmemdup(ie_buf, ie_len, GFP_KERNEL);
        if (!beacon_ie) {
+               kfree(bss_desc);
                dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
                return -ENOMEM;
        }
@@ -1534,11 +1535,6 @@ done:
        return 0;
 }
 
-static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
-{
-       kfree(bss->priv);
-}
-
 /*
  * This function handles the command response of scan.
  *
@@ -1764,7 +1760,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                              cap_info_bitmap, beacon_period,
                                              ie_buf, ie_len, rssi, GFP_KERNEL);
                                *(u8 *)bss->priv = band;
-                               bss->free_priv = mwifiex_free_bss_priv;
+                               cfg80211_put_bss(bss);
 
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
index 283171bbcedf70a1b9cec51c33b3e7c7874196c4..ffaf3f3a57df047beea84986504a071b4b05e3ca 100644 (file)
@@ -1630,14 +1630,14 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        card->mpa_tx.pkt_cnt = 0;
        card->mpa_tx.start_port = 0;
 
-       card->mpa_tx.enabled = 0;
+       card->mpa_tx.enabled = 1;
        card->mpa_tx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        card->mpa_rx.buf_len = 0;
        card->mpa_rx.pkt_cnt = 0;
        card->mpa_rx.start_port = 0;
 
-       card->mpa_rx.enabled = 0;
+       card->mpa_rx.enabled = 1;
        card->mpa_rx.pkt_aggr_limit = SDIO_MP_AGGR_DEF_PKT_LIMIT;
 
        /* Allocate buffers for SDIO MP-A */
index 27430512f7cd038a91d42d4848609991f297a72f..5e1ef7e5da4f3f5b2679c47d012588e642be093f 100644 (file)
@@ -126,6 +126,9 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
        u16 rx_pkt_type;
        struct mwifiex_private *priv = adapter->priv[rx_info->bss_index];
 
+       if (!priv)
+               return -1;
+
        local_rx_pd = (struct rxpd *) (skb->data);
        rx_pkt_type = local_rx_pd->rx_pkt_type;
 
@@ -189,12 +192,11 @@ int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *adapter,
                                             (u8) local_rx_pd->rx_pkt_type,
                                             skb);
 
-       if (ret || (rx_pkt_type == PKT_TYPE_BAR)) {
-               if (priv && (ret == -1))
-                       priv->stats.rx_dropped++;
-
+       if (ret || (rx_pkt_type == PKT_TYPE_BAR))
                dev_kfree_skb_any(skb);
-       }
+
+       if (ret)
+               priv->stats.rx_dropped++;
 
        return ret;
 }
index e99ca1c1e0d8053689d7cbcabb5d07733dda03b1..96e39edfec770c58363237e9fa2955d4f16e567e 100644 (file)
@@ -76,6 +76,7 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        u8 *ie;
        u8 ie_buf[46];
        u64 timestamp;
@@ -121,9 +122,10 @@ static void orinoco_add_hostscan_result(struct orinoco_private *priv,
        beacon_interval = le16_to_cpu(bss->a.beacon_interv);
        signal = SIGNAL_TO_MBM(le16_to_cpu(bss->a.level));
 
-       cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
-                           capability, beacon_interval, ie_buf, ie_len,
-                           signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->a.bssid, timestamp,
+                                  capability, beacon_interval, ie_buf, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_extscan_result(struct orinoco_private *priv,
@@ -132,6 +134,7 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 {
        struct wiphy *wiphy = priv_to_wiphy(priv);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *cbss;
        const u8 *ie;
        u64 timestamp;
        s32 signal;
@@ -152,9 +155,10 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
        ie = bss->data;
        signal = SIGNAL_TO_MBM(bss->level);
 
-       cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
-                           capability, beacon_interval, ie, ie_len,
-                           signal, GFP_KERNEL);
+       cbss = cfg80211_inform_bss(wiphy, channel, bss->bssid, timestamp,
+                                  capability, beacon_interval, ie, ie_len,
+                                  signal, GFP_KERNEL);
+       cfg80211_put_bss(cbss);
 }
 
 void orinoco_add_hostscan_results(struct orinoco_private *priv,
index 0c13840a7de57c0d675e026267a3ca3b95edc9fa..620e3c0e88e039152b39ddbe3f2173be46b6aa1e 100644 (file)
@@ -414,6 +414,7 @@ struct ndis_80211_pmkid {
 #define RNDIS_WLAN_ALG_TKIP    (1<<1)
 #define RNDIS_WLAN_ALG_CCMP    (1<<2)
 
+#define RNDIS_WLAN_NUM_KEYS            4
 #define RNDIS_WLAN_KEY_MGMT_NONE       0
 #define RNDIS_WLAN_KEY_MGMT_802_1X     (1<<0)
 #define RNDIS_WLAN_KEY_MGMT_PSK                (1<<1)
@@ -516,7 +517,7 @@ struct rndis_wlan_private {
 
        /* encryption stuff */
        int  encr_tx_key_index;
-       struct rndis_wlan_encr_key encr_keys[4];
+       struct rndis_wlan_encr_key encr_keys[RNDIS_WLAN_NUM_KEYS];
        int  wpa_version;
 
        u8 command_buffer[COMMAND_BUFFER_SIZE];
@@ -1535,6 +1536,9 @@ static int remove_key(struct usbnet *usbdev, int index, const u8 *bssid)
        bool is_wpa;
        int ret;
 
+       if (index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        if (priv->encr_keys[index].len == 0)
                return 0;
 
@@ -1972,11 +1976,12 @@ static int rndis_scan(struct wiphy *wiphy, struct net_device *dev,
        return ret;
 }
 
-static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
-                                       struct ndis_80211_bssid_ex *bssid)
+static bool rndis_bss_info_update(struct usbnet *usbdev,
+                                 struct ndis_80211_bssid_ex *bssid)
 {
        struct rndis_wlan_private *priv = get_rndis_wlan_priv(usbdev);
        struct ieee80211_channel *channel;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2015,9 +2020,12 @@ static struct cfg80211_bss *rndis_bss_info_update(struct usbnet *usbdev,
        capability = le16_to_cpu(fixed->capabilities);
        beacon_interval = le16_to_cpu(fixed->beacon_interval);
 
-       return cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid->mac,
                timestamp, capability, beacon_interval, ie, ie_len, signal,
                GFP_KERNEL);
+       cfg80211_put_bss(bss);
+
+       return (bss != NULL);
 }
 
 static struct ndis_80211_bssid_ex *next_bssid_list_item(
@@ -2451,6 +2459,9 @@ static int rndis_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
 
        netdev_dbg(usbdev->net, "%s(%i)\n", __func__, key_index);
 
+       if (key_index >= RNDIS_WLAN_NUM_KEYS)
+               return -ENOENT;
+
        priv->encr_tx_key_index = key_index;
 
        if (is_wpa_key(priv, key_index))
@@ -2641,6 +2652,7 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
        struct ieee80211_channel *channel;
        struct ndis_80211_conf config;
        struct ndis_80211_ssid ssid;
+       struct cfg80211_bss *bss;
        s32 signal;
        u64 timestamp;
        u16 capability;
@@ -2714,9 +2726,10 @@ static void rndis_wlan_craft_connected_bss(struct usbnet *usbdev, u8 *bssid,
                bssid, (u32)timestamp, capability, beacon_interval, ie_len,
                ssid.essid, signal);
 
-       cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
+       bss = cfg80211_inform_bss(priv->wdev.wiphy, channel, bssid,
                timestamp, capability, beacon_interval, ie_buf, ie_len,
                signal, GFP_KERNEL);
+       cfg80211_put_bss(bss);
 }
 
 /*
index c244f2f1b83fb6658569cd545ac37ec3a2772a18..94a3e17061582e7afacab5cb590590bd69fbb8f2 100644 (file)
@@ -275,6 +275,8 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8191, rtl92cu_hal_cfg)},
 
        /****** 8188CU ********/
+       /* RTL8188CTV */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x018a, rtl92cu_hal_cfg)},
        /* 8188CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8170, rtl92cu_hal_cfg)},
        /* 8188cu 1*1 dongle */
@@ -291,14 +293,14 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817e, rtl92cu_hal_cfg)},
        /* 8188RU in Alfa AWUS036NHR */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817f, rtl92cu_hal_cfg)},
+       /* RTL8188CUS-VL */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x818a, rtl92cu_hal_cfg)},
        /* 8188 Combo for BC4 */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8754, rtl92cu_hal_cfg)},
 
        /****** 8192CU ********/
-       /* 8191cu 1*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8177, rtl92cu_hal_cfg)},
        /* 8192cu 2*2 */
-       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817b, rtl92cu_hal_cfg)},
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x8178, rtl92cu_hal_cfg)},
        /* 8192CE-VAU USB minCard */
        {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x817c, rtl92cu_hal_cfg)},
 
@@ -309,13 +311,17 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x07b8, 0x8188, rtl92cu_hal_cfg)}, /*Abocom - Abocom*/
        {RTL_USB_DEVICE(0x07b8, 0x8189, rtl92cu_hal_cfg)}, /*Funai - Abocom*/
        {RTL_USB_DEVICE(0x0846, 0x9041, rtl92cu_hal_cfg)}, /*NetGear WNA1000M*/
-       {RTL_USB_DEVICE(0x0Df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0052, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x005c, rtl92cu_hal_cfg)}, /*Sitecom - Edimax*/
        {RTL_USB_DEVICE(0x0eb0, 0x9071, rtl92cu_hal_cfg)}, /*NO Brand - Etop*/
        /* HP - Lite-On ,8188CUS Slim Combo */
        {RTL_USB_DEVICE(0x103c, 0x1629, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x13d3, 0x3357, rtl92cu_hal_cfg)}, /* AzureWave */
        {RTL_USB_DEVICE(0x2001, 0x3308, rtl92cu_hal_cfg)}, /*D-Link - Alpha*/
+       {RTL_USB_DEVICE(0x2019, 0x4902, rtl92cu_hal_cfg)}, /*Planex - Etop*/
        {RTL_USB_DEVICE(0x2019, 0xab2a, rtl92cu_hal_cfg)}, /*Planex - Abocom*/
+       /*SW-WF02-AD15 -Abocom*/
+       {RTL_USB_DEVICE(0x2019, 0xab2e, rtl92cu_hal_cfg)},
        {RTL_USB_DEVICE(0x2019, 0xed17, rtl92cu_hal_cfg)}, /*PCI - Edimax*/
        {RTL_USB_DEVICE(0x20f4, 0x648b, rtl92cu_hal_cfg)}, /*TRENDnet - Cameo*/
        {RTL_USB_DEVICE(0x7392, 0x7811, rtl92cu_hal_cfg)}, /*Edimax - Edimax*/
@@ -326,14 +332,36 @@ static struct usb_device_id rtl8192c_usb_ids[] = {
        {RTL_USB_DEVICE(0x4855, 0x0091, rtl92cu_hal_cfg)}, /* NetweeN-Feixun */
        {RTL_USB_DEVICE(0x9846, 0x9041, rtl92cu_hal_cfg)}, /* Netgear Cameo */
 
+       /****** 8188 RU ********/
+       /* Netcore */
+       {RTL_USB_DEVICE(USB_VENDER_ID_REALTEK, 0x317f, rtl92cu_hal_cfg)},
+
+       /****** 8188CUS Slim Solo********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff7, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaff9, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffa, rtl92cu_hal_cfg)}, /*Xavi*/
+
+       /****** 8188CUS Slim Combo ********/
+       {RTL_USB_DEVICE(0x04f2, 0xaff8, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffb, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x04f2, 0xaffc, rtl92cu_hal_cfg)}, /*Xavi*/
+       {RTL_USB_DEVICE(0x2019, 0x1201, rtl92cu_hal_cfg)}, /*Planex-Vencer*/
+
        /****** 8192CU ********/
+       {RTL_USB_DEVICE(0x050d, 0x2102, rtl92cu_hal_cfg)}, /*Belcom-Sercomm*/
+       {RTL_USB_DEVICE(0x050d, 0x2103, rtl92cu_hal_cfg)}, /*Belcom-Edimax*/
        {RTL_USB_DEVICE(0x0586, 0x341f, rtl92cu_hal_cfg)}, /*Zyxel -Abocom*/
        {RTL_USB_DEVICE(0x07aa, 0x0056, rtl92cu_hal_cfg)}, /*ATKK-Gemtek*/
        {RTL_USB_DEVICE(0x07b8, 0x8178, rtl92cu_hal_cfg)}, /*Funai -Abocom*/
+       {RTL_USB_DEVICE(0x0846, 0x9021, rtl92cu_hal_cfg)}, /*Netgear-Sercomm*/
+       {RTL_USB_DEVICE(0x0b05, 0x17ab, rtl92cu_hal_cfg)}, /*ASUS-Edimax*/
+       {RTL_USB_DEVICE(0x0df6, 0x0061, rtl92cu_hal_cfg)}, /*Sitecom-Edimax*/
+       {RTL_USB_DEVICE(0x0e66, 0x0019, rtl92cu_hal_cfg)}, /*Hawking-Edimax*/
        {RTL_USB_DEVICE(0x2001, 0x3307, rtl92cu_hal_cfg)}, /*D-Link-Cameo*/
        {RTL_USB_DEVICE(0x2001, 0x3309, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2001, 0x330a, rtl92cu_hal_cfg)}, /*D-Link-Alpha*/
        {RTL_USB_DEVICE(0x2019, 0xab2b, rtl92cu_hal_cfg)}, /*Planex -Abocom*/
+       {RTL_USB_DEVICE(0x20f4, 0x624d, rtl92cu_hal_cfg)}, /*TRENDNet*/
        {RTL_USB_DEVICE(0x7392, 0x7822, rtl92cu_hal_cfg)}, /*Edimax -Edimax*/
        {}
 };
index 128ccb79318c86c7e0a8bc4a65c61389b58e959f..fc29c671cf3b34db3fc695fbd70209720a3c52e8 100644 (file)
@@ -559,7 +559,7 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                                                break;
                                        }
                                /* Fail if SSID isn't present in the filters */
-                               if (j == req->n_ssids) {
+                               if (j == cmd->n_ssids) {
                                        ret = -EINVAL;
                                        goto out_free;
                                }
index 9a6115e7cf631583f808d6807619c0207c0a5a0c..49c1704173e757a5e75db1dca27fbf4081aa2dd7 100644 (file)
@@ -64,4 +64,7 @@
 #define SO_DOMAIN              39
 
 #define SO_RXQ_OVFL             40
+
+#define SO_WIFI_STATUS         41
+#define SCM_WIFI_STATUS        SO_WIFI_STATUS
 #endif /* __ASM_GENERIC_SOCKET_H */
index 034072cea853eafc7f4eb5bed66649ee129da448..c9f522bd17e4df214e297eafa73cae7003f1b763 100644 (file)
@@ -17,7 +17,8 @@ struct sock_extended_err {
 #define SO_EE_ORIGIN_LOCAL     1
 #define SO_EE_ORIGIN_ICMP      2
 #define SO_EE_ORIGIN_ICMP6     3
-#define SO_EE_ORIGIN_TIMESTAMPING 4
+#define SO_EE_ORIGIN_TXSTATUS  4
+#define SO_EE_ORIGIN_TIMESTAMPING SO_EE_ORIGIN_TXSTATUS
 
 #define SO_EE_OFFENDER(ee)     ((struct sockaddr*)((ee)+1))
 
index 48363c3c40f8f6de0e1ebb062a35eef498f6077a..66cedf6eb5c2421b3fda7339df9290dbb1e3492e 100644 (file)
 #define IEEE80211_QOS_CTL_ACK_POLICY_NOACK     0x0020
 #define IEEE80211_QOS_CTL_ACK_POLICY_NO_EXPL   0x0040
 #define IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK  0x0060
+#define IEEE80211_QOS_CTL_ACK_POLICY_MASK      0x0060
 /* A-MSDU 802.11n */
 #define IEEE80211_QOS_CTL_A_MSDU_PRESENT       0x0080
 /* Mesh Control 802.11s */
@@ -770,6 +771,9 @@ struct ieee80211_mgmt {
        } u;
 } __attribute__ ((packed));
 
+/* Supported Rates value encodings in 802.11n-2009 7.3.2.2 */
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
 /* mgmt header + 1 byte category code */
 #define IEEE80211_MIN_ACTION_SIZE offsetof(struct ieee80211_mgmt, u.action.u)
 
@@ -1552,6 +1556,8 @@ enum ieee80211_sa_query_action {
 #define WLAN_CIPHER_SUITE_WEP104       0x000FAC05
 #define WLAN_CIPHER_SUITE_AES_CMAC     0x000FAC06
 
+#define WLAN_CIPHER_SUITE_SMS4         0x00147201
+
 /* AKM suite selectors */
 #define WLAN_AKM_SUITE_8021X           0x000FAC01
 #define WLAN_AKM_SUITE_PSK             0x000FAC02
index 8049bf77d799384bee4870c8e1e80bfe29b343ab..f9261c253735b362f22769f38aa4519f984118c3 100644 (file)
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *     (or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *     implement sending deauth to stations that send unexpected class 3
+ *     frames. Also used as the event sent by the kernel when such a frame
+ *     is received.
+ *     For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *     other attributes like the interface index are present.
+ *     If used as the command it must have an interface index and you can
+ *     only unsubscribe from the event by closing the socket. Subscription
+ *     is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *     associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *     and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *     to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *     by sending a null data frame to it and reporting when the frame is
+ *     acknowleged. This is used to allow timing out inactive clients. Uses
+ *     %NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *     direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *     up the event with the request. The event includes the same data and
+ *     has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *     other BSSes when any interfaces are in AP mode. This helps implement
+ *     OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *     messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -638,6 +667,14 @@ enum nl80211_commands {
        NL80211_CMD_TDLS_OPER,
        NL80211_CMD_TDLS_MGMT,
 
+       NL80211_CMD_UNEXPECTED_FRAME,
+
+       NL80211_CMD_PROBE_CLIENT,
+
+       NL80211_CMD_REGISTER_BEACONS,
+
+       NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -658,6 +695,8 @@ enum nl80211_commands {
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
 /* source-level API compatibility */
 #define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
 #define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
@@ -1109,6 +1148,28 @@ enum nl80211_commands {
  *     %NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver to perform a TDLS operation.
  *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *     that have AP support to indicate that they have the AP SME integrated
+ *     with support for the features listed in this attribute, see
+ *     &enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *     the driver to not wait for an acknowledgement. Note that due to this,
+ *     it will also not give a status callback nor return a cookie. This is
+ *     mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *     &enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *     requests while operating in AP-mode.
+ *     This attribute holds a bitmap of the supported protocols for
+ *     offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *     probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *     to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1337,6 +1398,16 @@ enum nl80211_attrs {
        NL80211_ATTR_TDLS_SUPPORT,
        NL80211_ATTR_TDLS_EXTERNAL_SETUP,
 
+       NL80211_ATTR_DEVICE_AP_SME,
+
+       NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+       NL80211_ATTR_FEATURE_FLAGS,
+
+       NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+       NL80211_ATTR_PROBE_RESP,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1371,6 +1442,7 @@ enum nl80211_attrs {
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -2650,4 +2722,43 @@ enum nl80211_tdls_operation {
        NL80211_TDLS_DISABLE_LINK,
 };
 
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *     TX status to the socket error queue when requested with the
+ *     socket option.
+ */
+enum nl80211_feature_flags {
+       NL80211_FEATURE_SK_TX_STATUS    = 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *     protocols for probe-response offloading by the driver/FW.
+ *     To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *     Each enum value represents a bit in the bitmap of supported
+ *     protocols. Typically a subset of probe-requests belonging to a
+ *     supported protocol will be excluded from offload and uploaded
+ *     to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =        1<<0,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =       1<<1,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =        1<<2,
+       NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =     1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
index b93117389cfe6f7fc0ffc6cc6ee36d3fcc4b06ea..09b7ea566d666506fb37af4bb5623134fe09987b 100644 (file)
@@ -218,6 +218,9 @@ enum {
 
        /* device driver supports TX zero-copy buffers */
        SKBTX_DEV_ZEROCOPY = 1 << 4,
+
+       /* generate wifi status information (where possible) */
+       SKBTX_WIFI_STATUS = 1 << 5,
 };
 
 /*
@@ -352,6 +355,8 @@ typedef unsigned char *sk_buff_data_t;
  *     @ooo_okay: allow the mapping of a socket to a queue to be changed
  *     @l4_rxhash: indicate rxhash is a canonical 4-tuple hash over transport
  *             ports.
+ *     @wifi_acked_valid: wifi_acked was set
+ *     @wifi_acked: whether frame was acked on wifi or not
  *     @dma_cookie: a cookie to one of several possible DMA operations
  *             done by skb DMA functions
  *     @secmark: security marking
@@ -445,10 +450,11 @@ struct sk_buff {
 #endif
        __u8                    ooo_okay:1;
        __u8                    l4_rxhash:1;
+       __u8                    wifi_acked_valid:1;
+       __u8                    wifi_acked:1;
+       /* 10/12 bit hole (depending on ndisc_nodetype presence) */
        kmemcheck_bitfield_end(flags2);
 
-       /* 0/13 bit hole */
-
 #ifdef CONFIG_NET_DMA
        dma_cookie_t            dma_cookie;
 #endif
@@ -2265,6 +2271,15 @@ static inline void skb_tx_timestamp(struct sk_buff *skb)
        sw_tx_timestamp(skb);
 }
 
+/**
+ * skb_complete_wifi_ack - deliver skb with wifi status
+ *
+ * @skb: the original outgoing packet
+ * @acked: ack status
+ *
+ */
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked);
+
 extern __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len);
 extern __sum16 __skb_checksum_complete(struct sk_buff *skb);
 
index e86af08293a8217153b48a98a4802015376185db..835f3b229b8450d53f2ec434078dd9a3c0e8be52 100644 (file)
@@ -77,6 +77,33 @@ struct bt_power {
 #define BT_POWER_FORCE_ACTIVE_OFF 0
 #define BT_POWER_FORCE_ACTIVE_ON  1
 
+#define BT_CHANNEL_POLICY      10
+
+/* BR/EDR only (default policy)
+ *   AMP controllers cannot be used.
+ *   Channel move requests from the remote device are denied.
+ *   If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_BREDR_ONLY           0
+
+/* BR/EDR Preferred
+ *   Allow use of AMP controllers.
+ *   If the L2CAP channel is currently on AMP, move it to BR/EDR.
+ *   Channel move requests from the remote device are allowed.
+ */
+#define BT_CHANNEL_POLICY_BREDR_PREFERRED      1
+
+/* AMP Preferred
+ *   Allow use of AMP controllers
+ *   If the L2CAP channel is currently on BR/EDR and AMP controller
+ *     resources are available, initiate a channel move to AMP.
+ *   Channel move requests from the remote device are allowed.
+ *   If the L2CAP socket has not been connected yet, try to create
+ *     and configure the channel directly on an AMP controller rather
+ *     than BR/EDR.
+ */
+#define BT_CHANNEL_POLICY_AMP_PREFERRED                2
+
 __printf(2, 3)
 int bt_printk(const char *level, const char *fmt, ...);
 
@@ -158,7 +185,7 @@ struct bt_skb_cb {
        __u8 pkt_type;
        __u8 incoming;
        __u16 expect;
-       __u8 tx_seq;
+       __u16 tx_seq;
        __u8 retries;
        __u8 sar;
        unsigned short channel;
index aaf79af7243262592607924aa1e4dd609da7d2aa..139ce2aa6eee700ba396343a268eda4962daa142 100644 (file)
@@ -264,6 +264,13 @@ enum {
 #define HCI_LK_SMP_IRK                 0x82
 #define HCI_LK_SMP_CSRK                        0x83
 
+/* ---- HCI Error Codes ---- */
+#define HCI_ERROR_AUTH_FAILURE         0x05
+#define HCI_ERROR_REJ_BAD_ADDR         0x0f
+#define HCI_ERROR_REMOTE_USER_TERM     0x13
+#define HCI_ERROR_LOCAL_HOST_TERM      0x16
+#define HCI_ERROR_PAIRING_NOT_ALLOWED  0x18
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
 
@@ -726,6 +733,21 @@ struct hci_cp_write_page_scan_activity {
        #define PAGE_SCAN_TYPE_STANDARD         0x00
        #define PAGE_SCAN_TYPE_INTERLACED       0x01
 
+#define HCI_OP_READ_LOCAL_AMP_INFO     0x1409
+struct hci_rp_read_local_amp_info {
+       __u8     status;
+       __u8     amp_status;
+       __le32   total_bw;
+       __le32   max_bw;
+       __le32   min_latency;
+       __le32   max_pdu;
+       __u8     amp_type;
+       __le16   pal_cap;
+       __le16   max_assoc_size;
+       __le32   max_flush_to;
+       __le32   be_flush_to;
+} __packed;
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
index 3779ea3622576e9746dc72ebac57780c0f377e11..f333e7682607b1dbcc86871e3d0fd6c93a94c6cf 100644 (file)
@@ -32,6 +32,9 @@
 #define HCI_PROTO_L2CAP        0
 #define HCI_PROTO_SCO  1
 
+/* HCI priority */
+#define HCI_PRIO_MAX   7
+
 /* HCI Core structures */
 struct inquiry_data {
        bdaddr_t        bdaddr;
@@ -64,6 +67,12 @@ struct hci_conn_hash {
        unsigned int     le_num;
 };
 
+struct hci_chan_hash {
+       struct list_head list;
+       spinlock_t       lock;
+       unsigned int     num;
+};
+
 struct bdaddr_list {
        struct list_head list;
        bdaddr_t bdaddr;
@@ -150,6 +159,17 @@ struct hci_dev {
        __u16           sniff_min_interval;
        __u16           sniff_max_interval;
 
+       __u8            amp_status;
+       __u32           amp_total_bw;
+       __u32           amp_max_bw;
+       __u32           amp_min_latency;
+       __u32           amp_max_pdu;
+       __u8            amp_type;
+       __u16           amp_pal_cap;
+       __u16           amp_assoc_size;
+       __u32           amp_max_flush_to;
+       __u32           amp_be_flush_to;
+
        unsigned int    auto_accept_delay;
 
        unsigned long   quirks;
@@ -173,8 +193,10 @@ struct hci_dev {
        struct workqueue_struct *workqueue;
 
        struct work_struct      power_on;
-       struct work_struct      power_off;
-       struct timer_list       off_timer;
+       struct delayed_work     power_off;
+
+       __u16                   discov_timeout;
+       struct delayed_work     discov_off;
 
        struct timer_list       cmd_timer;
        struct tasklet_struct   cmd_task;
@@ -195,6 +217,8 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
+       struct list_head        mgmt_pending;
+
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -273,6 +297,7 @@ struct hci_conn {
        unsigned int    sent;
 
        struct sk_buff_head data_q;
+       struct hci_chan_hash chan_hash;
 
        struct timer_list disc_timer;
        struct timer_list idle_timer;
@@ -295,6 +320,14 @@ struct hci_conn {
        void (*disconn_cfm_cb)  (struct hci_conn *conn, u8 reason);
 };
 
+struct hci_chan {
+       struct list_head list;
+
+       struct hci_conn *conn;
+       struct sk_buff_head data_q;
+       unsigned int    sent;
+};
+
 extern struct hci_proto *hci_proto[];
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
@@ -455,6 +488,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
        return NULL;
 }
 
+static inline void hci_chan_hash_init(struct hci_conn *c)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       INIT_LIST_HEAD(&h->list);
+       spin_lock_init(&h->lock);
+       h->num = 0;
+}
+
+static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_add(&chan->list, &h->list);
+       h->num++;
+}
+
+static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
+{
+       struct hci_chan_hash *h = &c->chan_hash;
+       list_del(&chan->list);
+       h->num--;
+}
+
 void hci_acl_connect(struct hci_conn *conn);
 void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
 void hci_add_sco(struct hci_conn *conn, __u16 handle);
@@ -466,6 +521,10 @@ int hci_conn_del(struct hci_conn *conn);
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+int hci_chan_del(struct hci_chan *chan);
+void hci_chan_hash_flush(struct hci_conn *conn);
+
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                                __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -545,7 +604,7 @@ struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
-int hci_unregister_dev(struct hci_dev *hdev);
+void hci_unregister_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
@@ -599,8 +658,9 @@ int hci_recv_frame(struct sk_buff *skb);
 int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
-int hci_register_sysfs(struct hci_dev *hdev);
-void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_init_sysfs(struct hci_dev *hdev);
+int hci_add_sysfs(struct hci_dev *hdev);
+void hci_del_sysfs(struct hci_dev *hdev);
 void hci_conn_init_sysfs(struct hci_conn *conn);
 void hci_conn_add_sysfs(struct hci_conn *conn);
 void hci_conn_del_sysfs(struct hci_conn *conn);
@@ -676,7 +736,7 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
 static inline int hci_proto_disconn_ind(struct hci_conn *conn)
 {
        register struct hci_proto *hp;
-       int reason = 0x13;
+       int reason = HCI_ERROR_REMOTE_USER_TERM;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->disconn_ind)
@@ -836,7 +896,7 @@ int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
@@ -849,34 +909,41 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 
 /* Management interface */
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
-int mgmt_index_added(u16 index);
-int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint);
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
+int mgmt_index_added(struct hci_dev *hdev);
+int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_powered(struct hci_dev *hdev, u8 powered);
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent);
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+int mgmt_disconnect_failed(struct hci_dev *hdev);
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
                                                                u8 status);
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                                                u8 status);
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir);
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
-int mgmt_discovering(u16 index, u8 discovering);
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint);
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status);
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
@@ -915,4 +982,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
 void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
+int hci_do_inquiry(struct hci_dev *hdev, u8 length);
+int hci_cancel_inquiry(struct hci_dev *hdev);
+
 #endif /* __HCI_CORE_H */
index ab90ae0970a69b2f3646c712aac0b56e2332509e..875021ad0675098e6e9bb5cfa1cfc5dea170bcad 100644 (file)
 #ifndef __L2CAP_H
 #define __L2CAP_H
 
+#include <asm/unaligned.h>
+
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU              672
 #define L2CAP_DEFAULT_MIN_MTU          48
 #define L2CAP_DEFAULT_FLUSH_TO         0xffff
 #define L2CAP_DEFAULT_TX_WINDOW                63
+#define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
 #define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
 #define L2CAP_DEFAULT_ACK_TO           200
 #define L2CAP_LE_DEFAULT_MTU           23
+#define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
+#define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
+#define L2CAP_DEFAULT_ACC_LAT          0xFFFFFFFF
 
-#define L2CAP_CONN_TIMEOUT     (40000) /* 40 seconds */
-#define L2CAP_INFO_TIMEOUT     (4000)  /*  4 seconds */
+#define L2CAP_DISC_TIMEOUT             (100)
+#define L2CAP_DISC_REJ_TIMEOUT         (5000)  /*  5 seconds */
+#define L2CAP_ENC_TIMEOUT              (5000)  /*  5 seconds */
+#define L2CAP_CONN_TIMEOUT             (40000) /* 40 seconds */
+#define L2CAP_INFO_TIMEOUT             (4000)  /*  4 seconds */
 
 /* L2CAP socket address */
 struct sockaddr_l2 {
@@ -88,52 +97,82 @@ struct l2cap_conninfo {
 #define L2CAP_ECHO_RSP         0x09
 #define L2CAP_INFO_REQ         0x0a
 #define L2CAP_INFO_RSP         0x0b
+#define L2CAP_CREATE_CHAN_REQ  0x0c
+#define L2CAP_CREATE_CHAN_RSP  0x0d
+#define L2CAP_MOVE_CHAN_REQ    0x0e
+#define L2CAP_MOVE_CHAN_RSP    0x0f
+#define L2CAP_MOVE_CHAN_CFM    0x10
+#define L2CAP_MOVE_CHAN_CFM_RSP        0x11
 #define L2CAP_CONN_PARAM_UPDATE_REQ    0x12
 #define L2CAP_CONN_PARAM_UPDATE_RSP    0x13
 
-/* L2CAP feature mask */
+/* L2CAP extended feature mask */
 #define L2CAP_FEAT_FLOWCTL     0x00000001
 #define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_BIDIR_QOS   0x00000004
 #define L2CAP_FEAT_ERTM                0x00000008
 #define L2CAP_FEAT_STREAMING   0x00000010
 #define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_EXT_FLOW    0x00000040
 #define L2CAP_FEAT_FIXED_CHAN  0x00000080
+#define L2CAP_FEAT_EXT_WINDOW  0x00000100
+#define L2CAP_FEAT_UCD         0x00000200
 
 /* L2CAP checksum option */
 #define L2CAP_FCS_NONE         0x00
 #define L2CAP_FCS_CRC16                0x01
 
+/* L2CAP fixed channels */
+#define L2CAP_FC_L2CAP         0x02
+#define L2CAP_FC_A2MP          0x08
+
 /* L2CAP Control Field bit masks */
-#define L2CAP_CTRL_SAR               0xC000
-#define L2CAP_CTRL_REQSEQ            0x3F00
-#define L2CAP_CTRL_TXSEQ             0x007E
-#define L2CAP_CTRL_RETRANS           0x0080
-#define L2CAP_CTRL_FINAL             0x0080
-#define L2CAP_CTRL_POLL              0x0010
-#define L2CAP_CTRL_SUPERVISE         0x000C
-#define L2CAP_CTRL_FRAME_TYPE        0x0001 /* I- or S-Frame */
-
-#define L2CAP_CTRL_TXSEQ_SHIFT      1
-#define L2CAP_CTRL_REQSEQ_SHIFT     8
-#define L2CAP_CTRL_SAR_SHIFT       14
+#define L2CAP_CTRL_SAR                 0xC000
+#define L2CAP_CTRL_REQSEQ              0x3F00
+#define L2CAP_CTRL_TXSEQ               0x007E
+#define L2CAP_CTRL_SUPERVISE           0x000C
+
+#define L2CAP_CTRL_RETRANS             0x0080
+#define L2CAP_CTRL_FINAL               0x0080
+#define L2CAP_CTRL_POLL                        0x0010
+#define L2CAP_CTRL_FRAME_TYPE          0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT         1
+#define L2CAP_CTRL_SUPER_SHIFT         2
+#define L2CAP_CTRL_REQSEQ_SHIFT                8
+#define L2CAP_CTRL_SAR_SHIFT           14
+
+/* L2CAP Extended Control Field bit mask */
+#define L2CAP_EXT_CTRL_TXSEQ           0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR             0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE       0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ          0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL            0x00040000
+#define L2CAP_EXT_CTRL_FINAL           0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE      0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT    2
+#define L2CAP_EXT_CTRL_SAR_SHIFT       16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT     16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT     18
 
 /* L2CAP Supervisory Function */
-#define L2CAP_SUPER_RCV_READY           0x0000
-#define L2CAP_SUPER_REJECT              0x0004
-#define L2CAP_SUPER_RCV_NOT_READY       0x0008
-#define L2CAP_SUPER_SELECT_REJECT       0x000C
+#define L2CAP_SUPER_RR         0x00
+#define L2CAP_SUPER_REJ                0x01
+#define L2CAP_SUPER_RNR                0x02
+#define L2CAP_SUPER_SREJ       0x03
 
 /* L2CAP Segmentation and Reassembly */
-#define L2CAP_SDU_UNSEGMENTED       0x0000
-#define L2CAP_SDU_START             0x4000
-#define L2CAP_SDU_END               0x8000
-#define L2CAP_SDU_CONTINUE          0xC000
+#define L2CAP_SAR_UNSEGMENTED  0x00
+#define L2CAP_SAR_START                0x01
+#define L2CAP_SAR_END          0x02
+#define L2CAP_SAR_CONTINUE     0x03
 
 /* L2CAP Command rej. reasons */
-#define L2CAP_REJ_NOT_UNDERSTOOD      0x0000
-#define L2CAP_REJ_MTU_EXCEEDED        0x0001
-#define L2CAP_REJ_INVALID_CID         0x0002
-
+#define L2CAP_REJ_NOT_UNDERSTOOD       0x0000
+#define L2CAP_REJ_MTU_EXCEEDED         0x0001
+#define L2CAP_REJ_INVALID_CID          0x0002
 
 /* L2CAP structures */
 struct l2cap_hdr {
@@ -141,6 +180,12 @@ struct l2cap_hdr {
        __le16     cid;
 } __packed;
 #define L2CAP_HDR_SIZE         4
+#define L2CAP_ENH_HDR_SIZE     6
+#define L2CAP_EXT_HDR_SIZE     8
+
+#define L2CAP_FCS_SIZE         2
+#define L2CAP_SDULEN_SIZE      2
+#define L2CAP_PSMLEN_SIZE      2
 
 struct l2cap_cmd_hdr {
        __u8       code;
@@ -185,14 +230,15 @@ struct l2cap_conn_rsp {
 #define L2CAP_CID_DYN_START    0x0040
 #define L2CAP_CID_DYN_END      0xffff
 
-/* connect result */
+/* connect/create channel results */
 #define L2CAP_CR_SUCCESS       0x0000
 #define L2CAP_CR_PEND          0x0001
 #define L2CAP_CR_BAD_PSM       0x0002
 #define L2CAP_CR_SEC_BLOCK     0x0003
 #define L2CAP_CR_NO_MEM                0x0004
+#define L2CAP_CR_BAD_AMP       0x0005
 
-/* connect status */
+/* connect/create channel status */
 #define L2CAP_CS_NO_INFO       0x0000
 #define L2CAP_CS_AUTHEN_PEND   0x0001
 #define L2CAP_CS_AUTHOR_PEND   0x0002
@@ -214,6 +260,8 @@ struct l2cap_conf_rsp {
 #define L2CAP_CONF_UNACCEPT    0x0001
 #define L2CAP_CONF_REJECT      0x0002
 #define L2CAP_CONF_UNKNOWN     0x0003
+#define L2CAP_CONF_PENDING     0x0004
+#define L2CAP_CONF_EFS_REJECT  0x0005
 
 struct l2cap_conf_opt {
        __u8       type;
@@ -230,6 +278,8 @@ struct l2cap_conf_opt {
 #define L2CAP_CONF_QOS         0x03
 #define L2CAP_CONF_RFC         0x04
 #define L2CAP_CONF_FCS         0x05
+#define L2CAP_CONF_EFS         0x06
+#define L2CAP_CONF_EWS         0x07
 
 #define L2CAP_CONF_MAX_SIZE    22
 
@@ -248,6 +298,21 @@ struct l2cap_conf_rfc {
 #define L2CAP_MODE_ERTM                0x03
 #define L2CAP_MODE_STREAMING   0x04
 
+struct l2cap_conf_efs {
+       __u8    id;
+       __u8    stype;
+       __le16  msdu;
+       __le32  sdu_itime;
+       __le32  acc_lat;
+       __le32  flush_to;
+} __packed;
+
+#define L2CAP_SERV_NOTRAFIC    0x00
+#define L2CAP_SERV_BESTEFFORT  0x01
+#define L2CAP_SERV_GUARANTEED  0x02
+
+#define L2CAP_BESTEFFORT_ID    0x01
+
 struct l2cap_disconn_req {
        __le16     dcid;
        __le16     scid;
@@ -268,14 +333,57 @@ struct l2cap_info_rsp {
        __u8        data[0];
 } __packed;
 
+struct l2cap_create_chan_req {
+       __le16      psm;
+       __le16      scid;
+       __u8        amp_id;
+} __packed;
+
+struct l2cap_create_chan_rsp {
+       __le16      dcid;
+       __le16      scid;
+       __le16      result;
+       __le16      status;
+} __packed;
+
+struct l2cap_move_chan_req {
+       __le16      icid;
+       __u8        dest_amp_id;
+} __packed;
+
+struct l2cap_move_chan_rsp {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MR_SUCCESS       0x0000
+#define L2CAP_MR_PEND          0x0001
+#define L2CAP_MR_BAD_ID                0x0002
+#define L2CAP_MR_SAME_ID       0x0003
+#define L2CAP_MR_NOT_SUPP      0x0004
+#define L2CAP_MR_COLLISION     0x0005
+#define L2CAP_MR_NOT_ALLOWED   0x0006
+
+struct l2cap_move_chan_cfm {
+       __le16      icid;
+       __le16      result;
+} __packed;
+
+#define L2CAP_MC_CONFIRMED     0x0000
+#define L2CAP_MC_UNCONFIRMED   0x0001
+
+struct l2cap_move_chan_cfm_rsp {
+       __le16      icid;
+} __packed;
+
 /* info type */
-#define L2CAP_IT_CL_MTU     0x0001
-#define L2CAP_IT_FEAT_MASK  0x0002
-#define L2CAP_IT_FIXED_CHAN 0x0003
+#define L2CAP_IT_CL_MTU                0x0001
+#define L2CAP_IT_FEAT_MASK     0x0002
+#define L2CAP_IT_FIXED_CHAN    0x0003
 
 /* info result */
-#define L2CAP_IR_SUCCESS    0x0000
-#define L2CAP_IR_NOTSUPP    0x0001
+#define L2CAP_IR_SUCCESS       0x0000
+#define L2CAP_IR_NOTSUPP       0x0001
 
 struct l2cap_conn_param_update_req {
        __le16      min;
@@ -294,7 +402,7 @@ struct l2cap_conn_param_update_rsp {
 
 /* ----- L2CAP channels and connections ----- */
 struct srej_list {
-       __u   tx_seq;
+       __u16   tx_seq;
        struct list_head list;
 };
 
@@ -316,14 +424,11 @@ struct l2cap_chan {
        __u16           flush_to;
        __u8            mode;
        __u8            chan_type;
+       __u8            chan_policy;
 
        __le16          sport;
 
        __u8            sec_level;
-       __u8            role_switch;
-       __u8            force_reliable;
-       __u8            flushable;
-       __u8            force_active;
 
        __u8            ident;
 
@@ -334,7 +439,8 @@ struct l2cap_chan {
 
        __u8            fcs;
 
-       __u8            tx_win;
+       __u16           tx_win;
+       __u16           tx_win_max;
        __u8            max_tx;
        __u16           retrans_timeout;
        __u16           monitor_timeout;
@@ -342,25 +448,40 @@ struct l2cap_chan {
 
        unsigned long   conf_state;
        unsigned long   conn_state;
-
-       __u8            next_tx_seq;
-       __u8            expected_ack_seq;
-       __u8            expected_tx_seq;
-       __u8            buffer_seq;
-       __u8            buffer_seq_srej;
-       __u8            srej_save_reqseq;
-       __u8            frames_sent;
-       __u8            unacked_frames;
+       unsigned long   flags;
+
+       __u16           next_tx_seq;
+       __u16           expected_ack_seq;
+       __u16           expected_tx_seq;
+       __u16           buffer_seq;
+       __u16           buffer_seq_srej;
+       __u16           srej_save_reqseq;
+       __u16           frames_sent;
+       __u16           unacked_frames;
        __u8            retry_count;
        __u8            num_acked;
        __u16           sdu_len;
        struct sk_buff  *sdu;
        struct sk_buff  *sdu_last_frag;
 
-       __u           remote_tx_win;
+       __u16           remote_tx_win;
        __u8            remote_max_tx;
        __u16           remote_mps;
 
+       __u8            local_id;
+       __u8            local_stype;
+       __u16           local_msdu;
+       __u32           local_sdu_itime;
+       __u32           local_acc_lat;
+       __u32           local_flush_to;
+
+       __u8            remote_id;
+       __u8            remote_stype;
+       __u16           remote_msdu;
+       __u32           remote_sdu_itime;
+       __u32           remote_acc_lat;
+       __u32           remote_flush_to;
+
        struct timer_list       chan_timer;
        struct timer_list       retrans_timer;
        struct timer_list       monitor_timer;
@@ -388,6 +509,7 @@ struct l2cap_ops {
 
 struct l2cap_conn {
        struct hci_conn *hcon;
+       struct hci_chan *hchan;
 
        bdaddr_t        *dst;
        bdaddr_t        *src;
@@ -442,6 +564,9 @@ enum {
        CONF_CONNECT_PEND,
        CONF_NO_FCS_RECV,
        CONF_STATE2_DEVICE,
+       CONF_EWS_RECV,
+       CONF_LOC_CONF_PEND,
+       CONF_REM_CONF_PEND,
 };
 
 #define L2CAP_CONF_MAX_CONF_REQ 2
@@ -459,6 +584,16 @@ enum {
        CONN_RNR_SENT,
 };
 
+/* Definitions for flags in l2cap_chan */
+enum {
+       FLAG_ROLE_SWITCH,
+       FLAG_FORCE_ACTIVE,
+       FLAG_FORCE_RELIABLE,
+       FLAG_FLUSHABLE,
+       FLAG_EXT_CTRL,
+       FLAG_EFS_ENABLE,
+};
+
 #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
 #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
 #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
@@ -471,6 +606,22 @@ enum {
                L2CAP_DEFAULT_ACK_TO);
 #define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
 
+static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
+{
+       int offset;
+
+       offset = (seq1 - seq2) % (chan->tx_win_max + 1);
+       if (offset < 0)
+               offset += (chan->tx_win_max + 1);
+
+       return offset;
+}
+
+static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
+{
+       return (seq + 1) % (chan->tx_win_max + 1);
+}
+
 static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
 {
        int sub;
@@ -483,13 +634,165 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
        return sub == ch->remote_tx_win;
 }
 
-#define __get_txseq(ctrl)      (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
-#define __get_reqseq(ctrl)     (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
-#define __is_iframe(ctrl)      (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
-#define __is_sframe(ctrl)      ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
-#define __is_sar_start(ctrl)   (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
+static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
+                                               L2CAP_EXT_CTRL_REQSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
+}
+
+static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_REQSEQ;
+       else
+               return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
+}
+
+static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
+                                               L2CAP_EXT_CTRL_TXSEQ_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
+}
+
+static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
+                                                       L2CAP_EXT_CTRL_TXSEQ;
+       else
+               return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
+}
+
+static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return ctrl & L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u32 __set_sframe(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FRAME_TYPE;
+       else
+               return L2CAP_CTRL_FRAME_TYPE;
+}
+
+static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
+}
+
+static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
+       else
+               return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
+}
+
+static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
+{
+       return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
+}
+
+static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_SAR;
+       else
+               return L2CAP_CTRL_SAR;
+}
+
+static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
+                                               L2CAP_EXT_CTRL_SUPER_SHIFT;
+       else
+               return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
+}
+
+static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
+                                               L2CAP_EXT_CTRL_SUPERVISE;
+       else
+               return (super << L2CAP_CTRL_SUPER_SHIFT) &
+                                                       L2CAP_CTRL_SUPERVISE;
+}
+
+static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_FINAL;
+       else
+               return L2CAP_CTRL_FINAL;
+}
+
+static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_FINAL;
+       else
+               return ctrl & L2CAP_CTRL_FINAL;
+}
+
+static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_CTRL_POLL;
+       else
+               return L2CAP_CTRL_POLL;
+}
+
+static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return ctrl & L2CAP_EXT_CTRL_POLL;
+       else
+               return ctrl & L2CAP_CTRL_POLL;
+}
+
+static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return get_unaligned_le32(p);
+       else
+               return get_unaligned_le16(p);
+}
+
+static inline void __put_control(struct l2cap_chan *chan, __u32 control,
+                                                               void *p)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return put_unaligned_le32(control, p);
+       else
+               return put_unaligned_le16(control, p);
+}
+
+static inline __u8 __ctrl_size(struct l2cap_chan *chan)
+{
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
+       else
+               return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
+}
 
 extern int disable_ertm;
+extern int enable_hs;
 
 int l2cap_init_sockets(void);
 void l2cap_cleanup_sockets(void);
@@ -504,7 +807,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 void l2cap_chan_destroy(struct l2cap_chan *chan);
 int l2cap_chan_connect(struct l2cap_chan *chan);
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority);
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 
 #endif /* __L2CAP_H */
index d66da0f94f95ae60e4ceb1d2fe713bc90c376e08..3e320c9cae8ffc7238d1c1197dc45c828a90931b 100644 (file)
@@ -69,6 +69,10 @@ struct mgmt_mode {
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
+struct mgmt_cp_set_discoverable {
+       __u8 val;
+       __u16 timeout;
+} __packed;
 
 #define MGMT_OP_SET_CONNECTABLE                0x0007
 
@@ -96,24 +100,22 @@ struct mgmt_cp_set_service_cache {
        __u8 enable;
 } __packed;
 
-struct mgmt_key_info {
+struct mgmt_link_key_info {
        bdaddr_t bdaddr;
        u8 type;
        u8 val[16];
        u8 pin_len;
-       u8 dlen;
-       u8 data[0];
 } __packed;
 
-#define MGMT_OP_LOAD_KEYS              0x000D
-struct mgmt_cp_load_keys {
+#define MGMT_OP_LOAD_LINK_KEYS         0x000D
+struct mgmt_cp_load_link_keys {
        __u8 debug_keys;
        __le16 key_count;
-       struct mgmt_key_info keys[0];
+       struct mgmt_link_key_info keys[0];
 } __packed;
 
-#define MGMT_OP_REMOVE_KEY             0x000E
-struct mgmt_cp_remove_key {
+#define MGMT_OP_REMOVE_KEYS            0x000E
+struct mgmt_cp_remove_keys {
        bdaddr_t bdaddr;
        __u8 disconnect;
 } __packed;
@@ -126,10 +128,20 @@ struct mgmt_rp_disconnect {
        bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_ADDR_BREDR                        0x00
+#define MGMT_ADDR_LE                   0x01
+#define MGMT_ADDR_BREDR_LE             0x02
+#define MGMT_ADDR_INVALID              0xff
+
+struct mgmt_addr_info {
+       bdaddr_t bdaddr;
+       __u8 type;
+} __packed;
+
 #define MGMT_OP_GET_CONNECTIONS                0x0010
 struct mgmt_rp_get_connections {
        __le16 conn_count;
-       bdaddr_t conn[0];
+       struct mgmt_addr_info addr[0];
 } __packed;
 
 #define MGMT_OP_PIN_CODE_REPLY         0x0011
@@ -245,26 +257,19 @@ struct mgmt_ev_controller_error {
 
 #define MGMT_EV_PAIRABLE               0x0009
 
-#define MGMT_EV_NEW_KEY                        0x000A
-struct mgmt_ev_new_key {
+#define MGMT_EV_NEW_LINK_KEY           0x000A
+struct mgmt_ev_new_link_key {
        __u8 store_hint;
-       struct mgmt_key_info key;
+       struct mgmt_link_key_info key;
 } __packed;
 
 #define MGMT_EV_CONNECTED              0x000B
-struct mgmt_ev_connected {
-       bdaddr_t bdaddr;
-       __u8 link_type;
-} __packed;
 
 #define MGMT_EV_DISCONNECTED           0x000C
-struct mgmt_ev_disconnected {
-       bdaddr_t bdaddr;
-} __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
 struct mgmt_ev_connect_failed {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 status;
 } __packed;
 
@@ -294,7 +299,7 @@ struct mgmt_ev_local_name_changed {
 
 #define MGMT_EV_DEVICE_FOUND           0x0012
 struct mgmt_ev_device_found {
-       bdaddr_t bdaddr;
+       struct mgmt_addr_info addr;
        __u8 dev_class[3];
        __s8 rssi;
        __u8 eir[HCI_MAX_EIR_LENGTH];
index 92cf1c2c30c9f0a94d193753a037cb851f8a60cd..8d7ba0961d3e694115f60b7c17dbaadc396b93b0 100644 (file)
@@ -391,6 +391,8 @@ struct cfg80211_crypto_settings {
  * @assocresp_ies: extra information element(s) to add into (Re)Association
  *     Response frames or %NULL
  * @assocresp_ies_len: length of assocresp_ies in octets
+ * @probe_resp_len: length of probe response template (@probe_resp)
+ * @probe_resp: probe response template (AP mode only)
  */
 struct beacon_parameters {
        u8 *head, *tail;
@@ -408,6 +410,8 @@ struct beacon_parameters {
        size_t proberesp_ies_len;
        const u8 *assocresp_ies;
        size_t assocresp_ies_len;
+       int probe_resp_len;
+       u8 *probe_resp;
 };
 
 /**
@@ -456,6 +460,9 @@ enum station_parameters_apply_mask {
  *     as the AC bitmap in the QoS info field
  * @max_sp: max Service Period. same format as the MAX_SP in the
  *     QoS info field (but already shifted down)
+ * @sta_modify_mask: bitmap indicating which parameters changed
+ *     (for those that don't have a natural "no change" value),
+ *     see &enum station_parameters_apply_mask
  */
 struct station_parameters {
        u8 *supported_rates;
@@ -615,6 +622,7 @@ struct sta_bss_parameters {
  *     user space MLME/SME implementation. The information is provided for
  *     the cfg80211_new_sta() calls to notify user space of the IEs.
  * @assoc_req_ies_len: Length of assoc_req_ies buffer in octets.
+ * @sta_flags: station flags mask & values
  */
 struct station_info {
        u32 filled;
@@ -1338,6 +1346,9 @@ struct cfg80211_gtk_rekey_data {
  *     doesn't verify much. Note, however, that the passed netdev may be
  *     %NULL as well if the user requested changing the channel for the
  *     device itself, or for a monitor interface.
+ * @get_channel: Get the current operating channel, should return %NULL if
+ *     there's no single defined operating channel if for example the
+ *     device implements channel hopping for multi-channel virtual interfaces.
  *
  * @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().
@@ -1428,6 +1439,9 @@ struct cfg80211_gtk_rekey_data {
  *
  * @tdls_mgmt: Transmit a TDLS management frame.
  * @tdls_oper: Perform a high-level TDLS operation (e.g. TDLS link setup).
+ *
+ * @probe_client: probe an associated client, must return a cookie that it
+ *     later passes to cfg80211_probe_status().
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -1581,7 +1595,7 @@ struct cfg80211_ops {
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       u64 cookie);
@@ -1617,6 +1631,11 @@ struct cfg80211_ops {
                             u16 status_code, const u8 *buf, size_t len);
        int     (*tdls_oper)(struct wiphy *wiphy, struct net_device *dev,
                             u8 *peer, enum nl80211_tdls_operation oper);
+
+       int     (*probe_client)(struct wiphy *wiphy, struct net_device *dev,
+                               const u8 *peer, u64 *cookie);
+
+       struct ieee80211_channel *(*get_channel)(struct wiphy *wiphy);
 };
 
 /*
@@ -1675,6 +1694,12 @@ struct cfg80211_ops {
  *     teardown packets should be sent through the @NL80211_CMD_TDLS_MGMT
  *     command. When this flag is not set, @NL80211_CMD_TDLS_OPER should be
  *     used for asking the driver/firmware to perform a TDLS operation.
+ * @WIPHY_FLAG_HAVE_AP_SME: device integrates AP SME
+ * @WIPHY_FLAG_REPORTS_OBSS: the device will report beacons from other BSSes
+ *     when there are virtual interfaces in AP mode by calling
+ *     cfg80211_report_obss_beacon().
+ * @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD: When operating as an AP, the device
+ *     responds to probe-requests in hardware.
  */
 enum wiphy_flags {
        WIPHY_FLAG_CUSTOM_REGULATORY            = BIT(0),
@@ -1693,6 +1718,9 @@ enum wiphy_flags {
        WIPHY_FLAG_AP_UAPSD                     = BIT(14),
        WIPHY_FLAG_SUPPORTS_TDLS                = BIT(15),
        WIPHY_FLAG_TDLS_EXTERNAL_SETUP          = BIT(16),
+       WIPHY_FLAG_HAVE_AP_SME                  = BIT(17),
+       WIPHY_FLAG_REPORTS_OBSS                 = BIT(18),
+       WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD        = BIT(19),
 };
 
 /**
@@ -1865,6 +1893,7 @@ struct wiphy_wowlan_support {
  * @software_iftypes: bitmask of software interface types, these are not
  *     subject to any restrictions since they are purely managed in SW.
  * @flags: wiphy flags, see &enum wiphy_flags
+ * @features: features advertised to nl80211, see &enum nl80211_feature_flags.
  * @bss_priv_size: each BSS struct has private data allocated with it,
  *     this variable determines its size
  * @max_scan_ssids: maximum number of SSIDs the device can scan for in
@@ -1903,6 +1932,8 @@ struct wiphy_wowlan_support {
  *     may request, if implemented.
  *
  * @wowlan: WoWLAN support information
+ *
+ * @ap_sme_capa: AP SME capabilities, flags from &enum nl80211_ap_sme_features.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -1924,7 +1955,9 @@ struct wiphy {
        /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */
        u16 interface_modes;
 
-       u32 flags;
+       u32 flags, features;
+
+       u32 ap_sme_capa;
 
        enum cfg80211_signal_type signal_type;
 
@@ -1956,6 +1989,13 @@ struct wiphy {
        u32 available_antennas_tx;
        u32 available_antennas_rx;
 
+       /*
+        * Bitmap of supported protocols for probe response offloading
+        * see &enum nl80211_probe_resp_offload_support_attr. Only valid
+        * when the wiphy flag @WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD is set.
+        */
+       u32 probe_resp_offload;
+
        /* If multiple wiphys are registered and you're handed e.g.
         * a regular netdev with assigned ieee80211_ptr, you won't
         * know whether it points to a wiphy your driver has registered
@@ -2179,6 +2219,8 @@ struct wireless_dev {
 
        int beacon_interval;
 
+       u32 ap_unexpected_nlpid;
+
 #ifdef CONFIG_CFG80211_WEXT
        /* wext data */
        struct {
@@ -2632,8 +2674,10 @@ void cfg80211_sched_scan_stopped(struct wiphy *wiphy);
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
@@ -2655,8 +2699,10 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
  *
  * This informs cfg80211 that BSS information was found and
  * the BSS should be updated/added.
+ *
+ * NOTE: Returns a referenced struct, must be released with cfg80211_put_bss()!
  */
-struct cfg80211_bss*
+struct cfg80211_bss * __must_check
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *channel,
                    const u8 *bssid,
@@ -3185,6 +3231,64 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
 void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
                                     const u8 *bssid, bool preauth, gfp_t gfp);
 
+/**
+ * cfg80211_rx_spurious_frame - inform userspace about a spurious frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * a spurious class 3 frame was received, to be able to deauth the
+ * sender.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_rx_unexpected_4addr_frame - inform about unexpected WDS frame
+ * @dev: The device the frame matched to
+ * @addr: the transmitter address
+ * @gfp: context flags
+ *
+ * This function is used in AP mode (only!) to inform userspace that
+ * an associated station sent a 4addr frame but that wasn't expected.
+ * It is allowed and desirable to send this event only once for each
+ * station to avoid event flooding.
+ * Returns %true if the frame was passed to userspace (or this failed
+ * for a reason other than not having a subscription.)
+ */
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp);
+
+/**
+ * cfg80211_probe_status - notify userspace about probe status
+ * @dev: the device the probe was sent on
+ * @addr: the address of the peer
+ * @cookie: the cookie filled in @probe_client previously
+ * @acked: indicates whether probe was acked or not
+ * @gfp: allocation flags
+ */
+void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp);
+
+/**
+ * cfg80211_report_obss_beacon - report beacon from other APs
+ * @wiphy: The wiphy that received the beacon
+ * @frame: the frame
+ * @len: length of the frame
+ * @freq: frequency the frame was received on
+ * @gfp: allocation flags
+ *
+ * Use this function to report to userspace when a beacon was
+ * received. It is not useful to call this when there is no
+ * netdev that is in AP/GO mode.
+ */
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 7e2c4d483ad0c4cf0ad1b39870baffdc92a78754..71392545d0a110906abbe4e51b8cb367cd4fc70f 100644 (file)
@@ -271,14 +271,6 @@ enum ieee80211_radiotap_type {
 #define IEEE80211_RADIOTAP_MCS_FEC_LDPC                0x10
 
 
-/* Ugly macro to convert literal channel numbers into their mhz equivalents
- * There are certianly some conditions that will break this (like feeding it '30')
- * but they shouldn't arise since nothing talks on channel 30. */
-#define ieee80211chan2mhz(x) \
-       (((x) <= 14) ? \
-       (((x) == 14) ? 2484 : ((x) * 5) + 2407) : \
-       ((x) + 1000) * 5)
-
 /* helpers */
 static inline int ieee80211_get_radiotap_len(unsigned char *data)
 {
index 72eddd1b410b9c8418216c17d74910585fdec975..0756049ae76d69c2a8cb9e2342deb868cefeaf94 100644 (file)
@@ -166,6 +166,7 @@ struct ieee80211_low_level_stats {
  *     that it is only ever disabled for station mode.
  * @BSS_CHANGED_IDLE: Idle changed for this BSS/interface.
  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
+ * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -184,6 +185,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_QOS                 = 1<<13,
        BSS_CHANGED_IDLE                = 1<<14,
        BSS_CHANGED_SSID                = 1<<15,
+       BSS_CHANGED_AP_PROBE_RESP       = 1<<16,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -518,7 +520,7 @@ struct ieee80211_tx_rate {
  * @flags: transmit info flags, defined above
  * @band: the band to transmit on (use for checking for races)
  * @antenna_sel_tx: antenna to use, 0 for automatic diversity
- * @pad: padding, ignore
+ * @ack_frame_id: internal frame ID for TX status, used internally
  * @control: union for control data
  * @status: union for status data
  * @driver_data: array of driver_data pointers
@@ -535,8 +537,7 @@ struct ieee80211_tx_info {
 
        u8 antenna_sel_tx;
 
-       /* 2 byte hole */
-       u8 pad[2];
+       u16 ack_frame_id;
 
        union {
                struct {
@@ -901,6 +902,10 @@ static inline bool ieee80211_vif_is_mesh(struct ieee80211_vif *vif)
  * @IEEE80211_KEY_FLAG_SW_MGMT: This flag should be set by the driver for a
  *     CCMP key if it requires CCMP encryption of management frames (MFP) to
  *     be done in software.
+ * @IEEE80211_KEY_FLAG_PUT_IV_SPACE: This flag should be set by the driver
+ *     for a CCMP key if space should be prepared for the IV, but the IV
+ *     itself should not be generated. Do not set together with
+ *     @IEEE80211_KEY_FLAG_GENERATE_IV on the same key.
  */
 enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_WMM_STA      = 1<<0,
@@ -908,6 +913,7 @@ enum ieee80211_key_flags {
        IEEE80211_KEY_FLAG_GENERATE_MMIC= 1<<2,
        IEEE80211_KEY_FLAG_PAIRWISE     = 1<<3,
        IEEE80211_KEY_FLAG_SW_MGMT      = 1<<4,
+       IEEE80211_KEY_FLAG_PUT_IV_SPACE = 1<<5,
 };
 
 /**
@@ -1303,6 +1309,16 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw,
        return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx];
 }
 
+/**
+ * ieee80211_free_txskb - free TX skb
+ * @hw: the hardware
+ * @skb: the skb
+ *
+ * Free a transmit skb. Use this funtion when some failure
+ * to transmit happened and thus status cannot be reported.
+ */
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 /**
  * DOC: Hardware crypto acceleration
  *
@@ -2660,6 +2676,19 @@ static inline struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        return ieee80211_beacon_get_tim(hw, vif, NULL, NULL);
 }
 
+/**
+ * ieee80211_proberesp_get - retrieve a Probe Response template
+ * @hw: pointer obtained from ieee80211_alloc_hw().
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ *
+ * Creates a Probe Response template which can, for example, be uploaded to
+ * hardware. The destination address should be set by the caller.
+ *
+ * Can only be called in AP mode.
+ */
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif);
+
 /**
  * ieee80211_pspoll_get - retrieve a PS Poll template
  * @hw: pointer obtained from ieee80211_alloc_hw().
index 39b85bc0804fbf7dd33d3c612b8a7d0e4a14ca73..cdbe671393432e92015920e9827c9614ace17666 100644 (file)
 /* NCI Status Codes */
 #define        NCI_STATUS_OK                                           0x00
 #define        NCI_STATUS_REJECTED                                     0x01
-#define        NCI_STATUS_MESSAGE_CORRUPTED                            0x02
-#define        NCI_STATUS_BUFFER_FULL                                  0x03
-#define        NCI_STATUS_FAILED                                       0x04
-#define        NCI_STATUS_NOT_INITIALIZED                              0x05
-#define        NCI_STATUS_SYNTAX_ERROR                                 0x06
-#define        NCI_STATUS_SEMANTIC_ERROR                               0x07
-#define        NCI_STATUS_UNKNOWN_GID                                  0x08
-#define        NCI_STATUS_UNKNOWN_OID                                  0x09
-#define        NCI_STATUS_INVALID_PARAM                                0x0a
-#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0b
+#define        NCI_STATUS_RF_FRAME_CORRUPTED                           0x02
+#define        NCI_STATUS_FAILED                                       0x03
+#define        NCI_STATUS_NOT_INITIALIZED                              0x04
+#define        NCI_STATUS_SYNTAX_ERROR                                 0x05
+#define        NCI_STATUS_SEMANTIC_ERROR                               0x06
+#define        NCI_STATUS_UNKNOWN_GID                                  0x07
+#define        NCI_STATUS_UNKNOWN_OID                                  0x08
+#define        NCI_STATUS_INVALID_PARAM                                0x09
+#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0a
 /* Discovery Specific Status Codes */
 #define        NCI_STATUS_DISCOVERY_ALREADY_STARTED                    0xa0
 #define        NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED           0xa1
+#define        NCI_STATUS_DISCOVERY_TEAR_DOWN                          0xa2
 /* RF Interface Specific Status Codes */
 #define        NCI_STATUS_RF_TRANSMISSION_ERROR                        0xb0
 #define        NCI_STATUS_RF_PROTOCOL_ERROR                            0xb1
 #define        NCI_STATUS_RF_TIMEOUT_ERROR                             0xb2
-#define        NCI_STATUS_RF_LINK_LOSS_ERROR                           0xb3
 /* NFCEE Interface Specific Status Codes */
 #define        NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED          0xc0
 #define        NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED            0xc1
 #define NCI_NFC_A_ACTIVE_LISTEN_MODE                           0x83
 #define NCI_NFC_F_ACTIVE_LISTEN_MODE                           0x85
 
+/* NCI RF Technologies */
+#define NCI_NFC_RF_TECHNOLOGY_A                                        0x00
+#define NCI_NFC_RF_TECHNOLOGY_B                                        0x01
+#define NCI_NFC_RF_TECHNOLOGY_F                                        0x02
+#define NCI_NFC_RF_TECHNOLOGY_15693                            0x03
+
+/* NCI Bit Rates */
+#define NCI_NFC_BIT_RATE_106                                   0x00
+#define NCI_NFC_BIT_RATE_212                                   0x01
+#define NCI_NFC_BIT_RATE_424                                   0x02
+#define NCI_NFC_BIT_RATE_848                                   0x03
+#define NCI_NFC_BIT_RATE_1696                                  0x04
+#define NCI_NFC_BIT_RATE_3392                                  0x05
+#define NCI_NFC_BIT_RATE_6784                                  0x06
+
 /* NCI RF Protocols */
 #define NCI_RF_PROTOCOL_UNKNOWN                                        0x00
 #define NCI_RF_PROTOCOL_T1T                                    0x01
 #define NCI_RF_PROTOCOL_NFC_DEP                                        0x05
 
 /* NCI RF Interfaces */
-#define NCI_RF_INTERFACE_RFU                                   0x00
+#define NCI_RF_INTERFACE_NFCEE_DIRECT                          0x00
 #define        NCI_RF_INTERFACE_FRAME                                  0x01
 #define        NCI_RF_INTERFACE_ISO_DEP                                0x02
 #define        NCI_RF_INTERFACE_NFC_DEP                                0x03
 
+/* NCI Reset types */
+#define NCI_RESET_TYPE_KEEP_CONFIG                             0x00
+#define NCI_RESET_TYPE_RESET_CONFIG                            0x01
+
+/* NCI Static RF connection ID */
+#define NCI_STATIC_RF_CONN_ID                                  0x00
+
+/* NCI Data Flow Control */
+#define NCI_DATA_FLOW_CONTROL_NOT_USED                         0xff
+
 /* NCI RF_DISCOVER_MAP_CMD modes */
 #define NCI_DISC_MAP_MODE_POLL                                 0x01
 #define NCI_DISC_MAP_MODE_LISTEN                               0x02
 #define        NCI_DISCOVERY_TYPE_POLL_F_PASSIVE                       0x02
 #define        NCI_DISCOVERY_TYPE_POLL_A_ACTIVE                        0x03
 #define        NCI_DISCOVERY_TYPE_POLL_F_ACTIVE                        0x05
-#define        NCI_DISCOVERY_TYPE_WAKEUP_A_PASSIVE                     0x06
-#define        NCI_DISCOVERY_TYPE_WAKEUP_B_PASSIVE                     0x07
 #define        NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE                      0x09
 #define        NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE                     0x80
 #define        NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE                     0x81
 #define        NCI_DEACTIVATE_TYPE_IDLE_MODE                           0x00
 #define        NCI_DEACTIVATE_TYPE_SLEEP_MODE                          0x01
 #define        NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE                       0x02
-#define        NCI_DEACTIVATE_TYPE_RF_LINK_LOSS                        0x03
-#define        NCI_DEACTIVATE_TYPE_DISCOVERY_ERROR                     0x04
+#define        NCI_DEACTIVATE_TYPE_DISCOVERY                           0x03
 
 /* Message Type (MT) */
 #define NCI_MT_DATA_PKT                                                0x00
@@ -169,18 +190,11 @@ struct nci_data_hdr {
 /* -----  NCI Commands ---- */
 /* ------------------------ */
 #define NCI_OP_CORE_RESET_CMD          nci_opcode_pack(NCI_GID_CORE, 0x00)
-
-#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
-
-#define NCI_OP_CORE_SET_CONFIG_CMD     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_CMD    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_cmd {
-       __u8    target_handle;
-       __u8    num_target_specific_params;
+struct nci_core_reset_cmd {
+       __u8    reset_type;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_CMD     nci_opcode_pack(NCI_GID_CORE, 0x06)
+#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
 
 #define NCI_OP_RF_DISCOVER_MAP_CMD     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 struct disc_map_config {
@@ -218,6 +232,7 @@ struct nci_rf_deactivate_cmd {
 struct nci_core_reset_rsp {
        __u8    status;
        __u8    nci_ver;
+       __u8    config_status;
 } __packed;
 
 #define NCI_OP_CORE_INIT_RSP           nci_opcode_pack(NCI_GID_CORE, 0x01)
@@ -232,24 +247,14 @@ struct nci_core_init_rsp_1 {
 struct nci_core_init_rsp_2 {
        __u8    max_logical_connections;
        __le16  max_routing_table_size;
-       __u8    max_control_packet_payload_length;
-       __le16  rf_sending_buffer_size;
-       __le16  rf_receiving_buffer_size;
-       __le16  manufacturer_id;
-} __packed;
-
-#define NCI_OP_CORE_SET_CONFIG_RSP     nci_opcode_pack(NCI_GID_CORE, 0x02)
-
-#define NCI_OP_CORE_CONN_CREATE_RSP    nci_opcode_pack(NCI_GID_CORE, 0x04)
-struct nci_core_conn_create_rsp {
-       __u8    status;
-       __u8    max_pkt_payload_size;
+       __u8    max_ctrl_pkt_payload_len;
+       __le16  max_size_for_large_params;
+       __u8    max_data_pkt_payload_size;
        __u8    initial_num_credits;
-       __u8    conn_id;
+       __u8    manufact_id;
+       __le32  manufact_specific_info;
 } __packed;
 
-#define NCI_OP_CORE_CONN_CLOSE_RSP     nci_opcode_pack(NCI_GID_CORE, 0x06)
-
 #define NCI_OP_RF_DISCOVER_MAP_RSP     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
 
 #define NCI_OP_RF_DISCOVER_RSP         nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
@@ -270,12 +275,7 @@ struct nci_core_conn_credit_ntf {
        struct conn_credit_entry        conn_entries[NCI_MAX_NUM_CONN];
 } __packed;
 
-#define NCI_OP_RF_FIELD_INFO_NTF       nci_opcode_pack(NCI_GID_CORE, 0x08)
-struct nci_rf_field_info_ntf {
-       __u8    rf_field_status;
-} __packed;
-
-#define NCI_OP_RF_ACTIVATE_NTF         nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
+#define NCI_OP_RF_INTF_ACTIVATED_NTF   nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
 struct rf_tech_specific_params_nfca_poll {
        __u16   sens_res;
        __u8    nfcid1_len;     /* 0, 4, 7, or 10 Bytes */
@@ -289,17 +289,20 @@ struct activation_params_nfca_poll_iso_dep {
        __u8    rats_res[20];
 };
 
-struct nci_rf_activate_ntf {
-       __u8    target_handle;
+struct nci_rf_intf_activated_ntf {
+       __u8    rf_discovery_id;
+       __u8    rf_interface_type;
        __u8    rf_protocol;
-       __u8    rf_tech_and_mode;
+       __u8    activation_rf_tech_and_mode;
        __u8    rf_tech_specific_params_len;
 
        union {
                struct rf_tech_specific_params_nfca_poll nfca_poll;
        } rf_tech_specific_params;
 
-       __u8    rf_interface_type;
+       __u8    data_exch_rf_tech_and_mode;
+       __u8    data_exch_tx_bit_rate;
+       __u8    data_exch_rx_bit_rate;
        __u8    activation_params_len;
 
        union {
@@ -309,5 +312,9 @@ struct nci_rf_activate_ntf {
 } __packed;
 
 #define NCI_OP_RF_DEACTIVATE_NTF       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+struct nci_rf_deactivate_ntf {
+       __u8    type;
+       __u8    reason;
+} __packed;
 
 #endif /* __NCI_H */
index b8b4bbd7e0fc2d6abfa70ae5d2be24b11471bb76..c92b69d7e0c2a821e77a0019b28bed558caa1a4a 100644 (file)
@@ -109,15 +109,12 @@ struct nci_dev {
                                [NCI_MAX_SUPPORTED_RF_INTERFACES];
        __u8                    max_logical_connections;
        __u16                   max_routing_table_size;
-       __u8                    max_control_packet_payload_length;
-       __u16                   rf_sending_buffer_size;
-       __u16                   rf_receiving_buffer_size;
-       __u16                   manufacturer_id;
-
-       /* received during NCI_OP_CORE_CONN_CREATE_RSP for static conn 0 */
-       __u8                    max_pkt_payload_size;
+       __u8                    max_ctrl_pkt_payload_len;
+       __u16                   max_size_for_large_params;
+       __u8                    max_data_pkt_payload_size;
        __u8                    initial_num_credits;
-       __u8                    conn_id;
+       __u8                    manufact_id;
+       __u32                   manufact_specific_info;
 
        /* stored during nci_data_exchange */
        data_exchange_cb_t      data_exchange_cb;
index 1331008ad88577d664f180fef4300716401d76de..1c28f394d8ec7a65c68a27ec060cbcd0995d3549 100644 (file)
@@ -563,6 +563,7 @@ enum sock_flags {
        SOCK_FASYNC, /* fasync() active */
        SOCK_RXQ_OVFL,
        SOCK_ZEROCOPY, /* buffers from userspace */
+       SOCK_WIFI_STATUS, /* push wifi status to userspace */
 };
 
 static inline void sock_copy_flags(struct sock *nsk, struct sock *osk)
@@ -1714,6 +1715,8 @@ static inline int sock_intr_errno(long timeo)
 
 extern void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
        struct sk_buff *skb);
+extern void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb);
 
 static __inline__ void
 sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
@@ -1741,6 +1744,9 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
                __sock_recv_timestamp(msg, sk, skb);
        else
                sk->sk_stamp = kt;
+
+       if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)
+               __sock_recv_wifi_status(msg, sk, skb);
 }
 
 extern void __sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
index 91bcd3a961ec22c501451ef588fe86b171c55ae3..a6cd856046ab247cb29da2d9831077153da8a642 100644 (file)
@@ -65,15 +65,13 @@ static DECLARE_RWSEM(bnep_session_sem);
 static struct bnep_session *__bnep_get_session(u8 *dst)
 {
        struct bnep_session *s;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &bnep_session_list) {
-               s = list_entry(p, struct bnep_session, list);
+       list_for_each_entry(s, &bnep_session_list, list)
                if (!compare_ether_addr(dst, s->eh.h_source))
                        return s;
-       }
+
        return NULL;
 }
 
@@ -667,17 +665,14 @@ static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 
 int bnep_get_connlist(struct bnep_connlist_req *req)
 {
-       struct list_head *p;
+       struct bnep_session *s;
        int err = 0, n = 0;
 
        down_read(&bnep_session_sem);
 
-       list_for_each(p, &bnep_session_list) {
-               struct bnep_session *s;
+       list_for_each_entry(s, &bnep_session_list, list) {
                struct bnep_conninfo ci;
 
-               s = list_entry(p, struct bnep_session, list);
-
                __bnep_copy_ci(&ci, s);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 7d00ddf9e9dcb55ab74cf768db31a3e15af647ac..9e8940b24bbad73c67dd37fd23b0e787090cacd8 100644 (file)
@@ -53,15 +53,13 @@ static LIST_HEAD(cmtp_session_list);
 static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
 {
        struct cmtp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &cmtp_session_list) {
-               session = list_entry(p, struct cmtp_session, list);
+       list_for_each_entry(session, &cmtp_session_list, list)
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
-       }
+
        return NULL;
 }
 
@@ -431,19 +429,16 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
 
 int cmtp_get_connlist(struct cmtp_connlist_req *req)
 {
-       struct list_head *p;
+       struct cmtp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&cmtp_session_sem);
 
-       list_for_each(p, &cmtp_session_list) {
-               struct cmtp_session *session;
+       list_for_each_entry(session, &cmtp_session_list, list) {
                struct cmtp_conninfo ci;
 
-               session = list_entry(p, struct cmtp_session, list);
-
                __cmtp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index c1c597e3e198e9ffba26dd4dcf2e59e2ffc923c3..de0b93e45980138235044550be69f960cd8cf9ab 100644 (file)
@@ -374,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 
        skb_queue_head_init(&conn->data_q);
 
+       hci_chan_hash_init(conn);
+
        setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
        setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
        setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn)
 
        tasklet_disable(&hdev->tx_task);
 
+       hci_chan_hash_flush(conn);
+
        hci_conn_hash_del(hdev, conn);
        if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -453,16 +457,13 @@ int hci_conn_del(struct hci_conn *conn)
 struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
 {
        int use_src = bacmp(src, BDADDR_ANY);
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
        read_lock_bh(&hci_dev_list_lock);
 
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
                        continue;
 
@@ -673,7 +674,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
                goto encrypt;
 
 auth:
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
                return 0;
 
        if (!hci_conn_auth(conn, sec_level, auth_type))
@@ -819,7 +820,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
 
                c->state = BT_CLOSED;
 
-               hci_proto_disconn_cfm(c, 0x16);
+               hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
                hci_conn_del(c);
        }
 }
@@ -855,10 +856,10 @@ EXPORT_SYMBOL(hci_conn_put_device);
 
 int hci_get_conn_list(void __user *arg)
 {
+       register struct hci_conn *c;
        struct hci_conn_list_req req, *cl;
        struct hci_conn_info *ci;
        struct hci_dev *hdev;
-       struct list_head *p;
        int n = 0, size, err;
 
        if (copy_from_user(&req, arg, sizeof(req)))
@@ -882,10 +883,7 @@ int hci_get_conn_list(void __user *arg)
        ci = cl->conn_info;
 
        hci_dev_lock_bh(hdev);
-       list_for_each(p, &hdev->conn_hash.list) {
-               register struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
                bacpy(&(ci + n)->bdaddr, &c->dst);
                (ci + n)->handle = c->handle;
                (ci + n)->type  = c->type;
@@ -956,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
 
        return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
 }
+
+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);
+
+       chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
+       if (!chan)
+               return NULL;
+
+       chan->conn = conn;
+       skb_queue_head_init(&chan->data_q);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_add(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       return chan;
+}
+
+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);
+
+       tasklet_disable(&hdev->tx_task);
+       hci_chan_hash_del(conn, chan);
+       tasklet_enable(&hdev->tx_task);
+
+       skb_queue_purge(&chan->data_q);
+       kfree(chan);
+
+       return 0;
+}
+
+void hci_chan_hash_flush(struct hci_conn *conn)
+{
+       struct hci_chan_hash *h = &conn->chan_hash;
+       struct hci_chan *chan, *tmp;
+
+       BT_DBG("conn %p", conn);
+
+       list_for_each_entry_safe(chan, tmp, &h->list, list)
+               hci_chan_del(chan);
+}
index be84ae33ae36bec88f4f67502780b4fe5333e270..fb3feeb185d7098359bdd71b0156fa8a67d0157f 100644 (file)
@@ -319,8 +319,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
  * Device is held on return. */
 struct hci_dev *hci_dev_get(int index)
 {
-       struct hci_dev *hdev = NULL;
-       struct list_head *p;
+       struct hci_dev *hdev = NULL, *d;
 
        BT_DBG("%d", index);
 
@@ -328,8 +327,7 @@ struct hci_dev *hci_dev_get(int index)
                return NULL;
 
        read_lock(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
+       list_for_each_entry(d, &hci_dev_list, list) {
                if (d->id == index) {
                        hdev = hci_dev_hold(d);
                        break;
@@ -551,8 +549,11 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
-               if (!test_bit(HCI_SETUP, &hdev->flags))
-                       mgmt_powered(hdev->id, 1);
+               if (!test_bit(HCI_SETUP, &hdev->flags)) {
+                       hci_dev_lock_bh(hdev);
+                       mgmt_powered(hdev, 1);
+                       hci_dev_unlock_bh(hdev);
+               }
        } else {
                /* Init failed, cleanup */
                tasklet_kill(&hdev->rx_task);
@@ -597,6 +598,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        tasklet_kill(&hdev->rx_task);
        tasklet_kill(&hdev->tx_task);
 
+       if (hdev->discov_timeout > 0) {
+               cancel_delayed_work(&hdev->discov_off);
+               hdev->discov_timeout = 0;
+       }
+
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work(&hdev->power_off);
+
        hci_dev_lock_bh(hdev);
        inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -636,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
         * and no tasks are scheduled. */
        hdev->close(hdev);
 
-       mgmt_powered(hdev->id, 0);
+       hci_dev_lock_bh(hdev);
+       mgmt_powered(hdev, 0);
+       hci_dev_unlock_bh(hdev);
 
        /* Clear flags */
        hdev->flags = 0;
@@ -794,9 +805,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
 int hci_get_dev_list(void __user *arg)
 {
+       struct hci_dev *hdev;
        struct hci_dev_list_req *dl;
        struct hci_dev_req *dr;
-       struct list_head *p;
        int n = 0, size, err;
        __u16 dev_num;
 
@@ -815,12 +826,9 @@ int hci_get_dev_list(void __user *arg)
        dr = dl->dev_req;
 
        read_lock_bh(&hci_dev_list_lock);
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *hdev;
-
-               hdev = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(hdev);
+       list_for_each_entry(hdev, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+                       cancel_delayed_work(&hdev->power_off);
 
                if (!test_bit(HCI_MGMT, &hdev->flags))
                        set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -855,7 +863,8 @@ int hci_get_dev_info(void __user *arg)
        if (!hdev)
                return -ENODEV;
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        if (!test_bit(HCI_MGMT, &hdev->flags))
                set_bit(HCI_PAIRABLE, &hdev->flags);
@@ -912,6 +921,7 @@ struct hci_dev *hci_alloc_dev(void)
        if (!hdev)
                return NULL;
 
+       hci_init_sysfs(hdev);
        skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
@@ -938,39 +948,41 @@ static void hci_power_on(struct work_struct *work)
                return;
 
        if (test_bit(HCI_AUTO_OFF, &hdev->flags))
-               mod_timer(&hdev->off_timer,
-                               jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
+               queue_delayed_work(hdev->workqueue, &hdev->power_off,
+                                       msecs_to_jiffies(AUTO_OFF_TIMEOUT));
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_added(hdev->id);
+               mgmt_index_added(hdev);
 }
 
 static void hci_power_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
+       struct hci_dev *hdev = container_of(work, struct hci_dev,
+                                                       power_off.work);
 
        BT_DBG("%s", hdev->name);
 
+       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+
        hci_dev_close(hdev->id);
 }
 
-static void hci_auto_off(unsigned long data)
+static void hci_discov_off(struct work_struct *work)
 {
-       struct hci_dev *hdev = (struct hci_dev *) data;
+       struct hci_dev *hdev;
+       u8 scan = SCAN_PAGE;
+
+       hdev = container_of(work, struct hci_dev, discov_off.work);
 
        BT_DBG("%s", hdev->name);
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
+       hci_dev_lock_bh(hdev);
 
-       queue_work(hdev->workqueue, &hdev->power_off);
-}
+       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
 
-void hci_del_off_timer(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
+       hdev->discov_timeout = 0;
 
-       clear_bit(HCI_AUTO_OFF, &hdev->flags);
-       del_timer(&hdev->off_timer);
+       hci_dev_unlock_bh(hdev);
 }
 
 int hci_uuids_clear(struct hci_dev *hdev)
@@ -1007,16 +1019,11 @@ int hci_link_keys_clear(struct hci_dev *hdev)
 
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->link_keys) {
-               struct link_key *k;
-
-               k = list_entry(p, struct link_key, list);
+       struct link_key *k;
 
+       list_for_each_entry(k, &hdev->link_keys, list)
                if (bacmp(bdaddr, &k->bdaddr) == 0)
                        return k;
-       }
 
        return NULL;
 }
@@ -1138,7 +1145,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
 
        persistent = hci_persistent_key(hdev, conn, type, old_key_type);
 
-       mgmt_new_key(hdev->id, key, persistent);
+       mgmt_new_link_key(hdev, key, persistent);
 
        if (!persistent) {
                list_del(&key->list);
@@ -1181,7 +1188,7 @@ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
        memcpy(id->rand, rand, sizeof(id->rand));
 
        if (new_key)
-               mgmt_new_key(hdev->id, key, old_key_type);
+               mgmt_new_link_key(hdev, key, old_key_type);
 
        return 0;
 }
@@ -1279,16 +1286,11 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
 struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
                                                bdaddr_t *bdaddr)
 {
-       struct list_head *p;
-
-       list_for_each(p, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(p, struct bdaddr_list, list);
+       struct bdaddr_list *b;
 
+       list_for_each_entry(b, &hdev->blacklist, list)
                if (bacmp(bdaddr, &b->bdaddr) == 0)
                        return b;
-       }
 
        return NULL;
 }
@@ -1327,7 +1329,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
        list_add(&entry->list, &hdev->blacklist);
 
-       return mgmt_device_blocked(hdev->id, bdaddr);
+       return mgmt_device_blocked(hdev, bdaddr);
 }
 
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
@@ -1346,7 +1348,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
        list_del(&entry->list);
        kfree(entry);
 
-       return mgmt_device_unblocked(hdev->id, bdaddr);
+       return mgmt_device_unblocked(hdev, bdaddr);
 }
 
 static void hci_clear_adv_cache(unsigned long arg)
@@ -1425,7 +1427,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
 int hci_register_dev(struct hci_dev *hdev)
 {
        struct list_head *head = &hci_dev_list, *p;
-       int i, id = 0;
+       int i, id, error;
 
        BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
                                                hdev->bus, hdev->owner);
@@ -1433,6 +1435,11 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->open || !hdev->close || !hdev->destruct)
                return -EINVAL;
 
+       /* Do not allow HCI_AMP devices to register at index 0,
+        * so the index can be used as the AMP controller ID.
+        */
+       id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
+
        write_lock_bh(&hci_dev_list_lock);
 
        /* Find first available device id */
@@ -1479,6 +1486,8 @@ int hci_register_dev(struct hci_dev *hdev)
 
        hci_conn_hash_init(hdev);
 
+       INIT_LIST_HEAD(&hdev->mgmt_pending);
+
        INIT_LIST_HEAD(&hdev->blacklist);
 
        INIT_LIST_HEAD(&hdev->uuids);
@@ -1492,8 +1501,9 @@ int hci_register_dev(struct hci_dev *hdev)
                                                (unsigned long) hdev);
 
        INIT_WORK(&hdev->power_on, hci_power_on);
-       INIT_WORK(&hdev->power_off, hci_power_off);
-       setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
+       INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
+
+       INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
 
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
@@ -1502,10 +1512,14 @@ int hci_register_dev(struct hci_dev *hdev)
        write_unlock_bh(&hci_dev_list_lock);
 
        hdev->workqueue = create_singlethread_workqueue(hdev->name);
-       if (!hdev->workqueue)
-               goto nomem;
+       if (!hdev->workqueue) {
+               error = -ENOMEM;
+               goto err;
+       }
 
-       hci_register_sysfs(hdev);
+       error = hci_add_sysfs(hdev);
+       if (error < 0)
+               goto err_wqueue;
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
                                RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
@@ -1524,17 +1538,19 @@ int hci_register_dev(struct hci_dev *hdev)
 
        return id;
 
-nomem:
+err_wqueue:
+       destroy_workqueue(hdev->workqueue);
+err:
        write_lock_bh(&hci_dev_list_lock);
        list_del(&hdev->list);
        write_unlock_bh(&hci_dev_list_lock);
 
-       return -ENOMEM;
+       return error;
 }
 EXPORT_SYMBOL(hci_register_dev);
 
 /* Unregister HCI device */
-int hci_unregister_dev(struct hci_dev *hdev)
+void hci_unregister_dev(struct hci_dev *hdev)
 {
        int i;
 
@@ -1550,8 +1566,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
                kfree_skb(hdev->reassembly[i]);
 
        if (!test_bit(HCI_INIT, &hdev->flags) &&
-                                       !test_bit(HCI_SETUP, &hdev->flags))
-               mgmt_index_removed(hdev->id);
+                                       !test_bit(HCI_SETUP, &hdev->flags)) {
+               hci_dev_lock_bh(hdev);
+               mgmt_index_removed(hdev);
+               hci_dev_unlock_bh(hdev);
+       }
+
+       /* mgmt_index_removed should take care of emptying the
+        * pending list */
+       BUG_ON(!list_empty(&hdev->mgmt_pending));
 
        hci_notify(hdev, HCI_DEV_UNREG);
 
@@ -1560,9 +1583,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
                rfkill_destroy(hdev->rfkill);
        }
 
-       hci_unregister_sysfs(hdev);
+       hci_del_sysfs(hdev);
 
-       hci_del_off_timer(hdev);
        del_timer(&hdev->adv_timer);
 
        destroy_workqueue(hdev->workqueue);
@@ -1576,8 +1598,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
        hci_dev_unlock_bh(hdev);
 
        __hci_dev_put(hdev);
-
-       return 0;
 }
 EXPORT_SYMBOL(hci_unregister_dev);
 
@@ -1948,23 +1968,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
+static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+                               struct sk_buff *skb, __u16 flags)
 {
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
 
-       BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
-
-       skb->dev = (void *) hdev;
-       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags);
-
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
                /* Non fragmented */
                BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
 
-               skb_queue_tail(&conn->data_q, skb);
+               skb_queue_tail(queue, skb);
        } else {
                /* Fragmented */
                BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1972,9 +1987,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                skb_shinfo(skb)->frag_list = NULL;
 
                /* Queue all fragments atomically */
-               spin_lock_bh(&conn->data_q.lock);
+               spin_lock_bh(&queue->lock);
 
-               __skb_queue_tail(&conn->data_q, skb);
+               __skb_queue_tail(queue, skb);
 
                flags &= ~ACL_START;
                flags |= ACL_CONT;
@@ -1987,11 +2002,25 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
 
-                       __skb_queue_tail(&conn->data_q, skb);
+                       __skb_queue_tail(queue, skb);
                } while (list);
 
-               spin_unlock_bh(&conn->data_q.lock);
+               spin_unlock_bh(&queue->lock);
        }
+}
+
+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);
+
+       skb->dev = (void *) hdev;
+       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
+       hci_add_acl_hdr(skb, conn->handle, flags);
+
+       hci_queue_acl(conn, &chan->data_q, skb, flags);
 
        tasklet_schedule(&hdev->tx_task);
 }
@@ -2026,16 +2055,12 @@ EXPORT_SYMBOL(hci_send_sco);
 static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct hci_conn *conn = NULL;
+       struct hci_conn *conn = NULL, *c;
        int num = 0, min = ~0;
-       struct list_head *p;
 
        /* We don't have to lock device here. Connections are always
         * added and removed with TX task disabled. */
-       list_for_each(p, &h->list) {
-               struct hci_conn *c;
-               c = list_entry(p, struct hci_conn, list);
-
+       list_for_each_entry(c, &h->list, list) {
                if (c->type != type || skb_queue_empty(&c->data_q))
                        continue;
 
@@ -2084,14 +2109,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
 static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
-       struct hci_conn  *c;
+       struct hci_conn *c;
 
        BT_ERR("%s link tx timeout", hdev->name);
 
        /* Kill stalled connections */
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
+       list_for_each_entry(c, &h->list, list) {
                if (c->type == type && c->sent) {
                        BT_ERR("%s killing stalled connection %s",
                                hdev->name, batostr(&c->dst));
@@ -2100,11 +2123,137 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        }
 }
 
-static inline void hci_sched_acl(struct hci_dev *hdev)
+static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
+                                               int *quote)
 {
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_chan *chan = NULL;
+       int num = 0, min = ~0, cur_prio = 0;
        struct hci_conn *conn;
+       int cnt, q, conn_num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *tmp;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               conn_num++;
+
+               ch = &conn->chan_hash;
+
+               list_for_each_entry(tmp, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (skb_queue_empty(&tmp->data_q))
+                               continue;
+
+                       skb = skb_peek(&tmp->data_q);
+                       if (skb->priority < cur_prio)
+                               continue;
+
+                       if (skb->priority > cur_prio) {
+                               num = 0;
+                               min = ~0;
+                               cur_prio = skb->priority;
+                       }
+
+                       num++;
+
+                       if (conn->sent < min) {
+                               min  = conn->sent;
+                               chan = tmp;
+                       }
+               }
+
+               if (hci_conn_num(hdev, type) == conn_num)
+                       break;
+       }
+
+       if (!chan)
+               return NULL;
+
+       switch (chan->conn->type) {
+       case ACL_LINK:
+               cnt = hdev->acl_cnt;
+               break;
+       case SCO_LINK:
+       case ESCO_LINK:
+               cnt = hdev->sco_cnt;
+               break;
+       case LE_LINK:
+               cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
+               break;
+       default:
+               cnt = 0;
+               BT_ERR("Unknown link type");
+       }
+
+       q = cnt / num;
+       *quote = q ? q : 1;
+       BT_DBG("chan %p quote %d", chan, *quote);
+       return chan;
+}
+
+static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn *conn;
+       int num = 0;
+
+       BT_DBG("%s", hdev->name);
+
+       list_for_each_entry(conn, &h->list, list) {
+               struct hci_chan_hash *ch;
+               struct hci_chan *chan;
+
+               if (conn->type != type)
+                       continue;
+
+               if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
+                       continue;
+
+               num++;
+
+               ch = &conn->chan_hash;
+               list_for_each_entry(chan, &ch->list, list) {
+                       struct sk_buff *skb;
+
+                       if (chan->sent) {
+                               chan->sent = 0;
+                               continue;
+                       }
+
+                       if (skb_queue_empty(&chan->data_q))
+                               continue;
+
+                       skb = skb_peek(&chan->data_q);
+                       if (skb->priority >= HCI_PRIO_MAX - 1)
+                               continue;
+
+                       skb->priority = HCI_PRIO_MAX - 1;
+
+                       BT_DBG("chan %p skb %p promoted to %d", chan, skb,
+                                                               skb->priority);
+               }
+
+               if (hci_conn_num(hdev, type) == num)
+                       break;
+       }
+}
+
+static inline void hci_sched_acl(struct hci_dev *hdev)
+{
+       struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
+       unsigned int cnt;
 
        BT_DBG("%s", hdev->name);
 
@@ -2118,19 +2267,35 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
                        hci_link_tx_to(hdev, ACL_LINK);
        }
 
-       while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       cnt = hdev->acl_cnt;
+
+       while (hdev->acl_cnt &&
+                       (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
 
-                       hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
+
+                       hci_conn_enter_active_mode(chan->conn,
+                                               bt_cb(skb)->force_active);
 
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
                        hdev->acl_cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
+       if (cnt != hdev->acl_cnt)
+               hci_prio_recalculate(hdev, ACL_LINK);
 }
 
 /* Schedule SCO */
@@ -2182,9 +2347,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 
 static inline void hci_sched_le(struct hci_dev *hdev)
 {
-       struct hci_conn *conn;
+       struct hci_chan *chan;
        struct sk_buff *skb;
-       int quote, cnt;
+       int quote, cnt, tmp;
 
        BT_DBG("%s", hdev->name);
 
@@ -2200,21 +2365,35 @@ static inline void hci_sched_le(struct hci_dev *hdev)
        }
 
        cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
-       while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
-               while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
-                       BT_DBG("skb %p len %d", skb, skb->len);
+       tmp = cnt;
+       while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
+               u32 priority = (skb_peek(&chan->data_q))->priority;
+               while (quote-- && (skb = skb_peek(&chan->data_q))) {
+                       BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
+                                       skb->len, skb->priority);
+
+                       /* Stop if priority has changed */
+                       if (skb->priority < priority)
+                               break;
+
+                       skb = skb_dequeue(&chan->data_q);
 
                        hci_send_frame(skb);
                        hdev->le_last_tx = jiffies;
 
                        cnt--;
-                       conn->sent++;
+                       chan->sent++;
+                       chan->conn->sent++;
                }
        }
+
        if (hdev->le_pkts)
                hdev->le_cnt = cnt;
        else
                hdev->acl_cnt = cnt;
+
+       if (cnt != tmp)
+               hci_prio_recalculate(hdev, LE_LINK);
 }
 
 static void hci_tx_task(unsigned long arg)
@@ -2407,3 +2586,31 @@ static void hci_cmd_task(unsigned long arg)
                }
        }
 }
+
+int hci_do_inquiry(struct hci_dev *hdev, u8 length)
+{
+       /* General inquiry access code (GIAC) */
+       u8 lap[3] = { 0x33, 0x8b, 0x9e };
+       struct hci_cp_inquiry cp;
+
+       BT_DBG("%s", hdev->name);
+
+       if (test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EINPROGRESS;
+
+       memset(&cp, 0, sizeof(cp));
+       memcpy(&cp.lap, lap, sizeof(cp.lap));
+       cp.length  = length;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+}
+
+int hci_cancel_inquiry(struct hci_dev *hdev)
+{
+       BT_DBG("%s", hdev->name);
+
+       if (!test_bit(HCI_INQUIRY, &hdev->flags))
+               return -EPERM;
+
+       return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+}
index d7d96b6b1f0d63b338e5ed58fb125fbc6290aff5..a89cf1f24e47697d14f009900ac8a3ee8fe0e549 100644 (file)
@@ -58,9 +58,11 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                       test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
+       clear_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 
        hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
 
@@ -76,10 +78,6 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
        if (status)
                return;
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_conn_check_pending(hdev);
 }
 
@@ -205,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_set_local_name_complete(hdev->id, sent, status);
+               mgmt_set_local_name_complete(hdev, sent, status);
 
-       if (status)
-               return;
+       if (status == 0)
+               memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
 
-       memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -274,7 +274,8 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
 static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
 {
-       __u8 status = *((__u8 *) skb->data);
+       __u8 param, status = *((__u8 *) skb->data);
+       int old_pscan, old_iscan;
        void *sent;
 
        BT_DBG("%s status 0x%x", hdev->name, status);
@@ -283,28 +284,40 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
-       if (!status) {
-               __u8 param = *((__u8 *) sent);
-               int old_pscan, old_iscan;
-
-               old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
-               old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+       param = *((__u8 *) sent);
 
-               if (param & SCAN_INQUIRY) {
-                       set_bit(HCI_ISCAN, &hdev->flags);
-                       if (!old_iscan)
-                               mgmt_discoverable(hdev->id, 1);
-               } else if (old_iscan)
-                       mgmt_discoverable(hdev->id, 0);
+       hci_dev_lock(hdev);
 
-               if (param & SCAN_PAGE) {
-                       set_bit(HCI_PSCAN, &hdev->flags);
-                       if (!old_pscan)
-                               mgmt_connectable(hdev->id, 1);
-               } else if (old_pscan)
-                       mgmt_connectable(hdev->id, 0);
+       if (status != 0) {
+               mgmt_write_scan_failed(hdev, param, status);
+               hdev->discov_timeout = 0;
+               goto done;
        }
 
+       old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
+       old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
+
+       if (param & SCAN_INQUIRY) {
+               set_bit(HCI_ISCAN, &hdev->flags);
+               if (!old_iscan)
+                       mgmt_discoverable(hdev, 1);
+               if (hdev->discov_timeout > 0) {
+                       int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
+                       queue_delayed_work(hdev->workqueue, &hdev->discov_off,
+                                                                       to);
+               }
+       } else if (old_iscan)
+               mgmt_discoverable(hdev, 0);
+
+       if (param & SCAN_PAGE) {
+               set_bit(HCI_PSCAN, &hdev->flags);
+               if (!old_pscan)
+                       mgmt_connectable(hdev, 1);
+       } else if (old_pscan)
+               mgmt_connectable(hdev, 0);
+
+done:
+       hci_dev_unlock(hdev);
        hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
 }
 
@@ -748,6 +761,30 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
        hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
 }
 
+static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
+               struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+
+       if (rp->status)
+               return;
+
+       hdev->amp_status = rp->amp_status;
+       hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
+       hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
+       hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
+       hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
+       hdev->amp_type = rp->amp_type;
+       hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
+       hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
+       hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
+       hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
+
+       hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+}
+
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
                                                        struct sk_buff *skb)
 {
@@ -804,19 +841,24 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
+               mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
 
        if (rp->status != 0)
-               return;
+               goto unlock;
 
        cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
        if (!cp)
-               return;
+               goto unlock;
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
        if (conn)
                conn->pin_length = cp->pin_len;
+
+unlock:
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -825,10 +867,15 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
+
 static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
                                       struct sk_buff *skb)
 {
@@ -855,9 +902,13 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
@@ -867,9 +918,13 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
+       hci_dev_lock(hdev);
+
        if (test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
+               mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
                                                                rp->status);
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
@@ -879,8 +934,10 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
 
        BT_DBG("%s status 0x%x", hdev->name, rp->status);
 
-       mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
+       hci_dev_lock(hdev);
+       mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
                                                rp->randomizer, rp->status);
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
@@ -955,12 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
        if (status) {
                hci_req_complete(hdev, HCI_OP_INQUIRY, status);
                hci_conn_check_pending(hdev);
+               hci_dev_lock(hdev);
+               if (test_bit(HCI_MGMT, &hdev->flags))
+                       mgmt_inquiry_failed(hdev, status);
+               hci_dev_unlock(hdev);
                return;
        }
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 1);
+       set_bit(HCI_INQUIRY, &hdev->flags);
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 1);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
@@ -1339,13 +1402,16 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
 
        BT_DBG("%s status %d", hdev->name, status);
 
-       if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
-                               test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_discovering(hdev->id, 0);
-
        hci_req_complete(hdev, HCI_OP_INQUIRY, status);
 
        hci_conn_check_pending(hdev);
+
+       if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
+               return;
+
+       hci_dev_lock(hdev);
+       mgmt_discovering(hdev, 0);
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1361,12 +1427,6 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        for (; num_rsp; num_rsp--, info++) {
                bacpy(&data.bdaddr, &info->bdaddr);
                data.pscan_rep_mode     = info->pscan_rep_mode;
@@ -1377,8 +1437,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
                data.rssi               = 0x00;
                data.ssp_mode           = 0x00;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
-                                                                       NULL);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                                               info->dev_class, 0, NULL);
        }
 
        hci_dev_unlock(hdev);
@@ -1412,7 +1472,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
                        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-                       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+                       mgmt_connected(hdev, &ev->bdaddr, conn->type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -1444,7 +1504,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        } else {
                conn->state = BT_CLOSED;
                if (conn->type == ACL_LINK)
-                       mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+                       mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
+                                                               ev->status);
        }
 
        if (conn->type == ACL_LINK)
@@ -1531,7 +1592,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
                struct hci_cp_reject_conn_req cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x0f;
+               cp.reason = HCI_ERROR_REJ_BAD_ADDR;
                hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
        }
 }
@@ -1544,7 +1605,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        BT_DBG("%s status %d", hdev->name, ev->status);
 
        if (ev->status) {
-               mgmt_disconnect_failed(hdev->id);
+               hci_dev_lock(hdev);
+               mgmt_disconnect_failed(hdev);
+               hci_dev_unlock(hdev);
                return;
        }
 
@@ -1557,7 +1620,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        conn->state = BT_CLOSED;
 
        if (conn->type == ACL_LINK || conn->type == LE_LINK)
-               mgmt_disconnected(hdev->id, &conn->dst);
+               mgmt_disconnected(hdev, &conn->dst, conn->type);
 
        hci_proto_disconn_cfm(conn, ev->reason);
        hci_conn_del(conn);
@@ -1588,7 +1651,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->sec_level = conn->pending_sec_level;
                }
        } else {
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
        }
 
        clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
@@ -1643,7 +1706,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
        hci_dev_lock(hdev);
 
        if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
-               mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
+               mgmt_remote_name(hdev, &ev->bdaddr, ev->name);
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
        if (!conn)
@@ -1898,6 +1961,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
                hci_cc_write_ca_timeout(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_AMP_INFO:
+               hci_cc_read_local_amp_info(hdev, skb);
+               break;
+
        case HCI_OP_DELETE_STORED_LINK_KEY:
                hci_cc_delete_stored_link_key(hdev, skb);
                break;
@@ -2029,7 +2096,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        case HCI_OP_DISCONNECT:
                if (ev->status != 0)
-                       mgmt_disconnect_failed(hdev->id);
+                       mgmt_disconnect_failed(hdev);
                break;
 
        case HCI_OP_LE_CREATE_CONN:
@@ -2194,7 +2261,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
                else
                        secure = 0;
 
-               mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
+               mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
        }
 
 unlock:
@@ -2363,12 +2430,6 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
 
        hci_dev_lock(hdev);
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
                struct inquiry_info_with_rssi_and_pscan_mode *info;
                info = (void *) (skb->data + 1);
@@ -2383,7 +2444,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2400,7 +2461,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
                        data.rssi               = info->rssi;
                        data.ssp_mode           = 0x00;
                        hci_inquiry_cache_update(hdev, &data);
-                       mgmt_device_found(hdev->id, &info->bdaddr,
+                       mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
                                                info->dev_class, info->rssi,
                                                NULL);
                }
@@ -2531,12 +2592,6 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
        if (!num_rsp)
                return;
 
-       if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
-
-               if (test_bit(HCI_MGMT, &hdev->flags))
-                       mgmt_discovering(hdev->id, 1);
-       }
-
        hci_dev_lock(hdev);
 
        for (; num_rsp; num_rsp--, info++) {
@@ -2549,8 +2604,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
                data.rssi               = info->rssi;
                data.ssp_mode           = 0x01;
                hci_inquiry_cache_update(hdev, &data);
-               mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
-                                               info->rssi, info->data);
+               mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
+                               info->dev_class, info->rssi, info->data);
        }
 
        hci_dev_unlock(hdev);
@@ -2614,7 +2669,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
                struct hci_cp_io_capability_neg_reply cp;
 
                bacpy(&cp.bdaddr, &ev->bdaddr);
-               cp.reason = 0x18; /* Pairing not allowed */
+               cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
 
                hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
                                                        sizeof(cp), &cp);
@@ -2706,7 +2761,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
        }
 
 confirm:
-       mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
+       mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
                                                                confirm_hint);
 
 unlock:
@@ -2732,7 +2787,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
         * event gets always produced as initiator and is also mapped to
         * the mgmt_auth_failed event */
        if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0)
-               mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
+               mgmt_auth_failed(hdev, &conn->dst, ev->status);
 
        hci_conn_put(conn);
 
@@ -2813,14 +2868,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
        }
 
        if (ev->status) {
-               mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
+               mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
                hci_proto_connect_cfm(conn, ev->status);
                conn->state = BT_CLOSED;
                hci_conn_del(conn);
                goto unlock;
        }
 
-       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
+       mgmt_connected(hdev, &ev->bdaddr, conn->type);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
@@ -3104,5 +3159,5 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
        kfree_skb(skb);
 }
 
-module_param(enable_le, bool, 0444);
+module_param(enable_le, bool, 0644);
 MODULE_PARM_DESC(enable_le, "Enable LE support");
index 661b461cf0b0873983b8fae4dbb83ad80d4de505..c62d254a1379f5cf255b97863f6df4009ce4a7d4 100644 (file)
@@ -436,17 +436,12 @@ static const struct file_operations inquiry_cache_fops = {
 static int blacklist_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bdaddr_list *b;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->blacklist) {
-               struct bdaddr_list *b;
-
-               b = list_entry(l, struct bdaddr_list, list);
-
+       list_for_each_entry(b, &hdev->blacklist, list)
                seq_printf(f, "%s\n", batostr(&b->bdaddr));
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -485,17 +480,12 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
 static int uuids_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *l;
+       struct bt_uuid *uuid;
 
        hci_dev_lock_bh(hdev);
 
-       list_for_each(l, &hdev->uuids) {
-               struct bt_uuid *uuid;
-
-               uuid = list_entry(l, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                print_bt_uuid(f, uuid->uuid);
-       }
 
        hci_dev_unlock_bh(hdev);
 
@@ -543,22 +533,28 @@ static int auto_accept_delay_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
                                        auto_accept_delay_set, "%llu\n");
 
-int hci_register_sysfs(struct hci_dev *hdev)
+void hci_init_sysfs(struct hci_dev *hdev)
+{
+       struct device *dev = &hdev->dev;
+
+       dev->type = &bt_host;
+       dev->class = bt_class;
+
+       dev_set_drvdata(dev, hdev);
+       device_initialize(dev);
+}
+
+int hci_add_sysfs(struct hci_dev *hdev)
 {
        struct device *dev = &hdev->dev;
        int err;
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       dev->type = &bt_host;
-       dev->class = bt_class;
        dev->parent = hdev->parent;
-
        dev_set_name(dev, "%s", hdev->name);
 
-       dev_set_drvdata(dev, hdev);
-
-       err = device_register(dev);
+       err = device_add(dev);
        if (err < 0)
                return err;
 
@@ -582,7 +578,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
        return 0;
 }
 
-void hci_unregister_sysfs(struct hci_dev *hdev)
+void hci_del_sysfs(struct hci_dev *hdev)
 {
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
index 075a3e920caffcbd44ff2f5a1e9e6ab4cc560e45..3c2d888925d7a8436b19ef8d1562fe9a7943a780 100644 (file)
@@ -81,24 +81,20 @@ static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
 static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
 {
        struct hidp_session *session;
-       struct list_head *p;
 
        BT_DBG("");
 
-       list_for_each(p, &hidp_session_list) {
-               session = list_entry(p, struct hidp_session, list);
+       list_for_each_entry(session, &hidp_session_list, list) {
                if (!bacmp(bdaddr, &session->bdaddr))
                        return session;
        }
+
        return NULL;
 }
 
 static void __hidp_link_session(struct hidp_session *session)
 {
-       __module_get(THIS_MODULE);
        list_add(&session->list, &hidp_session_list);
-
-       hci_conn_hold_device(session->conn);
 }
 
 static void __hidp_unlink_session(struct hidp_session *session)
@@ -106,7 +102,6 @@ static void __hidp_unlink_session(struct hidp_session *session)
        hci_conn_put_device(session->conn);
 
        list_del(&session->list);
-       module_put(THIS_MODULE);
 }
 
 static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
@@ -255,6 +250,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
 
        BT_DBG("session %p data %p size %d", session, data, size);
 
+       if (atomic_read(&session->terminate))
+               return -EIO;
+
        skb = alloc_skb(size + 1, GFP_ATOMIC);
        if (!skb) {
                BT_ERR("Can't allocate memory for new frame");
@@ -329,6 +327,7 @@ static int hidp_get_raw_report(struct hid_device *hid,
        struct sk_buff *skb;
        size_t len;
        int numbered_reports = hid->report_enum[report_type].numbered;
+       int ret;
 
        switch (report_type) {
        case HID_FEATURE_REPORT:
@@ -352,8 +351,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
        session->waiting_report_number = numbered_reports ? report_number : -1;
        set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        data[0] = report_number;
-       if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1))
-               goto err_eio;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
+       if (ret)
+               goto err;
 
        /* Wait for the return of the report. The returned report
           gets put in session->report_return.  */
@@ -365,11 +365,13 @@ static int hidp_get_raw_report(struct hid_device *hid,
                        5*HZ);
                if (res == 0) {
                        /* timeout */
-                       goto err_eio;
+                       ret = -EIO;
+                       goto err;
                }
                if (res < 0) {
                        /* signal */
-                       goto err_restartsys;
+                       ret = -ERESTARTSYS;
+                       goto err;
                }
        }
 
@@ -390,14 +392,10 @@ static int hidp_get_raw_report(struct hid_device *hid,
 
        return len;
 
-err_restartsys:
-       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
-       mutex_unlock(&session->report_mutex);
-       return -ERESTARTSYS;
-err_eio:
+err:
        clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
        mutex_unlock(&session->report_mutex);
-       return -EIO;
+       return ret;
 }
 
 static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
@@ -422,11 +420,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
 
        /* Set up our wait, and send the report request to the device. */
        set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
-       if (hidp_send_ctrl_message(hid->driver_data, report_type,
-                       data, count)) {
-               ret = -ENOMEM;
+       ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
+                                                                       count);
+       if (ret)
                goto err;
-       }
 
        /* Wait for the ACK from the device. */
        while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
@@ -496,10 +493,9 @@ static void hidp_process_handshake(struct hidp_session *session,
        case HIDP_HSHK_ERR_INVALID_REPORT_ID:
        case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
        case HIDP_HSHK_ERR_INVALID_PARAMETER:
-               if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
-                       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+               if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
                        wake_up_interruptible(&session->report_queue);
-               }
+
                /* FIXME: Call into SET_ GET_ handlers here */
                break;
 
@@ -520,10 +516,8 @@ static void hidp_process_handshake(struct hidp_session *session,
        }
 
        /* Wake up the waiting thread. */
-       if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
-               clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
                wake_up_interruptible(&session->report_queue);
-       }
 }
 
 static void hidp_process_hid_control(struct hidp_session *session,
@@ -663,25 +657,32 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
-static void hidp_process_transmit(struct hidp_session *session)
+static void hidp_process_intr_transmit(struct hidp_session *session)
 {
        struct sk_buff *skb;
 
        BT_DBG("session %p", session);
 
-       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
-               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->ctrl_transmit, skb);
+       while ((skb = skb_dequeue(&session->intr_transmit))) {
+               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->intr_transmit, skb);
                        break;
                }
 
                hidp_set_timer(session);
                kfree_skb(skb);
        }
+}
 
-       while ((skb = skb_dequeue(&session->intr_transmit))) {
-               if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
-                       skb_queue_head(&session->intr_transmit, skb);
+static void hidp_process_ctrl_transmit(struct hidp_session *session)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("session %p", session);
+
+       while ((skb = skb_dequeue(&session->ctrl_transmit))) {
+               if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
+                       skb_queue_head(&session->ctrl_transmit, skb);
                        break;
                }
 
@@ -700,6 +701,7 @@ static int hidp_session(void *arg)
 
        BT_DBG("session %p", session);
 
+       __module_get(THIS_MODULE);
        set_user_nice(current, -15);
 
        init_waitqueue_entry(&ctrl_wait, current);
@@ -714,23 +716,25 @@ static int hidp_session(void *arg)
                                intr_sk->sk_state != BT_CONNECTED)
                        break;
 
-               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
+               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_ctrl_frame(session, skb);
+                               hidp_recv_intr_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
+               hidp_process_intr_transmit(session);
+
+               while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
                        skb_orphan(skb);
                        if (!skb_linearize(skb))
-                               hidp_recv_intr_frame(session, skb);
+                               hidp_recv_ctrl_frame(session, skb);
                        else
                                kfree_skb(skb);
                }
 
-               hidp_process_transmit(session);
+               hidp_process_ctrl_transmit(session);
 
                schedule();
                set_current_state(TASK_INTERRUPTIBLE);
@@ -739,6 +743,10 @@ static int hidp_session(void *arg)
        remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
        remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
 
+       clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
+       clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
+       wake_up_interruptible(&session->report_queue);
+
        down_write(&hidp_session_sem);
 
        hidp_del_timer(session);
@@ -772,34 +780,37 @@ static int hidp_session(void *arg)
 
        kfree(session->rd_data);
        kfree(session);
+       module_put_and_exit(0);
        return 0;
 }
 
-static struct device *hidp_get_device(struct hidp_session *session)
+static struct hci_conn *hidp_get_connection(struct hidp_session *session)
 {
        bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
        bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
-       struct device *device = NULL;
+       struct hci_conn *conn;
        struct hci_dev *hdev;
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
                return NULL;
 
-       session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
-       if (session->conn)
-               device = &session->conn->dev;
+       hci_dev_lock_bh(hdev);
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+       if (conn)
+               hci_conn_hold_device(conn);
+       hci_dev_unlock_bh(hdev);
 
        hci_dev_put(hdev);
 
-       return device;
+       return conn;
 }
 
 static int hidp_setup_input(struct hidp_session *session,
                                struct hidp_connadd_req *req)
 {
        struct input_dev *input;
-       int err, i;
+       int i;
 
        input = input_allocate_device();
        if (!input)
@@ -842,17 +853,10 @@ static int hidp_setup_input(struct hidp_session *session,
                input->relbit[0] |= BIT_MASK(REL_WHEEL);
        }
 
-       input->dev.parent = hidp_get_device(session);
+       input->dev.parent = &session->conn->dev;
 
        input->event = hidp_input_event;
 
-       err = input_register_device(input);
-       if (err < 0) {
-               input_free_device(input);
-               session->input = NULL;
-               return err;
-       }
-
        return 0;
 }
 
@@ -949,7 +953,7 @@ static int hidp_setup_hid(struct hidp_session *session,
        strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
        strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
 
-       hid->dev.parent = hidp_get_device(session);
+       hid->dev.parent = &session->conn->dev;
        hid->ll_driver = &hidp_hid_driver;
 
        hid->hid_get_raw_report = hidp_get_raw_report;
@@ -976,18 +980,20 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
                return -ENOTUNIQ;
 
-       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
-       if (!session)
-               return -ENOMEM;
-
        BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
 
        down_write(&hidp_session_sem);
 
        s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
        if (s && s->state == BT_CONNECTED) {
-               err = -EEXIST;
-               goto failed;
+               up_write(&hidp_session_sem);
+               return -EEXIST;
+       }
+
+       session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
+       if (!session) {
+               up_write(&hidp_session_sem);
+               return -ENOMEM;
        }
 
        bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
@@ -1003,6 +1009,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->intr_sock = intr_sock;
        session->state     = BT_CONNECTED;
 
+       session->conn = hidp_get_connection(session);
+       if (!session->conn) {
+               err = -ENOTCONN;
+               goto failed;
+       }
+
        setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
 
        skb_queue_head_init(&session->ctrl_transmit);
@@ -1015,9 +1027,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
        session->flags   = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
        session->idle_to = req->idle_to;
 
+       __hidp_link_session(session);
+
        if (req->rd_size > 0) {
                err = hidp_setup_hid(session, req);
-               if (err && err != -ENODEV)
+               if (err)
                        goto purge;
        }
 
@@ -1027,8 +1041,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        goto purge;
        }
 
-       __hidp_link_session(session);
-
        hidp_set_timer(session);
 
        if (session->hid) {
@@ -1054,7 +1066,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
                        !session->waiting_for_startup);
        }
 
-       err = hid_add_device(session->hid);
+       if (session->hid)
+               err = hid_add_device(session->hid);
+       else
+               err = input_register_device(session->input);
+
        if (err < 0) {
                atomic_inc(&session->terminate);
                wake_up_process(session->task);
@@ -1077,8 +1093,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
 unlink:
        hidp_del_timer(session);
 
-       __hidp_unlink_session(session);
-
        if (session->input) {
                input_unregister_device(session->input);
                session->input = NULL;
@@ -1093,6 +1107,8 @@ unlink:
        session->rd_data = NULL;
 
 purge:
+       __hidp_unlink_session(session);
+
        skb_queue_purge(&session->ctrl_transmit);
        skb_queue_purge(&session->intr_transmit);
 
@@ -1134,19 +1150,16 @@ int hidp_del_connection(struct hidp_conndel_req *req)
 
 int hidp_get_connlist(struct hidp_connlist_req *req)
 {
-       struct list_head *p;
+       struct hidp_session *session;
        int err = 0, n = 0;
 
        BT_DBG("");
 
        down_read(&hidp_session_sem);
 
-       list_for_each(p, &hidp_session_list) {
-               struct hidp_session *session;
+       list_for_each_entry(session, &hidp_session_list, list) {
                struct hidp_conninfo ci;
 
-               session = list_entry(p, struct hidp_session, list);
-
                __hidp_copy_session(session, &ci);
 
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
index 8cd12917733b2cb37f21670edd846c9071e19459..e8a6837996cf311c3156c6c7b18ffc92cb0fba84 100644 (file)
 #include <net/bluetooth/smp.h>
 
 int disable_ertm;
+int enable_hs;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
-static u8 l2cap_fixed_chan[8] = { 0x02, };
+static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
 
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
@@ -219,7 +220,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 
 static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
 {
-       BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
+       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
 
        if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
                chan_hold(chan);
@@ -251,7 +252,7 @@ static void l2cap_chan_timeout(unsigned long arg)
 
        if (sock_owned_by_user(sk)) {
                /* sk is owned by user. Try again later */
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                chan_put(chan);
                return;
@@ -293,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
 
        atomic_set(&chan->refcnt, 1);
 
+       BT_DBG("sk %p chan %p", sk, chan);
+
        return chan;
 }
 
@@ -310,7 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        chan->conn = conn;
 
@@ -337,6 +340,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
                chan->omtu = L2CAP_DEFAULT_MTU;
        }
 
+       chan->local_id          = L2CAP_BESTEFFORT_ID;
+       chan->local_stype       = L2CAP_SERV_BESTEFFORT;
+       chan->local_msdu        = L2CAP_DEFAULT_MAX_SDU_SIZE;
+       chan->local_sdu_itime   = L2CAP_DEFAULT_SDU_ITIME;
+       chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
+       chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
+
        chan_hold(chan);
 
        list_add(&chan->list, &conn->chan_l);
@@ -556,34 +566,58 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
                flags = ACL_START;
 
        bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
+       skb->priority = HCI_PRIO_MAX;
+
+       hci_send_acl(conn->hchan, skb, flags);
+}
+
+static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+       struct hci_conn *hcon = chan->conn->hcon;
+       u16 flags;
+
+       BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
+                                                       skb->priority);
+
+       if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
+                                       lmp_no_flush_capable(hcon->hdev))
+               flags = ACL_START_NO_FLUSH;
+       else
+               flags = ACL_START;
 
-       hci_send_acl(conn->hcon, skb, flags);
+       bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+       hci_send_acl(chan->conn->hchan, skb, flags);
 }
 
-static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
 {
        struct sk_buff *skb;
        struct l2cap_hdr *lh;
        struct l2cap_conn *conn = chan->conn;
-       int count, hlen = L2CAP_HDR_SIZE + 2;
-       u8 flags;
+       int count, hlen;
 
        if (chan->state != BT_CONNECTED)
                return;
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
-       BT_DBG("chan %p, control 0x%2.2x", chan, control);
+       BT_DBG("chan %p, control 0x%8.8x", chan, control);
 
        count = min_t(unsigned int, conn->mtu, hlen);
-       control |= L2CAP_CTRL_FRAME_TYPE;
+
+       control |= __set_sframe(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
        if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_POLL;
+               control |= __set_ctrl_poll(chan);
 
        skb = bt_skb_alloc(count, GFP_ATOMIC);
        if (!skb)
@@ -592,32 +626,27 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               u16 fcs = crc16(0, (u8 *)lh, count - 2);
-               put_unaligned_le16(fcs, skb_put(skb, 2));
+               u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
        }
 
-       if (lmp_no_flush_capable(conn->hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-
-       hci_send_acl(chan->conn->hcon, skb, flags);
+       skb->priority = HCI_PRIO_MAX;
+       l2cap_do_send(chan, skb);
 }
 
-static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
+static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
 {
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        } else
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -947,7 +976,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        list_for_each_entry(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        sk->sk_err = err;
        }
 
@@ -986,6 +1015,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
                chan->ops->close(chan->data);
        }
 
+       hci_chan_del(conn->hchan);
+
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                del_timer_sync(&conn->info_timer);
 
@@ -1008,18 +1039,26 @@ static void security_timeout(unsigned long arg)
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct hci_chan *hchan;
 
        if (conn || status)
                return conn;
 
+       hchan = hci_chan_create(hcon);
+       if (!hchan)
+               return NULL;
+
        conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
-       if (!conn)
+       if (!conn) {
+               hci_chan_del(hchan);
                return NULL;
+       }
 
        hcon->l2cap_data = conn;
        conn->hcon = hcon;
+       conn->hchan = hchan;
 
-       BT_DBG("hcon %p conn %p", hcon, conn);
+       BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
 
        if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
                conn->mtu = hcon->hdev->le_mtu;
@@ -1043,7 +1082,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
                setup_timer(&conn->info_timer, l2cap_info_timeout,
                                                (unsigned long) conn);
 
-       conn->disc_reason = 0x13;
+       conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
 
        return conn;
 }
@@ -1245,47 +1284,35 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
                __clear_retrans_timer(chan);
 }
 
-static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
-{
-       struct hci_conn *hcon = chan->conn->hcon;
-       u16 flags;
-
-       BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
-
-       if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
-               flags = ACL_START_NO_FLUSH;
-       else
-               flags = ACL_START;
-
-       bt_cb(skb)->force_active = chan->force_active;
-       hci_send_acl(hcon, skb, flags);
-}
-
 static void l2cap_streaming_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb;
-       u16 control, fcs;
+       u32 control;
+       u16 fcs;
 
        while ((skb = skb_dequeue(&chan->tx_q))) {
-               control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
-               control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
-               put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
+               control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
+               control |= __set_txseq(chan, chan->next_tx_seq);
+               __put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs,
+                                       skb->data + skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, skb);
 
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
        }
 }
 
-static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
 
        skb = skb_peek(&chan->tx_q);
        if (!skb)
@@ -1308,20 +1335,23 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 
        tx_skb = skb_clone(skb, GFP_ATOMIC);
        bt_cb(skb)->retries++;
-       control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-       control &= L2CAP_CTRL_SAR;
+
+       control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+       control &= __get_sar_mask(chan);
 
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-               control |= L2CAP_CTRL_FINAL;
+               control |= __set_ctrl_final(chan);
 
-       control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                       | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
+       control |= __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_txseq(chan, tx_seq);
 
-       put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+       __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
-               put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
+               fcs = crc16(0, (u8 *)tx_skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+               put_unaligned_le16(fcs,
+                               tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
        }
 
        l2cap_do_send(chan, tx_skb);
@@ -1330,7 +1360,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
 static int l2cap_ertm_send(struct l2cap_chan *chan)
 {
        struct sk_buff *skb, *tx_skb;
-       u16 control, fcs;
+       u16 fcs;
+       u32 control;
        int nsent = 0;
 
        if (chan->state != BT_CONNECTED)
@@ -1348,20 +1379,22 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
 
                bt_cb(skb)->retries++;
 
-               control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
-               control &= L2CAP_CTRL_SAR;
+               control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
+               control &= __get_sar_mask(chan);
 
                if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
-                       control |= L2CAP_CTRL_FINAL;
+                       control |= __set_ctrl_final(chan);
 
-               control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
-                               | (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
-               put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
+               control |= __set_reqseq(chan, chan->buffer_seq);
+               control |= __set_txseq(chan, chan->next_tx_seq);
 
+               __put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
 
                if (chan->fcs == L2CAP_FCS_CRC16) {
-                       fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
-                       put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
+                       fcs = crc16(0, (u8 *)skb->data,
+                                               tx_skb->len - L2CAP_FCS_SIZE);
+                       put_unaligned_le16(fcs, skb->data +
+                                               tx_skb->len - L2CAP_FCS_SIZE);
                }
 
                l2cap_do_send(chan, tx_skb);
@@ -1369,7 +1402,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
                __set_retrans_timer(chan);
 
                bt_cb(skb)->tx_seq = chan->next_tx_seq;
-               chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
+
+               chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
 
                if (bt_cb(skb)->retries == 1)
                        chan->unacked_frames++;
@@ -1401,12 +1435,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
 
 static void l2cap_send_ack(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
                l2cap_send_sframe(chan, control);
                return;
@@ -1415,20 +1449,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
        if (l2cap_ertm_send(chan) > 0)
                return;
 
-       control |= L2CAP_SUPER_RCV_READY;
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
 }
 
 static void l2cap_send_srejtail(struct l2cap_chan *chan)
 {
        struct srej_list *tail;
-       u16 control;
+       u32 control;
 
-       control = L2CAP_SUPER_SELECT_REJECT;
-       control |= L2CAP_CTRL_FINAL;
+       control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+       control |= __set_ctrl_final(chan);
 
        tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
-       control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, tail->tx_seq);
 
        l2cap_send_sframe(chan, control);
 }
@@ -1456,6 +1490,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
                if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
                        return -EFAULT;
 
+               (*frag)->priority = skb->priority;
+
                sent += count;
                len  -= count;
 
@@ -1465,15 +1501,17 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
        return sent;
 }
 
-static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
        struct l2cap_hdr *lh;
 
-       BT_DBG("sk %p len %d", sk, (int)len);
+       BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1481,6 +1519,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1495,7 +1535,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
        return skb;
 }
 
-static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u32 priority)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
@@ -1511,6 +1553,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
        if (!skb)
                return ERR_PTR(err);
 
+       skb->priority = priority;
+
        /* Create L2CAP header */
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
@@ -1526,12 +1570,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
 
 static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
                                                struct msghdr *msg, size_t len,
-                                               u16 control, u16 sdulen)
+                                               u32 control, u16 sdulen)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
        struct sk_buff *skb;
-       int err, count, hlen = L2CAP_HDR_SIZE + 2;
+       int err, count, hlen;
        struct l2cap_hdr *lh;
 
        BT_DBG("sk %p len %d", sk, (int)len);
@@ -1539,11 +1583,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        if (!conn)
                return ERR_PTR(-ENOTCONN);
 
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hlen = L2CAP_EXT_HDR_SIZE;
+       else
+               hlen = L2CAP_ENH_HDR_SIZE;
+
        if (sdulen)
-               hlen += 2;
+               hlen += L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               hlen += 2;
+               hlen += L2CAP_FCS_SIZE;
 
        count = min_t(unsigned int, (conn->mtu - hlen), len);
        skb = bt_skb_send_alloc(sk, count + hlen,
@@ -1555,9 +1604,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->cid = cpu_to_le16(chan->dcid);
        lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
-       put_unaligned_le16(control, skb_put(skb, 2));
+
+       __put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
+
        if (sdulen)
-               put_unaligned_le16(sdulen, skb_put(skb, 2));
+               put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
 
        err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
        if (unlikely(err < 0)) {
@@ -1566,7 +1617,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
        }
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               put_unaligned_le16(0, skb_put(skb, 2));
+               put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
 
        bt_cb(skb)->retries = 0;
        return skb;
@@ -1576,11 +1627,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
 {
        struct sk_buff *skb;
        struct sk_buff_head sar_queue;
-       u16 control;
+       u32 control;
        size_t size = 0;
 
        skb_queue_head_init(&sar_queue);
-       control = L2CAP_SDU_START;
+       control = __set_ctrl_sar(chan, L2CAP_SAR_START);
        skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
        if (IS_ERR(skb))
                return PTR_ERR(skb);
@@ -1593,10 +1644,10 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
                size_t buflen;
 
                if (len > chan->remote_mps) {
-                       control = L2CAP_SDU_CONTINUE;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
                        buflen = chan->remote_mps;
                } else {
-                       control = L2CAP_SDU_END;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_END);
                        buflen = len;
                }
 
@@ -1617,15 +1668,16 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
        return size;
 }
 
-int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
+int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
+                                                               u32 priority)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
        int err;
 
        /* Connectionless channel */
        if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
-               skb = l2cap_create_connless_pdu(chan, msg, len);
+               skb = l2cap_create_connless_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1640,7 +1692,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
                        return -EMSGSIZE;
 
                /* Create a basic PDU */
-               skb = l2cap_create_basic_pdu(chan, msg, len);
+               skb = l2cap_create_basic_pdu(chan, msg, len, priority);
                if (IS_ERR(skb))
                        return PTR_ERR(skb);
 
@@ -1652,7 +1704,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
        case L2CAP_MODE_STREAMING:
                /* Entire SDU fits into one PDU */
                if (len <= chan->remote_mps) {
-                       control = L2CAP_SDU_UNSEGMENTED;
+                       control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
                        skb = l2cap_create_iframe_pdu(chan, msg, len, control,
                                                                        0);
                        if (IS_ERR(skb))
@@ -1850,6 +1902,37 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
        *ptr += L2CAP_CONF_OPT_SIZE + len;
 }
 
+static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
+{
+       struct l2cap_conf_efs efs;
+
+       switch(chan->mode) {
+       case L2CAP_MODE_ERTM:
+               efs.id          = chan->local_id;
+               efs.stype       = chan->local_stype;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
+               efs.flush_to    = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               break;
+
+       case L2CAP_MODE_STREAMING:
+               efs.id          = 1;
+               efs.stype       = L2CAP_SERV_BESTEFFORT;
+               efs.msdu        = cpu_to_le16(chan->local_msdu);
+               efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
+               efs.acc_lat     = 0;
+               efs.flush_to    = 0;
+               break;
+
+       default:
+               return;
+       }
+
+       l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
+                                                       (unsigned long) &efs);
+}
+
 static void l2cap_ack_timeout(unsigned long arg)
 {
        struct l2cap_chan *chan = (void *) arg;
@@ -1896,11 +1979,36 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
        }
 }
 
+static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
+}
+
+static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
+{
+       return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
+}
+
+static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
+{
+       if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
+                                               __l2cap_ews_supported(chan)) {
+               /* use extended control field */
+               set_bit(FLAG_EXT_CTRL, &chan->flags);
+               chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+       } else {
+               chan->tx_win = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
+       }
+}
+
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
 {
        struct l2cap_conf_req *req = data;
        struct l2cap_conf_rfc rfc = { .mode = chan->mode };
        void *ptr = req->data;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -1913,6 +2021,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
                if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
                        break;
 
+               if (__l2cap_efs_supported(chan))
+                       set_bit(FLAG_EFS_ENABLE, &chan->flags);
+
                /* fall through */
        default:
                chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
@@ -1942,17 +2053,27 @@ done:
 
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
-               rfc.txwin_size      = chan->tx_win;
                rfc.max_transmit    = chan->max_tx;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
+
+               l2cap_txwin_setup(chan);
+
+               rfc.txwin_size = min_t(u16, chan->tx_win,
+                                               L2CAP_DEFAULT_TX_WINDOW);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -1961,6 +2082,10 @@ done:
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
+
+               if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                               chan->tx_win);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -1969,13 +2094,19 @@ done:
                rfc.max_transmit    = 0;
                rfc.retrans_timeout = 0;
                rfc.monitor_timeout = 0;
-               rfc.max_pdu_size    = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
-               if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
-                       rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+
+               size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+               rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
                                                        (unsigned long) &rfc);
 
+               if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
+                       l2cap_add_opt_efs(&ptr, chan);
+
                if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
                        break;
 
@@ -2002,8 +2133,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
        int type, hint, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
+       struct l2cap_conf_efs efs;
+       u8 remote_efs = 0;
        u16 mtu = L2CAP_DEFAULT_MTU;
        u16 result = L2CAP_CONF_SUCCESS;
+       u16 size;
 
        BT_DBG("chan %p", chan);
 
@@ -2033,7 +2167,22 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                case L2CAP_CONF_FCS:
                        if (val == L2CAP_FCS_NONE)
                                set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       remote_efs = 1;
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *) val, olen);
+                       break;
+
+               case L2CAP_CONF_EWS:
+                       if (!enable_hs)
+                               return -ECONNREFUSED;
 
+                       set_bit(FLAG_EXT_CTRL, &chan->flags);
+                       set_bit(CONF_EWS_RECV, &chan->conf_state);
+                       chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
+                       chan->remote_tx_win = val;
                        break;
 
                default:
@@ -2058,6 +2207,13 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
                        break;
                }
 
+               if (remote_efs) {
+                       if (__l2cap_efs_supported(chan))
+                               set_bit(FLAG_EFS_ENABLE, &chan->flags);
+                       else
+                               return -ECONNREFUSED;
+               }
+
                if (chan->mode != rfc.mode)
                        return -ECONNREFUSED;
 
@@ -2076,7 +2232,6 @@ done:
                                        sizeof(rfc), (unsigned long) &rfc);
        }
 
-
        if (result == L2CAP_CONF_SUCCESS) {
                /* Configure output options and let the other side know
                 * which ones we don't like. */
@@ -2089,6 +2244,26 @@ done:
                }
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
 
+               if (remote_efs) {
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype) {
+
+                               result = L2CAP_CONF_UNACCEPT;
+
+                               if (chan->num_conf_req >= 1)
+                                       return -ECONNREFUSED;
+
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                                       sizeof(efs),
+                                                       (unsigned long) &efs);
+                       } else {
+                               /* Send PENDING Conf Rsp */
+                               result = L2CAP_CONF_PENDING;
+                               set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       }
+               }
+
                switch (rfc.mode) {
                case L2CAP_MODE_BASIC:
                        chan->fcs = L2CAP_FCS_NONE;
@@ -2096,13 +2271,20 @@ done:
                        break;
 
                case L2CAP_MODE_ERTM:
-                       chan->remote_tx_win = rfc.txwin_size;
-                       chan->remote_max_tx = rfc.max_transmit;
+                       if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
+                               chan->remote_tx_win = rfc.txwin_size;
+                       else
+                               rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
 
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
+                       chan->remote_max_tx = rfc.max_transmit;
 
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        rfc.retrans_timeout =
                                le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
@@ -2114,13 +2296,29 @@ done:
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
 
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->remote_id = efs.id;
+                               chan->remote_stype = efs.stype;
+                               chan->remote_msdu = le16_to_cpu(efs.msdu);
+                               chan->remote_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                               chan->remote_acc_lat =
+                                               le32_to_cpu(efs.acc_lat);
+                               chan->remote_sdu_itime =
+                                       le32_to_cpu(efs.sdu_itime);
+                               l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       }
                        break;
 
                case L2CAP_MODE_STREAMING:
-                       if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
-                               rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
-
-                       chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
+                       size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
+                                               chan->conn->mtu -
+                                               L2CAP_EXT_HDR_SIZE -
+                                               L2CAP_SDULEN_SIZE -
+                                               L2CAP_FCS_SIZE);
+                       rfc.max_pdu_size = cpu_to_le16(size);
+                       chan->remote_mps = size;
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
@@ -2153,6 +2351,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        int type, olen;
        unsigned long val;
        struct l2cap_conf_rfc rfc;
+       struct l2cap_conf_efs efs;
 
        BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
 
@@ -2188,6 +2387,26 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
                                        sizeof(rfc), (unsigned long) &rfc);
                        break;
+
+               case L2CAP_CONF_EWS:
+                       chan->tx_win = min_t(u16, val,
+                                               L2CAP_DEFAULT_EXT_WINDOW);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
+                                                       chan->tx_win);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       if (olen == sizeof(efs))
+                               memcpy(&efs, (void *)val, olen);
+
+                       if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
+                                       efs.stype != chan->local_stype)
+                               return -ECONNREFUSED;
+
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
+                                       sizeof(efs), (unsigned long) &efs);
+                       break;
                }
        }
 
@@ -2196,13 +2415,23 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
 
        chan->mode = rfc.mode;
 
-       if (*result == L2CAP_CONF_SUCCESS) {
+       if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
                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);
+
+                       if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
+                               chan->local_msdu = le16_to_cpu(efs.msdu);
+                               chan->local_sdu_itime =
+                                               le32_to_cpu(efs.sdu_itime);
+                               chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
+                               chan->local_flush_to =
+                                               le32_to_cpu(efs.flush_to);
+                       }
                        break;
+
                case L2CAP_MODE_STREAMING:
                        chan->mps    = le16_to_cpu(rfc.max_pdu_size);
                }
@@ -2330,7 +2559,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
-               conn->disc_reason = 0x05;
+               conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
        }
@@ -2488,7 +2717,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                if (sock_owned_by_user(sk)) {
                        l2cap_state_change(chan, BT_DISCONN);
                        __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ / 5);
+                       __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        break;
                }
 
@@ -2602,6 +2831,21 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                chan->num_conf_req++;
        }
 
+       /* Got Conf Rsp PENDING from remote side and asume we sent
+          Conf Rsp PENDING in the code above */
+       if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
+                       test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+
+               /* check compatibility */
+
+               clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+               set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                       l2cap_build_conf_rsp(chan, rsp,
+                                       L2CAP_CONF_SUCCESS, 0x0000), rsp);
+       }
+
 unlock:
        bh_unlock_sock(sk);
        return 0;
@@ -2631,8 +2875,33 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        switch (result) {
        case L2CAP_CONF_SUCCESS:
                l2cap_conf_rfc_get(chan, rsp->data, len);
+               clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
                break;
 
+       case L2CAP_CONF_PENDING:
+               set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
+
+               if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+                       char buf[64];
+
+                       len = l2cap_parse_conf_rsp(chan, rsp->data, len,
+                                                               buf, &result);
+                       if (len < 0) {
+                               l2cap_send_disconn_req(conn, chan, ECONNRESET);
+                               goto done;
+                       }
+
+                       /* check compatibility */
+
+                       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+                       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
+                                               l2cap_build_conf_rsp(chan, buf,
+                                               L2CAP_CONF_SUCCESS, 0x0000), buf);
+               }
+               goto done;
+
        case L2CAP_CONF_UNACCEPT:
                if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
                        char req[64];
@@ -2661,7 +2930,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
        default:
                sk->sk_err = ECONNRESET;
-               __set_chan_timer(chan, HZ * 5);
+               __set_chan_timer(chan, L2CAP_DISC_REJ_TIMEOUT);
                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                goto done;
        }
@@ -2718,7 +2987,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        if (sock_owned_by_user(sk)) {
                l2cap_state_change(chan, BT_DISCONN);
                __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                return 0;
        }
@@ -2752,7 +3021,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        if (sock_owned_by_user(sk)) {
                l2cap_state_change(chan,BT_DISCONN);
                __clear_chan_timer(chan);
-               __set_chan_timer(chan, HZ / 5);
+               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                bh_unlock_sock(sk);
                return 0;
        }
@@ -2782,15 +3051,25 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
                                                         | L2CAP_FEAT_FCS;
+               if (enable_hs)
+                       feat_mask |= L2CAP_FEAT_EXT_FLOW
+                                               | L2CAP_FEAT_EXT_WINDOW;
+
                put_unaligned_le32(feat_mask, rsp->data);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else if (type == L2CAP_IT_FIXED_CHAN) {
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+
+               if (enable_hs)
+                       l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
+               else
+                       l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
+
                rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
-               memcpy(buf + 4, l2cap_fixed_chan, 8);
+               memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
@@ -2857,6 +3136,165 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
        return 0;
 }
 
+static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                       void *data)
+{
+       struct l2cap_create_chan_req *req = data;
+       struct l2cap_create_chan_rsp rsp;
+       u16 psm, scid;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       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);
+
+       /* Placeholder: Always reject */
+       rsp.dcid = 0;
+       rsp.scid = cpu_to_le16(scid);
+       rsp.result = L2CAP_CR_NO_MEM;
+       rsp.status = L2CAP_CS_NO_INFO;
+
+       l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
+                      sizeof(rsp), &rsp);
+
+       return 0;
+}
+
+static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, void *data)
+{
+       BT_DBG("conn %p", conn);
+
+       return l2cap_connect_rsp(conn, cmd, data);
+}
+
+static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
+                                                       u16 icid, u16 result)
+{
+       struct l2cap_move_chan_rsp rsp;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       rsp.icid = cpu_to_le16(icid);
+       rsp.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
+}
+
+static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
+                               struct l2cap_chan *chan, u16 icid, u16 result)
+{
+       struct l2cap_move_chan_cfm cfm;
+       u8 ident;
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       ident = l2cap_get_ident(conn);
+       if (chan)
+               chan->ident = ident;
+
+       cfm.icid = cpu_to_le16(icid);
+       cfm.result = cpu_to_le16(result);
+
+       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
+}
+
+static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
+                                                               u16 icid)
+{
+       struct l2cap_move_chan_cfm_rsp rsp;
+
+       BT_DBG("icid %d", 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_move_chan_req *req = data;
+       u16 icid = 0;
+       u16 result = L2CAP_MR_NOT_ALLOWED;
+
+       if (cmd_len != sizeof(*req))
+               return -EPROTO;
+
+       icid = le16_to_cpu(req->icid);
+
+       BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
+
+       if (!enable_hs)
+               return -EINVAL;
+
+       /* Placeholder: Always refuse */
+       l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_rsp *rsp = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+       result = le16_to_cpu(rsp->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       /* Placeholder: Always unconfirmed */
+       l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm *cfm = data;
+       u16 icid, result;
+
+       if (cmd_len != sizeof(*cfm))
+               return -EPROTO;
+
+       icid = le16_to_cpu(cfm->icid);
+       result = le16_to_cpu(cfm->result);
+
+       BT_DBG("icid %d, result %d", icid, result);
+
+       l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
+
+       return 0;
+}
+
+static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
+                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
+{
+       struct l2cap_move_chan_cfm_rsp *rsp = data;
+       u16 icid;
+
+       if (cmd_len != sizeof(*rsp))
+               return -EPROTO;
+
+       icid = le16_to_cpu(rsp->icid);
+
+       BT_DBG("icid %d", icid);
+
+       return 0;
+}
+
 static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
                                                        u16 to_multiplier)
 {
@@ -2969,6 +3407,30 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                err = l2cap_information_rsp(conn, cmd, data);
                break;
 
+       case L2CAP_CREATE_CHAN_REQ:
+               err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_CREATE_CHAN_RSP:
+               err = l2cap_create_channel_rsp(conn, cmd, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_REQ:
+               err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_RSP:
+               err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM:
+               err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
+               break;
+
+       case L2CAP_MOVE_CHAN_CFM_RSP:
+               err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
+               break;
+
        default:
                BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
                err = -EINVAL;
@@ -3047,10 +3509,15 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 {
        u16 our_fcs, rcv_fcs;
-       int hdr_size = L2CAP_HDR_SIZE + 2;
+       int hdr_size;
+
+       if (test_bit(FLAG_EXT_CTRL, &chan->flags))
+               hdr_size = L2CAP_EXT_HDR_SIZE;
+       else
+               hdr_size = L2CAP_ENH_HDR_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16) {
-               skb_trim(skb, skb->len - 2);
+               skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
                rcv_fcs = get_unaligned_le16(skb->data + skb->len);
                our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
 
@@ -3062,14 +3529,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan,  struct sk_buff *skb)
 
 static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 {
-       u16 control = 0;
+       u32 control = 0;
 
        chan->frames_sent = 0;
 
-       control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+       control |= __set_reqseq(chan, chan->buffer_seq);
 
        if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
-               control |= L2CAP_SUPER_RCV_NOT_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
                l2cap_send_sframe(chan, control);
                set_bit(CONN_RNR_SENT, &chan->conn_state);
        }
@@ -3081,12 +3548,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
 
        if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
                        chan->frames_sent == 0) {
-               control |= L2CAP_SUPER_RCV_READY;
+               control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
                l2cap_send_sframe(chan, control);
        }
 }
 
-static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
+static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
 {
        struct sk_buff *next_skb;
        int tx_seq_offset, next_tx_seq_offset;
@@ -3100,18 +3567,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
                return 0;
        }
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        do {
                if (bt_cb(next_skb)->tx_seq == tx_seq)
                        return -EINVAL;
 
-               next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
-                                               chan->buffer_seq) % 64;
-               if (next_tx_seq_offset < 0)
-                       next_tx_seq_offset += 64;
+               next_tx_seq_offset = __seq_offset(chan,
+                               bt_cb(next_skb)->tx_seq, chan->buffer_seq);
 
                if (next_tx_seq_offset > tx_seq_offset) {
                        __skb_queue_before(&chan->srej_q, next_skb, skb);
@@ -3147,24 +3610,24 @@ static void append_skb_frag(struct sk_buff *skb,
        skb->truesize += new_frag->truesize;
 }
 
-static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
+static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
 {
        int err = -EINVAL;
 
-       switch (control & L2CAP_CTRL_SAR) {
-       case L2CAP_SDU_UNSEGMENTED:
+       switch (__get_ctrl_sar(chan, control)) {
+       case L2CAP_SAR_UNSEGMENTED:
                if (chan->sdu)
                        break;
 
                err = chan->ops->recv(chan->data, skb);
                break;
 
-       case L2CAP_SDU_START:
+       case L2CAP_SAR_START:
                if (chan->sdu)
                        break;
 
                chan->sdu_len = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               skb_pull(skb, L2CAP_SDULEN_SIZE);
 
                if (chan->sdu_len > chan->imtu) {
                        err = -EMSGSIZE;
@@ -3181,7 +3644,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_CONTINUE:
+       case L2CAP_SAR_CONTINUE:
                if (!chan->sdu)
                        break;
 
@@ -3195,7 +3658,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
                err = 0;
                break;
 
-       case L2CAP_SDU_END:
+       case L2CAP_SAR_END:
                if (!chan->sdu)
                        break;
 
@@ -3230,14 +3693,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
 
 static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        BT_DBG("chan %p, Enter local busy", chan);
 
        set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_NOT_READY;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
        l2cap_send_sframe(chan, control);
 
        set_bit(CONN_RNR_SENT, &chan->conn_state);
@@ -3247,13 +3710,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
 
 static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
 {
-       u16 control;
+       u32 control;
 
        if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
                goto done;
 
-       control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
-       control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
+       control = __set_reqseq(chan, chan->buffer_seq);
+       control |= __set_ctrl_poll(chan);
+       control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
        l2cap_send_sframe(chan, control);
        chan->retry_count = 1;
 
@@ -3279,10 +3743,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
        }
 }
 
-static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct sk_buff *skb;
-       u16 control;
+       u32 control;
 
        while ((skb = skb_peek(&chan->srej_q)) &&
                        !test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
@@ -3292,7 +3756,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
 
                skb = skb_dequeue(&chan->srej_q);
-               control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
+               control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
                err = l2cap_reassemble_sdu(chan, skb, control);
 
                if (err < 0) {
@@ -3300,16 +3764,15 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
                        break;
                }
 
-               chan->buffer_seq_srej =
-                       (chan->buffer_seq_srej + 1) % 64;
-               tx_seq = (tx_seq + 1) % 64;
+               chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
+               tx_seq = __next_seq(chan, tx_seq);
        }
 }
 
-static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *l, *tmp;
-       u16 control;
+       u32 control;
 
        list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
                if (l->tx_seq == tx_seq) {
@@ -3317,45 +3780,48 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
                        kfree(l);
                        return;
                }
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, l->tx_seq);
                l2cap_send_sframe(chan, control);
                list_del(&l->list);
                list_add_tail(&l->list, &chan->srej_l);
        }
 }
 
-static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
+static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
 {
        struct srej_list *new;
-       u16 control;
+       u32 control;
 
        while (tx_seq != chan->expected_tx_seq) {
-               control = L2CAP_SUPER_SELECT_REJECT;
-               control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
+               control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
+               control |= __set_reqseq(chan, chan->expected_tx_seq);
                l2cap_send_sframe(chan, control);
 
                new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
                new->tx_seq = chan->expected_tx_seq;
-               chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+               chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
+
                list_add_tail(&new->list, &chan->srej_l);
        }
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 }
 
-static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       u8 tx_seq = __get_txseq(rx_control);
-       u8 req_seq = __get_reqseq(rx_control);
-       u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
+       u16 tx_seq = __get_txseq(chan, rx_control);
+       u16 req_seq = __get_reqseq(chan, rx_control);
+       u8 sar = __get_ctrl_sar(chan, rx_control);
        int tx_seq_offset, expected_tx_seq_offset;
        int num_to_ack = (chan->tx_win/6) + 1;
        int err = 0;
 
-       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
+       BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
                                                        tx_seq, rx_control);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3366,9 +3832,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        chan->expected_ack_seq = req_seq;
        l2cap_drop_acked_frames(chan);
 
-       tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
-       if (tx_seq_offset < 0)
-               tx_seq_offset += 64;
+       tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
 
        /* invalid tx_seq */
        if (tx_seq_offset >= chan->tx_win) {
@@ -3416,10 +3880,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
                        l2cap_send_srejframe(chan, tx_seq);
                }
        } else {
-               expected_tx_seq_offset =
-                       (chan->expected_tx_seq - chan->buffer_seq) % 64;
-               if (expected_tx_seq_offset < 0)
-                       expected_tx_seq_offset += 64;
+               expected_tx_seq_offset = __seq_offset(chan,
+                               chan->expected_tx_seq, chan->buffer_seq);
 
                /* duplicated tx_seq */
                if (tx_seq_offset < expected_tx_seq_offset)
@@ -3444,7 +3906,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
        return 0;
 
 expected:
-       chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
+       chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
 
        if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                bt_cb(skb)->tx_seq = tx_seq;
@@ -3454,13 +3916,14 @@ expected:
        }
 
        err = l2cap_reassemble_sdu(chan, skb, rx_control);
-       chan->buffer_seq = (chan->buffer_seq + 1) % 64;
+       chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
+
        if (err < 0) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                return err;
        }
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        }
@@ -3478,15 +3941,15 @@ drop:
        return 0;
 }
 
-static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
-                                               rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
+                               __get_reqseq(chan, rx_control), rx_control);
 
-       chan->expected_ack_seq = __get_reqseq(rx_control);
+       chan->expected_ack_seq = __get_reqseq(chan, rx_control);
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
                if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
@@ -3499,7 +3962,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
                        l2cap_send_i_or_rr_or_rnr(chan);
                }
 
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
@@ -3518,18 +3981,18 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
        }
 }
 
-static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_FINAL) {
+       if (__is_ctrl_final(chan, rx_control)) {
                if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
                        l2cap_retransmit_frames(chan);
        } else {
@@ -3539,15 +4002,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
                        set_bit(CONN_REJ_ACT, &chan->conn_state);
        }
 }
-static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-       if (rx_control & L2CAP_CTRL_POLL) {
+       if (__is_ctrl_poll(chan, rx_control)) {
                chan->expected_ack_seq = tx_seq;
                l2cap_drop_acked_frames(chan);
 
@@ -3560,7 +4023,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
                        chan->srej_save_reqseq = tx_seq;
                        set_bit(CONN_SREJ_ACT, &chan->conn_state);
                }
-       } else if (rx_control & L2CAP_CTRL_FINAL) {
+       } else if (__is_ctrl_final(chan, rx_control)) {
                if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
                                chan->srej_save_reqseq == tx_seq)
                        clear_bit(CONN_SREJ_ACT, &chan->conn_state);
@@ -3575,37 +4038,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
        }
 }
 
-static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
+static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
 {
-       u8 tx_seq = __get_reqseq(rx_control);
+       u16 tx_seq = __get_reqseq(chan, rx_control);
 
-       BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
+       BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
 
        set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
        chan->expected_ack_seq = tx_seq;
        l2cap_drop_acked_frames(chan);
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control))
                set_bit(CONN_SEND_FBIT, &chan->conn_state);
 
        if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
                __clear_retrans_timer(chan);
-               if (rx_control & L2CAP_CTRL_POLL)
+               if (__is_ctrl_poll(chan, rx_control))
                        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
                return;
        }
 
-       if (rx_control & L2CAP_CTRL_POLL)
+       if (__is_ctrl_poll(chan, rx_control)) {
                l2cap_send_srejtail(chan);
-       else
-               l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
+       } else {
+               rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
+               l2cap_send_sframe(chan, rx_control);
+       }
 }
 
-static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
+static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
 {
-       BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
+       BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
 
-       if (L2CAP_CTRL_FINAL & rx_control &&
+       if (__is_ctrl_final(chan, rx_control) &&
                        test_bit(CONN_WAIT_F, &chan->conn_state)) {
                __clear_monitor_timer(chan);
                if (chan->unacked_frames > 0)
@@ -3613,20 +4078,20 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
                clear_bit(CONN_WAIT_F, &chan->conn_state);
        }
 
-       switch (rx_control & L2CAP_CTRL_SUPERVISE) {
-       case L2CAP_SUPER_RCV_READY:
+       switch (__get_ctrl_super(chan, rx_control)) {
+       case L2CAP_SUPER_RR:
                l2cap_data_channel_rrframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_REJECT:
+       case L2CAP_SUPER_REJ:
                l2cap_data_channel_rejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_SELECT_REJECT:
+       case L2CAP_SUPER_SREJ:
                l2cap_data_channel_srejframe(chan, rx_control);
                break;
 
-       case L2CAP_SUPER_RCV_NOT_READY:
+       case L2CAP_SUPER_RNR:
                l2cap_data_channel_rnrframe(chan, rx_control);
                break;
        }
@@ -3638,12 +4103,12 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
 {
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
-       u16 control;
-       u8 req_seq;
+       u32 control;
+       u16 req_seq;
        int len, next_tx_seq_offset, req_seq_offset;
 
-       control = get_unaligned_le16(skb->data);
-       skb_pull(skb, 2);
+       control = __get_control(chan, skb->data);
+       skb_pull(skb, __ctrl_size(chan));
        len = skb->len;
 
        /*
@@ -3654,26 +4119,23 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
        if (l2cap_check_fcs(chan, skb))
                goto drop;
 
-       if (__is_sar_start(control) && __is_iframe(control))
-               len -= 2;
+       if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
+               len -= L2CAP_SDULEN_SIZE;
 
        if (chan->fcs == L2CAP_FCS_CRC16)
-               len -= 2;
+               len -= L2CAP_FCS_SIZE;
 
        if (len > chan->mps) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                goto drop;
        }
 
-       req_seq = __get_reqseq(control);
-       req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
-       if (req_seq_offset < 0)
-               req_seq_offset += 64;
+       req_seq = __get_reqseq(chan, control);
 
-       next_tx_seq_offset =
-               (chan->next_tx_seq - chan->expected_ack_seq) % 64;
-       if (next_tx_seq_offset < 0)
-               next_tx_seq_offset += 64;
+       req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
+
+       next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
+                                               chan->expected_ack_seq);
 
        /* check for invalid req-seq */
        if (req_seq_offset > next_tx_seq_offset) {
@@ -3681,7 +4143,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
                goto drop;
        }
 
-       if (__is_iframe(control)) {
+       if (!__is_sframe(chan, control)) {
                if (len < 0) {
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
@@ -3709,8 +4171,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
 {
        struct l2cap_chan *chan;
        struct sock *sk = NULL;
-       u16 control;
-       u8 tx_seq;
+       u32 control;
+       u16 tx_seq;
        int len;
 
        chan = l2cap_get_chan_by_scid(conn, cid);
@@ -3751,23 +4213,23 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                goto done;
 
        case L2CAP_MODE_STREAMING:
-               control = get_unaligned_le16(skb->data);
-               skb_pull(skb, 2);
+               control = __get_control(chan, skb->data);
+               skb_pull(skb, __ctrl_size(chan));
                len = skb->len;
 
                if (l2cap_check_fcs(chan, skb))
                        goto drop;
 
-               if (__is_sar_start(control))
-                       len -= 2;
+               if (__is_sar_start(chan, control))
+                       len -= L2CAP_SDULEN_SIZE;
 
                if (chan->fcs == L2CAP_FCS_CRC16)
-                       len -= 2;
+                       len -= L2CAP_FCS_SIZE;
 
-               if (len > chan->mps || len < 0 || __is_sframe(control))
+               if (len > chan->mps || len < 0 || __is_sframe(chan, control))
                        goto drop;
 
-               tx_seq = __get_txseq(control);
+               tx_seq = __get_txseq(chan, control);
 
                if (chan->expected_tx_seq != tx_seq) {
                        /* Frame(s) missing - must discard partial SDU */
@@ -3779,7 +4241,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
                        /* TODO: Notify userland of missing data */
                }
 
-               chan->expected_tx_seq = (tx_seq + 1) % 64;
+               chan->expected_tx_seq = __next_seq(chan, tx_seq);
 
                if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
@@ -3933,12 +4395,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
                        lm1 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm1 |= HCI_LM_MASTER;
                        exact++;
                } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
                        lm2 |= HCI_LM_ACCEPT;
-                       if (c->role_switch)
+                       if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
                                lm2 |= HCI_LM_MASTER;
                }
        }
@@ -3973,7 +4435,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon)
        BT_DBG("hcon %p", hcon);
 
        if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
-               return 0x13;
+               return HCI_ERROR_REMOTE_USER_TERM;
 
        return conn->disc_reason;
 }
@@ -3998,7 +4460,7 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
        if (encrypt == 0x00) {
                if (chan->sec_level == BT_SECURITY_MEDIUM) {
                        __clear_chan_timer(chan);
-                       __set_chan_timer(chan, HZ * 5);
+                       __set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
                } else if (chan->sec_level == BT_SECURITY_HIGH)
                        l2cap_chan_close(chan, ECONNREFUSED);
        } else {
@@ -4066,7 +4528,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                        L2CAP_CONN_REQ, sizeof(req), &req);
                        } else {
                                __clear_chan_timer(chan);
-                               __set_chan_timer(chan, HZ / 10);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -4086,7 +4548,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                                }
                        } else {
                                l2cap_state_change(chan, BT_DISCONN);
-                               __set_chan_timer(chan, HZ / 10);
+                               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                                res = L2CAP_CR_SEC_BLOCK;
                                stat = L2CAP_CS_NO_INFO;
                        }
@@ -4306,3 +4768,6 @@ void l2cap_exit(void)
 
 module_param(disable_ertm, bool, 0644);
 MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
+
+module_param(enable_hs, bool, 0644);
+MODULE_PARM_DESC(enable_hs, "Enable High Speed");
index 5c406d3136f74fc206380968a0a98c3c4b742474..e2e785c746306a6f4b79f10353b8f3fe7aa5d986 100644 (file)
@@ -334,7 +334,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, len, sizeof(opts));
                if (copy_to_user(optval, (char *) &opts, len))
@@ -359,10 +359,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (chan->role_switch)
+               if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
                        opt |= L2CAP_LM_MASTER;
 
-               if (chan->force_reliable)
+               if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        opt |= L2CAP_LM_RELIABLE;
 
                if (put_user(opt, (u32 __user *) optval))
@@ -449,7 +449,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                break;
 
        case BT_FLUSHABLE:
-               if (put_user(chan->flushable, (u32 __user *) optval))
+               if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
+                                               (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
@@ -461,7 +462,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
-               pwr.force_active = chan->force_active;
+               pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
 
                len = min_t(unsigned int, len, sizeof(pwr));
                if (copy_to_user(optval, (char *) &pwr, len))
@@ -469,6 +470,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
                break;
 
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (put_user(chan->chan_policy, (u32 __user *) optval))
+                       err = -EFAULT;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -503,7 +514,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                opts.mode     = chan->mode;
                opts.fcs      = chan->fcs;
                opts.max_tx   = chan->max_tx;
-               opts.txwin_size = (__u16)chan->tx_win;
+               opts.txwin_size = chan->tx_win;
 
                len = min_t(unsigned int, sizeof(opts), optlen);
                if (copy_from_user((char *) &opts, optval, len)) {
@@ -511,7 +522,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                        break;
                }
 
-               if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
+               if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
                        err = -EINVAL;
                        break;
                }
@@ -535,7 +546,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->omtu = opts.omtu;
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
-               chan->tx_win = (__u8)opts.txwin_size;
+               chan->tx_win = opts.txwin_size;
                break;
 
        case L2CAP_LM:
@@ -551,8 +562,15 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                if (opt & L2CAP_LM_SECURE)
                        chan->sec_level = BT_SECURITY_HIGH;
 
-               chan->role_switch    = (opt & L2CAP_LM_MASTER);
-               chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
+               if (opt & L2CAP_LM_MASTER)
+                       set_bit(FLAG_ROLE_SWITCH, &chan->flags);
+               else
+                       clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
+
+               if (opt & L2CAP_LM_RELIABLE)
+                       set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
                break;
 
        default:
@@ -658,7 +676,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        }
                }
 
-               chan->flushable = opt;
+               if (opt)
+                       set_bit(FLAG_FLUSHABLE, &chan->flags);
+               else
+                       clear_bit(FLAG_FLUSHABLE, &chan->flags);
                break;
 
        case BT_POWER:
@@ -675,7 +696,36 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        err = -EFAULT;
                        break;
                }
-               chan->force_active = pwr.force_active;
+
+               if (pwr.force_active)
+                       set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               else
+                       clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
+               break;
+
+       case BT_CHANNEL_POLICY:
+               if (!enable_hs) {
+                       err = -ENOPROTOOPT;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (chan->mode != L2CAP_MODE_ERTM &&
+                               chan->mode != L2CAP_MODE_STREAMING) {
+                       err = -EOPNOTSUPP;
+                       break;
+               }
+
+               chan->chan_policy = (u8) opt;
                break;
 
        default:
@@ -709,7 +759,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
                return -ENOTCONN;
        }
 
-       err = l2cap_chan_send(chan, msg, len);
+       err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
 
        release_sock(sk);
        return err;
@@ -931,11 +981,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->fcs  = pchan->fcs;
                chan->max_tx = pchan->max_tx;
                chan->tx_win = pchan->tx_win;
+               chan->tx_win_max = pchan->tx_win_max;
                chan->sec_level = pchan->sec_level;
-               chan->role_switch = pchan->role_switch;
-               chan->force_reliable = pchan->force_reliable;
-               chan->flushable = pchan->flushable;
-               chan->force_active = pchan->force_active;
+               chan->flags = pchan->flags;
 
                security_sk_clone(parent, sk);
        } else {
@@ -964,12 +1012,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
                chan->max_tx = L2CAP_DEFAULT_MAX_TX;
                chan->fcs  = L2CAP_FCS_CRC16;
                chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
+               chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
                chan->sec_level = BT_SECURITY_LOW;
-               chan->role_switch = 0;
-               chan->force_reliable = 0;
-               chan->flushable = BT_FLUSHABLE_OFF;
-               chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
-
+               chan->flags = 0;
+               set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
        }
 
        /* Default config options */
index 2c76342968660f97a1911783f26d60a7a96b715a..94739d3c4f59ccabb5ed378c6795150a85c60c79 100644 (file)
 #define MGMT_VERSION   0
 #define MGMT_REVISION  1
 
+#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
+
 struct pending_cmd {
        struct list_head list;
-       __u16 opcode;
+       u16 opcode;
        int index;
        void *param;
        struct sock *sk;
        void *user_data;
 };
 
-static LIST_HEAD(cmd_list);
-
 static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_status *ev;
+       int err;
 
        BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
 
@@ -66,10 +67,11 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
        ev->status = status;
        put_unaligned_le16(cmd, &ev->opcode);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;
 }
 
 static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
@@ -78,6 +80,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
        struct mgmt_ev_cmd_complete *ev;
+       int err;
 
        BT_DBG("sock %p", sk);
 
@@ -97,10 +100,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
        if (rp)
                memcpy(ev->data, rp, rp_len);
 
-       if (sock_queue_rcv_skb(sk, skb) < 0)
+       err = sock_queue_rcv_skb(sk, skb);
+       if (err < 0)
                kfree_skb(skb);
 
-       return 0;
+       return err;;
 }
 
 static int read_version(struct sock *sk)
@@ -120,6 +124,7 @@ static int read_index_list(struct sock *sk)
 {
        struct mgmt_rp_read_index_list *rp;
        struct list_head *p;
+       struct hci_dev *d;
        size_t rp_len;
        u16 count;
        int i, err;
@@ -143,10 +148,9 @@ static int read_index_list(struct sock *sk)
        put_unaligned_le16(count, &rp->num_controllers);
 
        i = 0;
-       list_for_each(p, &hci_dev_list) {
-               struct hci_dev *d = list_entry(p, struct hci_dev, list);
-
-               hci_del_off_timer(d);
+       list_for_each_entry(d, &hci_dev_list, list) {
+               if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
+                       cancel_delayed_work(&d->power_off);
 
                if (test_bit(HCI_SETUP, &d->flags))
                        continue;
@@ -176,7 +180,8 @@ static int read_controller_info(struct sock *sk, u16 index)
        if (!hdev)
                return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
 
-       hci_del_off_timer(hdev);
+       if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
+               cancel_delayed_work_sync(&hdev->power_off);
 
        hci_dev_lock_bh(hdev);
 
@@ -221,7 +226,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
 }
 
 static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
-                                               u16 index, void *data, u16 len)
+                                                       struct hci_dev *hdev,
+                                                       void *data, u16 len)
 {
        struct pending_cmd *cmd;
 
@@ -230,7 +236,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
                return NULL;
 
        cmd->opcode = opcode;
-       cmd->index = index;
+       cmd->index = hdev->id;
 
        cmd->param = kmalloc(len, GFP_ATOMIC);
        if (!cmd->param) {
@@ -244,48 +250,36 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
        cmd->sk = sk;
        sock_hold(sk);
 
-       list_add(&cmd->list, &cmd_list);
+       list_add(&cmd->list, &hdev->mgmt_pending);
 
        return cmd;
 }
 
-static void mgmt_pending_foreach(u16 opcode, int index,
+static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
                                void (*cb)(struct pending_cmd *cmd, void *data),
                                void *data)
 {
        struct list_head *p, *n;
 
-       list_for_each_safe(p, n, &cmd_list) {
+       list_for_each_safe(p, n, &hdev->mgmt_pending) {
                struct pending_cmd *cmd;
 
                cmd = list_entry(p, struct pending_cmd, list);
 
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
+               if (opcode > 0 && cmd->opcode != opcode)
                        continue;
 
                cb(cmd, data);
        }
 }
 
-static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
+static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
 {
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
-
-               if (cmd->opcode != opcode)
-                       continue;
-
-               if (index >= 0 && cmd->index != index)
-                       continue;
+       struct pending_cmd *cmd;
 
-               return cmd;
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
+               if (cmd->opcode == opcode)
+                       return cmd;
        }
 
        return NULL;
@@ -323,12 +317,12 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -337,7 +331,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
        if (cp->val)
                queue_work(hdev->workqueue, &hdev->power_on);
        else
-               queue_work(hdev->workqueue, &hdev->power_off);
+               queue_work(hdev->workqueue, &hdev->power_off.work);
 
        err = 0;
 
@@ -350,7 +344,7 @@ failed:
 static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                                                                        u16 len)
 {
-       struct mgmt_mode *cp;
+       struct mgmt_cp_set_discoverable *cp;
        struct hci_dev *hdev;
        struct pending_cmd *cmd;
        u8 scan;
@@ -374,8 +368,8 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
                goto failed;
        }
@@ -386,7 +380,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -396,11 +390,16 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
 
        if (cp->val)
                scan |= SCAN_INQUIRY;
+       else
+               cancel_delayed_work(&hdev->discov_off);
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
+       if (cp->val)
+               hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
+
 failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -435,8 +434,8 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
-                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
+       if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
+                       mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
                goto failed;
        }
@@ -446,7 +445,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -468,8 +467,8 @@ failed:
        return err;
 }
 
-static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
-                                                       struct sock *skip_sk)
+static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
+                                       u16 data_len, struct sock *skip_sk)
 {
        struct sk_buff *skb;
        struct mgmt_hdr *hdr;
@@ -482,7 +481,10 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
 
        hdr = (void *) skb_put(skb, sizeof(*hdr));
        hdr->opcode = cpu_to_le16(event);
-       hdr->index = cpu_to_le16(index);
+       if (hdev)
+               hdr->index = cpu_to_le16(hdev->id);
+       else
+               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
        hdr->len = cpu_to_le16(data_len);
 
        if (data)
@@ -534,7 +536,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
 
        ev.val = cp->val;
 
-       err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
 
 failed:
        hci_dev_unlock_bh(hdev);
@@ -587,7 +589,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        u16 eir_len = 0;
        u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
        int i, truncated = 0;
-       struct list_head *p;
+       struct bt_uuid *uuid;
        size_t name_len;
 
        name_len = strlen(hdev->dev_name);
@@ -612,8 +614,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
        memset(uuid16_list, 0, sizeof(uuid16_list));
 
        /* Group all UUID16 types */
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
+       list_for_each_entry(uuid, &hdev->uuids, list) {
                u16 uuid16;
 
                uuid16 = get_uuid16(uuid->uuid);
@@ -689,14 +690,11 @@ static int update_eir(struct hci_dev *hdev)
 
 static u8 get_service_classes(struct hci_dev *hdev)
 {
-       struct list_head *p;
+       struct bt_uuid *uuid;
        u8 val = 0;
 
-       list_for_each(p, &hdev->uuids) {
-               struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
-
+       list_for_each_entry(uuid, &hdev->uuids, list)
                val |= uuid->svc_hint;
-       }
 
        return val;
 }
@@ -895,6 +893,9 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        if (err == 0)
                err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
                                                                        0);
+       else
+               cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
+
 
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
@@ -902,30 +903,32 @@ static int set_service_cache(struct sock *sk, u16 index,  unsigned char *data,
        return err;
 }
 
-static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_load_keys *cp;
+       struct mgmt_cp_load_link_keys *cp;
        u16 key_count, expected_len;
        int i;
 
        cp = (void *) data;
 
        if (len < sizeof(*cp))
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
 
        key_count = get_unaligned_le16(&cp->key_count);
 
-       expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
+       expected_len = sizeof(*cp) + key_count *
+                                       sizeof(struct mgmt_link_key_info);
        if (expected_len != len) {
-               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+               BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
                                                        len, expected_len);
-               return -EINVAL;
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
        }
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
 
        BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
                                                                key_count);
@@ -942,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
        for (i = 0; i < key_count; i++) {
-               struct mgmt_key_info *key = &cp->keys[i];
+               struct mgmt_link_key_info *key = &cp->keys[i];
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
@@ -954,27 +957,28 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        return 0;
 }
 
-static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
+static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
+                                                               u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_remove_key *cp;
+       struct mgmt_cp_remove_keys *cp;
        struct hci_conn *conn;
        int err;
 
        cp = (void *) data;
 
        if (len != sizeof(*cp))
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
 
        hdev = hci_dev_get(index);
        if (!hdev)
-               return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
+               return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
 
        hci_dev_lock_bh(hdev);
 
        err = hci_remove_link_key(hdev, &cp->bdaddr);
        if (err < 0) {
-               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
+               err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
                goto unlock;
        }
 
@@ -1026,7 +1030,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
+       if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
                goto failed;
        }
@@ -1040,7 +1044,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1060,10 +1064,23 @@ failed:
        return err;
 }
 
+static u8 link_to_mgmt(u8 link_type)
+{
+       switch (link_type) {
+       case LE_LINK:
+               return MGMT_ADDR_LE;
+       case ACL_LINK:
+               return MGMT_ADDR_BREDR;
+       default:
+               return MGMT_ADDR_INVALID;
+       }
+}
+
 static int get_connections(struct sock *sk, u16 index)
 {
        struct mgmt_rp_get_connections *rp;
        struct hci_dev *hdev;
+       struct hci_conn *c;
        struct list_head *p;
        size_t rp_len;
        u16 count;
@@ -1082,7 +1099,7 @@ static int get_connections(struct sock *sk, u16 index)
                count++;
        }
 
-       rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
+       rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
        rp = kmalloc(rp_len, GFP_ATOMIC);
        if (!rp) {
                err = -ENOMEM;
@@ -1092,12 +1109,17 @@ static int get_connections(struct sock *sk, u16 index)
        put_unaligned_le16(count, &rp->conn_count);
 
        i = 0;
-       list_for_each(p, &hdev->conn_hash.list) {
-               struct hci_conn *c = list_entry(p, struct hci_conn, list);
-
-               bacpy(&rp->conn[i++], &c->dst);
+       list_for_each_entry(c, &hdev->conn_hash.list, list) {
+               bacpy(&rp->addr[i].bdaddr, &c->dst);
+               rp->addr[i].type = link_to_mgmt(c->type);
+               if (rp->addr[i].type == MGMT_ADDR_INVALID)
+                       continue;
+               i++;
        }
 
+       /* Recalculate length in case of filtered SCO connections, etc */
+       rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
+
        err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
 
 unlock:
@@ -1113,7 +1135,7 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index,
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
                                                                sizeof(*cp));
        if (!cmd)
                return -ENOMEM;
@@ -1174,7 +1196,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1265,19 +1287,12 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
 static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
 {
        struct hci_dev *hdev = conn->hdev;
-       struct list_head *p;
-
-       list_for_each(p, &cmd_list) {
-               struct pending_cmd *cmd;
-
-               cmd = list_entry(p, struct pending_cmd, list);
+       struct pending_cmd *cmd;
 
+       list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
                if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
                        continue;
 
-               if (cmd->index != hdev->id)
-                       continue;
-
                if (cmd->user_data != conn)
                        continue;
 
@@ -1310,16 +1325,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
 static void pairing_complete_cb(struct hci_conn *conn, u8 status)
 {
        struct pending_cmd *cmd;
+       struct hci_dev *hdev = conn->hdev;
 
        BT_DBG("status %u", status);
 
+       hci_dev_lock_bh(hdev);
+
        cmd = find_pairing(conn);
-       if (!cmd) {
+       if (!cmd)
                BT_DBG("Unable to find a pending command");
-               return;
-       }
+       else
+               pairing_complete(cmd, status);
 
-       pairing_complete(cmd, status);
+       hci_dev_unlock_bh(hdev);
 }
 
 static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1370,7 +1388,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                hci_conn_put(conn);
@@ -1432,7 +1450,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
                goto failed;
        }
 
-       cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
+       cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1469,7 +1487,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
+       cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
@@ -1515,12 +1533,12 @@ static int read_local_oob_data(struct sock *sk, u16 index)
                goto unlock;
        }
 
-       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
+       if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
                err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
                goto unlock;
        }
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto unlock;
@@ -1607,8 +1625,6 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
 
 static int start_discovery(struct sock *sk, u16 index)
 {
-       u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       struct hci_cp_inquiry cp;
        struct pending_cmd *cmd;
        struct hci_dev *hdev;
        int err;
@@ -1621,18 +1637,18 @@ static int start_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
+       if (!test_bit(HCI_UP, &hdev->flags)) {
+               err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
+               goto failed;
+       }
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       memset(&cp, 0, sizeof(cp));
-       memcpy(&cp.lap, lap, 3);
-       cp.length  = 0x08;
-       cp.num_rsp = 0x00;
-
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
+       err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1657,13 +1673,13 @@ static int stop_discovery(struct sock *sk, u16 index)
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
+       cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
        if (!cmd) {
                err = -ENOMEM;
                goto failed;
        }
 
-       err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
+       err = hci_cancel_inquiry(hdev);
        if (err < 0)
                mgmt_pending_remove(cmd);
 
@@ -1678,7 +1694,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_block_device *cp = (void *) data;
        int err;
 
@@ -1695,23 +1710,13 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_add(hdev, &cp->bdaddr);
-
        if (err < 0)
                err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
        else
                err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1722,7 +1727,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct pending_cmd *cmd;
        struct mgmt_cp_unblock_device *cp = (void *) data;
        int err;
 
@@ -1739,12 +1743,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
 
        hci_dev_lock_bh(hdev);
 
-       cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
-       if (!cmd) {
-               err = -ENOMEM;
-               goto failed;
-       }
-
        err = hci_blacklist_del(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1753,9 +1751,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                NULL, 0);
 
-       mgmt_pending_remove(cmd);
-
-failed:
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
@@ -1883,11 +1878,11 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_SET_SERVICE_CACHE:
                err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_LOAD_KEYS:
-               err = load_keys(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_LOAD_LINK_KEYS:
+               err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
                break;
-       case MGMT_OP_REMOVE_KEY:
-               err = remove_key(sk, index, buf + sizeof(*hdr), len);
+       case MGMT_OP_REMOVE_KEYS:
+               err = remove_keys(sk, index, buf + sizeof(*hdr), len);
                break;
        case MGMT_OP_DISCONNECT:
                err = disconnect(sk, index, buf + sizeof(*hdr), len);
@@ -1958,14 +1953,26 @@ done:
        return err;
 }
 
-int mgmt_index_added(u16 index)
+static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
 {
-       return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
+       u8 *status = data;
+
+       cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
+       mgmt_pending_remove(cmd);
 }
 
-int mgmt_index_removed(u16 index)
+int mgmt_index_added(struct hci_dev *hdev)
 {
-       return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
+       return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
+}
+
+int mgmt_index_removed(struct hci_dev *hdev)
+{
+       u8 status = ENODEV;
+
+       mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+
+       return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
 }
 
 struct cmd_lookup {
@@ -1993,17 +2000,22 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_free(cmd);
 }
 
-int mgmt_powered(u16 index, u8 powered)
+int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { powered, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
+
+       if (!powered) {
+               u8 status = ENETDOWN;
+               mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
+       }
 
        ev.val = powered;
 
-       ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2011,17 +2023,17 @@ int mgmt_powered(u16 index, u8 powered)
        return ret;
 }
 
-int mgmt_discoverable(u16 index, u8 discoverable)
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { discoverable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
 
        ev.val = discoverable;
 
-       ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
+       ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
                                                                match.sk);
 
        if (match.sk)
@@ -2030,17 +2042,17 @@ int mgmt_discoverable(u16 index, u8 discoverable)
        return ret;
 }
 
-int mgmt_connectable(u16 index, u8 connectable)
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
 {
        struct mgmt_mode ev;
        struct cmd_lookup match = { connectable, NULL };
        int ret;
 
-       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
+       mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
 
        ev.val = connectable;
 
-       ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
+       ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
 
        if (match.sk)
                sock_put(match.sk);
@@ -2048,9 +2060,23 @@ int mgmt_connectable(u16 index, u8 connectable)
        return ret;
 }
 
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
+{
+       if (scan & SCAN_PAGE)
+               mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       if (scan & SCAN_INQUIRY)
+               mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
+                                               cmd_status_rsp, &status);
+
+       return 0;
+}
+
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent)
 {
-       struct mgmt_ev_new_key ev;
+       struct mgmt_ev_new_link_key ev;
 
        memset(&ev, 0, sizeof(ev));
 
@@ -2060,17 +2086,17 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
        memcpy(ev.key.val, key->val, 16);
        ev.key.pin_len = key->pin_len;
 
-       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
 {
-       struct mgmt_ev_connected ev;
+       struct mgmt_addr_info ev;
 
        bacpy(&ev.bdaddr, bdaddr);
-       ev.link_type = link_type;
+       ev.type = link_to_mgmt(link_type);
 
-       return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
 }
 
 static void disconnect_rsp(struct pending_cmd *cmd, void *data)
@@ -2089,17 +2115,18 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_remove(cmd);
 }
 
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
 {
-       struct mgmt_ev_disconnected ev;
+       struct mgmt_addr_info ev;
        struct sock *sk = NULL;
        int err;
 
-       mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
+       mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
 
        bacpy(&ev.bdaddr, bdaddr);
+       ev.type = link_to_mgmt(type);
 
-       err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
+       err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
 
        if (sk)
                sock_put(sk);
@@ -2107,57 +2134,60 @@ int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
        return err;
 }
 
-int mgmt_disconnect_failed(u16 index)
+int mgmt_disconnect_failed(struct hci_dev *hdev)
 {
        struct pending_cmd *cmd;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
+       cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
 
-       err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
+       err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                                               u8 status)
 {
        struct mgmt_ev_connect_failed ev;
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
 {
        struct mgmt_ev_pin_code_request ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.secure = secure;
 
-       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2165,20 +2195,21 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_pin_code_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
+       cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
                                                                sizeof(rp));
 
        mgmt_pending_remove(cmd);
@@ -2186,97 +2217,93 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
        return err;
 }
 
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint)
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint)
 {
        struct mgmt_ev_user_confirm_request ev;
 
-       BT_DBG("hci%u", index);
+       BT_DBG("%s", hdev->name);
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.confirm_hint = confirm_hint;
        put_unaligned_le32(value, &ev.value);
 
-       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
+       return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
                                                                        NULL);
 }
 
-static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
-                                                               u8 opcode)
+static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                       u8 status, u8 opcode)
 {
        struct pending_cmd *cmd;
        struct mgmt_rp_user_confirm_reply rp;
        int err;
 
-       cmd = mgmt_pending_find(opcode, index);
+       cmd = mgmt_pending_find(opcode, hdev);
        if (!cmd)
                return -ENOENT;
 
        bacpy(&rp.bdaddr, bdaddr);
        rp.status = status;
-       err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
+       err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
 
        mgmt_pending_remove(cmd);
 
        return err;
 }
 
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                                MGMT_OP_USER_CONFIRM_REPLY);
 }
 
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status)
 {
-       return confirm_reply_complete(index, bdaddr, status,
+       return confirm_reply_complete(hdev, bdaddr, status,
                                        MGMT_OP_USER_CONFIRM_NEG_REPLY);
 }
 
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
 {
        struct mgmt_ev_auth_failed ev;
 
        bacpy(&ev.bdaddr, bdaddr);
        ev.status = status;
 
-       return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
 {
        struct pending_cmd *cmd;
-       struct hci_dev *hdev;
        struct mgmt_cp_set_local_name ev;
        int err;
 
        memset(&ev, 0, sizeof(ev));
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
+       cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
        if (!cmd)
                goto send_event;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
+               err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
+                                                                       EIO);
                goto failed;
        }
 
-       hdev = hci_dev_get(index);
-       if (hdev) {
-               hci_dev_lock_bh(hdev);
-               update_eir(hdev);
-               hci_dev_unlock_bh(hdev);
-               hci_dev_put(hdev);
-       }
+       update_eir(hdev);
 
-       err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
+       err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
                                                                sizeof(ev));
        if (err < 0)
                goto failed;
 
 send_event:
-       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
+       err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
                                                        cmd ? cmd->sk : NULL);
 
 failed:
@@ -2285,29 +2312,30 @@ failed:
        return err;
 }
 
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
-                                                               u8 status)
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status)
 {
        struct pending_cmd *cmd;
        int err;
 
-       BT_DBG("hci%u status %u", index, status);
+       BT_DBG("%s status %u", hdev->name, status);
 
-       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
+       cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
        if (!cmd)
                return -ENOENT;
 
        if (status) {
-               err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                                       EIO);
+               err = cmd_status(cmd->sk, hdev->id,
+                                       MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
        } else {
                struct mgmt_rp_read_local_oob_data rp;
 
                memcpy(rp.hash, hash, sizeof(rp.hash));
                memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
 
-               err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
-                                                       &rp, sizeof(rp));
+               err = cmd_complete(cmd->sk, hdev->id,
+                                               MGMT_OP_READ_LOCAL_OOB_DATA,
+                                               &rp, sizeof(rp));
        }
 
        mgmt_pending_remove(cmd);
@@ -2315,14 +2343,15 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
        return err;
 }
 
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir)
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
+                                       u8 *dev_class, s8 rssi, u8 *eir)
 {
        struct mgmt_ev_device_found ev;
 
        memset(&ev, 0, sizeof(ev));
 
-       bacpy(&ev.bdaddr, bdaddr);
+       bacpy(&ev.addr.bdaddr, bdaddr);
+       ev.addr.type = link_to_mgmt(type);
        ev.rssi = rssi;
 
        if (eir)
@@ -2331,10 +2360,10 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
        if (dev_class)
                memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
 
-       return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
 {
        struct mgmt_ev_remote_name ev;
 
@@ -2343,37 +2372,64 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
        bacpy(&ev.bdaddr, bdaddr);
        memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
 
-       return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
+       return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_discovering(u16 index, u8 discovering)
+int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
 {
-       return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
+       struct pending_cmd *cmd;
+       int err;
+
+       cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       if (!cmd)
+               return -ENOENT;
+
+       err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
+       mgmt_pending_remove(cmd);
+
+       return err;
+}
+
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
+{
+       struct pending_cmd *cmd;
+
+       if (discovering)
+               cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
+       else
+               cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
+
+       if (cmd != NULL) {
+               cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
+               mgmt_pending_remove(cmd);
+       }
+
+       return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
                                                sizeof(discovering), NULL);
 }
 
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_blocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
 
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct pending_cmd *cmd;
        struct mgmt_ev_device_unblocked ev;
 
-       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
 
        bacpy(&ev.bdaddr, bdaddr);
 
-       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
-                                               cmd ? cmd->sk : NULL);
+       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
+                                                       cmd ? cmd->sk : NULL);
 }
index 4e32e18211f9187d8a98a27772a9ba97f5cf7112..8743f369ed3fac82dc80095eb2df8bf8bf6da1b8 100644 (file)
@@ -65,7 +65,8 @@ static DEFINE_MUTEX(rfcomm_mutex);
 
 static LIST_HEAD(session_list);
 
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority);
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
 static int rfcomm_queue_disc(struct rfcomm_dlc *d);
@@ -377,13 +378,11 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
 static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_dlc *d;
-       struct list_head *p;
 
-       list_for_each(p, &s->dlcs) {
-               d = list_entry(p, struct rfcomm_dlc, list);
+       list_for_each_entry(d, &s->dlcs, list)
                if (d->dlci == dlci)
                        return d;
-       }
+
        return NULL;
 }
 
@@ -749,19 +748,34 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
 }
 
 /* ---- RFCOMM frame sending ---- */
-static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
+static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
+                                                       u32 priority)
 {
        struct socket *sock = s->sock;
+       struct sock *sk = sock->sk;
        struct kvec iv = { data, len };
        struct msghdr msg;
 
-       BT_DBG("session %p len %d", s, len);
+       BT_DBG("session %p len %d priority %u", s, len, priority);
+
+       if (sk->sk_priority != priority) {
+               lock_sock(sk);
+               sk->sk_priority = priority;
+               release_sock(sk);
+       }
 
        memset(&msg, 0, sizeof(msg));
 
        return kernel_sendmsg(sock, &msg, &iv, 1, len);
 }
 
+static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
+{
+       BT_DBG("%p cmd %u", s, cmd->ctrl);
+
+       return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX);
+}
+
 static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_cmd cmd;
@@ -773,7 +787,7 @@ static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
@@ -787,7 +801,7 @@ static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
@@ -801,7 +815,7 @@ static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_queue_disc(struct rfcomm_dlc *d)
@@ -815,6 +829,8 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
        if (!skb)
                return -ENOMEM;
 
+       skb->priority = HCI_PRIO_MAX;
+
        cmd = (void *) __skb_put(skb, sizeof(*cmd));
        cmd->addr = d->addr;
        cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
@@ -837,7 +853,7 @@ static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
        cmd.len  = __len8(0);
        cmd.fcs  = __fcs2((u8 *) &cmd);
 
-       return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
+       return rfcomm_send_cmd(s, &cmd);
 }
 
 static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
@@ -862,7 +878,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
@@ -904,7 +920,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
@@ -942,7 +958,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
@@ -969,7 +985,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
@@ -996,7 +1012,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
@@ -1018,7 +1034,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
@@ -1040,7 +1056,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@@ -1091,7 +1107,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
 
        *ptr = __fcs(buf); ptr++;
 
-       return rfcomm_send_frame(s, buf, ptr - buf);
+       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
 }
 
 static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@@ -1769,7 +1785,8 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
                return skb_queue_len(&d->tx_queue);
 
        while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-               err = rfcomm_send_frame(d->session, skb->data, skb->len);
+               err = rfcomm_send_frame(d->session, skb->data, skb->len,
+                                                       skb->priority);
                if (err < 0) {
                        skb_queue_head(&d->tx_queue, skb);
                        break;
@@ -2120,15 +2137,13 @@ static struct hci_cb rfcomm_cb = {
 static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
 {
        struct rfcomm_session *s;
-       struct list_head *pp, *p;
 
        rfcomm_lock();
 
-       list_for_each(p, &session_list) {
-               s = list_entry(p, struct rfcomm_session, list);
-               list_for_each(pp, &s->dlcs) {
+       list_for_each_entry(s, &session_list, list) {
+               struct rfcomm_dlc *d;
+               list_for_each_entry(d, &s->dlcs, list) {
                        struct sock *sk = s->sock->sk;
-                       struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
 
                        seq_printf(f, "%s %s %ld %d %d %d %d\n",
                                                batostr(&bt_sk(sk)->src),
index 5417f6127323ec0db7cb51d75eb1e643fb8ec339..aea2bdd1510f2b4f083a4581105228b927cde858 100644 (file)
@@ -600,6 +600,8 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        break;
                }
 
+               skb->priority = sk->sk_priority;
+
                err = rfcomm_dlc_send(d, skb);
                if (err < 0) {
                        kfree_skb(skb);
index c258796313e08274c6005e8142ca3304046c5a70..fa8f4de53b997213b05a528434bf5ef14374651d 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/capability.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
+#include <linux/workqueue.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -65,7 +66,7 @@ struct rfcomm_dev {
        struct rfcomm_dlc       *dlc;
        struct tty_struct       *tty;
        wait_queue_head_t       wait;
-       struct tasklet_struct   wakeup_task;
+       struct work_struct      wakeup_task;
 
        struct device           *tty_dev;
 
@@ -81,7 +82,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
 static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
 static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
 
-static void rfcomm_tty_wakeup(unsigned long arg);
+static void rfcomm_tty_wakeup(struct work_struct *work);
 
 /* ---- Device functions ---- */
 static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
@@ -133,13 +134,10 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
 {
        struct rfcomm_dev *dev;
-       struct list_head  *p;
 
-       list_for_each(p, &rfcomm_dev_list) {
-               dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list)
                if (dev->id == id)
                        return dev;
-       }
 
        return NULL;
 }
@@ -197,7 +195,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
 
 static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 {
-       struct rfcomm_dev *dev;
+       struct rfcomm_dev *dev, *entry;
        struct list_head *head = &rfcomm_dev_list, *p;
        int err = 0;
 
@@ -212,8 +210,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        if (req->dev_id < 0) {
                dev->id = 0;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
+                       if (entry->id != dev->id)
                                break;
 
                        dev->id++;
@@ -222,9 +220,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        } else {
                dev->id = req->dev_id;
 
-               list_for_each(p, &rfcomm_dev_list) {
-                       struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
-
+               list_for_each_entry(entry, &rfcomm_dev_list, list) {
                        if (entry->id == dev->id) {
                                err = -EADDRINUSE;
                                goto out;
@@ -257,7 +253,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
        atomic_set(&dev->opened, 0);
 
        init_waitqueue_head(&dev->wait);
-       tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
+       INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
 
        skb_queue_head_init(&dev->pending);
 
@@ -351,7 +347,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
        struct rfcomm_dev *dev = (void *) skb->sk;
        atomic_sub(skb->truesize, &dev->wmem_alloc);
        if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
-               tasklet_schedule(&dev->wakeup_task);
+               queue_work(system_nrt_wq, &dev->wakeup_task);
        rfcomm_dev_put(dev);
 }
 
@@ -455,9 +451,9 @@ static int rfcomm_release_dev(void __user *arg)
 
 static int rfcomm_get_dev_list(void __user *arg)
 {
+       struct rfcomm_dev *dev;
        struct rfcomm_dev_list_req *dl;
        struct rfcomm_dev_info *di;
-       struct list_head *p;
        int n = 0, size, err;
        u16 dev_num;
 
@@ -479,8 +475,7 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        read_lock_bh(&rfcomm_dev_lock);
 
-       list_for_each(p, &rfcomm_dev_list) {
-               struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
+       list_for_each_entry(dev, &rfcomm_dev_list, list) {
                if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                        continue;
                (di + n)->id      = dev->id;
@@ -635,9 +630,10 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
 }
 
 /* ---- TTY functions ---- */
-static void rfcomm_tty_wakeup(unsigned long arg)
+static void rfcomm_tty_wakeup(struct work_struct *work)
 {
-       struct rfcomm_dev *dev = (void *) arg;
+       struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
+                                                               wakeup_task);
        struct tty_struct *tty = dev->tty;
        if (!tty)
                return;
@@ -762,7 +758,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
                rfcomm_dlc_close(dev->dlc, 0);
 
                clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
-               tasklet_kill(&dev->wakeup_task);
+               cancel_work_sync(&dev->wakeup_task);
 
                rfcomm_dlc_lock(dev->dlc);
                tty->driver_data = NULL;
@@ -1155,9 +1151,11 @@ static const struct tty_operations rfcomm_ops = {
 
 int __init rfcomm_init_ttys(void)
 {
+       int error;
+
        rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
        if (!rfcomm_tty_driver)
-               return -1;
+               return -ENOMEM;
 
        rfcomm_tty_driver->owner        = THIS_MODULE;
        rfcomm_tty_driver->driver_name  = "rfcomm";
@@ -1172,10 +1170,11 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
-       if (tty_register_driver(rfcomm_tty_driver)) {
+       error = tty_register_driver(rfcomm_tty_driver);
+       if (error) {
                BT_ERR("Can't register RFCOMM TTY driver");
                put_tty_driver(rfcomm_tty_driver);
-               return -1;
+               return error;
        }
 
        BT_INFO("RFCOMM TTY layer initialized");
index 759b63572641012b4c89fa5f48fcf6c68eee6918..94e94ca353848768e5bca28c3364a7b8554acdf3 100644 (file)
@@ -181,7 +181,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
        if (!skb)
                return;
 
-       hci_send_acl(conn->hcon, skb, 0);
+       skb->priority = HCI_PRIO_MAX;
+       hci_send_acl(conn->hchan, skb, 0);
 
        mod_timer(&conn->security_timer, jiffies +
                                        msecs_to_jiffies(SMP_TIMEOUT));
index cbc003b2914ae1a59ce695f3df21efc934aa8090..7dc05ecf040a374a5c5a1d26af49f73856968bf7 100644 (file)
@@ -3218,6 +3218,26 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,
 }
 EXPORT_SYMBOL_GPL(skb_tstamp_tx);
 
+void skb_complete_wifi_ack(struct sk_buff *skb, bool acked)
+{
+       struct sock *sk = skb->sk;
+       struct sock_exterr_skb *serr;
+       int err;
+
+       skb->wifi_acked_valid = 1;
+       skb->wifi_acked = acked;
+
+       serr = SKB_EXT_ERR(skb);
+       memset(serr, 0, sizeof(*serr));
+       serr->ee.ee_errno = ENOMSG;
+       serr->ee.ee_origin = SO_EE_ORIGIN_TXSTATUS;
+
+       err = sock_queue_err_skb(sk, skb);
+       if (err)
+               kfree_skb(skb);
+}
+EXPORT_SYMBOL_GPL(skb_complete_wifi_ack);
+
 
 /**
  * skb_partial_csum_set - set up and verify partial csum values for packet
index 2de9dc29595611fdd409d2bc96c5bd6845f72cf2..9a8b3fac14014be42177d93f75d5393929edd16c 100644 (file)
@@ -740,6 +740,11 @@ set_rcvbuf:
        case SO_RXQ_OVFL:
                sock_valbool_flag(sk, SOCK_RXQ_OVFL, valbool);
                break;
+
+       case SO_WIFI_STATUS:
+               sock_valbool_flag(sk, SOCK_WIFI_STATUS, valbool);
+               break;
+
        default:
                ret = -ENOPROTOOPT;
                break;
@@ -961,6 +966,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
                v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
                break;
 
+       case SO_WIFI_STATUS:
+               v.val = !!sock_flag(sk, SOCK_WIFI_STATUS);
+               break;
+
        default:
                return -ENOPROTOOPT;
        }
index 93b2434226592e335568195ccaeaa20e06788d19..476b106c0b1cbcb7e69631e49832c23cb6007816 100644 (file)
@@ -177,7 +177,8 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index b3f65520e7a716312adc51d48d8fa9d8e2993c3d..39d72ccaffb3d92b977dfa89e8bc366f39d65830 100644 (file)
@@ -78,7 +78,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
@@ -372,13 +373,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
               pubsta->addr, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
-       /*
-        * The aggregation code is not prepared to handle
-        * anything but STA/AP due to the BSSID handling.
-        * IBSS could work in the code but isn't supported
-        * by drivers or the standard.
-        */
        if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+           sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
            sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sdata->vif.type != NL80211_IFTYPE_AP)
                return -EINVAL;
index d06c65fa5526a88739a647b809067f37fd64fc24..1063a7e57d62a9d2cf68e965e71152c9f1eb3033 100644 (file)
@@ -411,7 +411,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                                BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) |
                                BIT(NL80211_STA_FLAG_WME) |
                                BIT(NL80211_STA_FLAG_MFP) |
-                               BIT(NL80211_STA_FLAG_AUTHENTICATED);
+                               BIT(NL80211_STA_FLAG_AUTHENTICATED) |
+                               BIT(NL80211_STA_FLAG_TDLS_PEER);
        if (test_sta_flag(sta, WLAN_STA_AUTHORIZED))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHORIZED);
        if (test_sta_flag(sta, WLAN_STA_SHORT_PREAMBLE))
@@ -422,6 +423,8 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_MFP);
        if (test_sta_flag(sta, WLAN_STA_AUTH))
                sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               sinfo->sta_flags.set |= BIT(NL80211_STA_FLAG_TDLS_PEER);
 }
 
 
@@ -488,6 +491,31 @@ static void ieee80211_config_ap_ssid(struct ieee80211_sub_if_data *sdata,
                (params->hidden_ssid != NL80211_HIDDEN_SSID_NOT_IN_USE);
 }
 
+static int ieee80211_set_probe_resp(struct ieee80211_sub_if_data *sdata,
+                                   u8 *resp, size_t resp_len)
+{
+       struct sk_buff *new, *old;
+
+       if (!resp || !resp_len)
+               return -EINVAL;
+
+       old = sdata->u.ap.probe_resp;
+
+       new = dev_alloc_skb(resp_len);
+       if (!new)
+               return -ENOMEM;
+
+       memcpy(skb_put(new, resp_len), resp, resp_len);
+
+       rcu_assign_pointer(sdata->u.ap.probe_resp, new);
+       synchronize_rcu();
+
+       if (old)
+               dev_kfree_skb(old);
+
+       return 0;
+}
+
 /*
  * This handles both adding a beacon and setting new beacon info
  */
@@ -498,6 +526,7 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
        int new_head_len, new_tail_len;
        int size;
        int err = -EINVAL;
+       u32 changed = 0;
 
        old = rtnl_dereference(sdata->u.ap.beacon);
 
@@ -581,11 +610,17 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
 
        kfree(old);
 
+       err = ieee80211_set_probe_resp(sdata, params->probe_resp,
+                                      params->probe_resp_len);
+       if (!err)
+               changed |= BSS_CHANGED_AP_PROBE_RESP;
+
        ieee80211_config_ap_ssid(sdata, params);
+       changed |= BSS_CHANGED_BEACON_ENABLED |
+                  BSS_CHANGED_BEACON |
+                  BSS_CHANGED_SSID;
 
-       ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
-                                               BSS_CHANGED_BEACON |
-                                               BSS_CHANGED_SSID);
+       ieee80211_bss_info_change_notify(sdata, changed);
        return 0;
 }
 
@@ -594,6 +629,8 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata;
        struct beacon_data *old;
+       struct ieee80211_sub_if_data *vlan;
+       int ret;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
@@ -601,7 +638,24 @@ static int ieee80211_add_beacon(struct wiphy *wiphy, struct net_device *dev,
        if (old)
                return -EALREADY;
 
-       return ieee80211_config_beacon(sdata, params);
+       ret = ieee80211_config_beacon(sdata, params);
+       if (ret)
+               return ret;
+
+       /*
+        * Apply control port protocol, this allows us to
+        * not encrypt dynamic WEP control frames.
+        */
+       sdata->control_port_protocol = params->crypto.control_port_ethertype;
+       sdata->control_port_no_encrypt = params->crypto.control_port_no_encrypt;
+       list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list) {
+               vlan->control_port_protocol =
+                       params->crypto.control_port_ethertype;
+               vlan->control_port_no_encrypt =
+                       params->crypto.control_port_no_encrypt;
+       }
+
+       return 0;
 }
 
 static int ieee80211_set_beacon(struct wiphy *wiphy, struct net_device *dev,
@@ -847,7 +901,12 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev,
 
        sta_apply_parameters(local, sta, params);
 
-       rate_control_rate_init(sta);
+       /*
+        * for TDLS, rate control should be initialized only when supported
+        * rates are known.
+        */
+       if (!test_sta_flag(sta, WLAN_STA_TDLS_PEER))
+               rate_control_rate_init(sta);
 
        layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
                sdata->vif.type == NL80211_IFTYPE_AP;
@@ -931,6 +990,9 @@ static int ieee80211_change_station(struct wiphy *wiphy,
 
        sta_apply_parameters(local, sta, params);
 
+       if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) && params->supported_rates)
+               rate_control_rate_init(sta);
+
        rcu_read_unlock();
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION &&
@@ -1394,7 +1456,7 @@ static int ieee80211_set_channel(struct wiphy *wiphy,
            (old_oper_type != local->_oper_channel_type))
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
 
-       if ((sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR) &&
+       if (sdata && sdata->vif.type != NL80211_IFTYPE_MONITOR &&
            old_vif_oper_type != sdata->vif.bss_conf.channel_type)
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_HT);
 
@@ -1917,7 +1979,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                             enum nl80211_channel_type channel_type,
                             bool channel_type_valid, unsigned int wait,
                             const u8 *buf, size_t len, bool no_cck,
-                            u64 *cookie)
+                            bool dont_wait_for_ack, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1925,10 +1987,15 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        struct sta_info *sta;
        struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
-       u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
-                   IEEE80211_TX_CTL_REQ_TX_STATUS;
+       u32 flags;
        bool is_offchan = false;
 
+       if (dont_wait_for_ack)
+               flags = IEEE80211_TX_CTL_NO_ACK;
+       else
+               flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+                       IEEE80211_TX_CTL_REQ_TX_STATUS;
+
        /* Check that we are on the requested channel for transmission */
        if (chan != local->tmp_channel &&
            chan != local->oper_channel)
@@ -2488,6 +2555,82 @@ static int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
+static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
+                                 const u8 *peer, u64 *cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_qos_hdr *nullfunc;
+       struct sk_buff *skb;
+       int size = sizeof(*nullfunc);
+       __le16 fc;
+       bool qos;
+       struct ieee80211_tx_info *info;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       sta = sta_info_get(sdata, peer);
+       if (sta) {
+               qos = test_sta_flag(sta, WLAN_STA_WME);
+               rcu_read_unlock();
+       } else {
+               rcu_read_unlock();
+               return -ENOLINK;
+       }
+
+       if (qos) {
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_QOS_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       } else {
+               size -= 2;
+               fc = cpu_to_le16(IEEE80211_FTYPE_DATA |
+                                IEEE80211_STYPE_NULLFUNC |
+                                IEEE80211_FCTL_FROMDS);
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + size);
+       if (!skb)
+               return -ENOMEM;
+
+       skb->dev = dev;
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (void *) skb_put(skb, size);
+       nullfunc->frame_control = fc;
+       nullfunc->duration_id = 0;
+       memcpy(nullfunc->addr1, sta->sta.addr, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->vif.addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, sdata->vif.addr, ETH_ALEN);
+       nullfunc->seq_ctrl = 0;
+
+       info = IEEE80211_SKB_CB(skb);
+
+       info->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS |
+                      IEEE80211_TX_INTFL_NL80211_FRAME_TX;
+
+       skb_set_queue_mapping(skb, IEEE80211_AC_VO);
+       skb->priority = 7;
+       if (qos)
+               nullfunc->qos_ctrl = cpu_to_le16(7);
+
+       local_bh_disable();
+       ieee80211_xmit(sdata, skb);
+       local_bh_enable();
+
+       *cookie = (unsigned long) skb;
+       return 0;
+}
+
+static struct ieee80211_channel *
+ieee80211_wiphy_get_channel(struct wiphy *wiphy)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       return local->oper_channel;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -2553,4 +2696,6 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_rekey_data = ieee80211_set_rekey_data,
        .tdls_oper = ieee80211_tdls_oper,
        .tdls_mgmt = ieee80211_tdls_mgmt,
+       .probe_client = ieee80211_probe_client,
+       .get_channel = ieee80211_wiphy_get_channel,
 };
index 883996b2f99fae26bd21e53d1ce12d7b322a8608..00cefcb493ebea1fb0cd8ba0fe7955ad424e5175 100644 (file)
@@ -190,7 +190,7 @@ static ssize_t uapsd_max_sp_len_write(struct file *file,
                return -EFAULT;
        buf[len] = '\0';
 
-       ret = strict_strtoul(buf, 0, &val);
+       ret = kstrtoul(buf, 0, &val);
 
        if (ret)
                return -EINVAL;
index 5f165d7eb2db4c22c3411129c4f93b72216a2794..b12ed52732c814b976bfc0084e680782faf5442d 100644 (file)
@@ -5,6 +5,11 @@
 #include "ieee80211_i.h"
 #include "driver-trace.h"
 
+static inline void check_sdata_in_driver(struct ieee80211_sub_if_data *sdata)
+{
+       WARN_ON(!(sdata->flags & IEEE80211_SDATA_IN_DRIVER));
+}
+
 static inline void drv_tx(struct ieee80211_local *local, struct sk_buff *skb)
 {
        local->ops->tx(&local->hw, skb);
@@ -69,15 +74,23 @@ static inline int drv_resume(struct ieee80211_local *local)
 #endif
 
 static inline int drv_add_interface(struct ieee80211_local *local,
-                                   struct ieee80211_vif *vif)
+                                   struct ieee80211_sub_if_data *sdata)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_add_interface(local, vif_to_sdata(vif));
-       ret = local->ops->add_interface(&local->hw, vif);
+       if (WARN_ON(sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR))
+               return -EINVAL;
+
+       trace_drv_add_interface(local, sdata);
+       ret = local->ops->add_interface(&local->hw, &sdata->vif);
        trace_drv_return_int(local, ret);
+
+       if (ret == 0)
+               sdata->flags |= IEEE80211_SDATA_IN_DRIVER;
+
        return ret;
 }
 
@@ -89,6 +102,8 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_change_interface(local, sdata, type, p2p);
        ret = local->ops->change_interface(&local->hw, &sdata->vif, type, p2p);
        trace_drv_return_int(local, ret);
@@ -96,12 +111,15 @@ static inline int drv_change_interface(struct ieee80211_local *local,
 }
 
 static inline void drv_remove_interface(struct ieee80211_local *local,
-                                       struct ieee80211_vif *vif)
+                                       struct ieee80211_sub_if_data *sdata)
 {
        might_sleep();
 
-       trace_drv_remove_interface(local, vif_to_sdata(vif));
-       local->ops->remove_interface(&local->hw, vif);
+       check_sdata_in_driver(sdata);
+
+       trace_drv_remove_interface(local, sdata);
+       local->ops->remove_interface(&local->hw, &sdata->vif);
+       sdata->flags &= ~IEEE80211_SDATA_IN_DRIVER;
        trace_drv_return_void(local);
 }
 
@@ -124,6 +142,8 @@ static inline void drv_bss_info_changed(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_bss_info_changed(local, sdata, info, changed);
        if (local->ops->bss_info_changed)
                local->ops->bss_info_changed(&local->hw, &sdata->vif, info, changed);
@@ -139,6 +159,8 @@ static inline int drv_tx_sync(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_tx_sync(local, sdata, bssid, type);
        if (local->ops->tx_sync)
                ret = local->ops->tx_sync(&local->hw, &sdata->vif,
@@ -154,6 +176,8 @@ static inline void drv_finish_tx_sync(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_finish_tx_sync(local, sdata, bssid, type);
        if (local->ops->finish_tx_sync)
                local->ops->finish_tx_sync(&local->hw, &sdata->vif,
@@ -211,6 +235,8 @@ static inline int drv_set_key(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_key(local, cmd, sdata, sta, key);
        ret = local->ops->set_key(&local->hw, cmd, &sdata->vif, sta, key);
        trace_drv_return_int(local, ret);
@@ -228,6 +254,8 @@ static inline void drv_update_tkip_key(struct ieee80211_local *local,
        if (sta)
                ista = &sta->sta;
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_update_tkip_key(local, sdata, conf, ista, iv32);
        if (local->ops->update_tkip_key)
                local->ops->update_tkip_key(&local->hw, &sdata->vif, conf,
@@ -243,6 +271,8 @@ static inline int drv_hw_scan(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_hw_scan(local, sdata);
        ret = local->ops->hw_scan(&local->hw, &sdata->vif, req);
        trace_drv_return_int(local, ret);
@@ -254,6 +284,8 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_cancel_hw_scan(local, sdata);
        local->ops->cancel_hw_scan(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -269,6 +301,8 @@ drv_sched_scan_start(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_start(local, sdata);
        ret = local->ops->sched_scan_start(&local->hw, &sdata->vif,
                                              req, ies);
@@ -281,6 +315,8 @@ static inline void drv_sched_scan_stop(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sched_scan_stop(local, sdata);
        local->ops->sched_scan_stop(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
@@ -377,6 +413,8 @@ static inline void drv_sta_notify(struct ieee80211_local *local,
                                  enum sta_notify_cmd cmd,
                                  struct ieee80211_sta *sta)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_notify(local, sdata, cmd, sta);
        if (local->ops->sta_notify)
                local->ops->sta_notify(&local->hw, &sdata->vif, cmd, sta);
@@ -391,6 +429,8 @@ static inline int drv_sta_add(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_add(local, sdata, sta);
        if (local->ops->sta_add)
                ret = local->ops->sta_add(&local->hw, &sdata->vif, sta);
@@ -406,6 +446,8 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_sta_remove(local, sdata, sta);
        if (local->ops->sta_remove)
                local->ops->sta_remove(&local->hw, &sdata->vif, sta);
@@ -421,6 +463,8 @@ static inline int drv_conf_tx(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_conf_tx(local, sdata, queue, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, &sdata->vif,
@@ -436,6 +480,8 @@ static inline u64 drv_get_tsf(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_get_tsf(local, sdata);
        if (local->ops->get_tsf)
                ret = local->ops->get_tsf(&local->hw, &sdata->vif);
@@ -449,6 +495,8 @@ static inline void drv_set_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_tsf(local, sdata, tsf);
        if (local->ops->set_tsf)
                local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
@@ -460,6 +508,8 @@ static inline void drv_reset_tsf(struct ieee80211_local *local,
 {
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_reset_tsf(local, sdata);
        if (local->ops->reset_tsf)
                local->ops->reset_tsf(&local->hw, &sdata->vif);
@@ -489,6 +539,8 @@ static inline int drv_ampdu_action(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_ampdu_action(local, sdata, action, sta, tid, ssn, buf_size);
 
        if (local->ops->ampdu_action)
@@ -644,6 +696,8 @@ static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
 
        might_sleep();
 
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_bitrate_mask(local, sdata, mask);
        if (local->ops->set_bitrate_mask)
                ret = local->ops->set_bitrate_mask(&local->hw,
@@ -657,6 +711,8 @@ static inline void drv_set_rekey_data(struct ieee80211_local *local,
                                      struct ieee80211_sub_if_data *sdata,
                                      struct cfg80211_gtk_rekey_data *data)
 {
+       check_sdata_in_driver(sdata);
+
        trace_drv_set_rekey_data(local, sdata, data);
        if (local->ops->set_rekey_data)
                local->ops->set_rekey_data(&local->hw, &sdata->vif, data);
index f0fb737efa8629bc8204f2f7cb8f5a568857853c..d06975098aad49b4ff9334d8b775b0227d7671ef 100644 (file)
@@ -196,7 +196,8 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        memcpy(mgmt->da, da, ETH_ALEN);
        memcpy(mgmt->sa, sdata->vif.addr, ETH_ALEN);
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
-           sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+           sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+           sdata->vif.type == NL80211_IFTYPE_MESH_POINT)
                memcpy(mgmt->bssid, sdata->vif.addr, ETH_ALEN);
        else if (sdata->vif.type == NL80211_IFTYPE_STATION)
                memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
index ede9a8b341acadd2c2a491b1277a585f68eaea19..7d84af70132f8f0b4a6cdbbf80876b71cdca24c4 100644 (file)
@@ -97,6 +97,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        /* if merging, indicate to driver that we leave the old IBSS */
        if (sdata->vif.bss_conf.ibss_joined) {
                sdata->vif.bss_conf.ibss_joined = false;
+               netif_carrier_off(sdata->dev);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_IBSS);
        }
 
@@ -207,6 +208,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        bss = cfg80211_inform_bss_frame(local->hw.wiphy, local->hw.conf.channel,
                                        mgmt, skb->len, 0, GFP_KERNEL);
        cfg80211_put_bss(bss);
+       netif_carrier_on(sdata->dev);
        cfg80211_ibss_joined(sdata->dev, ifibss->bssid, GFP_KERNEL);
 }
 
@@ -990,6 +992,7 @@ int ieee80211_ibss_leave(struct ieee80211_sub_if_data *sdata)
        }
 
        sta_info_flush(sdata->local, sdata);
+       netif_carrier_off(sdata->dev);
 
        /* remove beacon */
        kfree(sdata->u.ibss.ie);
index ea10a51babda9fa113c84ee000d46c62b86e69c6..068cc92d16aa8dea3f33ce2b7793f87aa7407798 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/spinlock.h>
 #include <linux/etherdevice.h>
 #include <linux/leds.h>
+#include <linux/idr.h>
 #include <net/ieee80211_radiotap.h>
 #include <net/cfg80211.h>
 #include <net/mac80211.h>
@@ -184,12 +185,15 @@ enum ieee80211_packet_rx_flags {
  * enum ieee80211_rx_flags - RX data flags
  *
  * @IEEE80211_RX_CMNTR: received on cooked monitor already
+ * @IEEE80211_RX_BEACON_REPORTED: This frame was already reported
+ *     to cfg80211_report_obss_beacon().
  *
  * These flags are used across handling multiple interfaces
  * for a single frame.
  */
 enum ieee80211_rx_flags {
        IEEE80211_RX_CMNTR              = BIT(0),
+       IEEE80211_RX_BEACON_REPORTED    = BIT(1),
 };
 
 struct ieee80211_rx_data {
@@ -228,6 +232,7 @@ struct beacon_data {
 
 struct ieee80211_if_ap {
        struct beacon_data __rcu *beacon;
+       struct sk_buff __rcu *probe_resp;
 
        struct list_head vlans;
 
@@ -543,6 +548,7 @@ struct ieee80211_if_mesh {
  *     associated stations and deliver multicast frames both
  *     back to wireless media and to the local net stack.
  * @IEEE80211_SDATA_DISCONNECT_RESUME: Disconnect after resume.
+ * @IEEE80211_SDATA_IN_DRIVER: indicates interface was added to driver
  */
 enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_ALLMULTI                = BIT(0),
@@ -550,6 +556,7 @@ enum ieee80211_sub_if_data_flags {
        IEEE80211_SDATA_OPERATING_GMODE         = BIT(2),
        IEEE80211_SDATA_DONT_BRIDGE_PACKETS     = BIT(3),
        IEEE80211_SDATA_DISCONNECT_RESUME       = BIT(4),
+       IEEE80211_SDATA_IN_DRIVER               = BIT(5),
 };
 
 /**
@@ -722,17 +729,16 @@ enum {
  *     operating channel
  * @SCAN_SET_CHANNEL: Set the next channel to be scanned
  * @SCAN_SEND_PROBE: Send probe requests and wait for probe responses
- * @SCAN_LEAVE_OPER_CHANNEL: Leave the operating channel, notify the AP
- *     about us leaving the channel and stop all associated STA interfaces
- * @SCAN_ENTER_OPER_CHANNEL: Enter the operating channel again, notify the
- *     AP about us being back and restart all associated STA interfaces
+ * @SCAN_SUSPEND: Suspend the scan and go back to operating channel to
+ *     send out data
+ * @SCAN_RESUME: Resume the scan and scan the next channel
  */
 enum mac80211_scan_state {
        SCAN_DECISION,
        SCAN_SET_CHANNEL,
        SCAN_SEND_PROBE,
-       SCAN_LEAVE_OPER_CHANNEL,
-       SCAN_ENTER_OPER_CHANNEL,
+       SCAN_SUSPEND,
+       SCAN_RESUME,
 };
 
 struct ieee80211_local {
@@ -1012,6 +1018,9 @@ struct ieee80211_local {
        u32 hw_roc_cookie;
        bool hw_roc_for_tx;
 
+       struct idr ack_status_frames;
+       spinlock_t ack_status_lock;
+
        /* dummy netdev for use w/ NAPI */
        struct net_device napi_dev;
 
@@ -1334,6 +1343,12 @@ void ieee80211_recalc_smps(struct ieee80211_local *local);
 size_t ieee80211_ie_split(const u8 *ies, size_t ielen,
                          const u8 *ids, int n_ids, size_t offset);
 size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap);
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                               struct ieee80211_sta_ht_cap *ht_cap,
+                               struct ieee80211_channel *channel,
+                               enum nl80211_channel_type channel_type);
 
 /* internal work items */
 void ieee80211_work_init(struct ieee80211_local *local);
@@ -1362,6 +1377,8 @@ ieee80211_get_channel_mode(struct ieee80211_local *local,
 bool ieee80211_set_channel_type(struct ieee80211_local *local,
                                struct ieee80211_sub_if_data *sdata,
                                enum nl80211_channel_type chantype);
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index 30d73552e9ab0f89ef53707e564dd67aee47a3b8..12a6d4bb5d3736b348996bac224b43d5651873a1 100644 (file)
@@ -188,11 +188,22 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                if (!is_valid_ether_addr(sdata->u.wds.remote_addr))
                        return -ENOLINK;
                break;
-       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_AP_VLAN: {
+               struct ieee80211_sub_if_data *master;
+
                if (!sdata->bss)
                        return -ENOLINK;
+
                list_add(&sdata->u.vlan.list, &sdata->bss->vlans);
+
+               master = container_of(sdata->bss,
+                                     struct ieee80211_sub_if_data, u.ap);
+               sdata->control_port_protocol =
+                       master->control_port_protocol;
+               sdata->control_port_no_encrypt =
+                       master->control_port_no_encrypt;
                break;
+               }
        case NL80211_IFTYPE_AP:
                sdata->bss = &sdata->u.ap;
                break;
@@ -265,7 +276,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                break;
        default:
                if (coming_up) {
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
                        if (res)
                                goto err_stop;
                }
@@ -282,10 +293,18 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
                changed |= ieee80211_reset_erp_info(sdata);
                ieee80211_bss_info_change_notify(sdata, changed);
 
-               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
+                   sdata->vif.type == NL80211_IFTYPE_ADHOC)
                        netif_carrier_off(dev);
                else
                        netif_carrier_on(dev);
+
+               /*
+                * set default queue parameters so drivers don't
+                * need to initialise the hardware if the hardware
+                * doesn't start up with sane defaults
+                */
+               ieee80211_set_wmm_default(sdata);
        }
 
        set_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -329,15 +348,8 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
        if (coming_up)
                local->open_count++;
 
-       if (hw_reconf_flags) {
+       if (hw_reconf_flags)
                ieee80211_hw_config(local, hw_reconf_flags);
-               /*
-                * set default queue parameters so drivers don't
-                * need to initialise the hardware if the hardware
-                * doesn't start up with sane defaults
-                */
-               ieee80211_set_wmm_default(sdata);
-       }
 
        ieee80211_recalc_ps(local, -1);
 
@@ -345,7 +357,7 @@ static int ieee80211_do_open(struct net_device *dev, bool coming_up)
 
        return 0;
  err_del_interface:
-       drv_remove_interface(local, &sdata->vif);
+       drv_remove_interface(local, sdata);
  err_stop:
        if (!local->open_count)
                drv_stop(local);
@@ -450,15 +462,19 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
                struct beacon_data *old_beacon =
                        rtnl_dereference(sdata->u.ap.beacon);
+               struct sk_buff *old_probe_resp =
+                       rtnl_dereference(sdata->u.ap.probe_resp);
 
                /* sdata_running will return false, so this will disable */
                ieee80211_bss_info_change_notify(sdata,
                                                 BSS_CHANGED_BEACON_ENABLED);
 
-               /* remove beacon */
+               /* remove beacon and probe response */
                RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+               RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
                synchronize_rcu();
                kfree(old_beacon);
+               kfree(old_probe_resp);
 
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
@@ -520,7 +536,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                ieee80211_free_keys(sdata);
 
                if (going_down)
-                       drv_remove_interface(local, &sdata->vif);
+                       drv_remove_interface(local, sdata);
        }
 
        sdata->bss = NULL;
index fb02ea52d2c2b46f760944de0f407f417d0fb492..87a89741432dce811cdb31168036788146f5721b 100644 (file)
@@ -134,9 +134,13 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
 
                if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+                     (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                        sdata->crypto_tx_tailroom_needed_cnt--;
 
+               WARN_ON((key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE) &&
+                       (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV));
+
                return 0;
        }
 
@@ -179,7 +183,8 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
        sdata = key->sdata;
 
        if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV) ||
+             (key->conf.flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)))
                increment_tailroom_need_count(sdata);
 
        if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
index d999bf3b84e1b27d0d79c91d44b7771756d92a3e..e323d4e6647bd702ab0a5f0a63e5d1dbfc4fed7d 100644 (file)
@@ -100,7 +100,7 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
  */
 bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        enum nl80211_channel_type channel_type;
 
        /* This logic needs to match logic in ieee80211_hw_config */
@@ -114,7 +114,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -126,8 +126,8 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
                return false;
 
        /* Check current hardware-config against oper_channel. */
-       if ((local->oper_channel != local->hw.conf.channel) ||
-           (local->_oper_channel_type != local->hw.conf.channel_type))
+       if (local->oper_channel != local->hw.conf.channel ||
+           local->_oper_channel_type != local->hw.conf.channel_type)
                return false;
 
        return true;
@@ -135,7 +135,7 @@ bool ieee80211_cfg_on_oper_channel(struct ieee80211_local *local)
 
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 {
-       struct ieee80211_channel *chan, *scan_chan;
+       struct ieee80211_channel *chan;
        int ret = 0;
        int power;
        enum nl80211_channel_type channel_type;
@@ -143,14 +143,12 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
 
        might_sleep();
 
-       scan_chan = local->scan_channel;
-
        /* If this off-channel logic ever changes,  ieee80211_on_oper_channel
         * may need to change as well.
         */
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
-       if (scan_chan) {
-               chan = scan_chan;
+       if (local->scan_channel) {
+               chan = local->scan_channel;
                /* If scanning on oper channel, use whatever channel-type
                 * is currently in use.
                 */
@@ -159,7 +157,7 @@ int ieee80211_hw_config(struct ieee80211_local *local, u32 changed)
                else
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
-               chan = scan_chan = local->tmp_channel;
+               chan = local->tmp_channel;
                channel_type = local->tmp_channel_type;
        } else {
                chan = local->oper_channel;
@@ -595,7 +593,10 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->flags |= WIPHY_FLAG_NETNS_OK |
                        WIPHY_FLAG_4ADDR_AP |
-                       WIPHY_FLAG_4ADDR_STATION;
+                       WIPHY_FLAG_4ADDR_STATION |
+                       WIPHY_FLAG_REPORTS_OBSS;
+
+       wiphy->features = NL80211_FEATURE_SK_TX_STATUS;
 
        if (!ops->set_key)
                wiphy->flags |= WIPHY_FLAG_IBSS_RSN;
@@ -670,6 +671,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        INIT_WORK(&local->sched_scan_stopped_work,
                  ieee80211_sched_scan_stopped_work);
 
+       spin_lock_init(&local->ack_status_lock);
+       idr_init(&local->ack_status_frames);
+       /* preallocate at least one entry */
+       idr_pre_get(&local->ack_status_frames, GFP_KERNEL);
+
        sta_info_init(local);
 
        for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
@@ -1045,6 +1051,13 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
 }
 EXPORT_SYMBOL(ieee80211_unregister_hw);
 
+static int ieee80211_free_ack_frame(int id, void *p, void *data)
+{
+       WARN_ONCE(1, "Have pending ack frames!\n");
+       kfree_skb(p);
+       return 0;
+}
+
 void ieee80211_free_hw(struct ieee80211_hw *hw)
 {
        struct ieee80211_local *local = hw_to_local(hw);
@@ -1055,6 +1068,10 @@ void ieee80211_free_hw(struct ieee80211_hw *hw)
        if (local->wiphy_ciphers_allocated)
                kfree(local->hw.wiphy->cipher_suites);
 
+       idr_for_each(&local->ack_status_frames,
+                    ieee80211_free_ack_frame, NULL);
+       idr_destroy(&local->ack_status_frames);
+
        wiphy_free(local->hw.wiphy);
 }
 EXPORT_SYMBOL(ieee80211_free_hw);
index a7078fdba8ca7e3cf2a1f047f1f39c57c643f63e..b3a125f60347d47a9b474bdde83291611a3e505a 100644 (file)
@@ -76,6 +76,7 @@ static void ieee80211_mesh_housekeeping_timer(unsigned long data)
 bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
+       struct ieee80211_local *local = sdata->local;
 
        /*
         * As support for each feature is added, check for matching
@@ -87,15 +88,23 @@ bool mesh_matches_local(struct ieee802_11_elems *ie, struct ieee80211_sub_if_dat
         *   - MDA enabled
         * - Power management control on fc
         */
-       if (ifmsh->mesh_id_len == ie->mesh_id_len &&
-               memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
-               (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
-               (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
-               (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
-               (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
-               (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth))
-               return true;
-
+       if (!(ifmsh->mesh_id_len == ie->mesh_id_len &&
+            memcmp(ifmsh->mesh_id, ie->mesh_id, ie->mesh_id_len) == 0 &&
+            (ifmsh->mesh_pp_id == ie->mesh_config->meshconf_psel) &&
+            (ifmsh->mesh_pm_id == ie->mesh_config->meshconf_pmetric) &&
+            (ifmsh->mesh_cc_id == ie->mesh_config->meshconf_congest) &&
+            (ifmsh->mesh_sp_id == ie->mesh_config->meshconf_synch) &&
+            (ifmsh->mesh_auth_id == ie->mesh_config->meshconf_auth)))
+               goto mismatch;
+
+       /* disallow peering with mismatched channel types for now */
+       if (ie->ht_info_elem &&
+           (local->_oper_channel_type !=
+            ieee80211_ht_info_to_channel_type(ie->ht_info_elem)))
+               goto mismatch;
+
+       return true;
+mismatch:
        return false;
 }
 
@@ -341,6 +350,49 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
        return 0;
 }
 
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       u8 *pos;
+
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+       if (!sband->ht_cap.ht_supported ||
+           local->_oper_channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_cap));
+       ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
+
+       return 0;
+}
+
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_channel *channel = local->oper_channel;
+       enum nl80211_channel_type channel_type = local->_oper_channel_type;
+       struct ieee80211_supported_band *sband =
+                               local->hw.wiphy->bands[channel->band];
+       struct ieee80211_sta_ht_cap *ht_cap = &sband->ht_cap;
+       u8 *pos;
+
+       if (!ht_cap->ht_supported || channel_type == NL80211_CHAN_NO_HT)
+               return 0;
+
+       if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_info))
+               return -ENOMEM;
+
+       pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_info));
+       ieee80211_ie_build_ht_info(pos, ht_cap, channel, channel_type);
+
+       return 0;
+}
 static void ieee80211_mesh_path_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
index 8c00e2d1d63612f3dfd483960805021f79acb204..622cc96eb4dea8fa900e9f17f8c29371a9768c1a 100644 (file)
@@ -31,6 +31,8 @@
  * @MESH_PATH_FIXED: the mesh path has been manually set and should not be
  *     modified
  * @MESH_PATH_RESOLVED: the mesh path can has been resolved
+ * @MESH_PATH_REQ_QUEUED: there is an unsent path request for this destination
+ * already queued up, waiting for the discovery process to start.
  *
  * MESH_PATH_RESOLVED is used by the mesh path timer to
  * decide when to stop or cancel the mesh path discovery.
@@ -41,6 +43,7 @@ enum mesh_path_flags {
        MESH_PATH_SN_VALID =    BIT(2),
        MESH_PATH_FIXED =       BIT(3),
        MESH_PATH_RESOLVED =    BIT(4),
+       MESH_PATH_REQ_QUEUED =  BIT(5),
 };
 
 /**
@@ -212,6 +215,10 @@ int mesh_add_vendor_ies(struct sk_buff *skb,
                        struct ieee80211_sub_if_data *sdata);
 int mesh_add_ds_params_ie(struct sk_buff *skb,
                          struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_cap_ie(struct sk_buff *skb,
+                      struct ieee80211_sub_if_data *sdata);
+int mesh_add_ht_info_ie(struct sk_buff *skb,
+                       struct ieee80211_sub_if_data *sdata);
 void mesh_rmc_free(struct ieee80211_sub_if_data *sdata);
 int mesh_rmc_init(struct ieee80211_sub_if_data *sdata);
 void ieee80211s_init(void);
index 174040a42887c3eaf1d466fcfcf003ab83bd248d..a7afb2d32def7bfe308566b0147328827eb80067 100644 (file)
@@ -113,20 +113,20 @@ static int mesh_path_sel_frame_tx(enum mpath_frame_type action, u8 flags,
                struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 37); /* max HWMP IE */
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -240,20 +240,20 @@ int mesh_path_error_tx(u8 ttl, u8 *target, __le32 target_sn,
                       struct ieee80211_sub_if_data *sdata)
 {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       int ie_len;
+       u8 *pos, ie_len;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.mesh_action) +
+                     sizeof(mgmt->u.action.u.mesh_action);
 
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + 15 /* PERR IE */);
        if (!skb)
                return -1;
        skb_reserve(skb, local->tx_headroom + local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.mesh_action));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.mesh_action));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
@@ -867,9 +867,19 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
                return;
        }
 
+       spin_lock_bh(&mpath->state_lock);
+       if (mpath->flags & MESH_PATH_REQ_QUEUED) {
+               spin_unlock_bh(&mpath->state_lock);
+               spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
+               return;
+       }
+
        memcpy(preq_node->dst, mpath->dst, ETH_ALEN);
        preq_node->flags = flags;
 
+       mpath->flags |= MESH_PATH_REQ_QUEUED;
+       spin_unlock_bh(&mpath->state_lock);
+
        list_add_tail(&preq_node->list, &ifmsh->preq_queue.list);
        ++ifmsh->preq_queue_len;
        spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
@@ -921,6 +931,7 @@ void mesh_path_start_discovery(struct ieee80211_sub_if_data *sdata)
                goto enddiscovery;
 
        spin_lock_bh(&mpath->state_lock);
+       mpath->flags &= ~MESH_PATH_REQ_QUEUED;
        if (preq_node->flags & PREQ_Q_F_START) {
                if (mpath->flags & MESH_PATH_RESOLVING) {
                        spin_unlock_bh(&mpath->state_lock);
@@ -1028,11 +1039,11 @@ int mesh_nexthop_lookup(struct sk_buff *skb,
                        mesh_queue_preq(mpath, PREQ_Q_F_START);
                }
 
-               if (skb_queue_len(&mpath->frame_queue) >=
-                               MESH_FRAME_QUEUE_LEN)
+               if (skb_queue_len(&mpath->frame_queue) >= MESH_FRAME_QUEUE_LEN)
                        skb_to_free = skb_dequeue(&mpath->frame_queue);
 
                info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
+               ieee80211_set_qos_hdr(sdata, skb);
                skb_queue_tail(&mpath->frame_queue, skb);
                if (skb_to_free)
                        mesh_path_discard_frame(skb_to_free, sdata);
@@ -1061,6 +1072,7 @@ void mesh_path_timer(unsigned long data)
        } else if (mpath->discovery_retries < max_preq_retries(sdata)) {
                ++mpath->discovery_retries;
                mpath->discovery_timeout *= 2;
+               mpath->flags &= ~MESH_PATH_REQ_QUEUED;
                spin_unlock_bh(&mpath->state_lock);
                mesh_queue_preq(mpath, 0);
        } else {
index 7f54c5042235dd75fb87963fc7e2da04554d219f..4fc23d1b9c3af921036643d6ed7f242e817685ce 100644 (file)
@@ -213,7 +213,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        struct ieee80211_hdr *hdr;
        struct sk_buff_head tmpq;
        unsigned long flags;
-       struct ieee80211_sub_if_data *sdata = mpath->sdata;
 
        rcu_assign_pointer(mpath->next_hop, sta);
 
@@ -224,8 +223,6 @@ void mesh_path_assign_nexthop(struct mesh_path *mpath, struct sta_info *sta)
        while ((skb = __skb_dequeue(&mpath->frame_queue)) != NULL) {
                hdr = (struct ieee80211_hdr *) skb->data;
                memcpy(hdr->addr1, sta->sta.addr, ETH_ALEN);
-               skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
-               ieee80211_set_qos_hdr(sdata, skb);
                __skb_queue_tail(&tmpq, skb);
        }
 
index 7e57f5d07f660ad7b19c432f95518952382832b9..0140e88a8220ce2f4c25c4758b6c555c2436b180 100644 (file)
@@ -80,11 +80,15 @@ static inline void mesh_plink_fsm_restart(struct sta_info *sta)
  *       on it in the lifecycle management section!
  */
 static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
-                                        u8 *hw_addr, u32 rates)
+                                        u8 *hw_addr, u32 rates,
+                                        struct ieee802_11_elems *elems)
 {
        struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
        struct sta_info *sta;
 
+       sband = local->hw.wiphy->bands[local->oper_channel->band];
+
        if (local->num_sta >= MESH_MAX_PLINKS)
                return NULL;
 
@@ -96,6 +100,9 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata,
        set_sta_flag(sta, WLAN_STA_AUTHORIZED);
        set_sta_flag(sta, WLAN_STA_WME);
        sta->sta.supp_rates[local->hw.conf.channel->band] = rates;
+       if (elems->ht_cap_elem)
+               ieee80211_ht_cap_ie_to_sta_ht_cap(sband, elems->ht_cap_elem,
+                                                 &sta->sta.ht_cap);
        rate_control_rate_init(sta);
 
        return sta;
@@ -153,23 +160,31 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                enum ieee80211_self_protected_actioncode action,
                u8 *da, __le16 llid, __le16 plid, __le16 reason) {
        struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
-                       sdata->u.mesh.ie_len);
+       struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        bool include_plid = false;
-       int ie_len = 4;
        u16 peering_proto = 0;
-       u8 *pos;
-
+       u8 *pos, ie_len = 4;
+       int hdr_len = offsetof(struct ieee80211_mgmt, u.action.u.self_prot) +
+                     sizeof(mgmt->u.action.u.self_prot);
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           hdr_len +
+                           2 + /* capability info */
+                           2 + /* AID */
+                           2 + 8 + /* supported rates */
+                           2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                           2 + sdata->u.mesh.mesh_id_len +
+                           2 + sizeof(struct ieee80211_meshconf_ie) +
+                           2 + sizeof(struct ieee80211_ht_cap) +
+                           2 + sizeof(struct ieee80211_ht_info) +
+                           2 + 8 + /* peering IE */
+                           sdata->u.mesh.ie_len);
        if (!skb)
                return -1;
        skb_reserve(skb, local->hw.extra_tx_headroom);
-       /* 25 is the size of the common mgmt part (24) plus the size of the
-        * common action part (1)
-        */
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 25 + sizeof(mgmt->u.action.u.self_prot));
-       memset(mgmt, 0, 25 + sizeof(mgmt->u.action.u.self_prot));
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+       memset(mgmt, 0, hdr_len);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        memcpy(mgmt->da, da, ETH_ALEN);
@@ -235,6 +250,13 @@ static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
                memcpy(pos, &reason, 2);
                pos += 2;
        }
+
+       if (action != WLAN_SP_MESH_PEERING_CLOSE) {
+               if (mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata))
+                       return -1;
+       }
+
        if (mesh_add_vendor_ies(skb, sdata))
                return -1;
 
@@ -261,7 +283,7 @@ void mesh_neighbour_update(u8 *hw_addr, u32 rates,
                                        elems->ie_start, elems->total_len,
                                        GFP_KERNEL);
                else
-                       sta = mesh_plink_alloc(sdata, hw_addr, rates);
+                       sta = mesh_plink_alloc(sdata, hw_addr, rates, elems);
                if (!sta)
                        return;
                if (sta_info_insert_rcu(sta)) {
@@ -552,7 +574,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                }
 
                rates = ieee80211_sta_get_rates(local, &elems, rx_status->band);
-               sta = mesh_plink_alloc(sdata, mgmt->sa, rates);
+               sta = mesh_plink_alloc(sdata, mgmt->sa, rates, &elems);
                if (!sta) {
                        mpl_dbg("Mesh plink error: plink table full\n");
                        return;
index 72c8bea81a6cc8f7b321c0700e3aa619a9a2c444..341e18344679fbeb37980a2a4bbe7699671377fb 100644 (file)
@@ -1468,6 +1468,47 @@ ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
        return RX_MGMT_CFG80211_DISASSOC;
 }
 
+static void ieee80211_get_rates(struct ieee80211_supported_band *sband,
+                               u8 *supp_rates, unsigned int supp_rates_len,
+                               u32 *rates, u32 *basic_rates,
+                               bool *have_higher_than_11mbit,
+                               int *min_rate, int *min_rate_index)
+{
+       int i, j;
+
+       for (i = 0; i < supp_rates_len; i++) {
+               int rate = (supp_rates[i] & 0x7f) * 5;
+               bool is_basic = !!(supp_rates[i] & 0x80);
+
+               if (rate > 110)
+                       *have_higher_than_11mbit = true;
+
+               /*
+                * BSS_MEMBERSHIP_SELECTOR_HT_PHY is defined in 802.11n-2009
+                * 7.3.2.2 as a magic value instead of a rate. Hence, skip it.
+                *
+                * Note: Even through the membership selector and the basic
+                *       rate flag share the same bit, they are not exactly
+                *       the same.
+                */
+               if (!!(supp_rates[i] & 0x80) &&
+                   (supp_rates[i] & 0x7f) == BSS_MEMBERSHIP_SELECTOR_HT_PHY)
+                       continue;
+
+               for (j = 0; j < sband->n_bitrates; j++) {
+                       if (sband->bitrates[j].bitrate == rate) {
+                               *rates |= BIT(j);
+                               if (is_basic)
+                                       *basic_rates |= BIT(j);
+                               if (rate < *min_rate) {
+                                       *min_rate = rate;
+                                       *min_rate_index = j;
+                               }
+                               break;
+                       }
+               }
+       }
+}
 
 static bool ieee80211_assoc_success(struct ieee80211_work *wk,
                                    struct ieee80211_mgmt *mgmt, size_t len)
@@ -1484,9 +1525,10 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        struct ieee802_11_elems elems;
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
        u32 changed = 0;
-       int i, j, err;
+       int err;
        bool have_higher_than_11mbit = false;
        u16 ap_ht_cap_flags;
+       int min_rate = INT_MAX, min_rate_index = -1;
 
        /* AssocResp and ReassocResp have identical structure */
 
@@ -1541,38 +1583,23 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
        basic_rates = 0;
        sband = local->hw.wiphy->bands[wk->chan->band];
 
-       for (i = 0; i < elems.supp_rates_len; i++) {
-               int rate = (elems.supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.supp_rates[i] & 0x80);
-
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
-
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               break;
-                       }
-               }
-       }
+       ieee80211_get_rates(sband, elems.supp_rates, elems.supp_rates_len,
+                           &rates, &basic_rates, &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
-       for (i = 0; i < elems.ext_supp_rates_len; i++) {
-               int rate = (elems.ext_supp_rates[i] & 0x7f) * 5;
-               bool is_basic = !!(elems.ext_supp_rates[i] & 0x80);
+       ieee80211_get_rates(sband, elems.ext_supp_rates,
+                           elems.ext_supp_rates_len, &rates, &basic_rates,
+                           &have_higher_than_11mbit,
+                           &min_rate, &min_rate_index);
 
-               if (rate > 110)
-                       have_higher_than_11mbit = true;
-
-               for (j = 0; j < sband->n_bitrates; j++) {
-                       if (sband->bitrates[j].bitrate == rate) {
-                               rates |= BIT(j);
-                               if (is_basic)
-                                       basic_rates |= BIT(j);
-                               break;
-                       }
-               }
+       /*
+        * some buggy APs don't advertise basic_rates. use the lowest
+        * supported rate instead.
+        */
+       if (unlikely(!basic_rates) && min_rate_index >= 0) {
+               printk(KERN_DEBUG "%s: No basic rates in AssocResp. "
+                      "Using min supported rate instead.\n", sdata->name);
+               basic_rates = BIT(min_rate_index);
        }
 
        sta->sta.supp_rates[wk->chan->band] = rates;
index 9ee7164b207c23017eba9b9fc064eb1ab0248537..596efaf50e096c354aaa3fb0c01abefe1afe87ab 100644 (file)
@@ -125,7 +125,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
-               drv_remove_interface(local, &sdata->vif);
+               drv_remove_interface(local, sdata);
        }
 
        /* stop hardware - this must stop RX */
index 58a89554b7882cc940ad6f7dce624c786e7f5c83..b39dda523f3986053c2d4e8d9a9619dce518d7c4 100644 (file)
@@ -334,8 +334,8 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta,
 
 
 static void
-calc_rate_durations(struct minstrel_sta_info *mi, struct ieee80211_local *local,
-                    struct minstrel_rate *d, struct ieee80211_rate *rate)
+calc_rate_durations(struct ieee80211_local *local, struct minstrel_rate *d,
+                   struct ieee80211_rate *rate)
 {
        int erp = !!(rate->flags & IEEE80211_RATE_ERP_G);
 
@@ -402,8 +402,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband,
 
                mr->rix = i;
                mr->bitrate = sband->bitrates[i].bitrate / 5;
-               calc_rate_durations(mi, local, mr,
-                               &sband->bitrates[i]);
+               calc_rate_durations(local, mr, &sband->bitrates[i]);
 
                /* calculate maximum number of retransmissions before
                 * fallback (based on maximum segment size) */
index bb53726cb04a6d1395f7738e87e58845df3716bf..4eafbfd891d552f6bc3fed468e4148dfbd5a47e4 100644 (file)
@@ -745,10 +745,11 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        struct ieee80211_local *local = rx->local;
        struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
        struct sta_info *sta = rx->sta;
        struct tid_ampdu_rx *tid_agg_rx;
        u16 sc;
-       int tid;
+       u8 tid, ack_policy;
 
        if (!ieee80211_is_data_qos(hdr->frame_control))
                goto dont_reorder;
@@ -761,6 +762,8 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (!sta)
                goto dont_reorder;
 
+       ack_policy = *ieee80211_get_qos_ctl(hdr) &
+                    IEEE80211_QOS_CTL_ACK_POLICY_MASK;
        tid = *ieee80211_get_qos_ctl(hdr) & IEEE80211_QOS_CTL_TID_MASK;
 
        tid_agg_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[tid]);
@@ -771,6 +774,15 @@ static void ieee80211_rx_reorder_ampdu(struct ieee80211_rx_data *rx)
        if (unlikely(hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_NULLFUNC)))
                goto dont_reorder;
 
+       /* not part of a BA session */
+       if (ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_BLOCKACK &&
+           ack_policy != IEEE80211_QOS_CTL_ACK_POLICY_NORMAL)
+               goto dont_reorder;
+
+       /* not actually part of this BA session */
+       if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
+               goto dont_reorder;
+
        /* new, potentially un-ordered, ampdu frame - process it */
 
        /* reset session timer */
@@ -855,6 +867,13 @@ ieee80211_rx_h_check(struct ieee80211_rx_data *rx)
                            rx->sdata->control_port_protocol)
                                return RX_CONTINUE;
                }
+
+               if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+                   cfg80211_rx_spurious_frame(rx->sdata->dev,
+                                              hdr->addr2,
+                                              GFP_ATOMIC))
+                       return RX_DROP_UNUSABLE;
+
                return RX_DROP_MONITOR;
        }
 
@@ -1324,15 +1343,20 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
                /*
                 * If we receive a 4-addr nullfunc frame from a STA
-                * that was not moved to a 4-addr STA vlan yet, drop
-                * the frame to the monitor interface, to make sure
-                * that hostapd sees it
+                * that was not moved to a 4-addr STA vlan yet send
+                * the event to userspace and for older hostapd drop
+                * the frame to the monitor interface.
                 */
                if (ieee80211_has_a4(hdr->frame_control) &&
                    (rx->sdata->vif.type == NL80211_IFTYPE_AP ||
                     (rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
-                     !rx->sdata->u.vlan.sta)))
+                     !rx->sdata->u.vlan.sta))) {
+                       if (!test_and_set_sta_flag(sta, WLAN_STA_4ADDR_EVENT))
+                               cfg80211_rx_unexpected_4addr_frame(
+                                       rx->sdata->dev, sta->sta.addr,
+                                       GFP_ATOMIC);
                        return RX_DROP_MONITOR;
+               }
                /*
                 * Update counter and free packet here to avoid
                 * counting this as a dropped packed.
@@ -1930,6 +1954,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
            compare_ether_addr(sdata->vif.addr, hdr->addr3) == 0)
                return RX_CONTINUE;
 
+       skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, skb));
        mesh_hdr->ttl--;
 
        if (status->rx_flags & IEEE80211_RX_RA_MATCH) {
@@ -1954,12 +1979,10 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
                        memset(info, 0, sizeof(*info));
                        info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
                        info->control.vif = &rx->sdata->vif;
+                       info->control.jiffies = jiffies;
                        if (is_multicast_ether_addr(fwd_hdr->addr1)) {
                                IEEE80211_IFSTA_MESH_CTR_INC(&sdata->u.mesh,
                                                                fwded_mcast);
-                               skb_set_queue_mapping(fwd_skb,
-                                       ieee80211_select_queue(sdata, fwd_skb));
-                               ieee80211_set_qos_hdr(sdata, fwd_skb);
                        } else {
                                int err;
                                /*
@@ -2011,12 +2034,17 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
                return RX_DROP_MONITOR;
 
        /*
-        * Allow the cooked monitor interface of an AP to see 4-addr frames so
-        * that a 4-addr station can be detected and moved into a separate VLAN
+        * Send unexpected-4addr-frame event to hostapd. For older versions,
+        * also drop the frame to cooked monitor interfaces.
         */
        if (ieee80211_has_a4(hdr->frame_control) &&
-           sdata->vif.type == NL80211_IFTYPE_AP)
+           sdata->vif.type == NL80211_IFTYPE_AP) {
+               if (rx->sta &&
+                   !test_and_set_sta_flag(rx->sta, WLAN_STA_4ADDR_EVENT))
+                       cfg80211_rx_unexpected_4addr_frame(
+                               rx->sdata->dev, rx->sta->sta.addr, GFP_ATOMIC);
                return RX_DROP_MONITOR;
+       }
 
        err = __ieee80211_data_to_8023(rx, &port_control);
        if (unlikely(err))
@@ -2171,6 +2199,18 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
        if (!ieee80211_is_mgmt(mgmt->frame_control))
                return RX_DROP_MONITOR;
 
+       if (rx->sdata->vif.type == NL80211_IFTYPE_AP &&
+           ieee80211_is_beacon(mgmt->frame_control) &&
+           !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
+               struct ieee80211_rx_status *status;
+
+               status = IEEE80211_SKB_RXCB(rx->skb);
+               cfg80211_report_obss_beacon(rx->local->hw.wiphy,
+                                           rx->skb->data, rx->skb->len,
+                                           status->freq, GFP_ATOMIC);
+               rx->flags |= IEEE80211_RX_BEACON_REPORTED;
+       }
+
        if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
                return RX_DROP_MONITOR;
 
@@ -2204,13 +2244,8 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 
        switch (mgmt->u.action.category) {
        case WLAN_CATEGORY_BACK:
-               /*
-                * The aggregation code is not prepared to handle
-                * anything but STA/AP due to the BSSID handling;
-                * IBSS could work in the code but isn't supported
-                * by drivers or the standard.
-                */
                if (sdata->vif.type != NL80211_IFTYPE_STATION &&
+                   sdata->vif.type != NL80211_IFTYPE_MESH_POINT &&
                    sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_AP)
                        break;
@@ -2490,6 +2525,10 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                goto out_free_skb;
        rx->flags |= IEEE80211_RX_CMNTR;
 
+       /* If there are no cooked monitor interfaces, just free the SKB */
+       if (!local->cooked_mntrs)
+               goto out_free_skb;
+
        if (skb_headroom(skb) < sizeof(*rthdr) &&
            pskb_expand_head(skb, sizeof(*rthdr), 0, GFP_ATOMIC))
                goto out_free_skb;
index 105436dbb90dda1a3430fea9923fd46fa47bca00..81863031e0a326116b6aad620ac4df6667929d7e 100644 (file)
@@ -213,12 +213,7 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
        if (bss)
                ieee80211_rx_bss_put(sdata->local, bss);
 
-       /* If we are on-operating-channel, and this packet is for the
-        * current channel, pass the pkt on up the stack so that
-        * the rest of the stack can make use of it.
-        */
-       if (ieee80211_cfg_on_oper_channel(sdata->local)
-           && (channel == sdata->local->oper_channel))
+       if (channel == sdata->local->oper_channel)
                return RX_CONTINUE;
 
        dev_kfree_skb(skb);
@@ -264,8 +259,6 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
                                       bool was_hw_scan)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       bool on_oper_chan;
-       bool enable_beacons = false;
 
        lockdep_assert_held(&local->mtx);
 
@@ -298,25 +291,13 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted,
        local->scanning = 0;
        local->scan_channel = NULL;
 
-       on_oper_chan = ieee80211_cfg_on_oper_channel(local);
-
-       if (was_hw_scan || !on_oper_chan)
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       else
-               /* Set power back to normal operating levels. */
-               ieee80211_hw_config(local, 0);
+       /* Set power back to normal operating levels. */
+       ieee80211_hw_config(local, 0);
 
        if (!was_hw_scan) {
-               bool on_oper_chan2;
                ieee80211_configure_filter(local);
                drv_sw_scan_complete(local);
-               on_oper_chan2 = ieee80211_cfg_on_oper_channel(local);
-               /* We should always be on-channel at this point. */
-               WARN_ON(!on_oper_chan2);
-               if (on_oper_chan2 && (on_oper_chan != on_oper_chan2))
-                       enable_beacons = true;
-
-               ieee80211_offchannel_return(local, enable_beacons, true);
+               ieee80211_offchannel_return(local, true, true);
        }
 
        ieee80211_recalc_idle(local);
@@ -361,11 +342,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        local->next_scan_state = SCAN_DECISION;
        local->scan_channel_idx = 0;
 
-       /* We always want to use off-channel PS, even if we
-        * are not really leaving oper-channel.  Don't
-        * tell the AP though, as long as we are on-channel.
-        */
-       ieee80211_offchannel_enable_all_ps(local, false);
+       ieee80211_offchannel_stop_vifs(local, true);
 
        ieee80211_configure_filter(local);
 
@@ -373,8 +350,7 @@ static int ieee80211_start_sw_scan(struct ieee80211_local *local)
        ieee80211_hw_config(local, 0);
 
        ieee80211_queue_delayed_work(&local->hw,
-                                    &local->scan_work,
-                                    IEEE80211_CHANNEL_TIME);
+                                    &local->scan_work, 0);
 
        return 0;
 }
@@ -510,96 +486,39 @@ static void ieee80211_scan_state_decision(struct ieee80211_local *local,
 
        next_chan = local->scan_req->channels[local->scan_channel_idx];
 
-       if (ieee80211_cfg_on_oper_channel(local)) {
-               /* We're currently on operating channel. */
-               if (next_chan == local->oper_channel)
-                       /* We don't need to move off of operating channel. */
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-               else
-                       /*
-                        * We do need to leave operating channel, as next
-                        * scan is somewhere else.
-                        */
-                       local->next_scan_state = SCAN_LEAVE_OPER_CHANNEL;
-       } else {
-               /*
-                * we're currently scanning a different channel, let's
-                * see if we can scan another channel without interfering
-                * with the current traffic situation.
-                *
-                * Since we don't know if the AP has pending frames for us
-                * we can only check for our tx queues and use the current
-                * pm_qos requirements for rx. Hence, if no tx traffic occurs
-                * at all we will scan as many channels in a row as the pm_qos
-                * latency allows us to. Additionally we also check for the
-                * currently negotiated listen interval to prevent losing
-                * frames unnecessarily.
-                *
-                * Otherwise switch back to the operating channel.
-                */
-
-               bad_latency = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
-
-               listen_int_exceeded = time_after(jiffies +
-                               ieee80211_scan_get_channel_time(next_chan),
-                               local->leave_oper_channel_time +
-                               usecs_to_jiffies(min_beacon_int * 1024) *
-                               local->hw.conf.listen_interval);
-
-               if (associated && ( !tx_empty || bad_latency ||
-                   listen_int_exceeded))
-                       local->next_scan_state = SCAN_ENTER_OPER_CHANNEL;
-               else
-                       local->next_scan_state = SCAN_SET_CHANNEL;
-       }
-
-       *next_delay = 0;
-}
-
-static void ieee80211_scan_state_leave_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* PS will already be in off-channel mode,
-        * we do that once at the beginning of scanning.
-        */
-       ieee80211_offchannel_stop_vifs(local, false);
-
        /*
-        * What if the nullfunc frames didn't arrive?
+        * we're currently scanning a different channel, let's
+        * see if we can scan another channel without interfering
+        * with the current traffic situation.
+        *
+        * Since we don't know if the AP has pending frames for us
+        * we can only check for our tx queues and use the current
+        * pm_qos requirements for rx. Hence, if no tx traffic occurs
+        * at all we will scan as many channels in a row as the pm_qos
+        * latency allows us to. Additionally we also check for the
+        * currently negotiated listen interval to prevent losing
+        * frames unnecessarily.
+        *
+        * Otherwise switch back to the operating channel.
         */
-       drv_flush(local, false);
-       if (local->ops->flush)
-               *next_delay = 0;
-       else
-               *next_delay = HZ / 10;
 
-       /* remember when we left the operating channel */
-       local->leave_oper_channel_time = jiffies;
+       bad_latency = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(pm_qos_request(PM_QOS_NETWORK_LATENCY)));
 
-       /* advance to the next channel to be scanned */
-       local->next_scan_state = SCAN_SET_CHANNEL;
-}
-
-static void ieee80211_scan_state_enter_oper_channel(struct ieee80211_local *local,
-                                                   unsigned long *next_delay)
-{
-       /* switch back to the operating channel */
-       local->scan_channel = NULL;
-       if (!ieee80211_cfg_on_oper_channel(local))
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       listen_int_exceeded = time_after(jiffies +
+                       ieee80211_scan_get_channel_time(next_chan),
+                       local->leave_oper_channel_time +
+                       usecs_to_jiffies(min_beacon_int * 1024) *
+                       local->hw.conf.listen_interval);
 
-       /*
-        * Re-enable vifs and beaconing.  Leave PS
-        * in off-channel state..will put that back
-        * on-channel at the end of scanning.
-        */
-       ieee80211_offchannel_return(local, true, false);
+       if (associated && (!tx_empty || bad_latency || listen_int_exceeded))
+               local->next_scan_state = SCAN_SUSPEND;
+       else
+               local->next_scan_state = SCAN_SET_CHANNEL;
 
-       *next_delay = HZ / 5;
-       local->next_scan_state = SCAN_DECISION;
+       *next_delay = 0;
 }
 
 static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
@@ -613,10 +532,8 @@ static void ieee80211_scan_state_set_channel(struct ieee80211_local *local,
 
        local->scan_channel = chan;
 
-       /* Only call hw-config if we really need to change channels. */
-       if (chan != local->hw.conf.channel)
-               if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
-                       skip = 1;
+       if (ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL))
+               skip = 1;
 
        /* advance state machine to next channel/band */
        local->scan_channel_idx++;
@@ -673,6 +590,44 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
        local->next_scan_state = SCAN_DECISION;
 }
 
+static void ieee80211_scan_state_suspend(struct ieee80211_local *local,
+                                        unsigned long *next_delay)
+{
+       /* switch back to the operating channel */
+       local->scan_channel = NULL;
+       ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+
+       /*
+        * Re-enable vifs and beaconing.  Leave PS
+        * in off-channel state..will put that back
+        * on-channel at the end of scanning.
+        */
+       ieee80211_offchannel_return(local, true, false);
+
+       *next_delay = HZ / 5;
+       /* afterwards, resume scan & go to next channel */
+       local->next_scan_state = SCAN_RESUME;
+}
+
+static void ieee80211_scan_state_resume(struct ieee80211_local *local,
+                                       unsigned long *next_delay)
+{
+       /* PS already is in off-channel mode */
+       ieee80211_offchannel_stop_vifs(local, false);
+
+       if (local->ops->flush) {
+               drv_flush(local, false);
+               *next_delay = 0;
+       } else
+               *next_delay = HZ / 10;
+
+       /* remember when we left the operating channel */
+       local->leave_oper_channel_time = jiffies;
+
+       /* advance to the next channel to be scanned */
+       local->next_scan_state = SCAN_DECISION;
+}
+
 void ieee80211_scan_work(struct work_struct *work)
 {
        struct ieee80211_local *local =
@@ -743,11 +698,11 @@ void ieee80211_scan_work(struct work_struct *work)
                case SCAN_SEND_PROBE:
                        ieee80211_scan_state_send_probe(local, &next_delay);
                        break;
-               case SCAN_LEAVE_OPER_CHANNEL:
-                       ieee80211_scan_state_leave_oper_channel(local, &next_delay);
+               case SCAN_SUSPEND:
+                       ieee80211_scan_state_suspend(local, &next_delay);
                        break;
-               case SCAN_ENTER_OPER_CHANNEL:
-                       ieee80211_scan_state_enter_oper_channel(local, &next_delay);
+               case SCAN_RESUME:
+                       ieee80211_scan_state_resume(local, &next_delay);
                        break;
                }
        } while (next_delay == 0);
index ce962d2c8782e5ec148884ca1ef90a0aaa8e6c18..8eaa746ec7a26d7281e28d42ed3064eb970c874c 100644 (file)
@@ -1354,12 +1354,12 @@ ieee80211_sta_ps_deliver_response(struct sta_info *sta,
                         * Use MoreData flag to indicate whether there are
                         * more buffered frames for this STA
                         */
-                       if (!more_data)
-                               hdr->frame_control &=
-                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
-                       else
+                       if (more_data || !skb_queue_empty(&frames))
                                hdr->frame_control |=
                                        cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+                       else
+                               hdr->frame_control &=
+                                       cpu_to_le16(~IEEE80211_FCTL_MOREDATA);
 
                        if (ieee80211_is_data_qos(hdr->frame_control) ||
                            ieee80211_is_qos_nullfunc(hdr->frame_control))
index 8c8ce05ad26fd0090d0b08eb41809b25bd89a6db..c5923ab8a070c167e125bc64e99ce3cee6c15cd2 100644 (file)
@@ -52,6 +52,7 @@
  *     unblocks the station.
  * @WLAN_STA_SP: Station is in a service period, so don't try to
  *     reply to other uAPSD trigger frames or PS-Poll.
+ * @WLAN_STA_4ADDR_EVENT: 4-addr event was already sent for this frame.
  */
 enum ieee80211_sta_info_flags {
        WLAN_STA_AUTH,
@@ -71,6 +72,7 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_TDLS_PEER_AUTH,
        WLAN_STA_UAPSD,
        WLAN_STA_SP,
+       WLAN_STA_4ADDR_EVENT,
 };
 
 #define STA_TID_NUM 16
@@ -390,6 +392,12 @@ static inline int test_and_clear_sta_flag(struct sta_info *sta,
        return test_and_clear_bit(flag, &sta->_flags);
 }
 
+static inline int test_and_set_sta_flag(struct sta_info *sta,
+                                       enum ieee80211_sta_info_flags flag)
+{
+       return test_and_set_bit(flag, &sta->_flags);
+}
+
 void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
                             struct tid_ampdu_tx *tid_tx);
 
index 80de436eae20eed9aa58f2a99fc7366b4f840649..a9da6ee69803a86c59474c847c434a6ae2f38dd5 100644 (file)
@@ -517,27 +517,54 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
        }
 
        if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-               struct ieee80211_work *wk;
                u64 cookie = (unsigned long)skb;
 
-               rcu_read_lock();
-               list_for_each_entry_rcu(wk, &local->work_list, list) {
-                       if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
-                               continue;
-                       if (wk->offchan_tx.frame != skb)
-                               continue;
-                       wk->offchan_tx.status = true;
-                       break;
-               }
-               rcu_read_unlock();
-               if (local->hw_roc_skb_for_status == skb) {
-                       cookie = local->hw_roc_cookie ^ 2;
-                       local->hw_roc_skb_for_status = NULL;
+               if (ieee80211_is_nullfunc(hdr->frame_control) ||
+                   ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+                       bool acked = info->flags & IEEE80211_TX_STAT_ACK;
+                       cfg80211_probe_status(skb->dev, hdr->addr1,
+                                             cookie, acked, GFP_ATOMIC);
+               } else {
+                       struct ieee80211_work *wk;
+
+                       rcu_read_lock();
+                       list_for_each_entry_rcu(wk, &local->work_list, list) {
+                               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                                       continue;
+                               if (wk->offchan_tx.frame != skb)
+                                       continue;
+                               wk->offchan_tx.status = true;
+                               break;
+                       }
+                       rcu_read_unlock();
+                       if (local->hw_roc_skb_for_status == skb) {
+                               cookie = local->hw_roc_cookie ^ 2;
+                               local->hw_roc_skb_for_status = NULL;
+                       }
+
+                       cfg80211_mgmt_tx_status(
+                               skb->dev, cookie, skb->data, skb->len,
+                               !!(info->flags & IEEE80211_TX_STAT_ACK),
+                               GFP_ATOMIC);
                }
+       }
 
-               cfg80211_mgmt_tx_status(
-                       skb->dev, cookie, skb->data, skb->len,
-                       !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       skb_complete_wifi_ack(ack_skb,
+                               info->flags & IEEE80211_TX_STAT_ACK);
        }
 
        /* this was a transmitted frame, but now we want to reuse it */
@@ -610,3 +637,29 @@ void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
                                    num_packets, GFP_ATOMIC);
 }
 EXPORT_SYMBOL(ieee80211_report_low_ack);
+
+void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ieee80211_local *local = hw_to_local(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               /* consumes ack_skb */
+               if (ack_skb)
+                       dev_kfree_skb_any(ack_skb);
+       }
+
+       dev_kfree_skb_any(skb);
+}
+EXPORT_SYMBOL(ieee80211_free_txskb);
index 1f8b120146d1d714c97dc949495a9fbb0afab51b..f044963feb9a13159b3137afe2c83caaa2d466a5 100644 (file)
@@ -1685,8 +1685,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        int nh_pos, h_pos;
        struct sta_info *sta = NULL;
        bool wme_sta = false, authorized = false, tdls_auth = false;
-       struct sk_buff *tmp_skb;
        bool tdls_direct = false;
+       bool multicast;
+       u32 info_flags = 0;
+       u16 info_id = 0;
 
        if (unlikely(skb->len < ETH_HLEN)) {
                ret = NETDEV_TX_OK;
@@ -1873,7 +1875,8 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
         * if it is a multicast address (which can only happen
         * in AP mode)
         */
-       if (!is_multicast_ether_addr(hdr.addr1)) {
+       multicast = is_multicast_ether_addr(hdr.addr1);
+       if (!multicast) {
                rcu_read_lock();
                sta = sta_info_get(sdata, hdr.addr1);
                if (sta) {
@@ -1914,11 +1917,54 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                goto fail;
        }
 
+       if (unlikely(!multicast && skb->sk &&
+                    skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) {
+               struct sk_buff *orig_skb = skb;
+
+               skb = skb_clone(skb, GFP_ATOMIC);
+               if (skb) {
+                       unsigned long flags;
+                       int id, r;
+
+                       spin_lock_irqsave(&local->ack_status_lock, flags);
+                       r = idr_get_new_above(&local->ack_status_frames,
+                                             orig_skb, 1, &id);
+                       if (r == -EAGAIN) {
+                               idr_pre_get(&local->ack_status_frames,
+                                           GFP_ATOMIC);
+                               r = idr_get_new_above(&local->ack_status_frames,
+                                                     orig_skb, 1, &id);
+                       }
+                       if (WARN_ON(!id) || id > 0xffff) {
+                               idr_remove(&local->ack_status_frames, id);
+                               r = -ERANGE;
+                       }
+                       spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+                       if (!r) {
+                               info_id = id;
+                               info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+                       } else if (skb_shared(skb)) {
+                               kfree_skb(orig_skb);
+                       } else {
+                               kfree_skb(skb);
+                               skb = orig_skb;
+                       }
+               } else {
+                       /* couldn't clone -- lose tx status ... */
+                       skb = orig_skb;
+               }
+       }
+
        /*
         * If the skb is shared we need to obtain our own copy.
         */
        if (skb_shared(skb)) {
-               tmp_skb = skb;
+               struct sk_buff *tmp_skb = skb;
+
+               /* can't happen -- skb is a clone if info_id != 0 */
+               WARN_ON(info_id);
+
                skb = skb_clone(skb, GFP_ATOMIC);
                kfree_skb(tmp_skb);
 
@@ -2019,6 +2065,10 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        memset(info, 0, sizeof(*info));
 
        dev->trans_start = jiffies;
+
+       info->flags = info_flags;
+       info->ack_frame_id = info_id;
+
        ieee80211_xmit(sdata, skb);
 
        return NETDEV_TX_OK;
@@ -2279,22 +2329,31 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
        } else if (ieee80211_vif_is_mesh(&sdata->vif)) {
                struct ieee80211_mgmt *mgmt;
                u8 *pos;
+               int hdr_len = offsetof(struct ieee80211_mgmt, u.beacon) +
+                             sizeof(mgmt->u.beacon);
 
 #ifdef CONFIG_MAC80211_MESH
                if (!sdata->u.mesh.mesh_id_len)
                        goto out;
 #endif
 
-               /* headroom, head length, tail length and maximum TIM length */
-               skb = dev_alloc_skb(local->tx_headroom + 400 +
-                               sdata->u.mesh.ie_len);
+               skb = dev_alloc_skb(local->tx_headroom +
+                                   hdr_len +
+                                   2 + /* NULL SSID */
+                                   2 + 8 + /* supported rates */
+                                   2 + 3 + /* DS params */
+                                   2 + (IEEE80211_MAX_SUPP_RATES - 8) +
+                                   2 + sizeof(struct ieee80211_ht_cap) +
+                                   2 + sizeof(struct ieee80211_ht_info) +
+                                   2 + sdata->u.mesh.mesh_id_len +
+                                   2 + sizeof(struct ieee80211_meshconf_ie) +
+                                   sdata->u.mesh.ie_len);
                if (!skb)
                        goto out;
 
                skb_reserve(skb, local->hw.extra_tx_headroom);
-               mgmt = (struct ieee80211_mgmt *)
-                       skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-               memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+               mgmt = (struct ieee80211_mgmt *) skb_put(skb, hdr_len);
+               memset(mgmt, 0, hdr_len);
                mgmt->frame_control =
                    cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON);
                memset(mgmt->da, 0xff, ETH_ALEN);
@@ -2313,6 +2372,8 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                    mesh_add_ds_params_ie(skb, sdata) ||
                    ieee80211_add_ext_srates_ie(&sdata->vif, skb) ||
                    mesh_add_rsn_ie(skb, sdata) ||
+                   mesh_add_ht_cap_ie(skb, sdata) ||
+                   mesh_add_ht_info_ie(skb, sdata) ||
                    mesh_add_meshid_ie(skb, sdata) ||
                    mesh_add_meshconf_ie(skb, sdata) ||
                    mesh_add_vendor_ies(skb, sdata)) {
@@ -2355,6 +2416,37 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(ieee80211_beacon_get_tim);
 
+struct sk_buff *ieee80211_proberesp_get(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif)
+{
+       struct ieee80211_if_ap *ap = NULL;
+       struct sk_buff *presp = NULL, *skb = NULL;
+       struct ieee80211_hdr *hdr;
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+
+       if (sdata->vif.type != NL80211_IFTYPE_AP)
+               return NULL;
+
+       rcu_read_lock();
+
+       ap = &sdata->u.ap;
+       presp = rcu_dereference(ap->probe_resp);
+       if (!presp)
+               goto out;
+
+       skb = skb_copy(presp, GFP_ATOMIC);
+       if (!skb)
+               goto out;
+
+       hdr = (struct ieee80211_hdr *) skb->data;
+       memset(hdr->addr1, 0, sizeof(hdr->addr1));
+
+out:
+       rcu_read_unlock();
+       return skb;
+}
+EXPORT_SYMBOL(ieee80211_proberesp_get);
+
 struct sk_buff *ieee80211_pspoll_get(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
index 51e256c5fb78801f8fd570192a78c38367ec9bf2..7683cb83fe4696a777a7646a0dd92adc317a6e34 100644 (file)
@@ -812,23 +812,8 @@ int ieee80211_build_preq_ies(struct ieee80211_local *local, u8 *buffer,
                offset = noffset;
        }
 
-       if (sband->ht_cap.ht_supported) {
-               u16 cap = sband->ht_cap.cap;
-               __le16 tmp;
-
-               *pos++ = WLAN_EID_HT_CAPABILITY;
-               *pos++ = sizeof(struct ieee80211_ht_cap);
-               memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-               tmp = cpu_to_le16(cap);
-               memcpy(pos, &tmp, sizeof(u16));
-               pos += sizeof(u16);
-               *pos++ = sband->ht_cap.ampdu_factor |
-                        (sband->ht_cap.ampdu_density <<
-                               IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-               memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-               pos += sizeof(sband->ht_cap.mcs);
-               pos += 2 + 4 + 1; /* ext info, BF cap, antsel */
-       }
+       if (sband->ht_cap.ht_supported)
+               pos = ieee80211_ie_build_ht_cap(pos, sband, sband->ht_cap.cap);
 
        /*
         * If adding more here, adjust code in main.c
@@ -1022,7 +1007,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                if (sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
                    sdata->vif.type != NL80211_IFTYPE_MONITOR &&
                    ieee80211_sdata_running(sdata))
-                       res = drv_add_interface(local, &sdata->vif);
+                       res = drv_add_interface(local, sdata);
        }
 
        /* add STAs back */
@@ -1073,7 +1058,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_BEACON_INT |
                          BSS_CHANGED_BSSID |
                          BSS_CHANGED_CQM |
-                         BSS_CHANGED_QOS;
+                         BSS_CHANGED_QOS |
+                         BSS_CHANGED_IDLE;
 
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
@@ -1086,7 +1072,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                        changed |= BSS_CHANGED_IBSS;
                        /* fall through */
                case NL80211_IFTYPE_AP:
-                       changed |= BSS_CHANGED_SSID;
+                       changed |= BSS_CHANGED_SSID |
+                                  BSS_CHANGED_AP_PROBE_RESP;
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
@@ -1108,6 +1095,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                }
        }
 
+       ieee80211_recalc_ps(local, -1);
+
        /*
         * Clear the WLAN_STA_BLOCK_BA flag so new aggregation
         * sessions can be established after a resume.
@@ -1363,6 +1352,103 @@ void ieee80211_disable_rssi_reports(struct ieee80211_vif *vif)
 }
 EXPORT_SYMBOL(ieee80211_disable_rssi_reports);
 
+u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_supported_band *sband,
+                             u16 cap)
+{
+       __le16 tmp;
+
+       *pos++ = WLAN_EID_HT_CAPABILITY;
+       *pos++ = sizeof(struct ieee80211_ht_cap);
+       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
+
+       /* capability flags */
+       tmp = cpu_to_le16(cap);
+       memcpy(pos, &tmp, sizeof(u16));
+       pos += sizeof(u16);
+
+       /* AMPDU parameters */
+       *pos++ = sband->ht_cap.ampdu_factor |
+                (sband->ht_cap.ampdu_density <<
+                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
+
+       /* MCS set */
+       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
+       pos += sizeof(sband->ht_cap.mcs);
+
+       /* extended capabilities */
+       pos += sizeof(__le16);
+
+       /* BF capabilities */
+       pos += sizeof(__le32);
+
+       /* antenna selection */
+       pos += sizeof(u8);
+
+       return pos;
+}
+
+u8 *ieee80211_ie_build_ht_info(u8 *pos,
+                              struct ieee80211_sta_ht_cap *ht_cap,
+                              struct ieee80211_channel *channel,
+                              enum nl80211_channel_type channel_type)
+{
+       struct ieee80211_ht_info *ht_info;
+       /* Build HT Information */
+       *pos++ = WLAN_EID_HT_INFORMATION;
+       *pos++ = sizeof(struct ieee80211_ht_info);
+       ht_info = (struct ieee80211_ht_info *)pos;
+       ht_info->control_chan =
+                       ieee80211_frequency_to_channel(channel->center_freq);
+       switch (channel_type) {
+       case NL80211_CHAN_HT40MINUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               break;
+       case NL80211_CHAN_HT20:
+       default:
+               ht_info->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
+               break;
+       }
+       if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+               ht_info->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
+       ht_info->operation_mode = 0x0000;
+       ht_info->stbc_param = 0x0000;
+
+       /* It seems that Basic MCS set and Supported MCS set
+          are identical for the first 10 bytes */
+       memset(&ht_info->basic_set, 0, 16);
+       memcpy(&ht_info->basic_set, &ht_cap->mcs, 10);
+
+       return pos + sizeof(struct ieee80211_ht_info);
+}
+
+enum nl80211_channel_type
+ieee80211_ht_info_to_channel_type(struct ieee80211_ht_info *ht_info)
+{
+       enum nl80211_channel_type channel_type;
+
+       if (!ht_info)
+               return NL80211_CHAN_NO_HT;
+
+       switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+       case IEEE80211_HT_PARAM_CHA_SEC_NONE:
+               channel_type = NL80211_CHAN_HT20;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+               channel_type = NL80211_CHAN_HT40PLUS;
+               break;
+       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+               channel_type = NL80211_CHAN_HT40MINUS;
+               break;
+       default:
+               channel_type = NL80211_CHAN_NO_HT;
+       }
+
+       return channel_type;
+}
+
 int ieee80211_add_srates_ie(struct ieee80211_vif *vif, struct sk_buff *skb)
 {
        struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
index fd52e695c071082b4b51bc3cbc20e535a9f47630..43327115b49098f0484b01922dea78dd385992b7 100644 (file)
@@ -83,7 +83,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
                break;
 #ifdef CONFIG_MAC80211_MESH
        case NL80211_IFTYPE_MESH_POINT:
-               ra = skb->data;
+               qos = true;
                break;
 #endif
        case NL80211_IFTYPE_STATION:
@@ -143,11 +143,15 @@ void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
        /* Fill in the QoS header if there is one. */
        if (ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *p = ieee80211_get_qos_ctl(hdr);
-               u8 ack_policy = 0, tid;
+               u8 ack_policy, tid;
 
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-               if (unlikely(sdata->local->wifi_wme_noack_test))
+               /* preserve EOSP bit */
+               ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
+
+               if (unlikely(sdata->local->wifi_wme_noack_test) ||
+                   is_multicast_ether_addr(hdr->addr1))
                        ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
                /* qos header is 2 bytes */
                *p++ = ack_policy | tid;
index 6c53b6d1002b5a2046837fe2ec60d7687bd0c973..3dd5a89e99a79f2cc37687928bee12ade66089d8 100644 (file)
@@ -103,7 +103,6 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        u8 *pos;
        u32 flags = channel->flags;
        u16 cap = sband->ht_cap.cap;
-       __le16 tmp;
 
        if (!sband->ht_cap.ht_supported)
                return;
@@ -154,34 +153,8 @@ static void ieee80211_add_ht_ie(struct sk_buff *skb, const u8 *ht_info_ie,
        }
 
        /* reserve and fill IE */
-
        pos = skb_put(skb, sizeof(struct ieee80211_ht_cap) + 2);
-       *pos++ = WLAN_EID_HT_CAPABILITY;
-       *pos++ = sizeof(struct ieee80211_ht_cap);
-       memset(pos, 0, sizeof(struct ieee80211_ht_cap));
-
-       /* capability flags */
-       tmp = cpu_to_le16(cap);
-       memcpy(pos, &tmp, sizeof(u16));
-       pos += sizeof(u16);
-
-       /* AMPDU parameters */
-       *pos++ = sband->ht_cap.ampdu_factor |
-                (sband->ht_cap.ampdu_density <<
-                       IEEE80211_HT_AMPDU_PARM_DENSITY_SHIFT);
-
-       /* MCS set */
-       memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs));
-       pos += sizeof(sband->ht_cap.mcs);
-
-       /* extended capabilities */
-       pos += sizeof(__le16);
-
-       /* BF capabilities */
-       pos += sizeof(__le32);
-
-       /* antenna selection */
-       pos += sizeof(u8);
+       ieee80211_ie_build_ht_cap(pos, sband, cap);
 }
 
 static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
@@ -969,10 +942,9 @@ static void ieee80211_work_work(struct work_struct *work)
                }
 
                if (!started && !local->tmp_channel) {
-                       bool on_oper_chan;
-                       bool tmp_chan_changed = false;
-                       bool on_oper_chan2;
+                       bool on_oper_chan, on_oper_chan2;
                        enum nl80211_channel_type wk_ct;
+
                        on_oper_chan = ieee80211_cfg_on_oper_channel(local);
 
                        /* Work with existing channel type if possible. */
@@ -981,11 +953,6 @@ static void ieee80211_work_work(struct work_struct *work)
                                wk_ct = ieee80211_calc_ct(wk->chan_type,
                                                local->hw.conf.channel_type);
 
-                       if (local->tmp_channel)
-                               if ((local->tmp_channel != wk->chan) ||
-                                   (local->tmp_channel_type != wk_ct))
-                                       tmp_chan_changed = true;
-
                        local->tmp_channel = wk->chan;
                        local->tmp_channel_type = wk_ct;
                        /*
@@ -1008,12 +975,7 @@ static void ieee80211_work_work(struct work_struct *work)
                                                                    true,
                                                                    false);
                                }
-                       } else if (tmp_chan_changed)
-                               /* Still off-channel, but on some other
-                                * channel, so update hardware.
-                                * PS should already be off-channel.
-                                */
-                               ieee80211_hw_config(local, 0);
+                       }
 
                        started = true;
                        wk->timeout = jiffies;
index f614ce7bb6e3b4aea4f9c445e2594b2c6366e6d0..106e15a4649f1f24ba5335227c44b5a79817e2fb 100644 (file)
@@ -390,7 +390,8 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
        u8 scratch[6 * AES_BLOCK_SIZE];
 
        if (info->control.hw_key &&
-           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) {
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV) &&
+           !(info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE)) {
                /*
                 * hwaccel has no need for preallocated room for CCMP
                 * header or MIC fields
@@ -412,6 +413,12 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb)
 
        pos = skb_push(skb, CCMP_HDR_LEN);
        memmove(pos, pos + CCMP_HDR_LEN, hdrlen);
+
+       /* the HW only needs room for the IV, but not the actual IV */
+       if (info->control.hw_key &&
+           (info->control.hw_key->flags & IEEE80211_KEY_FLAG_PUT_IV_SPACE))
+               return 0;
+
        hdr = (struct ieee80211_hdr *) pos;
        pos += hdrlen;
 
index 3925c6578767ea61be8cc66933d38a6c500cd1d2..fe5ca89abfce3b0facaba030fd7c0c188720a3b7 100644 (file)
@@ -126,7 +126,10 @@ static inline int nci_request(struct nci_dev *ndev,
 
 static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
 {
-       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 0, NULL);
+       struct nci_core_reset_cmd cmd;
+
+       cmd.reset_type = NCI_RESET_TYPE_RESET_CONFIG;
+       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 1, &cmd);
 }
 
 static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
@@ -136,17 +139,11 @@ static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
 
 static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
 {
-       struct nci_core_conn_create_cmd conn_cmd;
        struct nci_rf_disc_map_cmd cmd;
        struct disc_map_config *cfg = cmd.mapping_configs;
        __u8 *num = &cmd.num_mapping_configs;
        int i;
 
-       /* create static rf connection */
-       conn_cmd.target_handle = 0;
-       conn_cmd.num_target_specific_params = 0;
-       nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
-
        /* set rf mapping configurations */
        *num = 0;
 
@@ -470,7 +467,7 @@ static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
        ndev->data_exchange_cb = cb;
        ndev->data_exchange_cb_context = cb_context;
 
-       rc = nci_send_data(ndev, ndev->conn_id, skb);
+       rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
        if (rc)
                clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
 
@@ -726,7 +723,10 @@ static void nci_tx_work(struct work_struct *work)
                if (!skb)
                        return;
 
-               atomic_dec(&ndev->credits_cnt);
+               /* Check if data flow control is used */
+               if (atomic_read(&ndev->credits_cnt) !=
+                               NCI_DATA_FLOW_CONTROL_NOT_USED)
+                       atomic_dec(&ndev->credits_cnt);
 
                nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
                                nci_pbf(skb->data),
index e5ed90fc1a9cf1bf6024e22bb2989644a48ed837..511fb96e21bc47252b58bf0c736bc19b31831cbc 100644 (file)
@@ -95,7 +95,8 @@ static int nci_queue_tx_data_frags(struct nci_dev *ndev,
        __skb_queue_head_init(&frags_q);
 
        while (total_len) {
-               frag_len = min_t(int, total_len, ndev->max_pkt_payload_size);
+               frag_len =
+                       min_t(int, total_len, ndev->max_data_pkt_payload_size);
 
                skb_frag = nci_skb_alloc(ndev,
                                        (NCI_DATA_HDR_SIZE + frag_len),
@@ -151,7 +152,7 @@ int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
        nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
 
        /* check if the packet need to be fragmented */
-       if (skb->len <= ndev->max_pkt_payload_size) {
+       if (skb->len <= ndev->max_data_pkt_payload_size) {
                /* no need to fragment packet */
                nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
 
index b19dc2fa90e13982352122615aa278bb8280ab77..e99adcfb1bcf10e2c4dd506f778d2a53f2539426 100644 (file)
@@ -42,12 +42,9 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_REJECTED:
                return -EBUSY;
 
-       case NCI_STATUS_MESSAGE_CORRUPTED:
+       case NCI_STATUS_RF_FRAME_CORRUPTED:
                return -EBADMSG;
 
-       case NCI_STATUS_BUFFER_FULL:
-               return -ENOBUFS;
-
        case NCI_STATUS_NOT_INITIALIZED:
                return -EHOSTDOWN;
 
@@ -80,9 +77,6 @@ int nci_to_errno(__u8 code)
        case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
                return -ETIMEDOUT;
 
-       case NCI_STATUS_RF_LINK_LOSS_ERROR:
-               return -ENOLINK;
-
        case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
                return -EDQUOT;
 
index 96633f5cda4f790d3bae4ecdfa4f3a6435c5797c..c1bf54172c25bbc606ea385a7251ed6d878c9cd0 100644 (file)
@@ -54,7 +54,7 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                        ntf->conn_entries[i].conn_id,
                        ntf->conn_entries[i].credits);
 
-               if (ntf->conn_entries[i].conn_id == ndev->conn_id) {
+               if (ntf->conn_entries[i].conn_id == NCI_STATIC_RF_CONN_ID) {
                        /* found static rf connection */
                        atomic_add(ntf->conn_entries[i].credits,
                                &ndev->credits_cnt);
@@ -66,22 +66,12 @@ static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
                queue_work(ndev->tx_wq, &ndev->tx_work);
 }
 
-static void nci_rf_field_info_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
-{
-       struct nci_rf_field_info_ntf *ntf = (void *) skb->data;
-
-       nfc_dbg("entry, rf_field_status %d", ntf->rf_field_status);
-}
-
-static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
-                       struct nci_rf_activate_ntf *ntf, __u8 *data)
+static __u8 *nci_extract_rf_params_nfca_passive_poll(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
 {
        struct rf_tech_specific_params_nfca_poll *nfca_poll;
-       struct activation_params_nfca_poll_iso_dep *nfca_poll_iso_dep;
 
        nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
-       nfca_poll_iso_dep = &ntf->activation_params.nfca_poll_iso_dep;
 
        nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
        data += 2;
@@ -100,32 +90,32 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
        if (nfca_poll->sel_res_len != 0)
                nfca_poll->sel_res = *data++;
 
-       ntf->rf_interface_type = *data++;
-       ntf->activation_params_len = *data++;
-
-       nfc_dbg("sel_res_len %d, sel_res 0x%x, rf_interface_type %d, activation_params_len %d",
+       nfc_dbg("sel_res_len %d, sel_res 0x%x",
                nfca_poll->sel_res_len,
-               nfca_poll->sel_res,
-               ntf->rf_interface_type,
-               ntf->activation_params_len);
-
-       switch (ntf->rf_interface_type) {
-       case NCI_RF_INTERFACE_ISO_DEP:
-               nfca_poll_iso_dep->rats_res_len = *data++;
-               if (nfca_poll_iso_dep->rats_res_len > 0) {
-                       memcpy(nfca_poll_iso_dep->rats_res,
+               nfca_poll->sel_res);
+
+       return data;
+}
+
+static int nci_extract_activation_params_iso_dep(struct nci_dev *ndev,
+                       struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
+{
+       struct activation_params_nfca_poll_iso_dep *nfca_poll;
+
+       switch (ntf->activation_rf_tech_and_mode) {
+       case NCI_NFC_A_PASSIVE_POLL_MODE:
+               nfca_poll = &ntf->activation_params.nfca_poll_iso_dep;
+               nfca_poll->rats_res_len = *data++;
+               if (nfca_poll->rats_res_len > 0) {
+                       memcpy(nfca_poll->rats_res,
                                data,
-                               nfca_poll_iso_dep->rats_res_len);
+                               nfca_poll->rats_res_len);
                }
                break;
 
-       case NCI_RF_INTERFACE_FRAME:
-               /* no activation params */
-               break;
-
        default:
-               nfc_err("unsupported rf_interface_type 0x%x",
-                       ntf->rf_interface_type);
+               nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                       ntf->activation_rf_tech_and_mode);
                return -EPROTO;
        }
 
@@ -133,7 +123,7 @@ static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
 }
 
 static void nci_target_found(struct nci_dev *ndev,
-                               struct nci_rf_activate_ntf *ntf)
+                               struct nci_rf_intf_activated_ntf *ntf)
 {
        struct nfc_target nfc_tgt;
 
@@ -141,6 +131,8 @@ static void nci_target_found(struct nci_dev *ndev,
                nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
        else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)   /* 4A */
                nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
+       else
+               nfc_tgt.supported_protocols = 0;
 
        nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
        nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
@@ -158,49 +150,86 @@ static void nci_target_found(struct nci_dev *ndev,
        nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
 }
 
-static void nci_rf_activate_ntf_packet(struct nci_dev *ndev,
-                                       struct sk_buff *skb)
+static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
+                                               struct sk_buff *skb)
 {
-       struct nci_rf_activate_ntf ntf;
+       struct nci_rf_intf_activated_ntf ntf;
        __u8 *data = skb->data;
-       int rc = -1;
+       int err = 0;
 
        clear_bit(NCI_DISCOVERY, &ndev->flags);
        set_bit(NCI_POLL_ACTIVE, &ndev->flags);
 
-       ntf.target_handle = *data++;
+       ntf.rf_discovery_id = *data++;
+       ntf.rf_interface_type = *data++;
        ntf.rf_protocol = *data++;
-       ntf.rf_tech_and_mode = *data++;
+       ntf.activation_rf_tech_and_mode = *data++;
        ntf.rf_tech_specific_params_len = *data++;
 
-       nfc_dbg("target_handle %d, rf_protocol 0x%x, rf_tech_and_mode 0x%x, rf_tech_specific_params_len %d",
-               ntf.target_handle,
-               ntf.rf_protocol,
-               ntf.rf_tech_and_mode,
+       nfc_dbg("rf_discovery_id %d", ntf.rf_discovery_id);
+       nfc_dbg("rf_interface_type 0x%x", ntf.rf_interface_type);
+       nfc_dbg("rf_protocol 0x%x", ntf.rf_protocol);
+       nfc_dbg("activation_rf_tech_and_mode 0x%x",
+               ntf.activation_rf_tech_and_mode);
+       nfc_dbg("rf_tech_specific_params_len %d",
                ntf.rf_tech_specific_params_len);
 
-       switch (ntf.rf_tech_and_mode) {
-       case NCI_NFC_A_PASSIVE_POLL_MODE:
-               rc = nci_rf_activate_nfca_passive_poll(ndev, &ntf,
-                       data);
-               break;
+       if (ntf.rf_tech_specific_params_len > 0) {
+               switch (ntf.activation_rf_tech_and_mode) {
+               case NCI_NFC_A_PASSIVE_POLL_MODE:
+                       data = nci_extract_rf_params_nfca_passive_poll(ndev,
+                               &ntf, data);
+                       break;
+
+               default:
+                       nfc_err("unsupported activation_rf_tech_and_mode 0x%x",
+                               ntf.activation_rf_tech_and_mode);
+                       return;
+               }
+       }
 
-       default:
-               nfc_err("unsupported rf_tech_and_mode 0x%x",
-                       ntf.rf_tech_and_mode);
-               return;
+       ntf.data_exch_rf_tech_and_mode = *data++;
+       ntf.data_exch_tx_bit_rate = *data++;
+       ntf.data_exch_rx_bit_rate = *data++;
+       ntf.activation_params_len = *data++;
+
+       nfc_dbg("data_exch_rf_tech_and_mode 0x%x",
+               ntf.data_exch_rf_tech_and_mode);
+       nfc_dbg("data_exch_tx_bit_rate 0x%x",
+               ntf.data_exch_tx_bit_rate);
+       nfc_dbg("data_exch_rx_bit_rate 0x%x",
+               ntf.data_exch_rx_bit_rate);
+       nfc_dbg("activation_params_len %d",
+               ntf.activation_params_len);
+
+       if (ntf.activation_params_len > 0) {
+               switch (ntf.rf_interface_type) {
+               case NCI_RF_INTERFACE_ISO_DEP:
+                       err = nci_extract_activation_params_iso_dep(ndev,
+                               &ntf, data);
+                       break;
+
+               case NCI_RF_INTERFACE_FRAME:
+                       /* no activation params */
+                       break;
+
+               default:
+                       nfc_err("unsupported rf_interface_type 0x%x",
+                               ntf.rf_interface_type);
+                       return;
+               }
        }
 
-       if (!rc)
+       if (!err)
                nci_target_found(ndev, &ntf);
 }
 
 static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
-       __u8 type = skb->data[0];
+       struct nci_rf_deactivate_ntf *ntf = (void *) skb->data;
 
-       nfc_dbg("entry, type 0x%x", type);
+       nfc_dbg("entry, type 0x%x, reason 0x%x", ntf->type, ntf->reason);
 
        clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
        ndev->target_active_prot = 0;
@@ -214,6 +243,9 @@ static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
                ndev->rx_data_reassembly = 0;
        }
 
+       /* set the available credits to initial value */
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+
        /* complete the data exchange transaction, if exists */
        if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
                nci_data_exchange_complete(ndev, NULL, -EIO);
@@ -237,12 +269,8 @@ void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_conn_credits_ntf_packet(ndev, skb);
                break;
 
-       case NCI_OP_RF_FIELD_INFO_NTF:
-               nci_rf_field_info_ntf_packet(ndev, skb);
-               break;
-
-       case NCI_OP_RF_ACTIVATE_NTF:
-               nci_rf_activate_ntf_packet(ndev, skb);
+       case NCI_OP_RF_INTF_ACTIVATED_NTF:
+               nci_rf_intf_activated_ntf_packet(ndev, skb);
                break;
 
        case NCI_OP_RF_DEACTIVATE_NTF:
index 0403d4cd091769de0731909d4497645f84ff650b..0591f5aff89fbc8c721bcc0e39bf43c3778e2625 100644 (file)
@@ -42,10 +42,11 @@ static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
 
        nfc_dbg("entry, status 0x%x", rsp->status);
 
-       if (rsp->status == NCI_STATUS_OK)
+       if (rsp->status == NCI_STATUS_OK) {
                ndev->nci_ver = rsp->nci_ver;
-
-       nfc_dbg("nci_ver 0x%x", ndev->nci_ver);
+               nfc_dbg("nci_ver 0x%x, config_status 0x%x",
+                       rsp->nci_ver, rsp->config_status);
+       }
 
        nci_req_complete(ndev, rsp->status);
 }
@@ -58,13 +59,13 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
        nfc_dbg("entry, status 0x%x", rsp_1->status);
 
        if (rsp_1->status != NCI_STATUS_OK)
-               return;
+               goto exit;
 
        ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
        ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
 
        if (ndev->num_supported_rf_interfaces >
-               NCI_MAX_SUPPORTED_RF_INTERFACES) {
+                       NCI_MAX_SUPPORTED_RF_INTERFACES) {
                ndev->num_supported_rf_interfaces =
                        NCI_MAX_SUPPORTED_RF_INTERFACES;
        }
@@ -73,20 +74,26 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                rsp_1->supported_rf_interfaces,
                ndev->num_supported_rf_interfaces);
 
-       rsp_2 = (void *) (skb->data + 6 + ndev->num_supported_rf_interfaces);
+       rsp_2 = (void *) (skb->data + 6 + rsp_1->num_supported_rf_interfaces);
 
        ndev->max_logical_connections =
                rsp_2->max_logical_connections;
        ndev->max_routing_table_size =
                __le16_to_cpu(rsp_2->max_routing_table_size);
-       ndev->max_control_packet_payload_length =
-               rsp_2->max_control_packet_payload_length;
-       ndev->rf_sending_buffer_size =
-               __le16_to_cpu(rsp_2->rf_sending_buffer_size);
-       ndev->rf_receiving_buffer_size =
-               __le16_to_cpu(rsp_2->rf_receiving_buffer_size);
-       ndev->manufacturer_id =
-               __le16_to_cpu(rsp_2->manufacturer_id);
+       ndev->max_ctrl_pkt_payload_len =
+               rsp_2->max_ctrl_pkt_payload_len;
+       ndev->max_size_for_large_params =
+               __le16_to_cpu(rsp_2->max_size_for_large_params);
+       ndev->max_data_pkt_payload_size =
+               rsp_2->max_data_pkt_payload_size;
+       ndev->initial_num_credits =
+               rsp_2->initial_num_credits;
+       ndev->manufact_id =
+               rsp_2->manufact_id;
+       ndev->manufact_specific_info =
+               __le32_to_cpu(rsp_2->manufact_specific_info);
+
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
 
        nfc_dbg("nfcc_features 0x%x",
                ndev->nfcc_features);
@@ -104,39 +111,23 @@ static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                ndev->max_logical_connections);
        nfc_dbg("max_routing_table_size %d",
                ndev->max_routing_table_size);
-       nfc_dbg("max_control_packet_payload_length %d",
-               ndev->max_control_packet_payload_length);
-       nfc_dbg("rf_sending_buffer_size %d",
-               ndev->rf_sending_buffer_size);
-       nfc_dbg("rf_receiving_buffer_size %d",
-               ndev->rf_receiving_buffer_size);
-       nfc_dbg("manufacturer_id 0x%x",
-               ndev->manufacturer_id);
-
+       nfc_dbg("max_ctrl_pkt_payload_len %d",
+               ndev->max_ctrl_pkt_payload_len);
+       nfc_dbg("max_size_for_large_params %d",
+               ndev->max_size_for_large_params);
+       nfc_dbg("max_data_pkt_payload_size %d",
+               ndev->max_data_pkt_payload_size);
+       nfc_dbg("initial_num_credits %d",
+               ndev->initial_num_credits);
+       nfc_dbg("manufact_id 0x%x",
+               ndev->manufact_id);
+       nfc_dbg("manufact_specific_info 0x%x",
+               ndev->manufact_specific_info);
+
+exit:
        nci_req_complete(ndev, rsp_1->status);
 }
 
-static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
-                                               struct sk_buff *skb)
-{
-       struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
-
-       nfc_dbg("entry, status 0x%x", rsp->status);
-
-       if (rsp->status != NCI_STATUS_OK)
-               return;
-
-       ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
-       ndev->initial_num_credits = rsp->initial_num_credits;
-       ndev->conn_id = rsp->conn_id;
-
-       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
-
-       nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
-       nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
-       nfc_dbg("conn_id %d", ndev->conn_id);
-}
-
 static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
                                        struct sk_buff *skb)
 {
@@ -196,10 +187,6 @@ void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
                nci_core_init_rsp_packet(ndev, skb);
                break;
 
-       case NCI_OP_CORE_CONN_CREATE_RSP:
-               nci_core_conn_create_rsp_packet(ndev, skb);
-               break;
-
        case NCI_OP_RF_DISCOVER_MAP_RSP:
                nci_rf_disc_map_rsp_packet(ndev, skb);
                break;
index 5be19575c340886ff869e94dc7ae65c0e959e00c..354760ebbbd254f1409a196e7c27140c0512e5e9 100644 (file)
@@ -644,7 +644,7 @@ static ssize_t rfkill_soft_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
@@ -688,7 +688,7 @@ static ssize_t rfkill_state_store(struct device *dev,
        if (!capable(CAP_NET_ADMIN))
                return -EPERM;
 
-       err = strict_strtoul(buf, 0, &state);
+       err = kstrtoul(buf, 0, &state);
        if (err)
                return err;
 
index 2877647f347b06e75aaaa7fd355799a43cd65bf3..425ef42704605e83c0f366fc1edb000d18eeb419 100644 (file)
@@ -538,6 +538,8 @@ int sock_tx_timestamp(struct sock *sk, __u8 *tx_flags)
                *tx_flags |= SKBTX_HW_TSTAMP;
        if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
                *tx_flags |= SKBTX_SW_TSTAMP;
+       if (sock_flag(sk, SOCK_WIFI_STATUS))
+               *tx_flags |= SKBTX_WIFI_STATUS;
        return 0;
 }
 EXPORT_SYMBOL(sock_tx_timestamp);
@@ -674,6 +676,22 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
 }
 EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
 
+void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk,
+       struct sk_buff *skb)
+{
+       int ack;
+
+       if (!sock_flag(sk, SOCK_WIFI_STATUS))
+               return;
+       if (!skb->wifi_acked_valid)
+               return;
+
+       ack = skb->wifi_acked;
+
+       put_cmsg(msg, SOL_SOCKET, SCM_WIFI_STATUS, sizeof(ack), &ack);
+}
+EXPORT_SYMBOL_GPL(__sock_recv_wifi_status);
+
 static inline void sock_recv_drops(struct msghdr *msg, struct sock *sk,
                                   struct sk_buff *skb)
 {
index 220f3bd176f89cc33192b72ddcc11f296cba54fd..ccdfed897651bba0a96c6d6111b5067a976457ca 100644 (file)
@@ -492,6 +492,10 @@ int wiphy_register(struct wiphy *wiphy)
                    !(wiphy->wowlan.flags & WIPHY_WOWLAN_SUPPORTS_GTK_REKEY)))
                return -EINVAL;
 
+       if (WARN_ON(wiphy->ap_sme_capa &&
+                   !(wiphy->flags & WIPHY_FLAG_HAVE_AP_SME)))
+               return -EINVAL;
+
        if (WARN_ON(wiphy->addresses && !wiphy->n_addresses))
                return -EINVAL;
 
index b9ec3061ed722c4dc58b526d0c545ce64ad5f163..1c7d4df5418cdef9929939a782c0fcf0893a0bd3 100644 (file)
@@ -54,6 +54,8 @@ struct cfg80211_registered_device {
        int opencount; /* also protected by devlist_mtx */
        wait_queue_head_t dev_wait;
 
+       u32 ap_beacons_nlpid;
+
        /* BSSes/scanning */
        spinlock_t bss_lock;
        struct list_head bss_list;
@@ -376,7 +378,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie);
+                         bool dont_wait_for_ack, u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
index 21fc9702f81c355a772803f507aa8496801adb0e..6c1bafd508c8dabddee9422448084f92c04a2be8 100644 (file)
@@ -879,6 +879,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid)
        }
 
        spin_unlock_bh(&wdev->mgmt_registrations_lock);
+
+       if (nlpid == wdev->ap_unexpected_nlpid)
+               wdev->ap_unexpected_nlpid = 0;
 }
 
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
@@ -901,7 +904,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, bool no_cck,
-                         u64 *cookie)
+                         bool dont_wait_for_ack, u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
@@ -992,7 +995,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        /* Transmit the Action frame as requested by user space */
        return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
                                  channel_type, channel_type_valid,
-                                 wait, buf, len, no_cck, cookie);
+                                 wait, buf, len, no_cck, dont_wait_for_ack,
+                                 cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
@@ -1107,3 +1111,30 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
        nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
+
+bool cfg80211_rx_spurious_frame(struct net_device *dev,
+                               const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO))
+               return false;
+
+       return nl80211_unexpected_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_spurious_frame);
+
+bool cfg80211_rx_unexpected_4addr_frame(struct net_device *dev,
+                                       const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (WARN_ON(wdev->iftype != NL80211_IFTYPE_AP &&
+                   wdev->iftype != NL80211_IFTYPE_P2P_GO &&
+                   wdev->iftype != NL80211_IFTYPE_AP_VLAN))
+               return false;
+
+       return nl80211_unexpected_4addr_frame(dev, addr, gfp);
+}
+EXPORT_SYMBOL(cfg80211_rx_unexpected_4addr_frame);
index 48260c2d092a820873f10769b9100a7864e8d2e0..6bc7c4b32fa5786196dd39e5755d2dd3282e25a0 100644 (file)
@@ -98,7 +98,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_ATTR_KEY_CIPHER] = { .type = NLA_U32 },
        [NL80211_ATTR_KEY_DEFAULT] = { .type = NLA_FLAG },
-       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_ATTR_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_ATTR_KEY_TYPE] = { .type = NLA_U32 },
 
        [NL80211_ATTR_BEACON_INTERVAL] = { .type = NLA_U32 },
@@ -132,8 +132,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_MESH_CONFIG] = { .type = NLA_NESTED },
        [NL80211_ATTR_SUPPORT_MESH_AUTH] = { .type = NLA_FLAG },
 
-       [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY,
-                                        .len = NL80211_HT_CAPABILITY_LEN },
+       [NL80211_ATTR_HT_CAPABILITY] = { .len = NL80211_HT_CAPABILITY_LEN },
 
        [NL80211_ATTR_MGMT_SUBTYPE] = { .type = NLA_U8 },
        [NL80211_ATTR_IE] = { .type = NLA_BINARY,
@@ -197,6 +196,9 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_TDLS_OPERATION] = { .type = NLA_U8 },
        [NL80211_ATTR_TDLS_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_TDLS_EXTERNAL_SETUP] = { .type = NLA_FLAG },
+       [NL80211_ATTR_DONT_WAIT_FOR_ACK] = { .type = NLA_FLAG },
+       [NL80211_ATTR_PROBE_RESP] = { .type = NLA_BINARY,
+                                     .len = IEEE80211_MAX_DATA_LEN },
 };
 
 /* policy for the key attributes */
@@ -204,7 +206,7 @@ static const struct nla_policy nl80211_key_policy[NL80211_KEY_MAX + 1] = {
        [NL80211_KEY_DATA] = { .type = NLA_BINARY, .len = WLAN_MAX_KEY_LEN },
        [NL80211_KEY_IDX] = { .type = NLA_U8 },
        [NL80211_KEY_CIPHER] = { .type = NLA_U32 },
-       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 8 },
+       [NL80211_KEY_SEQ] = { .type = NLA_BINARY, .len = 16 },
        [NL80211_KEY_DEFAULT] = { .type = NLA_FLAG },
        [NL80211_KEY_DEFAULT_MGMT] = { .type = NLA_FLAG },
        [NL80211_KEY_TYPE] = { .type = NLA_U32 },
@@ -759,6 +761,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
                    dev->wiphy.available_antennas_rx);
 
+       if (dev->wiphy.flags & WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD)
+               NLA_PUT_U32(msg, NL80211_ATTR_PROBE_RESP_OFFLOAD,
+                           dev->wiphy.probe_resp_offload);
+
        if ((dev->wiphy.available_antennas_tx ||
             dev->wiphy.available_antennas_rx) && dev->ops->get_antenna) {
                u32 tx_ant = 0, rx_ant = 0;
@@ -891,6 +897,11 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        }
        if (dev->wiphy.flags & WIPHY_FLAG_SUPPORTS_SCHED_SCAN)
                CMD(sched_scan_start, START_SCHED_SCAN);
+       CMD(probe_client, PROBE_CLIENT);
+       if (dev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS) {
+               i++;
+               NLA_PUT_U32(msg, i, NL80211_CMD_REGISTER_BEACONS);
+       }
 
 #undef CMD
 
@@ -1008,6 +1019,12 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        if (nl80211_put_iface_combinations(&dev->wiphy, msg))
                goto nla_put_failure;
 
+       if (dev->wiphy.flags & WIPHY_FLAG_HAVE_AP_SME)
+               NLA_PUT_U32(msg, NL80211_ATTR_DEVICE_AP_SME,
+                           dev->wiphy.ap_sme_capa);
+
+       NLA_PUT_U32(msg, NL80211_ATTR_FEATURE_FLAGS, dev->wiphy.features);
+
        return genlmsg_end(msg, hdr);
 
  nla_put_failure:
@@ -1253,6 +1270,12 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        goto bad_res;
                }
 
+               if (netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+                   netdev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO) {
+                       result = -EINVAL;
+                       goto bad_res;
+               }
+
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
@@ -2150,6 +2173,13 @@ static int nl80211_addset_beacon(struct sk_buff *skb, struct genl_info *info)
                        nla_len(info->attrs[NL80211_ATTR_IE_ASSOC_RESP]);
        }
 
+       if (info->attrs[NL80211_ATTR_PROBE_RESP]) {
+               params.probe_resp =
+                       nla_data(info->attrs[NL80211_ATTR_PROBE_RESP]);
+               params.probe_resp_len =
+                       nla_len(info->attrs[NL80211_ATTR_PROBE_RESP]);
+       }
+
        err = call(&rdev->wiphy, dev, &params);
        if (!err && params.interval)
                wdev->beacon_interval = params.interval;
@@ -5266,12 +5296,13 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        bool channel_type_valid = false;
        u32 freq;
        int err;
-       void *hdr;
+       void *hdr = NULL;
        u64 cookie;
-       struct sk_buff *msg;
+       struct sk_buff *msg = NULL;
        unsigned int wait = 0;
-       bool offchan;
-       bool no_cck;
+       bool offchan, no_cck, dont_wait_for_ack;
+
+       dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5315,29 +5346,36 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        if (chan == NULL)
                return -EINVAL;
 
-       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
-       if (!msg)
-               return -ENOMEM;
+       if (!dont_wait_for_ack) {
+               msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+               if (!msg)
+                       return -ENOMEM;
 
-       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
-                            NL80211_CMD_FRAME);
+               hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                                    NL80211_CMD_FRAME);
 
-       if (IS_ERR(hdr)) {
-               err = PTR_ERR(hdr);
-               goto free_msg;
+               if (IS_ERR(hdr)) {
+                       err = PTR_ERR(hdr);
+                       goto free_msg;
+               }
        }
+
        err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   no_cck, &cookie);
+                                   no_cck, dont_wait_for_ack, &cookie);
        if (err)
                goto free_msg;
 
-       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (msg) {
+               NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
 
-       genlmsg_end(msg, hdr);
-       return genlmsg_reply(msg, info);
+               genlmsg_end(msg, hdr);
+               return genlmsg_reply(msg, info);
+       }
+
+       return 0;
 
  nla_put_failure:
        err = -ENOBUFS;
@@ -5827,6 +5865,91 @@ static int nl80211_set_rekey_data(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_register_unexpected_frame(struct sk_buff *skb,
+                                            struct genl_info *info)
+{
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EINVAL;
+
+       if (wdev->ap_unexpected_nlpid)
+               return -EBUSY;
+
+       wdev->ap_unexpected_nlpid = info->snd_pid;
+       return 0;
+}
+
+static int nl80211_probe_client(struct sk_buff *skb,
+                               struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct sk_buff *msg;
+       void *hdr;
+       const u8 *addr;
+       u64 cookie;
+       int err;
+
+       if (wdev->iftype != NL80211_IFTYPE_AP &&
+           wdev->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       if (!info->attrs[NL80211_ATTR_MAC])
+               return -EINVAL;
+
+       if (!rdev->ops->probe_client)
+               return -EOPNOTSUPP;
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
+       if (!msg)
+               return -ENOMEM;
+
+       hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0,
+                            NL80211_CMD_PROBE_CLIENT);
+
+       if (IS_ERR(hdr)) {
+               err = PTR_ERR(hdr);
+               goto free_msg;
+       }
+
+       addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+       err = rdev->ops->probe_client(&rdev->wiphy, dev, addr, &cookie);
+       if (err)
+               goto free_msg;
+
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+
+       genlmsg_end(msg, hdr);
+
+       return genlmsg_reply(msg, info);
+
+ nla_put_failure:
+       err = -ENOBUFS;
+ free_msg:
+       nlmsg_free(msg);
+       return err;
+}
+
+static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+
+       if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
+               return -EOPNOTSUPP;
+
+       if (rdev->ap_beacons_nlpid)
+               return -EBUSY;
+
+       rdev->ap_beacons_nlpid = info->snd_pid;
+
+       return 0;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -6382,6 +6505,30 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_UNEXPECTED_FRAME,
+               .doit = nl80211_register_unexpected_frame,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_PROBE_CLIENT,
+               .doit = nl80211_probe_client,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
+       {
+               .cmd = NL80211_CMD_REGISTER_BEACONS,
+               .doit = nl80211_register_beacons,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_WIPHY |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -6634,10 +6781,7 @@ void nl80211_send_reg_change_event(struct regulatory_request *request)
        if (wiphy_idx_valid(request->wiphy_idx))
                NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -6673,10 +6817,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6757,10 +6898,7 @@ static void nl80211_send_mlme_timeout(struct cfg80211_registered_device *rdev,
        NLA_PUT_FLAG(msg, NL80211_ATTR_TIMED_OUT);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6816,10 +6954,7 @@ void nl80211_send_connect_result(struct cfg80211_registered_device *rdev,
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6857,10 +6992,7 @@ void nl80211_send_roamed(struct cfg80211_registered_device *rdev,
        if (resp_ie)
                NLA_PUT(msg, NL80211_ATTR_RESP_IE, resp_ie_len, resp_ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6898,10 +7030,7 @@ void nl80211_send_disconnected(struct cfg80211_registered_device *rdev,
        if (ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len, ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, GFP_KERNEL);
@@ -6934,10 +7063,7 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -6972,10 +7098,7 @@ void nl80211_send_new_peer_candidate(struct cfg80211_registered_device *rdev,
        if (ie_len && ie)
                NLA_PUT(msg, NL80211_ATTR_IE, ie_len , ie);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7014,10 +7137,7 @@ void nl80211_michael_mic_failure(struct cfg80211_registered_device *rdev,
        if (tsc)
                NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, 6, tsc);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7068,10 +7188,7 @@ void nl80211_send_beacon_hint_event(struct wiphy *wiphy,
                goto nla_put_failure;
        nla_nest_end(msg, nl_freq);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        rcu_read_lock();
        genlmsg_multicast_allns(msg, 0, nl80211_regulatory_mcgrp.id,
@@ -7114,10 +7231,7 @@ static void nl80211_send_remain_on_chan_event(
        if (cmd == NL80211_CMD_REMAIN_ON_CHANNEL)
                NLA_PUT_U32(msg, NL80211_ATTR_DURATION, duration);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7188,10 +7302,7 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
        NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7202,13 +7313,68 @@ void nl80211_send_sta_del_event(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
+static bool __nl80211_unexpected_frame(struct net_device *dev, u8 cmd,
+                                      const u8 *addr, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+       u32 nlpid = ACCESS_ONCE(wdev->ap_unexpected_nlpid);
+
+       if (!nlpid)
+               return false;
+
+       msg = nlmsg_new(100, gfp);
+       if (!msg)
+               return true;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, cmd);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return true;
+       }
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return true;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+       return true;
+}
+
+bool nl80211_unexpected_frame(struct net_device *dev, const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev, NL80211_CMD_UNEXPECTED_FRAME,
+                                         addr, gfp);
+}
+
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp)
+{
+       return __nl80211_unexpected_frame(dev,
+                                         NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+                                         addr, gfp);
+}
+
 int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
                      struct net_device *netdev, u32 nlpid,
                      int freq, const u8 *buf, size_t len, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
-       int err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
@@ -7225,16 +7391,9 @@ int nl80211_send_mgmt(struct cfg80211_registered_device *rdev,
        NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
        NLA_PUT(msg, NL80211_ATTR_FRAME, len, buf);
 
-       err = genlmsg_end(msg, hdr);
-       if (err < 0) {
-               nlmsg_free(msg);
-               return err;
-       }
+       genlmsg_end(msg, hdr);
 
-       err = genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
-       if (err < 0)
-               return err;
-       return 0;
+       return genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -7267,10 +7426,7 @@ void nl80211_send_mgmt_tx_status(struct cfg80211_registered_device *rdev,
        if (ack)
                NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast(msg, 0, nl80211_mlme_mcgrp.id, gfp);
        return;
@@ -7312,10 +7468,7 @@ nl80211_send_cqm_rssi_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7357,10 +7510,7 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, rekey_attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7403,10 +7553,7 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, attr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
-               nlmsg_free(msg);
-               return;
-       }
+       genlmsg_end(msg, hdr);
 
        genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
                                nl80211_mlme_mcgrp.id, gfp);
@@ -7448,7 +7595,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
 
        nla_nest_end(msg, pinfoattr);
 
-       if (genlmsg_end(msg, hdr) < 0) {
+       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 cfg80211_probe_status(struct net_device *dev, const u8 *addr,
+                          u64 cookie, bool acked, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PROBE_CLIENT);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);
+       NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+       NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, cookie);
+       if (acked)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_ACK);
+
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
                nlmsg_free(msg);
                return;
        }
@@ -7461,6 +7646,45 @@ nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
+EXPORT_SYMBOL(cfg80211_probe_status);
+
+void cfg80211_report_obss_beacon(struct wiphy *wiphy,
+                                const u8 *frame, size_t len,
+                                int freq, gfp_t gfp)
+{
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       u32 nlpid = ACCESS_ONCE(rdev->ap_beacons_nlpid);
+
+       if (!nlpid)
+               return;
+
+       msg = nlmsg_new(len + 100, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       if (freq)
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
+       NLA_PUT(msg, NL80211_ATTR_FRAME, len, frame);
+
+       genlmsg_end(msg, hdr);
+
+       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlpid);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_report_obss_beacon);
 
 static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
@@ -7475,9 +7699,12 @@ 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(rdev, &cfg80211_rdev_list, list) {
                list_for_each_entry_rcu(wdev, &rdev->netdev_list, list)
                        cfg80211_mlme_unregister_socket(wdev, notify->pid);
+               if (rdev->ap_beacons_nlpid == notify->pid)
+                       rdev->ap_beacons_nlpid = 0;
+       }
 
        rcu_read_unlock();
 
index f24a1fbeaf19a8bf3cee73a3ec8b3b33d6e0f0ad..12bf4d185abe7dd1f0e89494261c3441faab3680 100644 (file)
@@ -117,4 +117,9 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
                                    struct net_device *netdev, int index,
                                    const u8 *bssid, bool preauth, gfp_t gfp);
 
+bool nl80211_unexpected_frame(struct net_device *dev,
+                             const u8 *addr, gfp_t gfp);
+bool nl80211_unexpected_4addr_frame(struct net_device *dev,
+                                   const u8 *addr, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index 0fb1424104047ced0d99949be89388509e05fc5c..31119e32e092b6e2615a8653c768a5cd7531465b 100644 (file)
@@ -259,17 +259,20 @@ static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 {
        const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
        const u8 *ie2 = cfg80211_find_ie(num, ies2, len2);
-       int r;
 
+       /* equal if both missing */
        if (!ie1 && !ie2)
                return 0;
-       if (!ie1 || !ie2)
+       /* sort missing IE before (left of) present IE */
+       if (!ie1)
                return -1;
+       if (!ie2)
+               return 1;
 
-       r = memcmp(ie1 + 2, ie2 + 2, min(ie1[1], ie2[1]));
-       if (r == 0 && ie1[1] != ie2[1])
+       /* sort by length first, then by contents */
+       if (ie1[1] != ie2[1])
                return ie2[1] - ie1[1];
-       return r;
+       return memcmp(ie1 + 2, ie2 + 2, ie1[1]);
 }
 
 static bool is_bss(struct cfg80211_bss *a,
@@ -352,8 +355,8 @@ static bool is_mesh(struct cfg80211_bss *a,
            sizeof(struct ieee80211_meshconf_ie) - 2) == 0;
 }
 
-static int cmp_bss(struct cfg80211_bss *a,
-                  struct cfg80211_bss *b)
+static int cmp_bss_core(struct cfg80211_bss *a,
+                       struct cfg80211_bss *b)
 {
        int r;
 
@@ -375,7 +378,15 @@ static int cmp_bss(struct cfg80211_bss *a,
                               b->len_information_elements);
        }
 
-       r = memcmp(a->bssid, b->bssid, ETH_ALEN);
+       return memcmp(a->bssid, b->bssid, ETH_ALEN);
+}
+
+static int cmp_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       int r;
+
+       r = cmp_bss_core(a, b);
        if (r)
                return r;
 
@@ -386,6 +397,52 @@ static int cmp_bss(struct cfg80211_bss *a,
                       b->len_information_elements);
 }
 
+static int cmp_hidden_bss(struct cfg80211_bss *a,
+                  struct cfg80211_bss *b)
+{
+       const u8 *ie1;
+       const u8 *ie2;
+       int i;
+       int r;
+
+       r = cmp_bss_core(a, b);
+       if (r)
+               return r;
+
+       ie1 = cfg80211_find_ie(WLAN_EID_SSID,
+                       a->information_elements,
+                       a->len_information_elements);
+       ie2 = cfg80211_find_ie(WLAN_EID_SSID,
+                       b->information_elements,
+                       b->len_information_elements);
+
+       /* Key comparator must use same algorithm in any rb-tree
+        * search function (order is important), otherwise ordering
+        * of items in the tree is broken and search gives incorrect
+        * results. This code uses same order as cmp_ies() does. */
+
+       /* sort missing IE before (left of) present IE */
+       if (!ie1)
+               return -1;
+       if (!ie2)
+               return 1;
+
+       /* zero-size SSID is used as an indication of the hidden bss */
+       if (!ie2[1])
+               return 0;
+
+       /* sort by length first, then by contents */
+       if (ie1[1] != ie2[1])
+               return ie2[1] - ie1[1];
+
+       /* zeroed SSID ie is another indication of a hidden bss */
+       for (i = 0; i < ie2[1]; i++)
+               if (ie2[i + 2])
+                       return -1;
+
+       return 0;
+}
+
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
                                      const u8 *bssid,
@@ -501,6 +558,48 @@ rb_find_bss(struct cfg80211_registered_device *dev,
        return NULL;
 }
 
+static struct cfg80211_internal_bss *
+rb_find_hidden_bss(struct cfg80211_registered_device *dev,
+           struct cfg80211_internal_bss *res)
+{
+       struct rb_node *n = dev->bss_tree.rb_node;
+       struct cfg80211_internal_bss *bss;
+       int r;
+
+       while (n) {
+               bss = rb_entry(n, struct cfg80211_internal_bss, rbn);
+               r = cmp_hidden_bss(&res->pub, &bss->pub);
+
+               if (r == 0)
+                       return bss;
+               else if (r < 0)
+                       n = n->rb_left;
+               else
+                       n = n->rb_right;
+       }
+
+       return NULL;
+}
+
+static void
+copy_hidden_ies(struct cfg80211_internal_bss *res,
+                struct cfg80211_internal_bss *hidden)
+{
+       if (unlikely(res->pub.beacon_ies))
+               return;
+       if (WARN_ON(!hidden->pub.beacon_ies))
+               return;
+
+       res->pub.beacon_ies = kmalloc(hidden->pub.len_beacon_ies, GFP_ATOMIC);
+       if (unlikely(!res->pub.beacon_ies))
+               return;
+
+       res->beacon_ies_allocated = true;
+       res->pub.len_beacon_ies = hidden->pub.len_beacon_ies;
+       memcpy(res->pub.beacon_ies, hidden->pub.beacon_ies,
+                       res->pub.len_beacon_ies);
+}
+
 static struct cfg80211_internal_bss *
 cfg80211_bss_update(struct cfg80211_registered_device *dev,
                    struct cfg80211_internal_bss *res)
@@ -604,6 +703,21 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
                kref_put(&res->ref, bss_release);
        } else {
+               struct cfg80211_internal_bss *hidden;
+
+               /* First check if the beacon is a probe response from
+                * a hidden bss. If so, copy beacon ies (with nullified
+                * ssid) into the probe response bss entry (with real ssid).
+                * It is required basically for PSM implementation
+                * (probe responses do not contain tim ie) */
+
+               /* TODO: The code is not trying to update existing probe
+                * response bss entries when beacon ies are
+                * getting changed. */
+               hidden = rb_find_hidden_bss(dev, res);
+               if (hidden)
+                       copy_hidden_ies(res, hidden);
+
                /* this "consumes" the reference */
                list_add_tail(&res->list, &dev->bss_list);
                rb_insert_bss(dev, res);
index 6897436b1d3f9166c3df9ceafd7f1b84fabed9de..3c24eb97e9d7f0eaf60cff02f2372967f29e5284 100644 (file)
@@ -819,12 +819,24 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                                 struct iw_freq *freq, char *extra)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct ieee80211_channel *chan;
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
                return cfg80211_mgd_wext_giwfreq(dev, info, freq, extra);
        case NL80211_IFTYPE_ADHOC:
                return cfg80211_ibss_wext_giwfreq(dev, info, freq, extra);
+       case NL80211_IFTYPE_MONITOR:
+               if (!rdev->ops->get_channel)
+                       return -EINVAL;
+
+               chan = rdev->ops->get_channel(wdev->wiphy);
+               if (!chan)
+                       return -EINVAL;
+               freq->m = chan->center_freq;
+               freq->e = 6;
+               return 0;
        default:
                if (!wdev->channel)
                        return -EINVAL;