Merge branch 'for-linville' of git://github.com/kvalo/ath
authorJohn W. Linville <linville@tuxdriver.com>
Mon, 13 Jan 2014 19:40:03 +0000 (14:40 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Mon, 13 Jan 2014 19:40:03 +0000 (14:40 -0500)
291 files changed:
drivers/bcma/driver_chipcommon_sflash.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btsdio.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_vhci.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath9k/ar9002_hw.c
drivers/net/wireless/ath/ath9k/ar9002_mac.c
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar953x_initvals.h [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw-ops.h
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/link.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/spectral.c
drivers/net/wireless/ath/ath9k/wow.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/debug.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/rx.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/wil6210/interrupt.c
drivers/net/wireless/ath/wil6210/txrx.c
drivers/net/wireless/ath/wil6210/wil6210.h
drivers/net/wireless/atmel.c
drivers/net/wireless/atmel_cs.c
drivers/net/wireless/atmel_pci.c
drivers/net/wireless/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
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/fwsignal.c
drivers/net/wireless/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.c
drivers/net/wireless/brcm80211/brcmfmac/sdio_chip.h
drivers/net/wireless/brcm80211/brcmfmac/sdio_host.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
drivers/net/wireless/brcm80211/include/brcmu_wifi.h
drivers/net/wireless/cw1200/fwio.c
drivers/net/wireless/cw1200/main.c
drivers/net/wireless/cw1200/pm.c
drivers/net/wireless/hostap/hostap_cs.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/hostap/hostap_pci.c
drivers/net/wireless/hostap/hostap_plx.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/iwlegacy/3945-rs.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-rs.c
drivers/net/wireless/iwlegacy/4965.c
drivers/net/wireless/iwlegacy/common.c
drivers/net/wireless/iwlwifi/dvm/agn.h
drivers/net/wireless/iwlwifi/dvm/calib.c
drivers/net/wireless/iwlwifi/dvm/calib.h
drivers/net/wireless/iwlwifi/dvm/commands.h
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/devices.c
drivers/net/wireless/iwlwifi/dvm/led.c
drivers/net/wireless/iwlwifi/dvm/led.h
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/power.c
drivers/net/wireless/iwlwifi/dvm/power.h
drivers/net/wireless/iwlwifi/dvm/rs.c
drivers/net/wireless/iwlwifi/dvm/rs.h
drivers/net/wireless/iwlwifi/dvm/rx.c
drivers/net/wireless/iwlwifi/dvm/rxon.c
drivers/net/wireless/iwlwifi/dvm/scan.c
drivers/net/wireless/iwlwifi/dvm/sta.c
drivers/net/wireless/iwlwifi/dvm/tt.c
drivers/net/wireless/iwlwifi/dvm/tt.h
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-7000.c
drivers/net/wireless/iwlwifi/iwl-agn-hw.h
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-debug.h
drivers/net/wireless/iwlwifi/iwl-devtrace.c
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-drv.c
drivers/net/wireless/iwlwifi/iwl-drv.h
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.h
drivers/net/wireless/iwlwifi/iwl-eeprom-read.c
drivers/net/wireless/iwlwifi/iwl-eeprom-read.h
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-fw-file.h
drivers/net/wireless/iwlwifi/iwl-fw.h
drivers/net/wireless/iwlwifi/iwl-io.c
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-modparams.h
drivers/net/wireless/iwlwifi/iwl-notif-wait.c
drivers/net/wireless/iwlwifi/iwl-notif-wait.h
drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
drivers/net/wireless/iwlwifi/iwl-nvm-parse.h
drivers/net/wireless/iwlwifi/iwl-op-mode.h
drivers/net/wireless/iwlwifi/iwl-phy-db.c
drivers/net/wireless/iwlwifi/iwl-phy-db.h
drivers/net/wireless/iwlwifi/iwl-prph.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/mvm/binding.c
drivers/net/wireless/iwlwifi/mvm/bt-coex.c
drivers/net/wireless/iwlwifi/mvm/constants.h
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
drivers/net/wireless/iwlwifi/mvm/debugfs.c
drivers/net/wireless/iwlwifi/mvm/debugfs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-bt-coex.h
drivers/net/wireless/iwlwifi/mvm/fw-api-d3.h
drivers/net/wireless/iwlwifi/mvm/fw-api-mac.h
drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
drivers/net/wireless/iwlwifi/mvm/fw-api-scan.h
drivers/net/wireless/iwlwifi/mvm/fw-api-sta.h
drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/fw.c
drivers/net/wireless/iwlwifi/mvm/led.c
drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/mvm.h
drivers/net/wireless/iwlwifi/mvm/nvm.c
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
drivers/net/wireless/iwlwifi/mvm/power.c
drivers/net/wireless/iwlwifi/mvm/power_legacy.c
drivers/net/wireless/iwlwifi/mvm/quota.c
drivers/net/wireless/iwlwifi/mvm/rs.c
drivers/net/wireless/iwlwifi/mvm/rs.h
drivers/net/wireless/iwlwifi/mvm/rx.c
drivers/net/wireless/iwlwifi/mvm/scan.c
drivers/net/wireless/iwlwifi/mvm/sf.c
drivers/net/wireless/iwlwifi/mvm/sta.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/testmode.h
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h
drivers/net/wireless/iwlwifi/mvm/tt.c
drivers/net/wireless/iwlwifi/mvm/tx.c
drivers/net/wireless/iwlwifi/mvm/utils.c
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sta_cmd.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/hermes.c
drivers/net/wireless/orinoco/orinoco_cs.c
drivers/net/wireless/orinoco/orinoco_usb.c
drivers/net/wireless/orinoco/spectrum_cs.c
drivers/net/wireless/p54/eeprom.c
drivers/net/wireless/p54/fwio.c
drivers/net/wireless/p54/led.c
drivers/net/wireless/p54/main.c
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8180/grf5101.c
drivers/net/wireless/rtl818x/rtl8180/max2820.c
drivers/net/wireless/rtl818x/rtl8180/rtl8225.c
drivers/net/wireless/rtl818x/rtl8180/sa2400.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtl818x/rtl8187/rtl8225.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/ti/wl1251/acx.c
drivers/net/wireless/ti/wl1251/acx.h
drivers/net/wireless/ti/wl1251/boot.c
drivers/net/wireless/ti/wl1251/cmd.c
drivers/net/wireless/ti/wl1251/cmd.h
drivers/net/wireless/ti/wl1251/event.c
drivers/net/wireless/ti/wl1251/event.h
drivers/net/wireless/ti/wl1251/init.c
drivers/net/wireless/ti/wl1251/main.c
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/wireless/ti/wl1251/tx.c
drivers/net/wireless/ti/wl1251/wl1251.h
drivers/net/wireless/wl3501_cs.c
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/mei_phy.c
drivers/nfc/nfcmrvl/Kconfig [new file with mode: 0644]
drivers/nfc/nfcmrvl/Makefile [new file with mode: 0644]
drivers/nfc/nfcmrvl/main.c [new file with mode: 0644]
drivers/nfc/nfcmrvl/nfcmrvl.h [new file with mode: 0644]
drivers/nfc/nfcmrvl/usb.c [new file with mode: 0644]
drivers/nfc/pn533.c
drivers/nfc/pn544/pn544.c
drivers/nfc/port100.c
drivers/ssb/driver_chipcommon_sflash.c
include/linux/mmc/sdio_ids.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/digital.h
include/net/nfc/nci_core.h
include/uapi/linux/if_arp.h
include/uapi/linux/nl80211.h
net/bluetooth/6lowpan.c [new file with mode: 0644]
net/bluetooth/6lowpan.h [new file with mode: 0644]
net/bluetooth/Makefile
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/rfcomm/tty.c
net/ieee802154/6lowpan.c
net/ieee802154/6lowpan.h
net/ieee802154/6lowpan_iphc.c [new file with mode: 0644]
net/ieee802154/Makefile
net/ipv6/addrconf.c
net/mac80211/aes_cmac.c
net/mac80211/aes_cmac.h
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/tkip.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/nfc/core.c
net/nfc/digital_core.c
net/nfc/digital_dep.c
net/nfc/hci/core.c
net/nfc/llcp_commands.c
net/nfc/llcp_core.c
net/nfc/llcp_sock.c
net/nfc/nci/core.c
net/wireless/ap.c
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/nl80211.c
net/wireless/radiotap.c
net/wireless/rdev-ops.h
net/wireless/sme.c
net/wireless/trace.h
net/wireless/util.c

index 4d07cce9c5d97ad2d7d9733c90209bfcb5a094da..7e11ef4cb7dbed69bd52685cf03a177fe6a8a01a 100644 (file)
@@ -38,7 +38,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
-       { 0 },
+       { NULL },
 };
 
 static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
@@ -56,7 +56,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_sst_tbl[] = {
        { "SST25VF016", 0x41, 0x1000, 512, },
        { "SST25VF032", 0x4a, 0x1000, 1024, },
        { "SST25VF064", 0x4b, 0x1000, 2048, },
-       { 0 },
+       { NULL },
 };
 
 static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
@@ -67,7 +67,7 @@ static const struct bcma_sflash_tbl_e bcma_sflash_at_tbl[] = {
        { "AT45DB161", 0x2c, 512, 4096, },
        { "AT45DB321", 0x34, 512, 8192, },
        { "AT45DB642", 0x3c, 1024, 8192, },
-       { 0 },
+       { NULL },
 };
 
 static void bcma_sflash_cmd(struct bcma_drv_cc *cc, u32 opcode)
index d3fdc32b579d72afcee794d9ba68c68b1f4c367d..106d1d8e16ad4f87ac510f5d02b53dc36e8f23ef 100644 (file)
@@ -88,6 +88,7 @@ static const struct usb_device_id ath3k_table[] = {
        { USB_DEVICE(0x0CF3, 0xE004) },
        { USB_DEVICE(0x0CF3, 0xE005) },
        { USB_DEVICE(0x0930, 0x0219) },
+       { USB_DEVICE(0x0930, 0x0220) },
        { USB_DEVICE(0x0489, 0xe057) },
        { USB_DEVICE(0x13d3, 0x3393) },
        { USB_DEVICE(0x0489, 0xe04e) },
@@ -132,6 +133,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
index b61440aaee658210143f435a872ed51e649485e6..83f6437dd91df4014e27084f53ac6b02be5ed68a 100644 (file)
@@ -73,6 +73,7 @@ struct btsdio_data {
 #define REG_CL_INTRD 0x13      /* Interrupt Clear */
 #define REG_EN_INTRD 0x14      /* Interrupt Enable */
 #define REG_MD_STAT  0x20      /* Bluetooth Mode Status */
+#define REG_MD_SET   0x20      /* Bluetooth Mode Set */
 
 static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb)
 {
@@ -212,7 +213,7 @@ static int btsdio_open(struct hci_dev *hdev)
        }
 
        if (data->func->class == SDIO_CLASS_BT_B)
-               sdio_writeb(data->func, 0x00, REG_MD_STAT, NULL);
+               sdio_writeb(data->func, 0x00, REG_MD_SET, NULL);
 
        sdio_writeb(data->func, 0x01, REG_EN_INTRD, NULL);
 
@@ -333,6 +334,9 @@ static int btsdio_probe(struct sdio_func *func,
        hdev->flush    = btsdio_flush;
        hdev->send     = btsdio_send_frame;
 
+       if (func->vendor == 0x0104 && func->device == 0x00c5)
+               set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
        err = hci_register_dev(hdev);
        if (err < 0) {
                hci_free_dev(hdev);
index bfbcc5a772a61ecb1619d6bbb988eb22bb9f0fef..baeaaed299e4e339ee455833c94c9d7aa24421c4 100644 (file)
@@ -155,6 +155,7 @@ static const struct usb_device_id blacklist_table[] = {
        { USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0cf3, 0xe005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
+       { USB_DEVICE(0x0930, 0x0220), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe057), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0489, 0xe04e), .driver_info = BTUSB_ATH3012 },
@@ -964,6 +965,45 @@ static int btusb_setup_bcm92035(struct hci_dev *hdev)
        return 0;
 }
 
+static int btusb_setup_csr(struct hci_dev *hdev)
+{
+       struct hci_rp_read_local_version *rp;
+       struct sk_buff *skb;
+       int ret;
+
+       BT_DBG("%s", hdev->name);
+
+       skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL,
+                            HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb));
+               return -PTR_ERR(skb);
+       }
+
+       rp = (struct hci_rp_read_local_version *) skb->data;
+
+       if (!rp->status) {
+               if (le16_to_cpu(rp->manufacturer) != 10) {
+                       /* Clear the reset quirk since this is not an actual
+                        * early Bluetooth 1.1 device from CSR.
+                        */
+                       clear_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+                       /* These fake CSR controllers have all a broken
+                        * stored link key handling and so just disable it.
+                        */
+                       set_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY,
+                               &hdev->quirks);
+               }
+       }
+
+       ret = -bt_to_errno(rp->status);
+
+       kfree_skb(skb);
+
+       return ret;
+}
+
 struct intel_version {
        u8 status;
        u8 hw_platform;
@@ -1464,10 +1504,15 @@ static int btusb_probe(struct usb_interface *intf,
 
        if (id->driver_info & BTUSB_CSR) {
                struct usb_device *udev = data->udev;
+               u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice);
 
                /* Old firmware would otherwise execute USB reset */
-               if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
+               if (bcdDevice < 0x117)
                        set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
+               /* Fake CSR devices with broken commands */
+               if (bcdDevice <= 0x100)
+                       hdev->setup = btusb_setup_csr;
        }
 
        if (id->driver_info & BTUSB_SNIFFER) {
index 7b167385a1c4e8bdf7d0974707f0b0b43ea21f43..1ef6990a5c7e7c0387b4d9b6aafcb7a5c6f5cdc2 100644 (file)
@@ -141,22 +141,28 @@ static int vhci_create_device(struct vhci_data *data, __u8 dev_type)
 }
 
 static inline ssize_t vhci_get_user(struct vhci_data *data,
-                                   const char __user *buf, size_t count)
+                                   const struct iovec *iov,
+                                   unsigned long count)
 {
+       size_t len = iov_length(iov, count);
        struct sk_buff *skb;
        __u8 pkt_type, dev_type;
+       unsigned long i;
        int ret;
 
-       if (count < 2 || count > HCI_MAX_FRAME_SIZE)
+       if (len < 2 || len > HCI_MAX_FRAME_SIZE)
                return -EINVAL;
 
-       skb = bt_skb_alloc(count, GFP_KERNEL);
+       skb = bt_skb_alloc(len, GFP_KERNEL);
        if (!skb)
                return -ENOMEM;
 
-       if (copy_from_user(skb_put(skb, count), buf, count)) {
-               kfree_skb(skb);
-               return -EFAULT;
+       for (i = 0; i < count; i++) {
+               if (copy_from_user(skb_put(skb, iov[i].iov_len),
+                                  iov[i].iov_base, iov[i].iov_len)) {
+                       kfree_skb(skb);
+                       return -EFAULT;
+               }
        }
 
        pkt_type = *((__u8 *) skb->data);
@@ -205,7 +211,7 @@ static inline ssize_t vhci_get_user(struct vhci_data *data,
                return -EINVAL;
        }
 
-       return (ret < 0) ? ret : count;
+       return (ret < 0) ? ret : len;
 }
 
 static inline ssize_t vhci_put_user(struct vhci_data *data,
@@ -272,12 +278,13 @@ static ssize_t vhci_read(struct file *file,
        return ret;
 }
 
-static ssize_t vhci_write(struct file *file,
-                         const char __user *buf, size_t count, loff_t *pos)
+static ssize_t vhci_write(struct kiocb *iocb, const struct iovec *iov,
+                         unsigned long count, loff_t pos)
 {
+       struct file *file = iocb->ki_filp;
        struct vhci_data *data = file->private_data;
 
-       return vhci_get_user(data, buf, count);
+       return vhci_get_user(data, iov, count);
 }
 
 static unsigned int vhci_poll(struct file *file, poll_table *wait)
@@ -342,7 +349,7 @@ static int vhci_release(struct inode *inode, struct file *file)
 static const struct file_operations vhci_fops = {
        .owner          = THIS_MODULE,
        .read           = vhci_read,
-       .write          = vhci_write,
+       .aio_write      = vhci_write,
        .poll           = vhci_poll,
        .open           = vhci_open,
        .release        = vhci_release,
index cfce83e1f273f0259ee07d072fd8c8f59df8e99a..e888f1893179d439784e9b87f51ab61703df4205 100644 (file)
@@ -15,7 +15,6 @@
  * more details.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
index 14128fd265acd50cbf87b8d348cf014ce316a760..7e9ede6c5798a83c20c82a0e3ca087f74d80442b 100644 (file)
@@ -23,7 +23,6 @@
 #ifdef __IN_PCMCIA_PACKAGE__
 #include <pcmcia/k_compat.h>
 #endif
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
index 34c8a33cac06f67dfb5e4dc718767d6457449d86..031d4ec647792840ad5238993ac79491eb79b7ec 100644 (file)
@@ -1721,7 +1721,7 @@ static void at76_mac80211_tx(struct ieee80211_hw *hw,
         * following workaround is necessary. If the TX frame is an
         * authentication frame extract the bssid and send the CMD_JOIN. */
        if (mgmt->frame_control & cpu_to_le16(IEEE80211_STYPE_AUTH)) {
-               if (!ether_addr_equal(priv->bssid, mgmt->bssid)) {
+               if (!ether_addr_equal_64bits(priv->bssid, mgmt->bssid)) {
                        memcpy(priv->bssid, mgmt->bssid, ETH_ALEN);
                        ieee80211_queue_work(hw, &priv->work_join_bssid);
                        dev_kfree_skb_any(skb);
index 280fc3d53a36466ca8a3f4ff7fd73074efc86b75..8aa20df55e50d854407d7c84faf28ac11b1576e4 100644 (file)
@@ -25,7 +25,6 @@
  * that and only has minimal functionality.
  */
 #include <linux/compiler.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/list.h>
index 69f58b073e85ff1a183ec1f06e803ff9da00806c..6396ad4bce67c8f005ec5373bd214e0d7c30712b 100644 (file)
@@ -1245,7 +1245,7 @@ ath5k_check_ibss_tsf(struct ath5k_hw *ah, struct sk_buff *skb,
 
        if (ieee80211_is_beacon(mgmt->frame_control) &&
            le16_to_cpu(mgmt->u.beacon.capab_info) & WLAN_CAPABILITY_IBSS &&
-           ether_addr_equal(mgmt->bssid, common->curbssid)) {
+           ether_addr_equal_64bits(mgmt->bssid, common->curbssid)) {
                /*
                 * Received an IBSS beacon with the same BSSID. Hardware *must*
                 * have updated the local TSF. We have to work around various
@@ -1309,7 +1309,7 @@ ath5k_update_beacon_rssi(struct ath5k_hw *ah, struct sk_buff *skb, int rssi)
 
        /* only beacons from our BSSID */
        if (!ieee80211_is_beacon(mgmt->frame_control) ||
-           !ether_addr_equal(mgmt->bssid, common->curbssid))
+           !ether_addr_equal_64bits(mgmt->bssid, common->curbssid))
                return;
 
        ewma_add(&ah->ah_beacon_rssi_avg, rssi);
index 149aba3c7298c3af99f8f4d54b37eaf10da606ef..d480d2f3e18588843696bc3801d6a821ffbefee4 100644 (file)
@@ -383,6 +383,20 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah)
        }
 }
 
+static void ar9002_hw_init_hang_checks(struct ath_hw *ah)
+{
+       if (AR_SREV_9100(ah) || AR_SREV_9160(ah)) {
+               ah->config.hw_hang_checks |= HW_BB_RIFS_HANG;
+               ah->config.hw_hang_checks |= HW_BB_DFS_HANG;
+       }
+
+       if (AR_SREV_9280(ah))
+               ah->config.hw_hang_checks |= HW_BB_RX_CLEAR_STUCK_HANG;
+
+       if (AR_SREV_5416(ah) || AR_SREV_9100(ah) || AR_SREV_9160(ah))
+               ah->config.hw_hang_checks |= HW_MAC_HANG;
+}
+
 /* Sets up the AR5008/AR9001/AR9002 hardware familiy callbacks */
 int ar9002_hw_attach_ops(struct ath_hw *ah)
 {
@@ -395,6 +409,7 @@ int ar9002_hw_attach_ops(struct ath_hw *ah)
                return ret;
 
        priv_ops->init_mode_gain_regs = ar9002_hw_init_mode_gain_regs;
+       priv_ops->init_hang_checks = ar9002_hw_init_hang_checks;
 
        ops->config_pci_powersave = ar9002_hw_configpcipowersave;
 
index 857ede3a999ca1a902f0a004979503cd3b40c101..741b38ddcb378e8cb17dbfe0f79f33516be75527 100644 (file)
@@ -77,9 +77,16 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
                                mask2 |= ATH9K_INT_CST;
                        if (isr2 & AR_ISR_S2_TSFOOR)
                                mask2 |= ATH9K_INT_TSFOOR;
+
+                       if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                               REG_WRITE(ah, AR_ISR_S2, isr2);
+                               isr &= ~AR_ISR_BCNMISC;
+                       }
                }
 
-               isr = REG_READ(ah, AR_ISR_RAC);
+               if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)
+                       isr = REG_READ(ah, AR_ISR_RAC);
+
                if (isr == 0xffffffff) {
                        *masked = 0;
                        return false;
@@ -98,11 +105,23 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
 
                        *masked |= ATH9K_INT_TX;
 
-                       s0_s = REG_READ(ah, AR_ISR_S0_S);
+                       if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
+                               s0_s = REG_READ(ah, AR_ISR_S0_S);
+                               s1_s = REG_READ(ah, AR_ISR_S1_S);
+                       } else {
+                               s0_s = REG_READ(ah, AR_ISR_S0);
+                               REG_WRITE(ah, AR_ISR_S0, s0_s);
+                               s1_s = REG_READ(ah, AR_ISR_S1);
+                               REG_WRITE(ah, AR_ISR_S1, s1_s);
+
+                               isr &= ~(AR_ISR_TXOK |
+                                        AR_ISR_TXDESC |
+                                        AR_ISR_TXERR |
+                                        AR_ISR_TXEOL);
+                       }
+
                        ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXOK);
                        ah->intr_txqs |= MS(s0_s, AR_ISR_S0_QCU_TXDESC);
-
-                       s1_s = REG_READ(ah, AR_ISR_S1_S);
                        ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXERR);
                        ah->intr_txqs |= MS(s1_s, AR_ISR_S1_QCU_TXEOL);
                }
@@ -115,13 +134,15 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
                *masked |= mask2;
        }
 
-       if (AR_SREV_9100(ah))
-               return true;
-
-       if (isr & AR_ISR_GENTMR) {
+       if (!AR_SREV_9100(ah) && (isr & AR_ISR_GENTMR)) {
                u32 s5_s;
 
-               s5_s = REG_READ(ah, AR_ISR_S5_S);
+               if (pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED) {
+                       s5_s = REG_READ(ah, AR_ISR_S5_S);
+               } else {
+                       s5_s = REG_READ(ah, AR_ISR_S5);
+               }
+
                ah->intr_gen_timer_trigger =
                                MS(s5_s, AR_ISR_S5_GENTIMER_TRIG);
 
@@ -134,8 +155,21 @@ static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked,
                if ((s5_s & AR_ISR_S5_TIM_TIMER) &&
                    !(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP))
                        *masked |= ATH9K_INT_TIM_TIMER;
+
+               if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+                       REG_WRITE(ah, AR_ISR_S5, s5_s);
+                       isr &= ~AR_ISR_GENTMR;
+               }
        }
 
+       if (!(pCap->hw_caps & ATH9K_HW_CAP_RAC_SUPPORTED)) {
+               REG_WRITE(ah, AR_ISR, isr);
+               REG_READ(ah, AR_ISR);
+       }
+
+       if (AR_SREV_9100(ah))
+               return true;
+
        if (sync_cause) {
                if (sync_cause_p)
                        *sync_cause_p = sync_cause;
index 97e09d5f3a427eade9008c33959a8e7f29836951..8c145cd98c1c50505f15d8616002fa472733e1b1 100644 (file)
@@ -326,6 +326,224 @@ static void ar9003_hw_init_cal_settings(struct ath_hw *ah)
        ah->supp_cals = IQ_MISMATCH_CAL;
 }
 
+#define OFF_UPPER_LT 24
+#define OFF_LOWER_LT 7
+
+static bool ar9003_hw_dynamic_osdac_selection(struct ath_hw *ah,
+                                             bool txiqcal_done)
+{
+       struct ath_common *common = ath9k_hw_common(ah);
+       int ch0_done, osdac_ch0, dc_off_ch0_i1, dc_off_ch0_q1, dc_off_ch0_i2,
+               dc_off_ch0_q2, dc_off_ch0_i3, dc_off_ch0_q3;
+       int ch1_done, osdac_ch1, dc_off_ch1_i1, dc_off_ch1_q1, dc_off_ch1_i2,
+               dc_off_ch1_q2, dc_off_ch1_i3, dc_off_ch1_q3;
+       int ch2_done, osdac_ch2, dc_off_ch2_i1, dc_off_ch2_q1, dc_off_ch2_i2,
+               dc_off_ch2_q2, dc_off_ch2_i3, dc_off_ch2_q3;
+       bool status;
+       u32 temp, val;
+
+       /*
+        * Clear offset and IQ calibration, run AGC cal.
+        */
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_CLR_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+                   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+       REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                 REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
+
+       status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                              AR_PHY_AGC_CONTROL_CAL,
+                              0, AH_WAIT_TIMEOUT);
+       if (!status) {
+               ath_dbg(common, CALIBRATE,
+                       "AGC cal without offset cal failed to complete in 1ms");
+               return false;
+       }
+
+       /*
+        * Allow only offset calibration and disable the others
+        * (Carrier Leak calibration, TX Filter calibration and
+        *  Peak Detector offset calibration).
+        */
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL,
+                   AR_PHY_CL_CAL_ENABLE);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_FLTR_CAL);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_PKDET_CAL);
+
+       ch0_done = 0;
+       ch1_done = 0;
+       ch2_done = 0;
+
+       while ((ch0_done == 0) || (ch1_done == 0) || (ch2_done == 0)) {
+               osdac_ch0 = (REG_READ(ah, AR_PHY_65NM_CH0_BB1) >> 30) & 0x3;
+               osdac_ch1 = (REG_READ(ah, AR_PHY_65NM_CH1_BB1) >> 30) & 0x3;
+               osdac_ch2 = (REG_READ(ah, AR_PHY_65NM_CH2_BB1) >> 30) & 0x3;
+
+               REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                         REG_READ(ah, AR_PHY_AGC_CONTROL) | AR_PHY_AGC_CONTROL_CAL);
+
+               status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                      AR_PHY_AGC_CONTROL_CAL,
+                                      0, AH_WAIT_TIMEOUT);
+               if (!status) {
+                       ath_dbg(common, CALIBRATE,
+                               "DC offset cal failed to complete in 1ms");
+                       return false;
+               }
+
+               REG_CLR_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+               /*
+                * High gain.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (1 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (1 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (1 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q1 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q1 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i1 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q1 = (temp >> 21) & 0x1f;
+
+               /*
+                * Low gain.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (2 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (2 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (2 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q2 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q2 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i2 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q2 = (temp >> 21) & 0x1f;
+
+               /*
+                * Loopback.
+                */
+               REG_WRITE(ah, AR_PHY_65NM_CH0_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH0_BB3) & 0xfffffcff) | (3 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH1_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH1_BB3) & 0xfffffcff) | (3 << 8)));
+               REG_WRITE(ah, AR_PHY_65NM_CH2_BB3,
+                         ((REG_READ(ah, AR_PHY_65NM_CH2_BB3) & 0xfffffcff) | (3 << 8)));
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH0_BB3);
+               dc_off_ch0_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch0_q3 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH1_BB3);
+               dc_off_ch1_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch1_q3 = (temp >> 21) & 0x1f;
+
+               temp = REG_READ(ah, AR_PHY_65NM_CH2_BB3);
+               dc_off_ch2_i3 = (temp >> 26) & 0x1f;
+               dc_off_ch2_q3 = (temp >> 21) & 0x1f;
+
+               if ((dc_off_ch0_i1 > OFF_UPPER_LT) || (dc_off_ch0_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_i2 > OFF_UPPER_LT) || (dc_off_ch0_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_i3 > OFF_UPPER_LT) || (dc_off_ch0_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q1 > OFF_UPPER_LT) || (dc_off_ch0_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q2 > OFF_UPPER_LT) || (dc_off_ch0_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch0_q3 > OFF_UPPER_LT) || (dc_off_ch0_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch0 == 3) {
+                               ch0_done = 1;
+                       } else {
+                               osdac_ch0++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH0_BB1) & 0x3fffffff;
+                               val |= (osdac_ch0 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH0_BB1, val);
+
+                               ch0_done = 0;
+                       }
+               } else {
+                       ch0_done = 1;
+               }
+
+               if ((dc_off_ch1_i1 > OFF_UPPER_LT) || (dc_off_ch1_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_i2 > OFF_UPPER_LT) || (dc_off_ch1_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_i3 > OFF_UPPER_LT) || (dc_off_ch1_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q1 > OFF_UPPER_LT) || (dc_off_ch1_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q2 > OFF_UPPER_LT) || (dc_off_ch1_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch1_q3 > OFF_UPPER_LT) || (dc_off_ch1_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch1 == 3) {
+                               ch1_done = 1;
+                       } else {
+                               osdac_ch1++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH1_BB1) & 0x3fffffff;
+                               val |= (osdac_ch1 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH1_BB1, val);
+
+                               ch1_done = 0;
+                       }
+               } else {
+                       ch1_done = 1;
+               }
+
+               if ((dc_off_ch2_i1 > OFF_UPPER_LT) || (dc_off_ch2_i1 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_i2 > OFF_UPPER_LT) || (dc_off_ch2_i2 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_i3 > OFF_UPPER_LT) || (dc_off_ch2_i3 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q1 > OFF_UPPER_LT) || (dc_off_ch2_q1 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q2 > OFF_UPPER_LT) || (dc_off_ch2_q2 < OFF_LOWER_LT) ||
+                   (dc_off_ch2_q3 > OFF_UPPER_LT) || (dc_off_ch2_q3 < OFF_LOWER_LT)) {
+                       if (osdac_ch2 == 3) {
+                               ch2_done = 1;
+                       } else {
+                               osdac_ch2++;
+
+                               val = REG_READ(ah, AR_PHY_65NM_CH2_BB1) & 0x3fffffff;
+                               val |= (osdac_ch2 << 30);
+                               REG_WRITE(ah, AR_PHY_65NM_CH2_BB1, val);
+
+                               ch2_done = 0;
+                       }
+               } else {
+                       ch2_done = 1;
+               }
+       }
+
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                   AR_PHY_AGC_CONTROL_OFFSET_CAL);
+       REG_SET_BIT(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
+
+       /*
+        * We don't need to check txiqcal_done here since it is always
+        * set for AR9550.
+        */
+       REG_SET_BIT(ah, AR_PHY_TX_IQCAL_CONTROL_0,
+                   AR_PHY_TX_IQCAL_CONTROL_0_ENABLE_TXIQ_CAL);
+
+       return true;
+}
+
 /*
  * solve 4x4 linear equation used in loopback iq cal.
  */
@@ -1271,6 +1489,11 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
                REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN);
        }
 
+       if (AR_SREV_9550(ah) && IS_CHAN_2GHZ(chan)) {
+               if (!ar9003_hw_dynamic_osdac_selection(ah, txiqcal_done))
+                       return false;
+       }
+
 skip_tx_iqcal:
        if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
                if (AR_SREV_9330_11(ah))
index c8d22eccfef8778b88e1a2a05c9ba0dbe0e206b8..25243cbc07f0ba4ed9c27a6779ff2ea3be7be77d 100644 (file)
@@ -3598,7 +3598,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
                                AR_SWITCH_TABLE_COM_AR9462_ALL, value);
-       } else if (AR_SREV_9550(ah)) {
+       } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
                                AR_SWITCH_TABLE_COM_AR9550_ALL, value);
        } else
@@ -3975,7 +3975,7 @@ static void ar9003_hw_apply_tuning_caps(struct ath_hw *ah)
        struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
        u8 tuning_caps_param = eep->baseEepHeader.params_for_tuning_caps[0];
 
-       if (AR_SREV_9340(ah))
+       if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
                return;
 
        if (eep->baseEepHeader.featureEnable & 0x40) {
@@ -4030,7 +4030,10 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz)
        if (!(eep->baseEepHeader.featureEnable & 0x80))
                return;
 
-       if (!AR_SREV_9300(ah) && !AR_SREV_9340(ah) && !AR_SREV_9580(ah))
+       if (!AR_SREV_9300(ah) &&
+           !AR_SREV_9340(ah) &&
+           !AR_SREV_9580(ah) &&
+           !AR_SREV_9531(ah))
                return;
 
        xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn;
@@ -4163,7 +4166,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
        ar9003_hw_xlna_bias_strength_apply(ah, is2ghz);
        ar9003_hw_atten_apply(ah, chan);
        ar9003_hw_quick_drop_apply(ah, chan->channel);
-       if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
+       if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9531(ah))
                ar9003_hw_internal_regulator_apply(ah);
        ar9003_hw_apply_tuning_caps(ah);
        ar9003_hw_apply_minccapwr_thresh(ah, chan);
@@ -4788,7 +4791,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,
        }
 
 tempslope:
-       if (AR_SREV_9550(ah)) {
+       if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                /*
                 * AR955x has tempSlope register for each chain.
                 * Check whether temp_compensation feature is enabled or not.
index 29613ebbc5d730832b06bbfdf3fb11df32c858d8..ec1da0cc25f53b14412414f2d3aebef7eb1224cc 100644 (file)
@@ -28,6 +28,7 @@
 #include "ar9462_2p1_initvals.h"
 #include "ar9565_1p0_initvals.h"
 #include "ar9565_1p1_initvals.h"
+#include "ar953x_initvals.h"
 
 /* General hardware code for the AR9003 hadware family */
 
@@ -308,6 +309,31 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                /* Fast clock modal settings */
                INIT_INI_ARRAY(&ah->iniModesFastClock,
                                ar955x_1p0_modes_fast_clock);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+                              qca953x_1p0_mac_core);
+               INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+                              qca953x_1p0_mac_postamble);
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+                              qca953x_1p0_baseband_core);
+               INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+                              qca953x_1p0_baseband_postamble);
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+                              qca953x_1p0_radio_core);
+               INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+                              qca953x_1p0_radio_postamble);
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+                              qca953x_1p0_soc_preamble);
+               INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+                              qca953x_1p0_soc_postamble);
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_wo_xlna_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_wo_xlna_rx_gain_bounds);
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                              qca953x_1p0_modes_no_xpa_tx_gain_table);
+               INIT_INI_ARRAY(&ah->iniModesFastClock,
+                              qca953x_1p0_modes_fast_clock);
        } else if (AR_SREV_9580(ah)) {
                /* mac */
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -485,6 +511,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
        else if (AR_SREV_9550(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar955x_1p0_modes_xpa_tx_gain_table);
+       else if (AR_SREV_9531(ah))
+               INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       qca953x_1p0_modes_xpa_tx_gain_table);
        else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9580_1p0_lowest_ob_db_tx_gain_table);
@@ -525,7 +554,14 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
        else if (AR_SREV_9550(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar955x_1p0_modes_no_xpa_tx_gain_table);
-       else if (AR_SREV_9462_21(ah))
+       else if (AR_SREV_9531(ah)) {
+               if (AR_SREV_9531_11(ah))
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                                      qca953x_1p1_modes_no_xpa_tx_gain_table);
+               else
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                                      qca953x_1p0_modes_no_xpa_tx_gain_table);
+       } else if (AR_SREV_9462_21(ah))
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                        ar9462_2p1_modes_high_ob_db_tx_gain);
        else if (AR_SREV_9462_20(ah))
@@ -699,6 +735,11 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
                                ar955x_1p0_common_rx_gain_table);
                INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
                                ar955x_1p0_common_rx_gain_bounds);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_rx_gain_bounds);
        } else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                                ar9580_1p0_rx_gain_table);
@@ -744,6 +785,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
                        ar955x_1p0_common_wo_xlna_rx_gain_table);
                INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
                        ar955x_1p0_common_wo_xlna_rx_gain_bounds);
+       } else if (AR_SREV_9531(ah)) {
+               INIT_INI_ARRAY(&ah->iniModesRxGain,
+                              qca953x_1p0_common_wo_xlna_rx_gain_table);
+               INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+                              qca953x_1p0_common_wo_xlna_rx_gain_bounds);
        } else if (AR_SREV_9580(ah))
                INIT_INI_ARRAY(&ah->iniModesRxGain,
                        ar9580_1p0_wo_xlna_rx_gain_table);
@@ -872,6 +918,117 @@ static void ar9003_hw_configpcipowersave(struct ath_hw *ah,
        }
 }
 
+static void ar9003_hw_init_hang_checks(struct ath_hw *ah)
+{
+       /*
+        * All chips support detection of BB/MAC hangs.
+        */
+       ah->config.hw_hang_checks |= HW_BB_WATCHDOG;
+       ah->config.hw_hang_checks |= HW_MAC_HANG;
+
+       /*
+        * This is not required for AR9580 1.0
+        */
+       if (AR_SREV_9300_22(ah))
+               ah->config.hw_hang_checks |= HW_PHYRESTART_CLC_WAR;
+
+       if (AR_SREV_9330(ah))
+               ah->bb_watchdog_timeout_ms = 85;
+       else
+               ah->bb_watchdog_timeout_ms = 25;
+}
+
+/*
+ * MAC HW hang check
+ * =================
+ *
+ * Signature: dcu_chain_state is 0x6 and dcu_complete_state is 0x1.
+ *
+ * The state of each DCU chain (mapped to TX queues) is available from these
+ * DMA debug registers:
+ *
+ * Chain 0 state : Bits 4:0   of AR_DMADBG_4
+ * Chain 1 state : Bits 9:5   of AR_DMADBG_4
+ * Chain 2 state : Bits 14:10 of AR_DMADBG_4
+ * Chain 3 state : Bits 19:15 of AR_DMADBG_4
+ * Chain 4 state : Bits 24:20 of AR_DMADBG_4
+ * Chain 5 state : Bits 29:25 of AR_DMADBG_4
+ * Chain 6 state : Bits 4:0   of AR_DMADBG_5
+ * Chain 7 state : Bits 9:5   of AR_DMADBG_5
+ * Chain 8 state : Bits 14:10 of AR_DMADBG_5
+ * Chain 9 state : Bits 19:15 of AR_DMADBG_5
+ *
+ * The DCU chain state "0x6" means "WAIT_FRDONE" - wait for TX frame to be done.
+ */
+
+#define NUM_STATUS_READS 50
+
+static bool ath9k_hw_verify_hang(struct ath_hw *ah, unsigned int queue)
+{
+       u32 dma_dbg_chain, dma_dbg_complete;
+       u8 dcu_chain_state, dcu_complete_state;
+       int i;
+
+       for (i = 0; i < NUM_STATUS_READS; i++) {
+               if (queue < 6)
+                       dma_dbg_chain = REG_READ(ah, AR_DMADBG_4);
+               else
+                       dma_dbg_chain = REG_READ(ah, AR_DMADBG_5);
+
+               dma_dbg_complete = REG_READ(ah, AR_DMADBG_6);
+
+               dcu_chain_state = (dma_dbg_chain >> (5 * queue)) & 0x1f;
+               dcu_complete_state = dma_dbg_complete & 0x3;
+
+               if ((dcu_chain_state != 0x6) || (dcu_complete_state != 0x1))
+                       return false;
+       }
+
+       ath_dbg(ath9k_hw_common(ah), RESET,
+               "MAC Hang signature found for queue: %d\n", queue);
+
+       return true;
+}
+
+static bool ar9003_hw_detect_mac_hang(struct ath_hw *ah)
+{
+       u32 dma_dbg_4, dma_dbg_5, dma_dbg_6, chk_dbg;
+       u8 dcu_chain_state, dcu_complete_state;
+       bool dcu_wait_frdone = false;
+       unsigned long chk_dcu = 0;
+       unsigned int i = 0;
+
+       dma_dbg_4 = REG_READ(ah, AR_DMADBG_4);
+       dma_dbg_5 = REG_READ(ah, AR_DMADBG_5);
+       dma_dbg_6 = REG_READ(ah, AR_DMADBG_6);
+
+       dcu_complete_state = dma_dbg_6 & 0x3;
+       if (dcu_complete_state != 0x1)
+               goto exit;
+
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
+               if (i < 6)
+                       chk_dbg = dma_dbg_4;
+               else
+                       chk_dbg = dma_dbg_5;
+
+               dcu_chain_state = (chk_dbg >> (5 * i)) & 0x1f;
+               if (dcu_chain_state == 0x6) {
+                       dcu_wait_frdone = true;
+                       chk_dcu |= BIT(i);
+               }
+       }
+
+       if ((dcu_complete_state == 0x1) && dcu_wait_frdone) {
+               for_each_set_bit(i, &chk_dcu, ATH9K_NUM_TX_QUEUES) {
+                       if (ath9k_hw_verify_hang(ah, i))
+                               return true;
+               }
+       }
+exit:
+       return false;
+}
+
 /* Sets up the AR9003 hardware familiy callbacks */
 void ar9003_hw_attach_ops(struct ath_hw *ah)
 {
@@ -880,6 +1037,8 @@ void ar9003_hw_attach_ops(struct ath_hw *ah)
 
        ar9003_hw_init_mode_regs(ah);
        priv_ops->init_mode_gain_regs = ar9003_hw_init_mode_gain_regs;
+       priv_ops->init_hang_checks = ar9003_hw_init_hang_checks;
+       priv_ops->detect_mac_hang = ar9003_hw_detect_mac_hang;
 
        ops->config_pci_powersave = ar9003_hw_configpcipowersave;
 
index 9f051a08e1431e4696d52536197752fd4d305918..09facba1dc6d8069583f0eb0fdf41e59d96a15f8 100644 (file)
@@ -103,7 +103,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                        } else {
                                channelSel = CHANSEL_2G(freq) >> 1;
                        }
-               } else if (AR_SREV_9550(ah)) {
+               } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                        if (ah->is_clk_25mhz)
                                div = 75;
                        else
@@ -118,7 +118,7 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
                /* Set to 2G mode */
                bMode = 1;
        } else {
-               if ((AR_SREV_9340(ah) || AR_SREV_9550(ah)) &&
+               if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) &&
                    ah->is_clk_25mhz) {
                        channelSel = freq / 75;
                        chan_frac = ((freq % 75) * 0x20000) / 75;
@@ -810,10 +810,12 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        /*
         * TXGAIN initvals.
         */
-       if (AR_SREV_9550(ah)) {
-               int modes_txgain_index;
+       if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+               int modes_txgain_index = 1;
+
+               if (AR_SREV_9550(ah))
+                       modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
 
-               modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
                if (modes_txgain_index < 0)
                        return -EINVAL;
 
@@ -1814,6 +1816,68 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
        memcpy(ah->nf_regs, ar9300_cca_regs, sizeof(ah->nf_regs));
 }
 
+/*
+ * Baseband Watchdog signatures:
+ *
+ * 0x04000539: BB hang when operating in HT40 DFS Channel.
+ *             Full chip reset is not required, but a recovery
+ *             mechanism is needed.
+ *
+ * 0x1300000a: Related to CAC deafness.
+ *             Chip reset is not required.
+ *
+ * 0x0400000a: Related to CAC deafness.
+ *             Full chip reset is required.
+ *
+ * 0x04000b09: RX state machine gets into an illegal state
+ *             when a packet with unsupported rate is received.
+ *             Full chip reset is required and PHY_RESTART has
+ *             to be disabled.
+ *
+ * 0x04000409: Packet stuck on receive.
+ *             Full chip reset is required for all chips except AR9340.
+ */
+
+/*
+ * ar9003_hw_bb_watchdog_check(): Returns true if a chip reset is required.
+ */
+bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah)
+{
+       u32 val;
+
+       switch(ah->bb_watchdog_last_status) {
+       case 0x04000539:
+               val = REG_READ(ah, AR_PHY_RADAR_0);
+               val &= (~AR_PHY_RADAR_0_FIRPWR);
+               val |= SM(0x7f, AR_PHY_RADAR_0_FIRPWR);
+               REG_WRITE(ah, AR_PHY_RADAR_0, val);
+               udelay(1);
+               val = REG_READ(ah, AR_PHY_RADAR_0);
+               val &= ~AR_PHY_RADAR_0_FIRPWR;
+               val |= SM(AR9300_DFS_FIRPWR, AR_PHY_RADAR_0_FIRPWR);
+               REG_WRITE(ah, AR_PHY_RADAR_0, val);
+
+               return false;
+       case 0x1300000a:
+               return false;
+       case 0x0400000a:
+       case 0x04000b09:
+               return true;
+       case 0x04000409:
+               if (AR_SREV_9340(ah) || AR_SREV_9531(ah))
+                       return false;
+               else
+                       return true;
+       default:
+               /*
+                * For any other unknown signatures, do a
+                * full chip reset.
+                */
+               return true;
+       }
+}
+EXPORT_SYMBOL(ar9003_hw_bb_watchdog_check);
+
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1930,6 +1994,7 @@ EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
 
 void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
 {
+       u8 result;
        u32 val;
 
        /* While receiving unsupported rate frame rx state machine
@@ -1937,15 +2002,13 @@ void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
         * state, BB would go hang. If RXSM is in 0xb state after
         * first bb panic, ensure to disable the phy_restart.
         */
-       if (!((MS(ah->bb_watchdog_last_status,
-                 AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) ||
-           ah->bb_hang_rx_ofdm))
-               return;
-
-       ah->bb_hang_rx_ofdm = true;
-       val = REG_READ(ah, AR_PHY_RESTART);
-       val &= ~AR_PHY_RESTART_ENA;
+       result = MS(ah->bb_watchdog_last_status, AR_PHY_WATCHDOG_RX_OFDM_SM);
 
-       REG_WRITE(ah, AR_PHY_RESTART, val);
+       if ((result == 0xb) || ah->bb_hang_rx_ofdm) {
+               ah->bb_hang_rx_ofdm = true;
+               val = REG_READ(ah, AR_PHY_RESTART);
+               val &= ~AR_PHY_RESTART_ENA;
+               REG_WRITE(ah, AR_PHY_RESTART, val);
+       }
 }
 EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
index 1b441715ba390216a26963ec7e272bbc5d05f60d..fd090b1f2d0ffd9ded907c412ae78abcac10dc87 100644 (file)
 #define AR_PHY_CCA_NOM_VAL_9300_5GHZ          -115
 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_2GHZ     -125
 #define AR_PHY_CCA_MIN_GOOD_VAL_9300_5GHZ     -125
-#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -95
-#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -100
-
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_2GHZ     -60
+#define AR_PHY_CCA_MAX_GOOD_VAL_9300_5GHZ     -60
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_2GHZ -95
 #define AR_PHY_CCA_MAX_GOOD_VAL_9300_FCC_5GHZ -100
 
 #define AR_PHY_65NM_CH1_RXTX4       0x1650c
 #define AR_PHY_65NM_CH2_RXTX4       0x1690c
 
+#define AR_PHY_65NM_CH0_BB1         0x16140
+#define AR_PHY_65NM_CH0_BB2         0x16144
+#define AR_PHY_65NM_CH0_BB3         0x16148
+#define AR_PHY_65NM_CH1_BB1         0x16540
+#define AR_PHY_65NM_CH1_BB2         0x16544
+#define AR_PHY_65NM_CH1_BB3         0x16548
+#define AR_PHY_65NM_CH2_BB1         0x16940
+#define AR_PHY_65NM_CH2_BB2         0x16944
+#define AR_PHY_65NM_CH2_BB3         0x16948
+
 #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3           0x00780000
 #define AR_PHY_65NM_CH0_SYNTH12_VREFMUL3_S         19
 #define AR_PHY_65NM_CH0_RXTX2_SYNTHON_MASK         0x00000004
 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT                   0x00000004
 #define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S                 2
 
+#define AR9300_DFS_FIRPWR -28
+
 #endif  /* AR9003_PHY_H */
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
new file mode 100644 (file)
index 0000000..3c9113d
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_953X_H
+#define INITVALS_953X_H
+
+#define qca953x_1p0_mac_postamble ar9300_2p2_mac_postamble
+
+#define qca953x_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define qca953x_1p0_common_rx_gain_table ar9300Common_rx_gain_table_2p2
+
+#define qca953x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define qca953x_1p0_modes_fast_clock ar9300Modes_fast_clock_2p2
+
+static const u32 qca953x_1p0_mac_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00000008, 0x00000000},
+       {0x00000030, 0x00020085},
+       {0x00000034, 0x00000005},
+       {0x00000040, 0x00000000},
+       {0x00000044, 0x00000000},
+       {0x00000048, 0x00000008},
+       {0x0000004c, 0x00000010},
+       {0x00000050, 0x00000000},
+       {0x00001040, 0x002ffc0f},
+       {0x00001044, 0x002ffc0f},
+       {0x00001048, 0x002ffc0f},
+       {0x0000104c, 0x002ffc0f},
+       {0x00001050, 0x002ffc0f},
+       {0x00001054, 0x002ffc0f},
+       {0x00001058, 0x002ffc0f},
+       {0x0000105c, 0x002ffc0f},
+       {0x00001060, 0x002ffc0f},
+       {0x00001064, 0x002ffc0f},
+       {0x000010f0, 0x00000100},
+       {0x00001270, 0x00000000},
+       {0x000012b0, 0x00000000},
+       {0x000012f0, 0x00000000},
+       {0x0000143c, 0x00000000},
+       {0x0000147c, 0x00000000},
+       {0x00008000, 0x00000000},
+       {0x00008004, 0x00000000},
+       {0x00008008, 0x00000000},
+       {0x0000800c, 0x00000000},
+       {0x00008018, 0x00000000},
+       {0x00008020, 0x00000000},
+       {0x00008038, 0x00000000},
+       {0x0000803c, 0x00000000},
+       {0x00008040, 0x00000000},
+       {0x00008044, 0x00000000},
+       {0x00008048, 0x00000000},
+       {0x0000804c, 0xffffffff},
+       {0x00008054, 0x00000000},
+       {0x00008058, 0x00000000},
+       {0x0000805c, 0x000fc78f},
+       {0x00008060, 0x0000000f},
+       {0x00008064, 0x00000000},
+       {0x00008070, 0x00000310},
+       {0x00008074, 0x00000020},
+       {0x00008078, 0x00000000},
+       {0x0000809c, 0x0000000f},
+       {0x000080a0, 0x00000000},
+       {0x000080a4, 0x02ff0000},
+       {0x000080a8, 0x0e070605},
+       {0x000080ac, 0x0000000d},
+       {0x000080b0, 0x00000000},
+       {0x000080b4, 0x00000000},
+       {0x000080b8, 0x00000000},
+       {0x000080bc, 0x00000000},
+       {0x000080c0, 0x2a800000},
+       {0x000080c4, 0x06900168},
+       {0x000080c8, 0x13881c22},
+       {0x000080cc, 0x01f40000},
+       {0x000080d0, 0x00252500},
+       {0x000080d4, 0x00a00000},
+       {0x000080d8, 0x00400000},
+       {0x000080dc, 0x00000000},
+       {0x000080e0, 0xffffffff},
+       {0x000080e4, 0x0000ffff},
+       {0x000080e8, 0x3f3f3f3f},
+       {0x000080ec, 0x00000000},
+       {0x000080f0, 0x00000000},
+       {0x000080f4, 0x00000000},
+       {0x000080fc, 0x00020000},
+       {0x00008100, 0x00000000},
+       {0x00008108, 0x00000052},
+       {0x0000810c, 0x00000000},
+       {0x00008110, 0x00000000},
+       {0x00008114, 0x000007ff},
+       {0x00008118, 0x000000aa},
+       {0x0000811c, 0x00003210},
+       {0x00008124, 0x00000000},
+       {0x00008128, 0x00000000},
+       {0x0000812c, 0x00000000},
+       {0x00008130, 0x00000000},
+       {0x00008134, 0x00000000},
+       {0x00008138, 0x00000000},
+       {0x0000813c, 0x0000ffff},
+       {0x00008140, 0x000000fe},
+       {0x00008144, 0xffffffff},
+       {0x00008168, 0x00000000},
+       {0x0000816c, 0x00000000},
+       {0x000081c0, 0x00000000},
+       {0x000081c4, 0x33332210},
+       {0x000081ec, 0x00000000},
+       {0x000081f0, 0x00000000},
+       {0x000081f4, 0x00000000},
+       {0x000081f8, 0x00000000},
+       {0x000081fc, 0x00000000},
+       {0x00008240, 0x00100000},
+       {0x00008244, 0x0010f3d7},
+       {0x00008248, 0x00000852},
+       {0x0000824c, 0x0001e7ae},
+       {0x00008250, 0x00000000},
+       {0x00008254, 0x00000000},
+       {0x00008258, 0x00000000},
+       {0x0000825c, 0x40000000},
+       {0x00008260, 0x00080922},
+       {0x00008264, 0x9d400010},
+       {0x00008268, 0xffffffff},
+       {0x0000826c, 0x0000ffff},
+       {0x00008270, 0x00000000},
+       {0x00008274, 0x40000000},
+       {0x00008278, 0x003e4180},
+       {0x0000827c, 0x00000004},
+       {0x00008284, 0x0000002c},
+       {0x00008288, 0x0000002c},
+       {0x0000828c, 0x000000ff},
+       {0x00008294, 0x00000000},
+       {0x00008298, 0x00000000},
+       {0x0000829c, 0x00000000},
+       {0x00008300, 0x00001d40},
+       {0x00008314, 0x00000000},
+       {0x0000831c, 0x0000010d},
+       {0x00008328, 0x00000000},
+       {0x0000832c, 0x0000001f},
+       {0x00008330, 0x00000302},
+       {0x00008334, 0x00000700},
+       {0x00008338, 0xffff0000},
+       {0x0000833c, 0x02400000},
+       {0x00008340, 0x000107ff},
+       {0x00008344, 0xaa48107b},
+       {0x00008348, 0x008f0000},
+       {0x0000835c, 0x00000000},
+       {0x00008360, 0xffffffff},
+       {0x00008364, 0xffffffff},
+       {0x00008368, 0x00000000},
+       {0x00008370, 0x00000000},
+       {0x00008374, 0x000000ff},
+       {0x00008378, 0x00000000},
+       {0x0000837c, 0x00000000},
+       {0x00008380, 0xffffffff},
+       {0x00008384, 0xffffffff},
+       {0x00008390, 0xffffffff},
+       {0x00008394, 0xffffffff},
+       {0x00008398, 0x00000000},
+       {0x0000839c, 0x00000000},
+       {0x000083a0, 0x00000000},
+       {0x000083a4, 0x0000fa14},
+       {0x000083a8, 0x000f0c00},
+       {0x000083ac, 0x33332210},
+       {0x000083b0, 0x33332210},
+       {0x000083b4, 0x33332210},
+       {0x000083b8, 0x33332210},
+       {0x000083bc, 0x00000000},
+       {0x000083c0, 0x00000000},
+       {0x000083c4, 0x00000000},
+       {0x000083c8, 0x00000000},
+       {0x000083cc, 0x00000200},
+       {0x000083d0, 0x8c7901ff},
+};
+
+static const u32 qca953x_1p0_baseband_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00009800, 0xafe68e30},
+       {0x00009804, 0xfd14e000},
+       {0x00009808, 0x9c0a9f6b},
+       {0x0000980c, 0x04900000},
+       {0x00009814, 0x0280c00a},
+       {0x00009818, 0x00000000},
+       {0x0000981c, 0x00020028},
+       {0x00009834, 0x6400a190},
+       {0x00009838, 0x0108ecff},
+       {0x0000983c, 0x14000600},
+       {0x00009880, 0x201fff00},
+       {0x00009884, 0x00001042},
+       {0x000098a4, 0x00200400},
+       {0x000098b0, 0x32840bbe},
+       {0x000098bc, 0x00000002},
+       {0x000098d0, 0x004b6a8e},
+       {0x000098d4, 0x00000820},
+       {0x000098dc, 0x00000000},
+       {0x000098f0, 0x00000000},
+       {0x000098f4, 0x00000000},
+       {0x00009c04, 0xff55ff55},
+       {0x00009c08, 0x0320ff55},
+       {0x00009c0c, 0x00000000},
+       {0x00009c10, 0x00000000},
+       {0x00009c14, 0x00046384},
+       {0x00009c18, 0x05b6b440},
+       {0x00009c1c, 0x00b6b440},
+       {0x00009d00, 0xc080a333},
+       {0x00009d04, 0x40206c10},
+       {0x00009d08, 0x009c4060},
+       {0x00009d0c, 0x9883800a},
+       {0x00009d10, 0x01884061},
+       {0x00009d14, 0x00c0040b},
+       {0x00009d18, 0x00000000},
+       {0x00009e08, 0x0038230c},
+       {0x00009e24, 0x990bb515},
+       {0x00009e28, 0x0c6f0000},
+       {0x00009e30, 0x06336f77},
+       {0x00009e34, 0x6af6532f},
+       {0x00009e38, 0x0cc80c00},
+       {0x00009e40, 0x0d261820},
+       {0x00009e4c, 0x00001004},
+       {0x00009e50, 0x00ff03f1},
+       {0x00009fc0, 0x813e4788},
+       {0x00009fc4, 0x0001efb5},
+       {0x00009fcc, 0x40000014},
+       {0x00009fd0, 0x01193b91},
+       {0x0000a20c, 0x00000000},
+       {0x0000a220, 0x00000000},
+       {0x0000a224, 0x00000000},
+       {0x0000a228, 0x10002310},
+       {0x0000a23c, 0x00000000},
+       {0x0000a244, 0x0c000000},
+       {0x0000a248, 0x00000140},
+       {0x0000a2a0, 0x00000007},
+       {0x0000a2c0, 0x00000007},
+       {0x0000a2c8, 0x00000000},
+       {0x0000a2d4, 0x00000000},
+       {0x0000a2ec, 0x00000000},
+       {0x0000a2f0, 0x00000000},
+       {0x0000a2f4, 0x00000000},
+       {0x0000a2f8, 0x00000000},
+       {0x0000a344, 0x00000000},
+       {0x0000a34c, 0x00000000},
+       {0x0000a350, 0x0000a000},
+       {0x0000a364, 0x00000000},
+       {0x0000a370, 0x00000000},
+       {0x0000a390, 0x00000001},
+       {0x0000a394, 0x00000444},
+       {0x0000a398, 0x1f020503},
+       {0x0000a39c, 0x29180c03},
+       {0x0000a3a0, 0x9a8b6844},
+       {0x0000a3a4, 0x000000ff},
+       {0x0000a3a8, 0x6a6a6a6a},
+       {0x0000a3ac, 0x6a6a6a6a},
+       {0x0000a3b0, 0x00c8641a},
+       {0x0000a3b4, 0x0000001a},
+       {0x0000a3b8, 0x0088642a},
+       {0x0000a3bc, 0x000001fa},
+       {0x0000a3c0, 0x20202020},
+       {0x0000a3c4, 0x22222220},
+       {0x0000a3c8, 0x20200020},
+       {0x0000a3cc, 0x20202020},
+       {0x0000a3d0, 0x20202020},
+       {0x0000a3d4, 0x20202020},
+       {0x0000a3d8, 0x20202020},
+       {0x0000a3dc, 0x20202020},
+       {0x0000a3e0, 0x20202020},
+       {0x0000a3e4, 0x20202020},
+       {0x0000a3e8, 0x20202020},
+       {0x0000a3ec, 0x20202020},
+       {0x0000a3f0, 0x00000000},
+       {0x0000a3f4, 0x00000000},
+       {0x0000a3f8, 0x0c9bd380},
+       {0x0000a3fc, 0x000f0f01},
+       {0x0000a400, 0x8fa91f01},
+       {0x0000a404, 0x00000000},
+       {0x0000a408, 0x0e79e5c6},
+       {0x0000a40c, 0x00820820},
+       {0x0000a414, 0x1ce42108},
+       {0x0000a418, 0x2d001dce},
+       {0x0000a41c, 0x1ce73908},
+       {0x0000a420, 0x000001ce},
+       {0x0000a424, 0x1ce738e7},
+       {0x0000a428, 0x000001ce},
+       {0x0000a42c, 0x1ce739ce},
+       {0x0000a430, 0x1ce739ce},
+       {0x0000a434, 0x00000000},
+       {0x0000a438, 0x00001801},
+       {0x0000a43c, 0x00100000},
+       {0x0000a444, 0x00000000},
+       {0x0000a448, 0x05000080},
+       {0x0000a44c, 0x00000001},
+       {0x0000a450, 0x00010000},
+       {0x0000a458, 0x00000000},
+       {0x0000a644, 0xbfad9d74},
+       {0x0000a648, 0x0048060a},
+       {0x0000a64c, 0x00003c37},
+       {0x0000a670, 0x03020100},
+       {0x0000a674, 0x09080504},
+       {0x0000a678, 0x0d0c0b0a},
+       {0x0000a67c, 0x13121110},
+       {0x0000a680, 0x31301514},
+       {0x0000a684, 0x35343332},
+       {0x0000a688, 0x00000036},
+       {0x0000a690, 0x08000838},
+       {0x0000a7cc, 0x00000000},
+       {0x0000a7d0, 0x00000000},
+       {0x0000a7d4, 0x00000004},
+       {0x0000a7dc, 0x00000000},
+       {0x0000a8d0, 0x004b6a8e},
+       {0x0000a8d4, 0x00000820},
+       {0x0000a8dc, 0x00000000},
+       {0x0000a8f0, 0x00000000},
+       {0x0000a8f4, 0x00000000},
+       {0x0000b2d0, 0x00000080},
+       {0x0000b2d4, 0x00000000},
+       {0x0000b2ec, 0x00000000},
+       {0x0000b2f0, 0x00000000},
+       {0x0000b2f4, 0x00000000},
+       {0x0000b2f8, 0x00000000},
+       {0x0000b408, 0x0e79e5c0},
+       {0x0000b40c, 0x00820820},
+       {0x0000b420, 0x00000000},
+};
+
+static const u32 qca953x_1p0_baseband_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+       {0x00009820, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e},
+       {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0},
+       {0x00009828, 0x06903081, 0x06903081, 0x06903881, 0x06903881},
+       {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+       {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+       {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+       {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+       {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+       {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
+       {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e},
+       {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x3379605e, 0x33795d5e},
+       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+       {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
+       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+       {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+       {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+       {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x005c0ec4, 0x005c0ec0},
+       {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+       {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+       {0x0000a230, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b},
+       {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+       {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+       {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+       {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+       {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+       {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
+       {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+       {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
+       {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+       {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+       {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+       {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
+       {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
+       {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
+       {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+       {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+       {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001ce, 0x000001ce},
+       {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+};
+
+static const u32 qca953x_1p0_radio_core[][2] = {
+       /* Addr      allmodes  */
+       {0x00016000, 0x36db6db6},
+       {0x00016004, 0x6db6db40},
+       {0x00016008, 0x73f00000},
+       {0x0001600c, 0x00000000},
+       {0x00016040, 0x3f80fff8},
+       {0x0001604c, 0x000f0278},
+       {0x00016050, 0x8036db6c},
+       {0x00016054, 0x6db60000},
+       {0x00016080, 0x00080000},
+       {0x00016084, 0x0e48048c},
+       {0x00016088, 0x14214514},
+       {0x0001608c, 0x119f080a},
+       {0x00016090, 0x24926490},
+       {0x00016094, 0x00000000},
+       {0x000160a0, 0xc2108ffe},
+       {0x000160a4, 0x812fc370},
+       {0x000160a8, 0x423c8000},
+       {0x000160b4, 0x92480080},
+       {0x000160c0, 0x006db6d8},
+       {0x000160c4, 0x24b6db6c},
+       {0x000160c8, 0x6db6db6c},
+       {0x000160cc, 0x6db6fb7c},
+       {0x000160d0, 0x6db6da44},
+       {0x00016100, 0x07ff8001},
+       {0x00016108, 0x00080010},
+       {0x00016144, 0x01884080},
+       {0x00016148, 0x000080d8},
+       {0x00016280, 0x01000901},
+       {0x00016284, 0x15d30000},
+       {0x00016288, 0x00318000},
+       {0x0001628c, 0x50000000},
+       {0x00016380, 0x00000000},
+       {0x00016384, 0x00000000},
+       {0x00016388, 0x00800700},
+       {0x0001638c, 0x00800700},
+       {0x00016390, 0x00800700},
+       {0x00016394, 0x00000000},
+       {0x00016398, 0x00000000},
+       {0x0001639c, 0x00000000},
+       {0x000163a0, 0x00000001},
+       {0x000163a4, 0x00000001},
+       {0x000163a8, 0x00000000},
+       {0x000163ac, 0x00000000},
+       {0x000163b0, 0x00000000},
+       {0x000163b4, 0x00000000},
+       {0x000163b8, 0x00000000},
+       {0x000163bc, 0x00000000},
+       {0x000163c0, 0x000000a0},
+       {0x000163c4, 0x000c0000},
+       {0x000163c8, 0x14021402},
+       {0x000163cc, 0x00001402},
+       {0x000163d0, 0x00000000},
+       {0x000163d4, 0x00000000},
+       {0x00016400, 0x36db6db6},
+       {0x00016404, 0x6db6db40},
+       {0x00016408, 0x73f00000},
+       {0x0001640c, 0x00000000},
+       {0x00016440, 0x3f80fff8},
+       {0x0001644c, 0x000f0278},
+       {0x00016450, 0x8036db6c},
+       {0x00016454, 0x6db60000},
+       {0x00016500, 0x07ff8001},
+       {0x00016508, 0x00080010},
+       {0x00016544, 0x01884080},
+       {0x00016548, 0x000080d8},
+       {0x00016780, 0x00000000},
+       {0x00016784, 0x00000000},
+       {0x00016788, 0x00800700},
+       {0x0001678c, 0x00800700},
+       {0x00016790, 0x00800700},
+       {0x00016794, 0x00000000},
+       {0x00016798, 0x00000000},
+       {0x0001679c, 0x00000000},
+       {0x000167a0, 0x00000001},
+       {0x000167a4, 0x00000001},
+       {0x000167a8, 0x00000000},
+       {0x000167ac, 0x00000000},
+       {0x000167b0, 0x00000000},
+       {0x000167b4, 0x00000000},
+       {0x000167b8, 0x00000000},
+       {0x000167bc, 0x00000000},
+       {0x000167c0, 0x000000a0},
+       {0x000167c4, 0x000c0000},
+       {0x000167c8, 0x14021402},
+       {0x000167cc, 0x00001402},
+       {0x000167d0, 0x00000000},
+       {0x000167d4, 0x00000000},
+};
+
+static const u32 qca953x_1p0_radio_postamble[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c},
+       {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25},
+       {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800},
+       {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46},
+       {0x00016104, 0xb7a00001, 0xb7a00001, 0xfff80005, 0xfff80005},
+       {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+       {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+       {0x00016504, 0xb7a00001, 0xb7a00001, 0xfff80001, 0xfff80001},
+       {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+       {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+};
+
+static const u32 qca953x_1p0_soc_preamble[][2] = {
+       /* Addr      allmodes  */
+       {0x00007000, 0x00000000},
+       {0x00007004, 0x00000000},
+       {0x00007008, 0x00000000},
+       {0x0000700c, 0x00000000},
+       {0x0000701c, 0x00000000},
+       {0x00007020, 0x00000000},
+       {0x00007024, 0x00000000},
+       {0x00007028, 0x00000000},
+       {0x0000702c, 0x00000000},
+       {0x00007030, 0x00000000},
+       {0x00007034, 0x00000002},
+       {0x00007038, 0x000004c2},
+       {0x00007048, 0x00000000},
+};
+
+static const u32 qca953x_1p0_common_rx_gain_bounds[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302018, 0x50302018},
+};
+
+static const u32 qca953x_1p0_common_wo_xlna_rx_gain_bounds[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+       {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+};
+
+static const u32 qca953x_1p0_modes_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xfffd5aaa},
+       {0x0000a2e0, 0xfffe9ccc},
+       {0x0000a2e4, 0xffffe0f0},
+       {0x0000a2e8, 0xfffcff00},
+       {0x0000a410, 0x000050da},
+       {0x0000a500, 0x00000000},
+       {0x0000a504, 0x04000002},
+       {0x0000a508, 0x08000004},
+       {0x0000a50c, 0x0c000006},
+       {0x0000a510, 0x0f00000a},
+       {0x0000a514, 0x1300000c},
+       {0x0000a518, 0x1700000e},
+       {0x0000a51c, 0x1b000064},
+       {0x0000a520, 0x1f000242},
+       {0x0000a524, 0x23000229},
+       {0x0000a528, 0x270002a2},
+       {0x0000a52c, 0x2c001203},
+       {0x0000a530, 0x30001803},
+       {0x0000a534, 0x33000881},
+       {0x0000a538, 0x38001809},
+       {0x0000a53c, 0x3a000814},
+       {0x0000a540, 0x3f001a0c},
+       {0x0000a544, 0x43001a0e},
+       {0x0000a548, 0x46001812},
+       {0x0000a54c, 0x49001884},
+       {0x0000a550, 0x4d001e84},
+       {0x0000a554, 0x50001e69},
+       {0x0000a558, 0x550006f4},
+       {0x0000a55c, 0x59000ad3},
+       {0x0000a560, 0x5e000ad5},
+       {0x0000a564, 0x61001ced},
+       {0x0000a568, 0x660018d4},
+       {0x0000a56c, 0x660018d4},
+       {0x0000a570, 0x660018d4},
+       {0x0000a574, 0x660018d4},
+       {0x0000a578, 0x660018d4},
+       {0x0000a57c, 0x660018d4},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x03804000},
+       {0x0000a610, 0x0300ca02},
+       {0x0000a614, 0x00000e04},
+       {0x0000a618, 0x03014000},
+       {0x0000a61c, 0x00000000},
+       {0x0000a620, 0x00000000},
+       {0x0000a624, 0x03014000},
+       {0x0000a628, 0x03804c05},
+       {0x0000a62c, 0x0701de06},
+       {0x0000a630, 0x07819c07},
+       {0x0000a634, 0x0701dc07},
+       {0x0000a638, 0x0701dc07},
+       {0x0000a63c, 0x0701dc07},
+       {0x0000b2dc, 0xfffd5aaa},
+       {0x0000b2e0, 0xfffe9ccc},
+       {0x0000b2e4, 0xffffe0f0},
+       {0x0000b2e8, 0xfffcff00},
+       {0x00016044, 0x010002d4},
+       {0x00016048, 0x66482400},
+       {0x00016280, 0x01000015},
+       {0x00016444, 0x010002d4},
+       {0x00016448, 0x66482400},
+};
+
+static const u32 qca953x_1p0_modes_no_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xffd5f552},
+       {0x0000a2e0, 0xffe60664},
+       {0x0000a2e4, 0xfff80780},
+       {0x0000a2e8, 0xfffff800},
+       {0x0000a410, 0x000050d6},
+       {0x0000a500, 0x00060020},
+       {0x0000a504, 0x04060060},
+       {0x0000a508, 0x080600a0},
+       {0x0000a50c, 0x0c068020},
+       {0x0000a510, 0x10068060},
+       {0x0000a514, 0x140680a0},
+       {0x0000a518, 0x18090040},
+       {0x0000a51c, 0x1b090080},
+       {0x0000a520, 0x1f0900c0},
+       {0x0000a524, 0x240c0041},
+       {0x0000a528, 0x280d0021},
+       {0x0000a52c, 0x2d0f0061},
+       {0x0000a530, 0x310f00a1},
+       {0x0000a534, 0x350e00a2},
+       {0x0000a538, 0x360e80a2},
+       {0x0000a53c, 0x380f00a2},
+       {0x0000a540, 0x3b0e00a3},
+       {0x0000a544, 0x3d110083},
+       {0x0000a548, 0x3e1100a3},
+       {0x0000a54c, 0x401100e3},
+       {0x0000a550, 0x421380e3},
+       {0x0000a554, 0x431780e3},
+       {0x0000a558, 0x461f80e3},
+       {0x0000a55c, 0x461f80e3},
+       {0x0000a560, 0x461f80e3},
+       {0x0000a564, 0x461f80e3},
+       {0x0000a568, 0x461f80e3},
+       {0x0000a56c, 0x461f80e3},
+       {0x0000a570, 0x461f80e3},
+       {0x0000a574, 0x461f80e3},
+       {0x0000a578, 0x461f80e3},
+       {0x0000a57c, 0x461f80e3},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00804201},
+       {0x0000a610, 0x01008201},
+       {0x0000a614, 0x0180c402},
+       {0x0000a618, 0x0180c603},
+       {0x0000a61c, 0x0180c603},
+       {0x0000a620, 0x01c10603},
+       {0x0000a624, 0x01c10704},
+       {0x0000a628, 0x02c18b05},
+       {0x0000a62c, 0x0301cc07},
+       {0x0000a630, 0x0301cc07},
+       {0x0000a634, 0x0301cc07},
+       {0x0000a638, 0x0301cc07},
+       {0x0000a63c, 0x0301cc07},
+       {0x0000b2dc, 0xffd5f552},
+       {0x0000b2e0, 0xffe60664},
+       {0x0000b2e4, 0xfff80780},
+       {0x0000b2e8, 0xfffff800},
+       {0x00016044, 0x049242db},
+       {0x00016048, 0x6c927a70},
+       {0x00016444, 0x049242db},
+       {0x00016448, 0x6c927a70},
+};
+
+static const u32 qca953x_1p1_modes_no_xpa_tx_gain_table[][2] = {
+       /* Addr      allmodes  */
+       {0x0000a2dc, 0xffd5f552},
+       {0x0000a2e0, 0xffe60664},
+       {0x0000a2e4, 0xfff80780},
+       {0x0000a2e8, 0xfffff800},
+       {0x0000a410, 0x000050de},
+       {0x0000a500, 0x00000061},
+       {0x0000a504, 0x04000063},
+       {0x0000a508, 0x08000065},
+       {0x0000a50c, 0x0c000261},
+       {0x0000a510, 0x10000263},
+       {0x0000a514, 0x14000265},
+       {0x0000a518, 0x18000482},
+       {0x0000a51c, 0x1b000484},
+       {0x0000a520, 0x1f000486},
+       {0x0000a524, 0x240008c2},
+       {0x0000a528, 0x28000cc1},
+       {0x0000a52c, 0x2d000ce3},
+       {0x0000a530, 0x31000ce5},
+       {0x0000a534, 0x350010e5},
+       {0x0000a538, 0x360012e5},
+       {0x0000a53c, 0x380014e5},
+       {0x0000a540, 0x3b0018e5},
+       {0x0000a544, 0x3d001d04},
+       {0x0000a548, 0x3e001d05},
+       {0x0000a54c, 0x40001d07},
+       {0x0000a550, 0x42001f27},
+       {0x0000a554, 0x43001f67},
+       {0x0000a558, 0x46001fe7},
+       {0x0000a55c, 0x47001f2b},
+       {0x0000a560, 0x49001f0d},
+       {0x0000a564, 0x4b001ed2},
+       {0x0000a568, 0x4c001ed4},
+       {0x0000a56c, 0x4e001f15},
+       {0x0000a570, 0x4f001ff6},
+       {0x0000a574, 0x4f001ff6},
+       {0x0000a578, 0x4f001ff6},
+       {0x0000a57c, 0x4f001ff6},
+       {0x0000a600, 0x00000000},
+       {0x0000a604, 0x00000000},
+       {0x0000a608, 0x00000000},
+       {0x0000a60c, 0x00804201},
+       {0x0000a610, 0x01008201},
+       {0x0000a614, 0x0180c402},
+       {0x0000a618, 0x0180c603},
+       {0x0000a61c, 0x0180c603},
+       {0x0000a620, 0x01c10603},
+       {0x0000a624, 0x01c10704},
+       {0x0000a628, 0x02c18b05},
+       {0x0000a62c, 0x02c14c07},
+       {0x0000a630, 0x01008704},
+       {0x0000a634, 0x01c10402},
+       {0x0000a638, 0x0301cc07},
+       {0x0000a63c, 0x0301cc07},
+       {0x0000b2dc, 0xffd5f552},
+       {0x0000b2e0, 0xffe60664},
+       {0x0000b2e4, 0xfff80780},
+       {0x0000b2e8, 0xfffff800},
+       {0x00016044, 0x049242db},
+       {0x00016048, 0x6c927a70},
+       {0x00016444, 0x049242db},
+       {0x00016448, 0x6c927a70},
+};
+
+#endif /* INITVALS_953X_H */
index f2202e78fa7b3de875f1c06fca9438dc01a59f5e..f622a986c8cc8f0df8a98b12ea4f05580faa27ec 100644 (file)
@@ -455,10 +455,8 @@ bool ath9k_csa_is_finished(struct ath_softc *sc);
 
 void ath_tx_complete_poll_work(struct work_struct *work);
 void ath_reset_work(struct work_struct *work);
-void ath_hw_check(struct work_struct *work);
+bool ath_hw_check(struct ath_softc *sc);
 void ath_hw_pll_work(struct work_struct *work);
-void ath_rx_poll(unsigned long data);
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
 void ath_start_ani(struct ath_softc *sc);
@@ -722,12 +720,10 @@ struct ath_softc {
        spinlock_t sc_pcu_lock;
        struct mutex mutex;
        struct work_struct paprd_work;
-       struct work_struct hw_check_work;
        struct work_struct hw_reset_work;
        struct completion paprd_complete;
        wait_queue_head_t tx_wait;
 
-       unsigned int hw_busy_count;
        unsigned long sc_flags;
        unsigned long driver_data;
 
@@ -761,7 +757,6 @@ struct ath_softc {
        struct ath_beacon_config cur_beacon_conf;
        struct delayed_work tx_complete_work;
        struct delayed_work hw_pll_work;
-       struct timer_list rx_poll_timer;
        struct timer_list sleep_timer;
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
index 112aff720e1377791ab939616b6c0b2ed9598e3e..2e8bba0eb361b5846af5666a87854e002f24b20f 100644 (file)
@@ -337,8 +337,14 @@ void ath9k_beacon_tasklet(unsigned long data)
 
                ath9k_hw_check_nav(ah);
 
-               if (!ath9k_hw_check_alive(ah))
-                       ieee80211_queue_work(sc->hw, &sc->hw_check_work);
+               /*
+                * If the previous beacon has not been transmitted
+                * and a MAC/BB hang has been identified, return
+                * here because a chip reset would have been
+                * initiated.
+                */
+               if (!ath_hw_check(sc))
+                       return;
 
                if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) {
                        ath_dbg(common, BSTUCK,
index 9a2657fdd9ccd4ec62f96f8a639182e2ded29fec..608d739d13782233db4271f9248c3472601b1a5f 100644 (file)
@@ -127,21 +127,26 @@ static void ath9k_htc_bssid_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        struct ath9k_vif_iter_data *iter_data = data;
        int i;
 
-       for (i = 0; i < ETH_ALEN; i++)
-               iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
+       if (iter_data->hw_macaddr != NULL) {
+               for (i = 0; i < ETH_ALEN; i++)
+                       iter_data->mask[i] &= ~(iter_data->hw_macaddr[i] ^ mac[i]);
+       } else {
+               iter_data->hw_macaddr = mac;
+       }
 }
 
-static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
+static void ath9k_htc_set_mac_bssid_mask(struct ath9k_htc_priv *priv,
                                     struct ieee80211_vif *vif)
 {
        struct ath_common *common = ath9k_hw_common(priv->ah);
        struct ath9k_vif_iter_data iter_data;
 
        /*
-        * Use the hardware MAC address as reference, the hardware uses it
-        * together with the BSSID mask when matching addresses.
+        * Pick the MAC address of the first interface as the new hardware
+        * MAC address. The hardware will use it together with the BSSID mask
+        * when matching addresses.
         */
-       iter_data.hw_macaddr = common->macaddr;
+       iter_data.hw_macaddr = NULL;
        memset(&iter_data.mask, 0xff, ETH_ALEN);
 
        if (vif)
@@ -153,6 +158,10 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
                ath9k_htc_bssid_iter, &iter_data);
 
        memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
+
+       if (iter_data.hw_macaddr)
+               memcpy(common->macaddr, iter_data.hw_macaddr, ETH_ALEN);
+
        ath_hw_setbssidmask(common);
 }
 
@@ -1063,7 +1072,7 @@ static int ath9k_htc_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       ath9k_htc_set_bssid_mask(priv, vif);
+       ath9k_htc_set_mac_bssid_mask(priv, vif);
 
        priv->vif_slot |= (1 << avp->index);
        priv->nvifs++;
@@ -1128,7 +1137,7 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
 
        ath9k_htc_set_opmode(priv);
 
-       ath9k_htc_set_bssid_mask(priv, vif);
+       ath9k_htc_set_mac_bssid_mask(priv, vif);
 
        /*
         * Stop ANI only if there are no associated station interfaces.
index c028df76b564971ffa9a878325dd63e826757ab1..b41e008298dce90da1cfb131072d75242faebf06 100644 (file)
@@ -1077,7 +1077,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
 
        if (ieee80211_is_beacon(hdr->frame_control) &&
            !is_zero_ether_addr(common->curbssid) &&
-           ether_addr_equal(hdr->addr3, common->curbssid)) {
+           ether_addr_equal_64bits(hdr->addr3, common->curbssid)) {
                s8 rssi = rxbuf->rxstatus.rs_rssi;
 
                if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER))
index cc58a8ee1223af3cab28878da2b40373794f4449..a47ea8423f1eb2a6a8d43f4d451475f55bac6674 100644 (file)
@@ -107,6 +107,21 @@ static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable)
 
 /* Private hardware call ops */
 
+static inline void ath9k_hw_init_hang_checks(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_hang_checks(ah);
+}
+
+static inline bool ath9k_hw_detect_mac_hang(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->detect_mac_hang(ah);
+}
+
+static inline bool ath9k_hw_detect_bb_hang(struct ath_hw *ah)
+{
+       return ath9k_hw_private_ops(ah)->detect_bb_hang(ah);
+}
+
 /* PHY ops */
 
 static inline int ath9k_hw_rf_set_freq(struct ath_hw *ah,
@@ -232,4 +247,31 @@ static inline void ath9k_hw_set_radar_params(struct ath_hw *ah)
        ath9k_hw_private_ops(ah)->set_radar_params(ah, &ah->radar_conf);
 }
 
+static inline void ath9k_hw_init_cal_settings(struct ath_hw *ah)
+{
+       ath9k_hw_private_ops(ah)->init_cal_settings(ah);
+}
+
+static inline u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
+                                              struct ath9k_channel *chan)
+{
+       return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
+}
+
+static inline void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
+               return;
+
+       ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
+}
+
+static inline void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
+{
+       if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
+               return;
+
+       ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
+}
+
 #endif /* ATH9K_HW_OPS_H */
index a4b1ae0262167144d7ecea0d7d6db95da356a4b1..ce41658a600344db2c027bcdfb9de41ccee50965 100644 (file)
@@ -37,57 +37,6 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
 MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
-static int __init ath9k_init(void)
-{
-       return 0;
-}
-module_init(ath9k_init);
-
-static void __exit ath9k_exit(void)
-{
-       return;
-}
-module_exit(ath9k_exit);
-
-/* Private hardware callbacks */
-
-static void ath9k_hw_init_cal_settings(struct ath_hw *ah)
-{
-       ath9k_hw_private_ops(ah)->init_cal_settings(ah);
-}
-
-static u32 ath9k_hw_compute_pll_control(struct ath_hw *ah,
-                                       struct ath9k_channel *chan)
-{
-       return ath9k_hw_private_ops(ah)->compute_pll_control(ah, chan);
-}
-
-static void ath9k_hw_init_mode_gain_regs(struct ath_hw *ah)
-{
-       if (!ath9k_hw_private_ops(ah)->init_mode_gain_regs)
-               return;
-
-       ath9k_hw_private_ops(ah)->init_mode_gain_regs(ah);
-}
-
-static void ath9k_hw_ani_cache_ini_regs(struct ath_hw *ah)
-{
-       /* You will not have this callback if using the old ANI */
-       if (!ath9k_hw_private_ops(ah)->ani_cache_ini_regs)
-               return;
-
-       ath9k_hw_private_ops(ah)->ani_cache_ini_regs(ah);
-}
-
-/********************/
-/* Helper Functions */
-/********************/
-
-#ifdef CONFIG_ATH9K_DEBUGFS
-
-#endif
-
-
 static void ath9k_hw_set_clockrate(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -296,6 +245,9 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
        case AR9300_DEVID_QCA955X:
                ah->hw_version.macVersion = AR_SREV_VERSION_9550;
                return;
+       case AR9300_DEVID_AR953X:
+               ah->hw_version.macVersion = AR_SREV_VERSION_9531;
+               return;
        }
 
        val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
@@ -397,9 +349,10 @@ static bool ath9k_hw_chip_test(struct ath_hw *ah)
 
 static void ath9k_hw_init_config(struct ath_hw *ah)
 {
+       struct ath_common *common = ath9k_hw_common(ah);
+
        ah->config.dma_beacon_response_time = 1;
        ah->config.sw_beacon_response_time = 6;
-       ah->config.ack_6mb = 0x0;
        ah->config.cwm_ignore_extcca = 0;
        ah->config.analog_shiftreg = 1;
 
@@ -423,6 +376,24 @@ static void ath9k_hw_init_config(struct ath_hw *ah)
         */
        if (num_possible_cpus() > 1)
                ah->config.serialize_regmode = SER_REG_MODE_AUTO;
+
+       if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
+               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
+                    !ah->is_pciexpress)) {
+                       ah->config.serialize_regmode = SER_REG_MODE_ON;
+               } else {
+                       ah->config.serialize_regmode = SER_REG_MODE_OFF;
+               }
+       }
+
+       ath_dbg(common, RESET, "serialize_regmode is %d\n",
+               ah->config.serialize_regmode);
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
+       else
+               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
 }
 
 static void ath9k_hw_init_defaults(struct ath_hw *ah)
@@ -435,15 +406,24 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
        ah->hw_version.magic = AR5416_MAGIC;
        ah->hw_version.subvendorid = 0;
 
-       ah->sta_id1_defaults =
-               AR_STA_ID1_CRPT_MIC_ENABLE |
-               AR_STA_ID1_MCAST_KSRCH;
+       ah->sta_id1_defaults = AR_STA_ID1_CRPT_MIC_ENABLE |
+                              AR_STA_ID1_MCAST_KSRCH;
        if (AR_SREV_9100(ah))
                ah->sta_id1_defaults |= AR_STA_ID1_AR9100_BA_FIX;
+
        ah->slottime = ATH9K_SLOT_TIME_9;
        ah->globaltxtimeout = (u32) -1;
        ah->power_mode = ATH9K_PM_UNDEFINED;
        ah->htc_reset_init = true;
+
+       ah->ani_function = ATH9K_ANI_ALL;
+       if (!AR_SREV_9300_20_OR_LATER(ah))
+               ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
+
+       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
+               ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
+       else
+               ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
 }
 
 static int ath9k_hw_init_macaddr(struct ath_hw *ah)
@@ -525,6 +505,31 @@ static int __ath9k_hw_init(struct ath_hw *ah)
 
        ath9k_hw_read_revisions(ah);
 
+       switch (ah->hw_version.macVersion) {
+       case AR_SREV_VERSION_5416_PCI:
+       case AR_SREV_VERSION_5416_PCIE:
+       case AR_SREV_VERSION_9160:
+       case AR_SREV_VERSION_9100:
+       case AR_SREV_VERSION_9280:
+       case AR_SREV_VERSION_9285:
+       case AR_SREV_VERSION_9287:
+       case AR_SREV_VERSION_9271:
+       case AR_SREV_VERSION_9300:
+       case AR_SREV_VERSION_9330:
+       case AR_SREV_VERSION_9485:
+       case AR_SREV_VERSION_9340:
+       case AR_SREV_VERSION_9462:
+       case AR_SREV_VERSION_9550:
+       case AR_SREV_VERSION_9565:
+       case AR_SREV_VERSION_9531:
+               break;
+       default:
+               ath_err(common,
+                       "Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
+                       ah->hw_version.macVersion, ah->hw_version.macRev);
+               return -EOPNOTSUPP;
+       }
+
        /*
         * Read back AR_WA into a permanent copy and set bits 14 and 17.
         * We need to do this to avoid RMW of this register. We cannot
@@ -558,50 +563,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
                return -EIO;
        }
 
-       if (NR_CPUS > 1 && ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
-                   ((AR_SREV_9160(ah) || AR_SREV_9280(ah) || AR_SREV_9287(ah)) &&
-                    !ah->is_pciexpress)) {
-                       ah->config.serialize_regmode =
-                               SER_REG_MODE_ON;
-               } else {
-                       ah->config.serialize_regmode =
-                               SER_REG_MODE_OFF;
-               }
-       }
-
-       ath_dbg(common, RESET, "serialize_regmode is %d\n",
-               ah->config.serialize_regmode);
-
-       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD >> 1;
-       else
-               ah->config.max_txtrig_level = MAX_TX_FIFO_THRESHOLD;
-
-       switch (ah->hw_version.macVersion) {
-       case AR_SREV_VERSION_5416_PCI:
-       case AR_SREV_VERSION_5416_PCIE:
-       case AR_SREV_VERSION_9160:
-       case AR_SREV_VERSION_9100:
-       case AR_SREV_VERSION_9280:
-       case AR_SREV_VERSION_9285:
-       case AR_SREV_VERSION_9287:
-       case AR_SREV_VERSION_9271:
-       case AR_SREV_VERSION_9300:
-       case AR_SREV_VERSION_9330:
-       case AR_SREV_VERSION_9485:
-       case AR_SREV_VERSION_9340:
-       case AR_SREV_VERSION_9462:
-       case AR_SREV_VERSION_9550:
-       case AR_SREV_VERSION_9565:
-               break;
-       default:
-               ath_err(common,
-                       "Mac Chip Rev 0x%02x.%x is not supported by this driver\n",
-                       ah->hw_version.macVersion, ah->hw_version.macRev);
-               return -EOPNOTSUPP;
-       }
-
        if (AR_SREV_9271(ah) || AR_SREV_9100(ah) || AR_SREV_9340(ah) ||
            AR_SREV_9330(ah) || AR_SREV_9550(ah))
                ah->is_pciexpress = false;
@@ -609,10 +570,6 @@ static int __ath9k_hw_init(struct ath_hw *ah)
        ah->hw_version.phyRev = REG_READ(ah, AR_PHY_CHIP_ID);
        ath9k_hw_init_cal_settings(ah);
 
-       ah->ani_function = ATH9K_ANI_ALL;
-       if (!AR_SREV_9300_20_OR_LATER(ah))
-               ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
-
        if (!ah->is_pciexpress)
                ath9k_hw_disablepcie(ah);
 
@@ -631,15 +588,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
                return r;
        }
 
-       if (AR_SREV_9285(ah) || AR_SREV_9271(ah))
-               ah->tx_trig_level = (AR_FTRIG_256B >> AR_FTRIG_S);
-       else
-               ah->tx_trig_level = (AR_FTRIG_512B >> AR_FTRIG_S);
-
-       if (AR_SREV_9330(ah))
-               ah->bb_watchdog_timeout_ms = 85;
-       else
-               ah->bb_watchdog_timeout_ms = 25;
+       ath9k_hw_init_hang_checks(ah);
 
        common->state = ATH_HW_INITIALIZED;
 
@@ -672,6 +621,7 @@ int ath9k_hw_init(struct ath_hw *ah)
        case AR9300_DEVID_AR9462:
        case AR9485_DEVID_AR1111:
        case AR9300_DEVID_AR9565:
+       case AR9300_DEVID_AR953X:
                break;
        default:
                if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -807,7 +757,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                /* program BB PLL phase_shift */
                REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
                              AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1);
-       } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah)) {
+       } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
                u32 regval, pll2_divint, pll2_divfrac, refdiv;
 
                REG_WRITE(ah, AR_RTC_PLL_CONTROL, 0x1142c);
@@ -817,9 +767,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                udelay(100);
 
                if (ah->is_clk_25mhz) {
-                       pll2_divint = 0x54;
-                       pll2_divfrac = 0x1eb85;
-                       refdiv = 3;
+                       if (AR_SREV_9531(ah)) {
+                               pll2_divint = 0x1c;
+                               pll2_divfrac = 0xa3d2;
+                               refdiv = 1;
+                       } else {
+                               pll2_divint = 0x54;
+                               pll2_divfrac = 0x1eb85;
+                               refdiv = 3;
+                       }
                } else {
                        if (AR_SREV_9340(ah)) {
                                pll2_divint = 88;
@@ -833,7 +789,10 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
                }
 
                regval = REG_READ(ah, AR_PHY_PLL_MODE);
-               regval |= (0x1 << 16);
+               if (AR_SREV_9531(ah))
+                       regval |= (0x1 << 22);
+               else
+                       regval |= (0x1 << 16);
                REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
                udelay(100);
 
@@ -843,14 +802,33 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
 
                regval = REG_READ(ah, AR_PHY_PLL_MODE);
                if (AR_SREV_9340(ah))
-                       regval = (regval & 0x80071fff) | (0x1 << 30) |
-                                (0x1 << 13) | (0x4 << 26) | (0x18 << 19);
+                       regval = (regval & 0x80071fff) |
+                               (0x1 << 30) |
+                               (0x1 << 13) |
+                               (0x4 << 26) |
+                               (0x18 << 19);
+               else if (AR_SREV_9531(ah))
+                       regval = (regval & 0x01c00fff) |
+                               (0x1 << 31) |
+                               (0x2 << 29) |
+                               (0xa << 25) |
+                               (0x1 << 19) |
+                               (0x6 << 12);
                else
-                       regval = (regval & 0x80071fff) | (0x3 << 30) |
-                                (0x1 << 13) | (0x4 << 26) | (0x60 << 19);
+                       regval = (regval & 0x80071fff) |
+                               (0x3 << 30) |
+                               (0x1 << 13) |
+                               (0x4 << 26) |
+                               (0x60 << 19);
                REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
-               REG_WRITE(ah, AR_PHY_PLL_MODE,
-                         REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+
+               if (AR_SREV_9531(ah))
+                       REG_WRITE(ah, AR_PHY_PLL_MODE,
+                                 REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff);
+               else
+                       REG_WRITE(ah, AR_PHY_PLL_MODE,
+                                 REG_READ(ah, AR_PHY_PLL_MODE) & 0xfffeffff);
+
                udelay(1000);
        }
 
@@ -1532,76 +1510,6 @@ static void ath9k_hw_apply_gpio_override(struct ath_hw *ah)
        }
 }
 
-static bool ath9k_hw_check_dcs(u32 dma_dbg, u32 num_dcu_states,
-                              int *hang_state, int *hang_pos)
-{
-       static u32 dcu_chain_state[] = {5, 6, 9}; /* DCU chain stuck states */
-       u32 chain_state, dcs_pos, i;
-
-       for (dcs_pos = 0; dcs_pos < num_dcu_states; dcs_pos++) {
-               chain_state = (dma_dbg >> (5 * dcs_pos)) & 0x1f;
-               for (i = 0; i < 3; i++) {
-                       if (chain_state == dcu_chain_state[i]) {
-                               *hang_state = chain_state;
-                               *hang_pos = dcs_pos;
-                               return true;
-                       }
-               }
-       }
-       return false;
-}
-
-#define DCU_COMPLETE_STATE        1
-#define DCU_COMPLETE_STATE_MASK 0x3
-#define NUM_STATUS_READS         50
-static bool ath9k_hw_detect_mac_hang(struct ath_hw *ah)
-{
-       u32 chain_state, comp_state, dcs_reg = AR_DMADBG_4;
-       u32 i, hang_pos, hang_state, num_state = 6;
-
-       comp_state = REG_READ(ah, AR_DMADBG_6);
-
-       if ((comp_state & DCU_COMPLETE_STATE_MASK) != DCU_COMPLETE_STATE) {
-               ath_dbg(ath9k_hw_common(ah), RESET,
-                       "MAC Hang signature not found at DCU complete\n");
-               return false;
-       }
-
-       chain_state = REG_READ(ah, dcs_reg);
-       if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
-               goto hang_check_iter;
-
-       dcs_reg = AR_DMADBG_5;
-       num_state = 4;
-       chain_state = REG_READ(ah, dcs_reg);
-       if (ath9k_hw_check_dcs(chain_state, num_state, &hang_state, &hang_pos))
-               goto hang_check_iter;
-
-       ath_dbg(ath9k_hw_common(ah), RESET,
-               "MAC Hang signature 1 not found\n");
-       return false;
-
-hang_check_iter:
-       ath_dbg(ath9k_hw_common(ah), RESET,
-               "DCU registers: chain %08x complete %08x Hang: state %d pos %d\n",
-               chain_state, comp_state, hang_state, hang_pos);
-
-       for (i = 0; i < NUM_STATUS_READS; i++) {
-               chain_state = REG_READ(ah, dcs_reg);
-               chain_state = (chain_state >> (5 * hang_pos)) & 0x1f;
-               comp_state = REG_READ(ah, AR_DMADBG_6);
-
-               if (((comp_state & DCU_COMPLETE_STATE_MASK) !=
-                                       DCU_COMPLETE_STATE) ||
-                   (chain_state != hang_state))
-                       return false;
-       }
-
-       ath_dbg(ath9k_hw_common(ah), RESET, "MAC Hang signature 1 found\n");
-
-       return true;
-}
-
 void ath9k_hw_check_nav(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
@@ -1676,7 +1584,6 @@ static void ath9k_hw_reset_opmode(struct ath_hw *ah,
 
        REG_RMW(ah, AR_STA_ID1, macStaId1
                  | AR_STA_ID1_RTS_USE_DEF
-                 | (ah->config.ack_6mb ? AR_STA_ID1_ACKCTS_6MB : 0)
                  | ah->sta_id1_defaults,
                  ~AR_STA_ID1_SADH_MASK);
        ath_hw_setbssidmask(common);
@@ -1735,7 +1642,7 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
                }
 #ifdef __BIG_ENDIAN
                else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
-                        AR_SREV_9550(ah))
+                        AR_SREV_9550(ah) || AR_SREV_9531(ah))
                        REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
                else
                        REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -1865,7 +1772,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        /* Save TSF before chip reset, a cold reset clears it */
        tsf = ath9k_hw_gettsf64(ah);
        getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000;
+       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000;
 
        saveLedState = REG_READ(ah, AR_CFG_LED) &
                (AR_CFG_LED_ASSOC_CTL | AR_CFG_LED_MODE_SEL |
@@ -1899,7 +1806,7 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
 
        /* Restore TSF */
        getrawmonotonic(&ts);
-       usec = ts.tv_sec * 1000 + ts.tv_nsec / 1000 - usec;
+       usec = ts.tv_sec * 1000000ULL + ts.tv_nsec / 1000 - usec;
        ath9k_hw_settsf64(ah, tsf + usec);
 
        if (AR_SREV_9280_20_OR_LATER(ah))
@@ -2008,10 +1915,11 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
-       if (AR_SREV_9300_20_OR_LATER(ah)) {
+       if (AR_SREV_9300_20_OR_LATER(ah))
                ar9003_hw_bb_watchdog_config(ah);
+
+       if (ah->config.hw_hang_checks & HW_PHYRESTART_CLC_WAR)
                ar9003_hw_disable_phy_restart(ah);
-       }
 
        ath9k_hw_apply_gpio_override(ah);
 
@@ -2135,7 +2043,11 @@ static bool ath9k_hw_set_power_awake(struct ath_hw *ah)
 
        REG_SET_BIT(ah, AR_RTC_FORCE_WAKE,
                    AR_RTC_FORCE_WAKE_EN);
-       udelay(50);
+
+       if (AR_SREV_9100(ah))
+               udelay(10000);
+       else
+               udelay(50);
 
        for (i = POWER_UP_TIME / 50; i > 0; i--) {
                val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M;
@@ -2564,13 +2476,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
            ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
                        pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
 
-       /*
-        * Fast channel change across bands is available
-        * only for AR9462 and AR9565.
-        */
-       if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
-               pCap->hw_caps |= ATH9K_HW_CAP_FCC_BAND_SWITCH;
-
        return 0;
 }
 
@@ -3084,14 +2989,14 @@ void ath_gen_timer_isr(struct ath_hw *ah)
        trigger_mask &= timer_table->timer_mask;
        thresh_mask &= timer_table->timer_mask;
 
-       trigger_mask &= ~thresh_mask;
-
        for_each_set_bit(index, &thresh_mask, ARRAY_SIZE(timer_table->timers)) {
                timer = timer_table->timers[index];
                if (!timer)
                    continue;
                if (!timer->overflow)
                    continue;
+
+               trigger_mask &= ~BIT(index);
                timer->overflow(timer->arg);
        }
 
index 6132ffeb304871108941af0ceef7a6632ecd1366..e766399bdcdaede07d547832e0797a89dfb8efb1 100644 (file)
@@ -52,6 +52,7 @@
 #define AR9300_DEVID_QCA955X   0x0038
 #define AR9485_DEVID_AR1111    0x0037
 #define AR9300_DEVID_AR9565     0x0036
+#define AR9300_DEVID_AR953X     0x003d
 
 #define AR5416_AR9100_DEVID    0x000b
 
@@ -277,10 +278,24 @@ struct ath9k_hw_capabilities {
        u8 txs_len;
 };
 
+#define AR_NO_SPUR             0x8000
+#define AR_BASE_FREQ_2GHZ      2300
+#define AR_BASE_FREQ_5GHZ      4900
+#define AR_SPUR_FEEQ_BOUND_HT40 19
+#define AR_SPUR_FEEQ_BOUND_HT20 10
+
+enum ath9k_hw_hang_checks {
+       HW_BB_WATCHDOG            = BIT(0),
+       HW_PHYRESTART_CLC_WAR     = BIT(1),
+       HW_BB_RIFS_HANG           = BIT(2),
+       HW_BB_DFS_HANG            = BIT(3),
+       HW_BB_RX_CLEAR_STUCK_HANG = BIT(4),
+       HW_MAC_HANG               = BIT(5),
+};
+
 struct ath9k_ops_config {
        int dma_beacon_response_time;
        int sw_beacon_response_time;
-       int ack_6mb;
        u32 cwm_ignore_extcca;
        u32 pcie_waen;
        u8 analog_shiftreg;
@@ -292,13 +307,9 @@ struct ath9k_ops_config {
        int serialize_regmode;
        bool rx_intr_mitigation;
        bool tx_intr_mitigation;
-#define AR_NO_SPUR             0x8000
-#define AR_BASE_FREQ_2GHZ      2300
-#define AR_BASE_FREQ_5GHZ      4900
-#define AR_SPUR_FEEQ_BOUND_HT40 19
-#define AR_SPUR_FEEQ_BOUND_HT20 10
        u8 max_txtrig_level;
        u16 ani_poll_interval; /* ANI poll interval in ms */
+       u16 hw_hang_checks;
 
        /* Platform specific config */
        u32 aspm_l1_fix;
@@ -573,6 +584,10 @@ struct ath_hw_radar_conf {
  *     register settings through the register initialization.
  */
 struct ath_hw_private_ops {
+       void (*init_hang_checks)(struct ath_hw *ah);
+       bool (*detect_mac_hang)(struct ath_hw *ah);
+       bool (*detect_bb_hang)(struct ath_hw *ah);
+
        /* Calibration ops */
        void (*init_cal_settings)(struct ath_hw *ah);
        bool (*init_cal)(struct ath_hw *ah, struct ath9k_channel *chan);
@@ -1029,6 +1044,7 @@ void ar9002_hw_enable_async_fifo(struct ath_hw *ah);
  * Code specific to AR9003, we stuff these here to avoid callbacks
  * for older families
  */
+bool ar9003_hw_bb_watchdog_check(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
index e63465b7eab9ccc7b0214382881b37d159f31546..f2a17fcf1ae412834bd7c0c0b16471429b007e59 100644 (file)
@@ -763,10 +763,8 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
 
        setup_timer(&sc->sleep_timer, ath_ps_full_sleep, (unsigned long)sc);
        INIT_WORK(&sc->hw_reset_work, ath_reset_work);
-       INIT_WORK(&sc->hw_check_work, ath_hw_check);
        INIT_WORK(&sc->paprd_work, ath_paprd_calibrate);
        INIT_DELAYED_WORK(&sc->hw_pll_work, ath_hw_pll_work);
-       setup_timer(&sc->rx_poll_timer, ath_rx_poll, (unsigned long)sc);
 
        /*
         * Cache line size is used to size and align various
index aed7e29dc50f152b954278020b8b2999f3e795e7..30dcef5aba100d0edfaf7171aa38726ef6e42674 100644 (file)
@@ -65,50 +65,26 @@ void ath_tx_complete_poll_work(struct work_struct *work)
 /*
  * Checks if the BB/MAC is hung.
  */
-void ath_hw_check(struct work_struct *work)
+bool ath_hw_check(struct ath_softc *sc)
 {
-       struct ath_softc *sc = container_of(work, struct ath_softc, hw_check_work);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       unsigned long flags;
-       int busy;
-       u8 is_alive, nbeacon = 1;
        enum ath_reset_type type;
+       bool is_alive;
 
        ath9k_ps_wakeup(sc);
+
        is_alive = ath9k_hw_check_alive(sc->sc_ah);
 
-       if ((is_alive && !AR_SREV_9300(sc->sc_ah)) || sc->tx99_state)
-               goto out;
-       else if (!is_alive && AR_SREV_9300(sc->sc_ah)) {
+       if (!is_alive) {
                ath_dbg(common, RESET,
-                       "DCU stuck is detected. Schedule chip reset\n");
+                       "HW hang detected, schedule chip reset\n");
                type = RESET_TYPE_MAC_HANG;
-               goto sched_reset;
-       }
-
-       spin_lock_irqsave(&common->cc_lock, flags);
-       busy = ath_update_survey_stats(sc);
-       spin_unlock_irqrestore(&common->cc_lock, flags);
-
-       ath_dbg(common, RESET, "Possible baseband hang, busy=%d (try %d)\n",
-               busy, sc->hw_busy_count + 1);
-       if (busy >= 99) {
-               if (++sc->hw_busy_count >= 3) {
-                       type = RESET_TYPE_BB_HANG;
-                       goto sched_reset;
-               }
-       } else if (busy >= 0) {
-               sc->hw_busy_count = 0;
-               nbeacon = 3;
+               ath9k_queue_reset(sc, type);
        }
 
-       ath_start_rx_poll(sc, nbeacon);
-       goto out;
-
-sched_reset:
-       ath9k_queue_reset(sc, type);
-out:
        ath9k_ps_restore(sc);
+
+       return is_alive;
 }
 
 /*
@@ -161,29 +137,6 @@ void ath_hw_pll_work(struct work_struct *work)
                                     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 }
 
-/*
- * RX Polling - monitors baseband hangs.
- */
-void ath_start_rx_poll(struct ath_softc *sc, u8 nbeacon)
-{
-       if (!AR_SREV_9300(sc->sc_ah))
-               return;
-
-       if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags))
-               return;
-
-       mod_timer(&sc->rx_poll_timer, jiffies + msecs_to_jiffies
-                 (nbeacon * sc->cur_beacon_conf.beacon_interval));
-}
-
-void ath_rx_poll(unsigned long data)
-{
-       struct ath_softc *sc = (struct ath_softc *)data;
-
-       if (!test_bit(SC_OP_INVALID, &sc->sc_flags))
-               ieee80211_queue_work(sc->hw, &sc->hw_check_work);
-}
-
 /*
  * PA Pre-distortion.
  */
@@ -409,10 +362,10 @@ void ath_ani_calibrate(unsigned long data)
 
        /* Call ANI routine if necessary */
        if (aniflag) {
-               spin_lock_irqsave(&common->cc_lock, flags);
+               spin_lock(&common->cc_lock);
                ath9k_hw_ani_monitor(ah, ah->curchan);
                ath_update_survey_stats(sc);
-               spin_unlock_irqrestore(&common->cc_lock, flags);
+               spin_unlock(&common->cc_lock);
        }
 
        /* Perform calibration if necessary */
index 89d7e206992b2ec28fb100b109d7b9e63d4a441d..5f727588ca2788b0e598ccf98450af8f396c7135 100644 (file)
@@ -922,11 +922,29 @@ void ath9k_hw_set_interrupts(struct ath_hw *ah)
                        mask2 |= AR_IMR_S2_CST;
        }
 
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
+               if (ints & ATH9K_INT_BB_WATCHDOG) {
+                       mask |= AR_IMR_BCNMISC;
+                       mask2 |= AR_IMR_S2_BB_WATCHDOG;
+               }
+       }
+
        ath_dbg(common, INTERRUPT, "new IMR 0x%x\n", mask);
        REG_WRITE(ah, AR_IMR, mask);
-       ah->imrs2_reg &= ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | AR_IMR_S2_DTIMSYNC |
-                          AR_IMR_S2_CABEND | AR_IMR_S2_CABTO |
-                          AR_IMR_S2_TSFOOR | AR_IMR_S2_GTT | AR_IMR_S2_CST);
+       ah->imrs2_reg &= ~(AR_IMR_S2_TIM |
+                          AR_IMR_S2_DTIM |
+                          AR_IMR_S2_DTIMSYNC |
+                          AR_IMR_S2_CABEND |
+                          AR_IMR_S2_CABTO |
+                          AR_IMR_S2_TSFOOR |
+                          AR_IMR_S2_GTT |
+                          AR_IMR_S2_CST);
+
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG) {
+               if (ints & ATH9K_INT_BB_WATCHDOG)
+                       ah->imrs2_reg &= ~AR_IMR_S2_BB_WATCHDOG;
+       }
+
        ah->imrs2_reg |= mask2;
        REG_WRITE(ah, AR_IMR_S2, ah->imrs2_reg);
 
index 173a889f9dbb35de8a49d87aea7f1c43400613bf..d0c3aec7c74e5ba4821eb2a234a1902476d4fa89 100644 (file)
@@ -170,7 +170,6 @@ void ath9k_ps_restore(struct ath_softc *sc)
 static void __ath_cancel_work(struct ath_softc *sc)
 {
        cancel_work_sync(&sc->paprd_work);
-       cancel_work_sync(&sc->hw_check_work);
        cancel_delayed_work_sync(&sc->tx_complete_work);
        cancel_delayed_work_sync(&sc->hw_pll_work);
 
@@ -194,7 +193,6 @@ void ath_restart_work(struct ath_softc *sc)
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work,
                                     msecs_to_jiffies(ATH_PLL_WORK_INTERVAL));
 
-       ath_start_rx_poll(sc, 3);
        ath_start_ani(sc);
 }
 
@@ -204,11 +202,7 @@ static bool ath_prepare_reset(struct ath_softc *sc)
        bool ret = true;
 
        ieee80211_stop_queues(sc->hw);
-
-       sc->hw_busy_count = 0;
        ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
-
        ath9k_hw_disable_interrupts(ah);
 
        if (!ath_drain_all_txq(sc))
@@ -336,7 +330,6 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
        struct ieee80211_hw *hw = sc->hw;
        struct ath9k_channel *hchan;
        struct ieee80211_channel *chan = chandef->chan;
-       unsigned long flags;
        bool offchannel;
        int pos = chan->hw_value;
        int old_pos = -1;
@@ -354,9 +347,9 @@ static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chand
                chan->center_freq, chandef->width);
 
        /* update survey stats for the old channel before switching */
-       spin_lock_irqsave(&common->cc_lock, flags);
+       spin_lock_bh(&common->cc_lock);
        ath_update_survey_stats(sc);
-       spin_unlock_irqrestore(&common->cc_lock, flags);
+       spin_unlock_bh(&common->cc_lock);
 
        ath9k_cmn_get_channel(hw, ah, chandef);
 
@@ -427,12 +420,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
        an->vif = vif;
 
        ath_tx_node_init(sc, an);
-
-       if (sta->ht_cap.ht_supported) {
-               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
-                                    sta->ht_cap.ampdu_factor);
-               an->mpdudensity = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
-       }
 }
 
 static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
@@ -454,14 +441,8 @@ void ath9k_tasklet(unsigned long data)
        ath9k_ps_wakeup(sc);
        spin_lock(&sc->sc_pcu_lock);
 
-       if ((status & ATH9K_INT_FATAL) ||
-           (status & ATH9K_INT_BB_WATCHDOG)) {
-
-               if (status & ATH9K_INT_FATAL)
-                       type = RESET_TYPE_FATAL_INT;
-               else
-                       type = RESET_TYPE_BB_WATCHDOG;
-
+       if (status & ATH9K_INT_FATAL) {
+               type = RESET_TYPE_FATAL_INT;
                ath9k_queue_reset(sc, type);
 
                /*
@@ -473,6 +454,28 @@ void ath9k_tasklet(unsigned long data)
                goto out;
        }
 
+       if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
+           (status & ATH9K_INT_BB_WATCHDOG)) {
+               spin_lock(&common->cc_lock);
+               ath_hw_cycle_counters_update(common);
+               ar9003_hw_bb_watchdog_dbg_info(ah);
+               spin_unlock(&common->cc_lock);
+
+               if (ar9003_hw_bb_watchdog_check(ah)) {
+                       type = RESET_TYPE_BB_WATCHDOG;
+                       ath9k_queue_reset(sc, type);
+
+                       /*
+                        * Increment the ref. counter here so that
+                        * interrupts are enabled in the reset routine.
+                        */
+                       atomic_inc(&ah->intr_ref_cnt);
+                       ath_dbg(common, ANY,
+                               "BB_WATCHDOG: Skipping interrupts\n");
+                       goto out;
+               }
+       }
+
        spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((status & ATH9K_INT_TSFOOR) && sc->ps_enabled) {
                /*
@@ -541,7 +544,7 @@ irqreturn_t ath_isr(int irq, void *dev)
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
        enum ath9k_int status;
-       u32 sync_cause;
+       u32 sync_cause = 0;
        bool sched = false;
 
        /*
@@ -593,16 +596,9 @@ irqreturn_t ath_isr(int irq, void *dev)
            !(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)))
                goto chip_reset;
 
-       if ((ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
-           (status & ATH9K_INT_BB_WATCHDOG)) {
-
-               spin_lock(&common->cc_lock);
-               ath_hw_cycle_counters_update(common);
-               ar9003_hw_bb_watchdog_dbg_info(ah);
-               spin_unlock(&common->cc_lock);
-
+       if ((ah->config.hw_hang_checks & HW_BB_WATCHDOG) &&
+           (status & ATH9K_INT_BB_WATCHDOG))
                goto chip_reset;
-       }
 
 #ifdef CONFIG_ATH9K_WOW
        if (status & ATH9K_INT_BMISS) {
@@ -732,11 +728,13 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
                ah->imask |= ATH9K_INT_RXHP |
-                            ATH9K_INT_RXLP |
-                            ATH9K_INT_BB_WATCHDOG;
+                            ATH9K_INT_RXLP;
        else
                ah->imask |= ATH9K_INT_RX;
 
+       if (ah->config.hw_hang_checks & HW_BB_WATCHDOG)
+               ah->imask |= ATH9K_INT_BB_WATCHDOG;
+
        ah->imask |= ATH9K_INT_GTT;
 
        if (ah->caps.hw_caps & ATH9K_HW_CAP_HT)
@@ -860,7 +858,6 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        mutex_lock(&sc->mutex);
 
        ath_cancel_work(sc);
-       del_timer_sync(&sc->rx_poll_timer);
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
@@ -994,8 +991,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
        struct ath_common *common = ath9k_hw_common(ah);
 
        /*
-        * Use the hardware MAC address as reference, the hardware uses it
-        * together with the BSSID mask when matching addresses.
+        * Pick the MAC address of the first interface as the new hardware
+        * MAC address. The hardware will use it together with the BSSID mask
+        * when matching addresses.
         */
        memset(iter_data, 0, sizeof(*iter_data));
        memset(&iter_data->mask, 0xff, ETH_ALEN);
@@ -1790,13 +1788,12 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
-       unsigned long flags;
        int pos;
 
        if (config_enabled(CONFIG_ATH9K_TX99))
                return -EOPNOTSUPP;
 
-       spin_lock_irqsave(&common->cc_lock, flags);
+       spin_lock_bh(&common->cc_lock);
        if (idx == 0)
                ath_update_survey_stats(sc);
 
@@ -1810,7 +1807,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
                sband = hw->wiphy->bands[IEEE80211_BAND_5GHZ];
 
        if (!sband || idx >= sband->n_channels) {
-               spin_unlock_irqrestore(&common->cc_lock, flags);
+               spin_unlock_bh(&common->cc_lock);
                return -ENOENT;
        }
 
@@ -1818,7 +1815,7 @@ static int ath9k_get_survey(struct ieee80211_hw *hw, int idx,
        pos = chan->hw_value;
        memcpy(survey, &sc->survey[pos], sizeof(*survey));
        survey->channel = chan;
-       spin_unlock_irqrestore(&common->cc_lock, flags);
+       spin_unlock_bh(&common->cc_lock);
 
        return 0;
 }
index e9a585758941fc9305fa859bab091992eb9946a8..55724b02316b17d44c9d7d788f0d55452c616286 100644 (file)
@@ -409,6 +409,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x11AD, /* LITEON */
                         0x0632),
          .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x06B2),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0842),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x11AD, /* LITEON */
@@ -424,6 +434,16 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x1B9A, /* XAVI */
                         0x2812),
          .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x28A1),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x218A),
+         .driver_data = ATH9K_PCI_AR9565_1ANT },
 
        /* WB335 1-ANT / Antenna Diversity */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -469,22 +489,17 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x11AD, /* LITEON */
-                        0x0682),
+                        0x06A2),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
-                        PCI_VENDOR_ID_AZWAVE,
-                        0x213A),
-         .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
-       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
-                        0x0036,
-                        PCI_VENDOR_ID_LENOVO,
-                        0x3026),
+                        0x11AD, /* LITEON */
+                        0x0682),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
-                        PCI_VENDOR_ID_LENOVO,
-                        0x4026),
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x213A),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
@@ -504,37 +519,35 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_DELL,
-                        0x020E),
+                        0x020C),
          .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
 
-       /* WB335 2-ANT */
+       /* WB335 2-ANT / Antenna-Diversity */
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411A),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411B),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411C),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411D),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_SAMSUNG,
                         0x411E),
-         .driver_data = ATH9K_PCI_AR9565_2ANT },
-
-       /* WB335 2-ANT / Antenna-Diversity */
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_ATHEROS,
@@ -560,11 +573,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x11AD, /* LITEON */
                         0x0612),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0832),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x11AD, /* LITEON */
+                        0x0692),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         PCI_VENDOR_ID_AZWAVE,
                         0x2130),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x213B),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_AZWAVE,
+                        0x2182),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x144F, /* ASKEY */
@@ -575,6 +608,11 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         0x1B9A, /* XAVI */
                         0x2810),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        0x1B9A, /* XAVI */
+                        0x28A2),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
        { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
                         0x0036,
                         0x185F, /* WNC */
@@ -590,6 +628,31 @@ static DEFINE_PCI_DEVICE_TABLE(ath_pci_id_table) = {
                         PCI_VENDOR_ID_FOXCONN,
                         0xE07F),
          .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_FOXCONN,
+                        0xE081),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x3026),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_LENOVO,
+                        0x4026),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_ASUSTEK,
+                        0x85F2),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0036,
+                        PCI_VENDOR_ID_DELL,
+                        0x020E),
+         .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
 
        /* PCI-E AR9565 (WB335) */
        { PCI_VDEVICE(ATHEROS, 0x0036),
index 3692b2a501a2e50d522d130e8a85883fe7d36d02..f7cc5b37a18ff4b54fd7be877629107c9ba2f576 100644 (file)
@@ -419,7 +419,7 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
                rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
        }
 
-       if (AR_SREV_9550(sc->sc_ah))
+       if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
                rfilt |= ATH9K_RX_FILTER_4ADDRESS;
 
        return rfilt;
@@ -850,20 +850,15 @@ static int ath9k_process_rate(struct ath_common *common,
        enum ieee80211_band band;
        unsigned int i = 0;
        struct ath_softc __maybe_unused *sc = common->priv;
+       struct ath_hw *ah = sc->sc_ah;
 
-       band = hw->conf.chandef.chan->band;
+       band = ah->curchan->chan->band;
        sband = hw->wiphy->bands[band];
 
-       switch (hw->conf.chandef.width) {
-       case NL80211_CHAN_WIDTH_5:
+       if (IS_CHAN_QUARTER_RATE(ah->curchan))
                rxs->flag |= RX_FLAG_5MHZ;
-               break;
-       case NL80211_CHAN_WIDTH_10:
+       else if (IS_CHAN_HALF_RATE(ah->curchan))
                rxs->flag |= RX_FLAG_10MHZ;
-               break;
-       default:
-               break;
-       }
 
        if (rx_stats->rs_rate & 0x80) {
                /* HT rate */
@@ -982,7 +977,7 @@ static bool ath9k_is_mybeacon(struct ath_softc *sc, struct ieee80211_hdr *hdr)
        if (ieee80211_is_beacon(hdr->frame_control)) {
                RX_STAT_INC(rx_beacons);
                if (!is_zero_ether_addr(common->curbssid) &&
-                   ether_addr_equal(hdr->addr3, common->curbssid))
+                   ether_addr_equal_64bits(hdr->addr3, common->curbssid))
                        return true;
        }
 
@@ -1077,9 +1072,13 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
        }
 
        rx_stats->is_mybeacon = ath9k_is_mybeacon(sc, hdr);
-       if (rx_stats->is_mybeacon) {
-               sc->hw_busy_count = 0;
-               ath_start_rx_poll(sc, 3);
+
+       /*
+        * This shouldn't happen, but have a safety check anyway.
+        */
+       if (WARN_ON(!ah->curchan)) {
+               ret = -EINVAL;
+               goto exit;
        }
 
        if (ath9k_process_rate(common, hw, rx_stats, rx_status)) {
@@ -1089,8 +1088,8 @@ static int ath9k_rx_skb_preprocess(struct ath_softc *sc,
 
        ath9k_process_rssi(common, hw, rx_stats, rx_status);
 
-       rx_status->band = hw->conf.chandef.chan->band;
-       rx_status->freq = hw->conf.chandef.chan->center_freq;
+       rx_status->band = ah->curchan->chan->band;
+       rx_status->freq = ah->curchan->chan->center_freq;
        rx_status->antenna = rx_stats->rs_antenna;
        rx_status->flag |= RX_FLAG_MACTIME_END;
 
index 9ad007312c9d4fa53b5c9365c3950f3fbfbb7a86..b1fd3fa84983df0e0b85d86b86b02c158883fd35 100644 (file)
 #define AR_IMR_S2              0x00ac
 #define AR_IMR_S2_QCU_TXURN    0x000003FF
 #define AR_IMR_S2_QCU_TXURN_S  0
+#define AR_IMR_S2_BB_WATCHDOG  0x00010000
 #define AR_IMR_S2_CST          0x00400000
 #define AR_IMR_S2_GTT          0x00800000
 #define AR_IMR_S2_TIM          0x01000000
 #define AR_SREV_REVISION_9565_101       1
 #define AR_SREV_REVISION_9565_11        2
 #define AR_SREV_VERSION_9550           0x400
+#define AR_SREV_VERSION_9531            0x500
+#define AR_SREV_REVISION_9531_10        0
+#define AR_SREV_REVISION_9531_11        1
 
 #define AR_SREV_5416(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
 #define AR_SREV_9580(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_9580_10))
-
 #define AR_SREV_9580_10(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9580) && \
        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9580_10))
 
+#define AR_SREV_9531(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531))
+#define AR_SREV_9531_10(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_10))
+#define AR_SREV_9531_11(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
+        ((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_11))
+
 /* NOTE: When adding chips newer than Peacock, add chip check here */
 #define AR_SREV_9580_10_OR_LATER(_ah) \
        (AR_SREV_9580(_ah))
index 11adb5eb51ccd701abd1165b07acad22c8c02965..99f4de95c264b0638108d58820efcb9b8390e8fc 100644 (file)
@@ -497,7 +497,7 @@ static int remove_buf_file_handler(struct dentry *dentry)
        return 0;
 }
 
-struct rchan_callbacks rfs_spec_scan_cb = {
+static struct rchan_callbacks rfs_spec_scan_cb = {
        .create_buf_file = create_buf_file_handler,
        .remove_buf_file = remove_buf_file_handler,
 };
index f1cde81bb7a2573f1905c2725c29c176da7013f0..1b3230fa36510916c740bbc62a2a1b6ec202f5a0 100644 (file)
@@ -197,7 +197,6 @@ int ath9k_suspend(struct ieee80211_hw *hw,
 
        ath_cancel_work(sc);
        ath_stop_ani(sc);
-       del_timer_sync(&sc->rx_poll_timer);
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags)) {
                ath_dbg(common, ANY, "Device not present\n");
index 475433288bbe4d2097d9bba9472a49c9bd6e5ee8..e8d0e7fc77dae5ecfe650276aa2cda1c759ed8d9 100644 (file)
@@ -774,11 +774,6 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
        if (bt_aggr_limit)
                aggr_limit = bt_aggr_limit;
 
-       /*
-        * h/w can accept aggregates up to 16 bit lengths (65535).
-        * The IE, however can hold up to 65536, which shows up here
-        * as zero. Ignore 65536 since we  are constrained by hw.
-        */
        if (tid->an->maxampdu)
                aggr_limit = min(aggr_limit, tid->an->maxampdu);
 
@@ -1269,6 +1264,10 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                                if (!rts_thresh || (len > rts_thresh))
                                        rts = true;
                        }
+
+                       if (!aggr)
+                               len = fi->framelen;
+
                        ath_buf_set_rate(sc, bf, &info, len, rts);
                }
 
@@ -1399,8 +1398,8 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
         * has already been added.
         */
        if (sta->ht_cap.ht_supported) {
-               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
-                                    sta->ht_cap.ampdu_factor);
+               an->maxampdu = (1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                     sta->ht_cap.ampdu_factor)) - 1;
                density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
                an->mpdudensity = density;
        }
index 3d70cd277fd73745b96eeb0fe2042eb9789b68f4..1c0af9cd9a85e3fa88b1f5f79c4e1042a0e0c920 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
index 349fa22a921adc48183bffcc24befb3741f1f392..4c3f576c3144befb6173e9ad9bd5b8487db6dc32 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
index e935f61c7fad1b8ea60cfbaad45affe081611222..1b1b20751ead35ae71aad63240d3f76836ff0a31 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
@@ -536,7 +535,7 @@ static void carl9170_ps_beacon(struct ar9170 *ar, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, ar->common.curbssid) ||
+       if (!ether_addr_equal_64bits(hdr->addr3, ar->common.curbssid) ||
            !ar->common.curaid)
                return;
 
@@ -602,8 +601,8 @@ static void carl9170_ba_check(struct ar9170 *ar, void *data, unsigned int len)
 
                if (bar->start_seq_num == entry_bar->start_seq_num &&
                    TID_CHECK(bar->control, entry_bar->control) &&
-                   ether_addr_equal(bar->ra, entry_bar->ta) &&
-                   ether_addr_equal(bar->ta, entry_bar->ra)) {
+                   ether_addr_equal_64bits(bar->ra, entry_bar->ta) &&
+                   ether_addr_equal_64bits(bar->ta, entry_bar->ra)) {
                        struct ieee80211_tx_info *tx_info;
 
                        tx_info = IEEE80211_SKB_CB(entry_skb);
index e3f696ee4d2393b00cbebd38d7f2840c51376149..4cadfd48ffdf8bd19f0206c138337f2e58177622 100644 (file)
@@ -37,7 +37,6 @@
  *    OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/etherdevice.h>
index 8205d3e4ab66613134ca4b6dff022a9995eb0e24..10919f95a83c19cd744003a2a49022ecda3b2a8c 100644 (file)
@@ -156,6 +156,19 @@ void wil6210_enable_irq(struct wil6210_priv *wil)
        iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
                  offsetof(struct RGF_ICR, ICC));
 
+       /* interrupt moderation parameters */
+       if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
+               /* disable interrupt moderation for monitor
+                * to get better timestamp precision
+                */
+               iowrite32(0, wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+       } else {
+               iowrite32(WIL6210_ITR_TRSH,
+                         wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+               iowrite32(BIT_DMA_ITR_CNT_CRL_EN,
+                         wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+       }
+
        wil6210_unmask_irq_pseudo(wil);
        wil6210_unmask_irq_tx(wil);
        wil6210_unmask_irq_rx(wil);
index d505b2676a736381366652e6815891286e6fe319..9b88440ef05b10bd613cf27e5bb0ccf76e4fc2b4 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/ip.h>
 #include <linux/ipv6.h>
 #include <net/ipv6.h>
+#include <asm/processor.h>
 
 #include "wil6210.h"
 #include "wmi.h"
@@ -377,6 +378,8 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
        }
        skb_trim(skb, dmalen);
 
+       prefetch(skb->data);
+
        wil_hex_dump_txrx("Rx ", DUMP_PREFIX_OFFSET, 16, 1,
                          skb->data, skb_headlen(skb), false);
 
@@ -673,9 +676,12 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
+       d->dma.b11 = ETH_HLEN; /* MAC header length */
+
        switch (skb->protocol) {
        case cpu_to_be16(ETH_P_IP):
                protocol = ip_hdr(skb)->protocol;
+               d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);
                break;
        case cpu_to_be16(ETH_P_IPV6):
                protocol = ipv6_hdr(skb)->nexthdr;
@@ -701,8 +707,6 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
        }
 
        d->dma.ip_length = skb_network_header_len(skb);
-       d->dma.b11 = ETH_HLEN; /* MAC header length */
-       d->dma.b11 |= BIT(DMA_CFG_DESC_TX_OFFLOAD_CFG_L3T_IPV4_POS);
        /* Enable TCP/UDP checksum */
        d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_TCP_UDP_CHECKSUM_EN_POS);
        /* Calculate pseudo-header */
index c4a51638736a27ab4a41ffe1e3e5026400e4e249..1f91eaf95bbebd0dfd70d316943558c5882ed54d 100644 (file)
@@ -39,6 +39,7 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
 #define WIL6210_MAX_TX_RINGS   (24) /* HW limit */
 #define WIL6210_MAX_CID                (8) /* HW limit */
 #define WIL6210_NAPI_BUDGET    (16) /* arbitrary */
+#define WIL6210_ITR_TRSH       (10000) /* arbitrary - about 15 IRQs/msec */
 
 /* Hardware definitions begin */
 
index b73b7e3e21961315b61b2515edd8a85bbd323698..bf93ea859f2d7f1fc05257a86a0b5b1525dd62c3 100644 (file)
@@ -39,7 +39,6 @@
 
 ******************************************************************************/
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 
 #include <linux/kernel.h>
index 5e2749dd112420562a4efde6ca3717de5cc16446..4cfb4d99ced0c3ceb22c05814008d5d21250ef04 100644 (file)
@@ -32,7 +32,6 @@
 #ifdef __IN_PCMCIA_PACKAGE__
 #include <pcmcia/k_compat.h>
 #endif
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
index 64d5973ec28b1c1ca62d7611bf03169eec45f4cf..5cd97e3cbee36d83a24ad0d15ae490db38718fcc 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/netdevice.h>
 #include "atmel.h"
 
index 12c27d13df7f459426e4abf736540c1b502a68e1..c229210d50badeb3b146320822d03057a98c28ce 100644 (file)
@@ -41,9 +41,6 @@ struct brcmf_proto_bcdc_dcmd {
        __le32 status;  /* status code returned from the device */
 };
 
-/* Max valid buffer size that can be sent to the dongle */
-#define BCDC_MAX_MSG_SIZE      (ETH_FRAME_LEN+ETH_FCS_LEN)
-
 /* BCDC flag definitions */
 #define BCDC_DCMD_ERROR                0x01            /* 1=cmd failed */
 #define BCDC_DCMD_SET          0x02            /* 0=get, 1=set cmd */
@@ -133,9 +130,12 @@ brcmf_proto_bcdc_msg(struct brcmf_pub *drvr, int ifidx, uint cmd, void *buf,
        if (buf)
                memcpy(bcdc->buf, buf, len);
 
+       len += sizeof(*msg);
+       if (len > BRCMF_TX_IOCTL_MAX_MSG_SIZE)
+               len = BRCMF_TX_IOCTL_MAX_MSG_SIZE;
+
        /* Send request */
-       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg,
-                              len + sizeof(struct brcmf_proto_bcdc_dcmd));
+       return brcmf_bus_txctl(drvr->bus_if, (unsigned char *)&bcdc->msg, len);
 }
 
 static int brcmf_proto_bcdc_cmplt(struct brcmf_pub *drvr, u32 id, u32 len)
index 2b5cde67e728daa9110345549b893e4934386333..34c993dd0602f161b7366478d3a972809b413c9a 100644 (file)
@@ -47,8 +47,6 @@
 
 #define SDIOH_API_ACCESS_RETRY_LIMIT   2
 
-#define SDIO_VENDOR_ID_BROADCOM                0x02d0
-
 #define DMA_ALIGN_MASK 0x03
 
 #define SDIO_FUNC1_BLOCKSIZE           64
@@ -216,94 +214,104 @@ static inline int brcmf_sdiod_f0_writeb(struct sdio_func *func,
        return err_ret;
 }
 
-static int brcmf_sdiod_request_byte(struct brcmf_sdio_dev *sdiodev, uint rw,
-                                   uint func, uint regaddr, u8 *byte)
+static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
+                                   u32 addr, u8 regsz, void *data, bool write)
 {
-       int err_ret;
+       struct sdio_func *func;
+       int ret;
 
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x\n", rw, func, regaddr);
+       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
+                 write, fn, addr, regsz);
 
-       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_byte_wait);
+       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
        if (brcmf_sdiod_pm_resume_error(sdiodev))
                return -EIO;
 
-       if (rw && func == 0) {
-               /* handle F0 separately */
-               err_ret = brcmf_sdiod_f0_writeb(sdiodev->func[func],
-                                               regaddr, *byte);
-       } else {
-               if (rw) /* CMD52 Write */
-                       sdio_writeb(sdiodev->func[func], *byte, regaddr,
-                                   &err_ret);
-               else if (func == 0) {
-                       *byte = sdio_f0_readb(sdiodev->func[func], regaddr,
-                                             &err_ret);
+       /* only allow byte access on F0 */
+       if (WARN_ON(regsz > 1 && !fn))
+               return -EINVAL;
+       func = sdiodev->func[fn];
+
+       switch (regsz) {
+       case sizeof(u8):
+               if (write) {
+                       if (fn)
+                               sdio_writeb(func, *(u8 *)data, addr, &ret);
+                       else
+                               ret = brcmf_sdiod_f0_writeb(func, addr,
+                                                           *(u8 *)data);
                } else {
-                       *byte = sdio_readb(sdiodev->func[func], regaddr,
-                                          &err_ret);
+                       if (fn)
+                               *(u8 *)data = sdio_readb(func, addr, &ret);
+                       else
+                               *(u8 *)data = sdio_f0_readb(func, addr, &ret);
                }
+               break;
+       case sizeof(u16):
+               if (write)
+                       sdio_writew(func, *(u16 *)data, addr, &ret);
+               else
+                       *(u16 *)data = sdio_readw(func, addr, &ret);
+               break;
+       case sizeof(u32):
+               if (write)
+                       sdio_writel(func, *(u32 *)data, addr, &ret);
+               else
+                       *(u32 *)data = sdio_readl(func, addr, &ret);
+               break;
+       default:
+               brcmf_err("invalid size: %d\n", regsz);
+               break;
        }
 
-       if (err_ret) {
+       if (ret) {
                /*
                 * SleepCSR register access can fail when
                 * waking up the device so reduce this noise
                 * in the logs.
                 */
-               if (regaddr != SBSDIO_FUNC1_SLEEPCSR)
-                       brcmf_err("Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
+               if (addr != SBSDIO_FUNC1_SLEEPCSR)
+                       brcmf_err("failed to %s data F%d@0x%05x, err: %d\n",
+                                 write ? "write" : "read", fn, addr, ret);
                else
-                       brcmf_dbg(SDIO, "Failed to %s byte F%d:@0x%05x=%02x, Err: %d\n",
-                                 rw ? "write" : "read", func, regaddr, *byte,
-                                 err_ret);
+                       brcmf_dbg(SDIO, "failed to %s data F%d@0x%05x, err: %d\n",
+                                 write ? "write" : "read", fn, addr, ret);
        }
-       return err_ret;
+       return ret;
 }
 
-static int brcmf_sdiod_request_word(struct brcmf_sdio_dev *sdiodev, uint rw,
-                                   uint func, uint addr, u32 *word,
-                                   uint nbytes)
+static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
+                                  u8 regsz, void *data, bool write)
 {
-       int err_ret = -EIO;
-
-       if (func == 0) {
-               brcmf_err("Only CMD52 allowed to F0\n");
-               return -EINVAL;
-       }
-
-       brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
-                 rw, func, addr, nbytes);
+       u8 func_num;
+       s32 retry = 0;
+       int ret;
 
-       brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
-       if (brcmf_sdiod_pm_resume_error(sdiodev))
-               return -EIO;
+       /*
+        * figure out how to read the register based on address range
+        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
+        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
+        * The rest: function 1 silicon backplane core registers
+        */
+       if ((addr & ~REG_F0_REG_MASK) == 0)
+               func_num = SDIO_FUNC_0;
+       else
+               func_num = SDIO_FUNC_1;
 
-       if (rw) {               /* CMD52 Write */
-               if (nbytes == 4)
-                       sdio_writel(sdiodev->func[func], *word, addr,
-                                   &err_ret);
-               else if (nbytes == 2)
-                       sdio_writew(sdiodev->func[func], (*word & 0xFFFF),
-                                   addr, &err_ret);
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       } else {                /* CMD52 Read */
-               if (nbytes == 4)
-                       *word = sdio_readl(sdiodev->func[func], addr, &err_ret);
-               else if (nbytes == 2)
-                       *word = sdio_readw(sdiodev->func[func], addr,
-                                          &err_ret) & 0xFFFF;
-               else
-                       brcmf_err("Invalid nbytes: %d\n", nbytes);
-       }
+       do {
+               if (!write)
+                       memset(data, 0, regsz);
+               /* for retry wait for 1 ms till bus get settled down */
+               if (retry)
+                       usleep_range(1000, 2000);
+               ret = brcmf_sdiod_request_data(sdiodev, func_num, addr, regsz,
+                                              data, write);
+       } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
 
-       if (err_ret)
-               brcmf_err("Failed to %s word, Err: 0x%08x\n",
-                         rw ? "write" : "read", err_ret);
+       if (ret != 0)
+               brcmf_err("failed with %d\n", ret);
 
-       return err_ret;
+       return ret;
 }
 
 static int
@@ -311,24 +319,17 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
 {
        int err = 0, i;
        u8 addr[3];
-       s32 retry;
 
        addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
        addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
        addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
 
        for (i = 0; i < 3; i++) {
-               retry = 0;
-               do {
-                       if (retry)
-                               usleep_range(1000, 2000);
-                       err = brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE,
-                                       SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
-                                       &addr[i]);
-               } while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
-
+               err = brcmf_sdiod_regrw_helper(sdiodev,
+                                              SBSDIO_FUNC1_SBADDRLOW + i,
+                                              sizeof(u8), &addr[i], true);
                if (err) {
-                       brcmf_err("failed at addr:0x%0x\n",
+                       brcmf_err("failed at addr: 0x%0x\n",
                                  SBSDIO_FUNC1_SBADDRLOW + i);
                        break;
                }
@@ -359,61 +360,14 @@ brcmf_sdiod_addrprep(struct brcmf_sdio_dev *sdiodev, uint width, u32 *addr)
        return 0;
 }
 
-static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
-                                   void *data, bool write)
-{
-       u8 func_num, reg_size;
-       s32 retry = 0;
-       int ret;
-
-       /*
-        * figure out how to read the register based on address range
-        * 0x00 ~ 0x7FF: function 0 CCCR and FBR
-        * 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
-        * The rest: function 1 silicon backplane core registers
-        */
-       if ((addr & ~REG_F0_REG_MASK) == 0) {
-               func_num = SDIO_FUNC_0;
-               reg_size = 1;
-       } else if ((addr & ~REG_F1_MISC_MASK) == 0) {
-               func_num = SDIO_FUNC_1;
-               reg_size = 1;
-       } else {
-               func_num = SDIO_FUNC_1;
-               reg_size = 4;
-
-               ret = brcmf_sdiod_addrprep(sdiodev, reg_size, &addr);
-               if (ret)
-                       goto done;
-       }
-
-       do {
-               if (!write)
-                       memset(data, 0, reg_size);
-               if (retry)      /* wait for 1 ms till bus get settled down */
-                       usleep_range(1000, 2000);
-               if (reg_size == 1)
-                       ret = brcmf_sdiod_request_byte(sdiodev, write,
-                                                      func_num, addr, data);
-               else
-                       ret = brcmf_sdiod_request_word(sdiodev, write,
-                                                      func_num, addr, data, 4);
-       } while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
-
-done:
-       if (ret != 0)
-               brcmf_err("failed with %d\n", ret);
-
-       return ret;
-}
-
 u8 brcmf_sdiod_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
 {
        u8 data;
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         false);
        brcmf_dbg(SDIO, "data:0x%02x\n", data);
 
        if (ret)
@@ -428,9 +382,14 @@ u32 brcmf_sdiod_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x\n", addr);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, false);
+       retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
+       if (retval)
+               goto done;
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         false);
        brcmf_dbg(SDIO, "data:0x%08x\n", data);
 
+done:
        if (ret)
                *ret = retval;
 
@@ -443,8 +402,8 @@ void brcmf_sdiod_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%02x\n", addr, data);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
-
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         true);
        if (ret)
                *ret = retval;
 }
@@ -455,8 +414,13 @@ void brcmf_sdiod_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(SDIO, "addr:0x%08x, data:0x%08x\n", addr, data);
-       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, &data, true);
+       retval = brcmf_sdiod_addrprep(sdiodev, sizeof(data), &addr);
+       if (retval)
+               goto done;
+       retval = brcmf_sdiod_regrw_helper(sdiodev, addr, sizeof(data), &data,
+                                         true);
 
+done:
        if (ret)
                *ret = retval;
 }
@@ -879,8 +843,8 @@ int brcmf_sdiod_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
        brcmf_dbg(SDIO, "Enter\n");
 
        /* issue abort cmd52 command through F0 */
-       brcmf_sdiod_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
-                                SDIO_CCCR_ABORT, &t_func);
+       brcmf_sdiod_request_data(sdiodev, SDIO_FUNC_0, SDIO_CCCR_ABORT,
+                                sizeof(t_func), &t_func, true);
 
        brcmf_dbg(SDIO, "Exit\n");
        return 0;
@@ -981,6 +945,7 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = {
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4329)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4330)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_4334)},
+       {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, SDIO_DEVICE_ID_BROADCOM_43362)},
        {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM,
                     SDIO_DEVICE_ID_BROADCOM_4335_4339)},
        { /* end: all zeroes */ },
@@ -1037,7 +1002,6 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
        sdiodev->pdata = brcmfmac_sdio_pdata;
 
        atomic_set(&sdiodev->suspend, false);
-       init_waitqueue_head(&sdiodev->request_byte_wait);
        init_waitqueue_head(&sdiodev->request_word_wait);
        init_waitqueue_head(&sdiodev->request_buffer_wait);
 
index 252024bcbc3ba736c65d18975f2b5106e026737a..939d6b13292248563f92bc4287632341c4997072 100644 (file)
@@ -21,8 +21,6 @@
 #ifndef _BRCMF_H_
 #define _BRCMF_H_
 
-#define BRCMF_VERSION_STR              "4.218.248.5"
-
 #include "fweh.h"
 
 #define TOE_TX_CSUM_OL         0x00000001
 #define BRCMF_DCMD_MEDLEN      1536
 #define BRCMF_DCMD_MAXLEN      8192
 
+/* IOCTL from host to device are limited in lenght. A device can only handle
+ * ethernet frame size. This limitation is to be applied by protocol layer.
+ */
+#define BRCMF_TX_IOCTL_MAX_MSG_SIZE    (ETH_FRAME_LEN+ETH_FCS_LEN)
+
 #define BRCMF_AMPDU_RX_REORDER_MAXFLOWS                256
 
 /* Length of firmware version string stored for
index 548dbb5542c63eb2631aafa8b2344013bfd90752..6a8983a1fb9c3451908c1cf28426d78e6600d091 100644 (file)
 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
 #define BRCMF_DEFAULT_PACKET_FILTER    "100 0 0 0 0x01 0x00"
 
-#ifdef DEBUG
-static const char brcmf_version[] =
-       "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
-       __DATE__ " at " __TIME__;
-#else
-static const char brcmf_version[] =
-       "Dongle Host Driver, version " BRCMF_VERSION_STR;
-#endif
-
 
 bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                      struct sk_buff *pkt, int prec)
index bce0b8e511fd22eb085077169050426f42714838..af39edae8c627db18494a17c7ed2a2144a000bbd 100644 (file)
@@ -702,7 +702,7 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked)
 
        brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name);
 
-       ndev->destructor = free_netdev;
+       ndev->destructor = brcmf_cfg80211_free_netdev;
        return 0;
 
 fail:
@@ -859,8 +859,6 @@ void brcmf_del_if(struct brcmf_pub *drvr, s32 bssidx)
                }
                /* unregister will take care of freeing it */
                unregister_netdev(ifp->ndev);
-               if (bssidx == 0)
-                       brcmf_cfg80211_detach(drvr->config);
        } else {
                kfree(ifp);
        }
@@ -963,8 +961,7 @@ int brcmf_bus_start(struct device *dev)
 fail:
        if (ret < 0) {
                brcmf_err("failed: %d\n", ret);
-               if (drvr->config)
-                       brcmf_cfg80211_detach(drvr->config);
+               brcmf_cfg80211_detach(drvr->config);
                if (drvr->fws) {
                        brcmf_fws_del_interface(ifp);
                        brcmf_fws_deinit(drvr);
@@ -1039,6 +1036,8 @@ void brcmf_detach(struct device *dev)
                        brcmf_del_if(drvr, i);
                }
 
+       brcmf_cfg80211_detach(drvr->config);
+
        brcmf_bus_detach(drvr);
 
        brcmf_proto_detach(drvr);
index f214510e3beec2d37ca8684b4d278474abcf4795..9c7f08a13105637d8dd8bdbd1d4eb54019e79d6c 100644 (file)
@@ -509,6 +509,8 @@ enum brcmf_sdio_frmtype {
 #define BCM4334_NVRAM_NAME             "brcm/brcmfmac4334-sdio.txt"
 #define BCM4335_FIRMWARE_NAME          "brcm/brcmfmac4335-sdio.bin"
 #define BCM4335_NVRAM_NAME             "brcm/brcmfmac4335-sdio.txt"
+#define BCM43362_FIRMWARE_NAME         "brcm/brcmfmac43362-sdio.bin"
+#define BCM43362_NVRAM_NAME            "brcm/brcmfmac43362-sdio.txt"
 #define BCM4339_FIRMWARE_NAME          "brcm/brcmfmac4339-sdio.bin"
 #define BCM4339_NVRAM_NAME             "brcm/brcmfmac4339-sdio.txt"
 
@@ -526,6 +528,8 @@ MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
 MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43362_NVRAM_NAME);
 MODULE_FIRMWARE(BCM4339_FIRMWARE_NAME);
 MODULE_FIRMWARE(BCM4339_NVRAM_NAME);
 
@@ -552,6 +556,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
        { BCM4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
        { BCM4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
        { BCM4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
+       { BCM43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
        { BCM4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) }
 };
 
@@ -3384,7 +3389,8 @@ err:
 
 static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
 {
-       u32 addr, reg;
+       u32 addr, reg, pmu_cc3_mask = ~0;
+       int err;
 
        brcmf_dbg(TRACE, "Enter\n");
 
@@ -3392,13 +3398,27 @@ static bool brcmf_sdio_sr_capable(struct brcmf_sdio *bus)
        if (bus->ci->pmurev < 17)
                return false;
 
-       /* read PMU chipcontrol register 3*/
-       addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
-       brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
-       addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
-       reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+       switch (bus->ci->chip) {
+       case BCM43241_CHIP_ID:
+       case BCM4335_CHIP_ID:
+       case BCM4339_CHIP_ID:
+               /* read PMU chipcontrol register 3 */
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_addr);
+               brcmf_sdiod_regwl(bus->sdiodev, addr, 3, NULL);
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, chipcontrol_data);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+               return (reg & pmu_cc3_mask) != 0;
+       default:
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, pmucapabilities_ext);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, &err);
+               if ((reg & PCAPEXT_SR_SUPPORTED_MASK) == 0)
+                       return false;
 
-       return (bool)reg;
+               addr = CORE_CC_REG(bus->ci->c_inf[0].base, retention_ctl);
+               reg = brcmf_sdiod_regrl(bus->sdiodev, addr, NULL);
+               return (reg & (PMU_RCTL_MACPHY_DISABLE_MASK |
+                              PMU_RCTL_LOGIC_DISABLE_MASK)) == 0;
+       }
 }
 
 static void brcmf_sdio_sr_init(struct brcmf_sdio *bus)
@@ -3615,7 +3635,7 @@ static int brcmf_sdio_bus_init(struct device *dev)
        }
 
        /* If we didn't come up, turn off backplane clock */
-       if (bus_if->state != BRCMF_BUS_DATA)
+       if (ret != 0)
                brcmf_sdio_clkctl(bus, CLK_NONE, false);
 
 exit:
@@ -3750,31 +3770,6 @@ static void brcmf_sdio_dataworker(struct work_struct *work)
        }
 }
 
-static void brcmf_sdio_release_malloc(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       kfree(bus->rxbuf);
-       bus->rxctl = bus->rxbuf = NULL;
-       bus->rxlen = 0;
-}
-
-static bool brcmf_sdio_probe_malloc(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (bus->sdiodev->bus_if->maxctl) {
-               bus->rxblen =
-                   roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
-                           ALIGNMENT) + bus->head_align;
-               bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
-               if (!(bus->rxbuf))
-                       return false;
-       }
-
-       return true;
-}
-
 static bool
 brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
 {
@@ -3888,39 +3883,6 @@ fail:
        return false;
 }
 
-static bool brcmf_sdio_probe_init(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       sdio_claim_host(bus->sdiodev->func[1]);
-
-       /* Disable F2 to clear any intermediate frame state on the dongle */
-       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
-
-       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
-       bus->rxflow = false;
-
-       /* Done with backplane-dependent accesses, can drop clock... */
-       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
-
-       sdio_release_host(bus->sdiodev->func[1]);
-
-       /* ...and initialize clock/power states */
-       bus->clkstate = CLK_SDONLY;
-       bus->idletime = BRCMF_IDLE_INTERVAL;
-       bus->idleclock = BRCMF_IDLE_ACTIVE;
-
-       /* Query the F2 block size, set roundup accordingly */
-       bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
-       bus->roundup = min(max_roundup, bus->blocksize);
-
-       /* SR state */
-       bus->sleeping = false;
-       bus->sr_enabled = false;
-
-       return true;
-}
-
 static int
 brcmf_sdio_watchdog_thread(void *data)
 {
@@ -3955,24 +3917,6 @@ brcmf_sdio_watchdog(unsigned long data)
        }
 }
 
-static void brcmf_sdio_release_dongle(struct brcmf_sdio *bus)
-{
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (bus->ci) {
-               sdio_claim_host(bus->sdiodev->func[1]);
-               brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
-               brcmf_sdio_clkctl(bus, CLK_NONE, false);
-               sdio_release_host(bus->sdiodev->func[1]);
-               brcmf_sdio_chip_detach(&bus->ci);
-               if (bus->vars && bus->varsz)
-                       kfree(bus->vars);
-               bus->vars = NULL;
-       }
-
-       brcmf_dbg(TRACE, "Disconnected\n");
-}
-
 static struct brcmf_bus_ops brcmf_sdio_bus_ops = {
        .stop = brcmf_sdio_bus_stop,
        .preinit = brcmf_sdio_bus_preinit,
@@ -4066,15 +4010,42 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
        }
 
        /* Allocate buffers */
-       if (!(brcmf_sdio_probe_malloc(bus))) {
-               brcmf_err("brcmf_sdio_probe_malloc failed\n");
-               goto fail;
+       if (bus->sdiodev->bus_if->maxctl) {
+               bus->rxblen =
+                   roundup((bus->sdiodev->bus_if->maxctl + SDPCM_HDRLEN),
+                           ALIGNMENT) + bus->head_align;
+               bus->rxbuf = kmalloc(bus->rxblen, GFP_ATOMIC);
+               if (!(bus->rxbuf)) {
+                       brcmf_err("rxbuf allocation failed\n");
+                       goto fail;
+               }
        }
 
-       if (!(brcmf_sdio_probe_init(bus))) {
-               brcmf_err("brcmf_sdio_probe_init failed\n");
-               goto fail;
-       }
+       sdio_claim_host(bus->sdiodev->func[1]);
+
+       /* Disable F2 to clear any intermediate frame state on the dongle */
+       sdio_disable_func(bus->sdiodev->func[SDIO_FUNC_2]);
+
+       bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+       bus->rxflow = false;
+
+       /* Done with backplane-dependent accesses, can drop clock... */
+       brcmf_sdiod_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
+
+       sdio_release_host(bus->sdiodev->func[1]);
+
+       /* ...and initialize clock/power states */
+       bus->clkstate = CLK_SDONLY;
+       bus->idletime = BRCMF_IDLE_INTERVAL;
+       bus->idleclock = BRCMF_IDLE_ACTIVE;
+
+       /* Query the F2 block size, set roundup accordingly */
+       bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
+       bus->roundup = min(max_roundup, bus->blocksize);
+
+       /* SR state */
+       bus->sleeping = false;
+       bus->sr_enabled = false;
 
        brcmf_sdio_debugfs_create(bus);
        brcmf_dbg(INFO, "completed!!\n");
@@ -4108,12 +4079,20 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
 
                if (bus->sdiodev->bus_if->drvr) {
                        brcmf_detach(bus->sdiodev->dev);
-                       brcmf_sdio_release_dongle(bus);
+               }
+
+               if (bus->ci) {
+                       sdio_claim_host(bus->sdiodev->func[1]);
+                       brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
+                       brcmf_sdio_clkctl(bus, CLK_NONE, false);
+                       sdio_release_host(bus->sdiodev->func[1]);
+                       brcmf_sdio_chip_detach(&bus->ci);
                }
 
                brcmu_pkt_buf_free_skb(bus->txglom_sgpad);
-               brcmf_sdio_release_malloc(bus);
+               kfree(bus->rxbuf);
                kfree(bus->hdrbuf);
+               kfree(bus->vars);
                kfree(bus);
        }
 
@@ -4131,7 +4110,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
        }
 
        /* don't start the wd until fw is loaded */
-       if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN)
+       if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
                return;
 
        if (wdtick) {
index 7918c10336622bf7fb005dbcfb5cbc85918b2b9a..c3e7d76dbf35f508e33a1e1d88164ede54b1967a 100644 (file)
@@ -1873,7 +1873,7 @@ int brcmf_fws_process_skb(struct brcmf_if *ifp, struct sk_buff *skb)
        brcmf_dbg(DATA, "tx proto=0x%X\n", ntohs(eh->h_proto));
        /* determine the priority */
        if (!skb->priority)
-               skb->priority = cfg80211_classify8021d(skb);
+               skb->priority = cfg80211_classify8021d(skb, NULL);
 
        drvr->tx_multicast += !!multicast;
        if (pae)
index d3180360725925c40f6e59bf09bdfb28e18a4300..e23c869bfe33bf96b02967dcb55b98815dff2665 100644 (file)
@@ -1956,21 +1956,21 @@ s32 brcmf_p2p_attach(struct brcmf_cfg80211_info *cfg)
                err = brcmf_fil_iovar_int_set(pri_ifp, "p2p_disc", 1);
                if (err < 0) {
                        brcmf_err("set p2p_disc error\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* obtain bsscfg index for P2P discovery */
                err = brcmf_fil_iovar_int_get(pri_ifp, "p2p_dev", &bssidx);
                if (err < 0) {
                        brcmf_err("retrieving discover bsscfg index failed\n");
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
                /* Verify that firmware uses same bssidx as driver !! */
                if (p2p_ifp->bssidx != bssidx) {
                        brcmf_err("Incorrect bssidx=%d, compared to p2p_ifp->bssidx=%d\n",
                                  bssidx, p2p_ifp->bssidx);
-                       brcmf_free_vif(cfg, p2p_vif);
+                       brcmf_free_vif(p2p_vif);
                        goto exit;
                }
 
@@ -1998,7 +1998,7 @@ void brcmf_p2p_detach(struct brcmf_p2p_info *p2p)
                brcmf_p2p_cancel_remain_on_channel(vif->ifp);
                brcmf_p2p_deinit_discovery(p2p);
                /* remove discovery interface */
-               brcmf_free_vif(p2p->cfg, vif);
+               brcmf_free_vif(vif);
                p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
        }
        /* just set it all to zero */
@@ -2223,7 +2223,7 @@ static struct wireless_dev *brcmf_p2p_create_p2pdev(struct brcmf_p2p_info *p2p,
        return &p2p_vif->wdev;
 
 fail:
-       brcmf_free_vif(p2p->cfg, p2p_vif);
+       brcmf_free_vif(p2p_vif);
        return ERR_PTR(err);
 }
 
@@ -2232,31 +2232,12 @@ fail:
  *
  * @vif: virtual interface object to delete.
  */
-static void brcmf_p2p_delete_p2pdev(struct brcmf_cfg80211_info *cfg,
+static void brcmf_p2p_delete_p2pdev(struct brcmf_p2p_info *p2p,
                                    struct brcmf_cfg80211_vif *vif)
 {
        cfg80211_unregister_wdev(&vif->wdev);
-       cfg->p2p.bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
-       brcmf_free_vif(cfg, vif);
-}
-
-/**
- * brcmf_p2p_free_p2p_if() - free up net device related data.
- *
- * @ndev: net device that needs to be freed.
- */
-static void brcmf_p2p_free_p2p_if(struct net_device *ndev)
-{
-       struct brcmf_cfg80211_info *cfg;
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_if *ifp;
-
-       ifp = netdev_priv(ndev);
-       cfg = ifp->drvr->config;
-       vif = ifp->vif;
-
-       brcmf_free_vif(cfg, vif);
-       free_netdev(ifp->ndev);
+       p2p->bss_idx[P2PAPI_BSSCFG_DEVICE].vif = NULL;
+       brcmf_free_vif(vif);
 }
 
 /**
@@ -2336,8 +2317,6 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
                brcmf_err("Registering netdevice failed\n");
                goto fail;
        }
-       /* override destructor */
-       ifp->ndev->destructor = brcmf_p2p_free_p2p_if;
 
        cfg->p2p.bss_idx[P2PAPI_BSSCFG_CONNECTION].vif = vif;
        /* Disable firmware roaming for P2P interface  */
@@ -2350,7 +2329,7 @@ struct wireless_dev *brcmf_p2p_add_vif(struct wiphy *wiphy, const char *name,
        return &ifp->vif->wdev;
 
 fail:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return ERR_PTR(err);
 }
 
@@ -2359,8 +2338,6 @@ fail:
  *
  * @wiphy: wiphy device of interface.
  * @wdev: wireless device of interface.
- *
- * TODO: not yet supported.
  */
 int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
 {
@@ -2386,7 +2363,7 @@ int brcmf_p2p_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev)
                break;
 
        case NL80211_IFTYPE_P2P_DEVICE:
-               brcmf_p2p_delete_p2pdev(cfg, vif);
+               brcmf_p2p_delete_p2pdev(p2p, vif);
                return 0;
        default:
                return -ENOTSUPP;
index 5f39f28e6efbe2c2e8bb7b84868a78e6ba024918..9fd40675f18e013036d9c49d9e7db0d4a891e810 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/netdevice.h>
 #include <linux/mmc/card.h>
 #include <linux/mmc/sdio_func.h>
+#include <linux/mmc/sdio_ids.h>
 #include <linux/ssb/ssb_regs.h>
 #include <linux/bcma/bcma.h>
 
@@ -83,6 +84,24 @@ static const struct sdiod_drive_str sdiod_drvstr_tab1_1v8[] = {
        {0, 0x1}
 };
 
+/* SDIO Drive Strength to sel value table for PMU Rev 13 (1.8v) */
+static const struct sdiod_drive_str sdiod_drive_strength_tab5_1v8[] = {
+        {6, 0x7},
+        {5, 0x6},
+        {4, 0x5},
+        {3, 0x4},
+        {2, 0x2},
+        {1, 0x1},
+        {0, 0x0}
+};
+
+/* SDIO Drive Strength to sel value table for PMU Rev 17 (1.8v) */
+static const struct sdiod_drive_str sdiod_drvstr_tab6_1v8[] = {
+       {3, 0x3},
+       {2, 0x2},
+       {1, 0x1},
+       {0, 0x0} };
+
 /* SDIO Drive Strength to sel value table for 43143 PMU Rev 17 (3.3V) */
 static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
        {16, 0x7},
@@ -569,6 +588,23 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
                ci->ramsize = 0xc0000;
                ci->rambase = 0x180000;
                break;
+       case BCM43362_CHIP_ID:
+               ci->c_inf[0].wrapbase = 0x18100000;
+               ci->c_inf[0].cib = 0x27004211;
+               ci->c_inf[1].id = BCMA_CORE_SDIO_DEV;
+               ci->c_inf[1].base = 0x18002000;
+               ci->c_inf[1].wrapbase = 0x18102000;
+               ci->c_inf[1].cib = 0x0a004211;
+               ci->c_inf[2].id = BCMA_CORE_INTERNAL_MEM;
+               ci->c_inf[2].base = 0x18004000;
+               ci->c_inf[2].wrapbase = 0x18104000;
+               ci->c_inf[2].cib = 0x08080401;
+               ci->c_inf[3].id = BCMA_CORE_ARM_CM3;
+               ci->c_inf[3].base = 0x18003000;
+               ci->c_inf[3].wrapbase = 0x18103000;
+               ci->c_inf[3].cib = 0x03004211;
+               ci->ramsize = 0x3C000;
+               break;
        default:
                brcmf_err("chipid 0x%x is not supported\n", ci->chip);
                return -ENODEV;
@@ -757,6 +793,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                str_mask = 0x00003800;
                str_shift = 11;
                break;
+       case SDIOD_DRVSTR_KEY(BCM4334_CHIP_ID, 17):
+               str_tab = sdiod_drvstr_tab6_1v8;
+               str_mask = 0x00001800;
+               str_shift = 11;
+               break;
        case SDIOD_DRVSTR_KEY(BCM43143_CHIP_ID, 17):
                /* note: 43143 does not support tristate */
                i = ARRAY_SIZE(sdiod_drvstr_tab2_3v3) - 1;
@@ -769,6 +810,11 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
                                  brcmf_sdio_chip_name(ci->chip, chn, 8),
                                  drivestrength);
                break;
+       case SDIOD_DRVSTR_KEY(BCM43362_CHIP_ID, 13):
+               str_tab = sdiod_drive_strength_tab5_1v8;
+               str_mask = 0x00003800;
+               str_shift = 11;
+               break;
        default:
                brcmf_err("No SDIO Drive strength init done for chip %s rev %d pmurev %d\n",
                          brcmf_sdio_chip_name(ci->chip, chn, 8),
index d0f4b45b24c740f282961697951998038607ddd7..7ea424e207736a527b72237a62f077d5ecf572ea 100644 (file)
 
 #define BRCMF_MAX_CORENUM      6
 
-/* SDIO device ID */
-#define SDIO_DEVICE_ID_BROADCOM_43143          43143
-#define SDIO_DEVICE_ID_BROADCOM_43241          0x4324
-#define SDIO_DEVICE_ID_BROADCOM_4329           0x4329
-#define SDIO_DEVICE_ID_BROADCOM_4330           0x4330
-#define SDIO_DEVICE_ID_BROADCOM_4334           0x4334
-#define SDIO_DEVICE_ID_BROADCOM_4335_4339      0x4335
-
 struct chip_core_info {
        u16 id;
        u16 rev;
index a0981b32c729d14c98d80487c36d1b6d8e9a29c6..092e9c8249926ac80a6831f75ec72c818ff86c43 100644 (file)
@@ -167,7 +167,6 @@ struct brcmf_sdio_dev {
        u32 sbwad;                      /* Save backplane window address */
        struct brcmf_sdio *bus;
        atomic_t suspend;               /* suspend flag */
-       wait_queue_head_t request_byte_wait;
        wait_queue_head_t request_word_wait;
        wait_queue_head_t request_buffer_wait;
        struct device *dev;
index 3966fe0fcfd971418fb3ca22bfc9fcaddf7afaf7..aad83aef7d93cc7014b7bf0cec97505add3c7b90 100644 (file)
@@ -1095,10 +1095,10 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
                                             BRCMF_C_DISASSOC, NULL, 0);
                if (err) {
                        brcmf_err("WLC_DISASSOC failed (%d)\n", err);
-                       cfg80211_disconnected(vif->wdev.netdev, 0,
-                                             NULL, 0, GFP_KERNEL);
                }
                clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
+               cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+
        }
        clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
        clear_bit(BRCMF_SCAN_STATUS_SUPPRESS, &cfg->scan_status);
@@ -1758,6 +1758,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
                return -EIO;
 
        clear_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state);
+       cfg80211_disconnected(ndev, reason_code, NULL, 0, GFP_KERNEL);
 
        memcpy(&scbval.ea, &profile->bssid, ETH_ALEN);
        scbval.val = cpu_to_le32(reason_code);
@@ -4359,9 +4360,6 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
 {
        struct brcmf_cfg80211_vif *vif;
 
-       if (cfg->vif_cnt == BRCMF_IFACE_MAX_CNT)
-               return ERR_PTR(-ENOSPC);
-
        brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n",
                  sizeof(*vif));
        vif = kzalloc(sizeof(*vif), GFP_KERNEL);
@@ -4378,21 +4376,25 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
        brcmf_init_prof(&vif->profile);
 
        list_add_tail(&vif->list, &cfg->vif_list);
-       cfg->vif_cnt++;
        return vif;
 }
 
-void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
-                   struct brcmf_cfg80211_vif *vif)
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 {
        list_del(&vif->list);
-       cfg->vif_cnt--;
-
        kfree(vif);
-       if (!cfg->vif_cnt) {
-               wiphy_unregister(cfg->wiphy);
-               wiphy_free(cfg->wiphy);
-       }
+}
+
+void brcmf_cfg80211_free_netdev(struct net_device *ndev)
+{
+       struct brcmf_cfg80211_vif *vif;
+       struct brcmf_if *ifp;
+
+       ifp = netdev_priv(ndev);
+       vif = ifp->vif;
+
+       brcmf_free_vif(vif);
+       free_netdev(ndev);
 }
 
 static bool brcmf_is_linkup(const struct brcmf_event_msg *e)
@@ -4979,20 +4981,20 @@ cfg80211_p2p_attach_out:
        wl_deinit_priv(cfg);
 
 cfg80211_attach_out:
-       brcmf_free_vif(cfg, vif);
+       brcmf_free_vif(vif);
        return NULL;
 }
 
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
 {
-       struct brcmf_cfg80211_vif *vif;
-       struct brcmf_cfg80211_vif *tmp;
+       if (!cfg)
+               return;
 
-       wl_deinit_priv(cfg);
+       WARN_ON(!list_empty(&cfg->vif_list));
+       wiphy_unregister(cfg->wiphy);
        brcmf_btcoex_detach(cfg);
-       list_for_each_entry_safe(vif, tmp, &cfg->vif_list, list) {
-               brcmf_free_vif(cfg, vif);
-       }
+       wl_deinit_priv(cfg);
+       wiphy_free(cfg->wiphy);
 }
 
 static s32
@@ -5087,7 +5089,8 @@ dongle_scantime_out:
 }
 
 
-static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
+static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg,
+                                  u32 bw_cap[])
 {
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
        struct ieee80211_channel *band_chan_arr;
@@ -5100,7 +5103,6 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
        enum ieee80211_band band;
        u32 channel;
        u32 *n_cnt;
-       bool ht40_allowed;
        u32 index;
        u32 ht40_flag;
        bool update;
@@ -5133,18 +5135,17 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                        array_size = ARRAY_SIZE(__wl_2ghz_channels);
                        n_cnt = &__wl_band_2ghz.n_channels;
                        band = IEEE80211_BAND_2GHZ;
-                       ht40_allowed = (bw_cap == WLC_N_BW_40ALL);
                } else if (ch.band == BRCMU_CHAN_BAND_5G) {
                        band_chan_arr = __wl_5ghz_a_channels;
                        array_size = ARRAY_SIZE(__wl_5ghz_a_channels);
                        n_cnt = &__wl_band_5ghz_a.n_channels;
                        band = IEEE80211_BAND_5GHZ;
-                       ht40_allowed = !(bw_cap == WLC_N_BW_20ALL);
                } else {
-                       brcmf_err("Invalid channel Sepc. 0x%x.\n", ch.chspec);
+                       brcmf_err("Invalid channel Spec. 0x%x.\n", ch.chspec);
                        continue;
                }
-               if (!ht40_allowed && ch.bw == BRCMU_CHAN_BW_40)
+               if (!(bw_cap[band] & WLC_BW_40MHZ_BIT) &&
+                   ch.bw == BRCMU_CHAN_BW_40)
                        continue;
                update = false;
                for (j = 0; (j < *n_cnt && (*n_cnt < array_size)); j++) {
@@ -5162,7 +5163,10 @@ static s32 brcmf_construct_reginfo(struct brcmf_cfg80211_info *cfg, u32 bw_cap)
                                ieee80211_channel_to_frequency(ch.chnum, band);
                        band_chan_arr[index].hw_value = ch.chnum;
 
-                       if (ch.bw == BRCMU_CHAN_BW_40 && ht40_allowed) {
+                       brcmf_err("channel %d: f=%d bw=%d sb=%d\n",
+                                 ch.chnum, band_chan_arr[index].center_freq,
+                                 ch.bw, ch.sb);
+                       if (ch.bw == BRCMU_CHAN_BW_40) {
                                /* assuming the order is HT20, HT40 Upper,
                                 * HT40 lower from chanspecs
                                 */
@@ -5213,6 +5217,46 @@ exit:
        return err;
 }
 
+static void brcmf_get_bwcap(struct brcmf_if *ifp, u32 bw_cap[])
+{
+       u32 band, mimo_bwcap;
+       int err;
+
+       band = WLC_BAND_2G;
+       err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+       if (!err) {
+               bw_cap[IEEE80211_BAND_2GHZ] = band;
+               band = WLC_BAND_5G;
+               err = brcmf_fil_iovar_int_get(ifp, "bw_cap", &band);
+               if (!err) {
+                       bw_cap[IEEE80211_BAND_5GHZ] = band;
+                       return;
+               }
+               WARN_ON(1);
+               return;
+       }
+       brcmf_dbg(INFO, "fallback to mimo_bw_cap info\n");
+       mimo_bwcap = 0;
+       err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &mimo_bwcap);
+       if (err)
+               /* assume 20MHz if firmware does not give a clue */
+               mimo_bwcap = WLC_N_BW_20ALL;
+
+       switch (mimo_bwcap) {
+       case WLC_N_BW_40ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20IN2G_40IN5G:
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_40MHZ_BIT;
+               /* fall-thru */
+       case WLC_N_BW_20ALL:
+               bw_cap[IEEE80211_BAND_2GHZ] |= WLC_BW_20MHZ_BIT;
+               bw_cap[IEEE80211_BAND_5GHZ] |= WLC_BW_20MHZ_BIT;
+               break;
+       default:
+               brcmf_err("invalid mimo_bw_cap value\n");
+       }
+}
 
 static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
 {
@@ -5221,13 +5265,13 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        s32 phy_list;
        u32 band_list[3];
        u32 nmode;
-       u32 bw_cap = 0;
+       u32 bw_cap[2] = { 0, 0 };
        s8 phy;
        s32 err;
        u32 nband;
        s32 i;
-       struct ieee80211_supported_band *bands[IEEE80211_NUM_BANDS];
-       s32 index;
+       struct ieee80211_supported_band *bands[2] = { NULL, NULL };
+       struct ieee80211_supported_band *band;
 
        err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
                                     &phy_list, sizeof(phy_list));
@@ -5253,11 +5297,10 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        if (err) {
                brcmf_err("nmode error (%d)\n", err);
        } else {
-               err = brcmf_fil_iovar_int_get(ifp, "mimo_bw_cap", &bw_cap);
-               if (err)
-                       brcmf_err("mimo_bw_cap error (%d)\n", err);
+               brcmf_get_bwcap(ifp, bw_cap);
        }
-       brcmf_dbg(INFO, "nmode=%d, mimo_bw_cap=%d\n", nmode, bw_cap);
+       brcmf_dbg(INFO, "nmode=%d, bw_cap=(%d, %d)\n", nmode,
+                 bw_cap[IEEE80211_BAND_2GHZ], bw_cap[IEEE80211_BAND_5GHZ]);
 
        err = brcmf_construct_reginfo(cfg, bw_cap);
        if (err) {
@@ -5266,40 +5309,33 @@ static s32 brcmf_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        }
 
        nband = band_list[0];
-       memset(bands, 0, sizeof(bands));
 
        for (i = 1; i <= nband && i < ARRAY_SIZE(band_list); i++) {
-               index = -1;
+               band = NULL;
                if ((band_list[i] == WLC_BAND_5G) &&
-                   (__wl_band_5ghz_a.n_channels > 0)) {
-                       index = IEEE80211_BAND_5GHZ;
-                       bands[index] = &__wl_band_5ghz_a;
-                       if ((bw_cap == WLC_N_BW_40ALL) ||
-                           (bw_cap == WLC_N_BW_20IN2G_40IN5G))
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               } else if ((band_list[i] == WLC_BAND_2G) &&
-                          (__wl_band_2ghz.n_channels > 0)) {
-                       index = IEEE80211_BAND_2GHZ;
-                       bands[index] = &__wl_band_2ghz;
-                       if (bw_cap == WLC_N_BW_40ALL)
-                               bands[index]->ht_cap.cap |=
-                                                       IEEE80211_HT_CAP_SGI_40;
-               }
+                   (__wl_band_5ghz_a.n_channels > 0))
+                       band = &__wl_band_5ghz_a;
+               else if ((band_list[i] == WLC_BAND_2G) &&
+                        (__wl_band_2ghz.n_channels > 0))
+                       band = &__wl_band_2ghz;
+               else
+                       continue;
 
-               if ((index >= 0) && nmode) {
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
-                       bands[index]->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
-                       bands[index]->ht_cap.ht_supported = true;
-                       bands[index]->ht_cap.ampdu_factor =
-                                               IEEE80211_HT_MAX_AMPDU_64K;
-                       bands[index]->ht_cap.ampdu_density =
-                                               IEEE80211_HT_MPDU_DENSITY_16;
-                       /* An HT shall support all EQM rates for one spatial
-                        * stream
-                        */
-                       bands[index]->ht_cap.mcs.rx_mask[0] = 0xff;
+               if (bw_cap[band->band] & WLC_BW_40MHZ_BIT) {
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_40;
+                       band->ht_cap.cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40;
                }
+               band->ht_cap.cap |= IEEE80211_HT_CAP_SGI_20;
+               band->ht_cap.cap |= IEEE80211_HT_CAP_DSSSCCK40;
+               band->ht_cap.ht_supported = true;
+               band->ht_cap.ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+               band->ht_cap.ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+               /* An HT shall support all EQM rates for one spatial
+                * stream
+                */
+               band->ht_cap.mcs.rx_mask[0] = 0xff;
+               band->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+               bands[band->band] = band;
        }
 
        wiphy = cfg_to_wiphy(cfg);
index d9bdaf9a72d0fd2d606a5ab041a6e283aec5770e..2dc6a074e8ede14c4d3709a2d899c390e1bd421c 100644 (file)
@@ -412,7 +412,6 @@ struct brcmf_cfg80211_info {
        struct work_struct escan_timeout_work;
        u8 *escan_ioctl_buf;
        struct list_head vif_list;
-       u8 vif_cnt;
        struct brcmf_cfg80211_vif_event vif_event;
        struct completion vif_disabled;
        struct brcmu_d11inf d11inf;
@@ -487,8 +486,7 @@ enum nl80211_iftype brcmf_cfg80211_get_iftype(struct brcmf_if *ifp);
 struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg,
                                           enum nl80211_iftype type,
                                           bool pm_block);
-void brcmf_free_vif(struct brcmf_cfg80211_info *cfg,
-                   struct brcmf_cfg80211_vif *vif);
+void brcmf_free_vif(struct brcmf_cfg80211_vif *vif);
 
 s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
                          const u8 *vndr_ie_buf, u32 vndr_ie_len);
@@ -507,5 +505,6 @@ s32 brcmf_notify_escan_complete(struct brcmf_cfg80211_info *cfg,
                                bool fw_abort);
 void brcmf_set_mpc(struct brcmf_if *ndev, int mpc);
 void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg);
+void brcmf_cfg80211_free_netdev(struct net_device *ndev);
 
 #endif                         /* _wl_cfg80211_h_ */
index 84113ea16f8434fcd0ee4383aeea18c0dfe9c480..6fa5d4863782ea2575089583270186c015b810fa 100644 (file)
@@ -41,6 +41,7 @@
 #define BCM4331_CHIP_ID                0x4331
 #define BCM4334_CHIP_ID                0x4334
 #define BCM4335_CHIP_ID                0x4335
+#define BCM43362_CHIP_ID       43362
 #define BCM4339_CHIP_ID                0x4339
 
 #endif                         /* _BRCM_HW_IDS_H_ */
index 0505cc065e0d6d18ae3c292ab234a7e8b9761ba8..7ca2aa1035b2101d1d8129c1ca480724863dd507 100644 (file)
 #define WLC_N_BW_40ALL                 1
 #define WLC_N_BW_20IN2G_40IN5G         2
 
+#define WLC_BW_20MHZ_BIT               BIT(0)
+#define WLC_BW_40MHZ_BIT               BIT(1)
+#define WLC_BW_80MHZ_BIT               BIT(2)
+#define WLC_BW_160MHZ_BIT              BIT(3)
+
+/* Bandwidth capabilities */
+#define WLC_BW_CAP_20MHZ               (WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_40MHZ               (WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_80MHZ               (WLC_BW_80MHZ_BIT|WLC_BW_40MHZ_BIT| \
+                                        WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_160MHZ              (WLC_BW_160MHZ_BIT|WLC_BW_80MHZ_BIT| \
+                                        WLC_BW_40MHZ_BIT|WLC_BW_20MHZ_BIT)
+#define WLC_BW_CAP_UNRESTRICTED                0xFF
+
 /* band types */
 #define        WLC_BAND_AUTO                   0       /* auto-select */
 #define        WLC_BAND_5G                     1       /* 5 Ghz */
index acdff0f7f952e03fa25b51b47a9e83eda37d85c6..5a9ffd3a6a6caa0d1c98a27cc238de4e8e5047cb 100644 (file)
@@ -14,7 +14,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/vmalloc.h>
 #include <linux/sched.h>
 #include <linux/firmware.h>
index 090f01577dd25314651156c551a8f48299f9a852..d1270da4dfeae0ee869de0a9f3d612a9c7ac757f 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
index b37abb9f0453b1ca530fd3f11e746b8558cc3054..6907c8fd4578d001293eaf77d4c1dbad6b96177f 100644 (file)
@@ -225,7 +225,7 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                cw1200_set_pm(priv, &priv->powersave_mode);
                if (wait_event_interruptible_timeout(priv->ps_mode_switch_done,
                                                     !priv->ps_mode_switch_in_progress, 1*HZ) <= 0) {
-                       goto revert3;
+                       goto revert4;
                }
        }
 
@@ -254,11 +254,11 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        /* Stop serving thread */
        if (cw1200_bh_suspend(priv))
-               goto revert4;
+               goto revert5;
 
        ret = timer_pending(&priv->mcast_timeout);
        if (ret)
-               goto revert5;
+               goto revert6;
 
        /* Store suspend state */
        pm_state->suspend_state = state;
@@ -280,9 +280,9 @@ int cw1200_wow_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
 
        return 0;
 
-revert5:
+revert6:
        WARN_ON(cw1200_bh_resume(priv));
-revert4:
+revert5:
        cw1200_resume_work(priv, &priv->bss_loss_work,
                           state->bss_loss_tmo);
        cw1200_resume_work(priv, &priv->join_timeout,
@@ -291,6 +291,7 @@ revert4:
                           state->direct_probe);
        cw1200_resume_work(priv, &priv->link_id_gc_work,
                           state->link_id_gc);
+revert4:
        kfree(state);
 revert3:
        wsm_set_udp_port_filter(priv, &cw1200_udp_port_filter_off);
index 56cd01ca8ad0b15394017a8f298760e769ed8043..9f825f2620da749ca2d8090c55171eb021bcf77a 100644 (file)
@@ -1,7 +1,6 @@
 #define PRISM2_PCCARD
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/slab.h>
 #include <linux/wait.h>
index e5090309824e53c04d1961c0fd6993e80c5aa61e..63e350affc7ed3b11b2928ddb0e634cd57c54d07 100644 (file)
@@ -2567,7 +2567,7 @@ static int prism2_ioctl_priv_prism2_param(struct net_device *dev,
                local->passive_scan_interval = value;
                if (timer_pending(&local->passive_scan_timer))
                        del_timer(&local->passive_scan_timer);
-               if (value > 0) {
+               if (value > 0 && value < INT_MAX / HZ) {
                        local->passive_scan_timer.expires = jiffies +
                                local->passive_scan_interval * HZ;
                        add_timer(&local->passive_scan_timer);
index 05ca3402dca707d8cca9eb9f1d5432fdc44b3b7b..91158e2e961c62a96ceb8c28aaa2bef09cde8017 100644 (file)
@@ -5,7 +5,6 @@
  * Andy Warner <andyw@pobox.com> */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index c3d067ee4db9cdbd2f34e3d5ede9461abe28f59c..3bf530d9a40f1bb2c80c877ee35ac42a76a337b0 100644 (file)
@@ -8,7 +8,6 @@
 
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index 570d6fb889671b514a996bc468eab1ac39efcb31..aa301d1eee3cbe50435e48f6fdf5ba84ed7f22d4 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/mutex.h>
 
index 9ffe65931b293e4d6e4dd1f685dd75376e8dce96..ce2785948be15f0a513d857f1f171d629de7b6e2 100644 (file)
@@ -1468,7 +1468,7 @@ static inline int is_same_network(struct libipw_network *src,
         * as one network */
        return ((src->ssid_len == dst->ssid_len) &&
                (src->channel == dst->channel) &&
-               ether_addr_equal(src->bssid, dst->bssid) &&
+               ether_addr_equal_64bits(src->bssid, dst->bssid) &&
                !memcmp(src->ssid, dst->ssid, src->ssid_len));
 }
 
index aea667b430c3ac7e70295562f33de2227813a198..9a45f6f626f69633c938bd386242cdacff6496e7 100644 (file)
@@ -25,7 +25,6 @@
  *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index f09e257759d5a930cfdaa1c2a69484355677403f..d37a6fd90d400a6dfd90d20cdf02d73e7e536d42 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
@@ -466,10 +465,10 @@ il3945_is_network_packet(struct il_priv *il, struct ieee80211_hdr *header)
        switch (il->iw_mode) {
        case NL80211_IFTYPE_ADHOC:      /* Header: Dest. | Source    | BSSID */
                /* packets to our IBSS update information */
-               return ether_addr_equal(header->addr3, il->bssid);
+               return ether_addr_equal_64bits(header->addr3, il->bssid);
        case NL80211_IFTYPE_STATION:    /* Header: Dest. | AP{BSSID} | Source */
                /* packets to our IBSS update information */
-               return ether_addr_equal(header->addr2, il->bssid);
+               return ether_addr_equal_64bits(header->addr2, il->bssid);
        default:
                return 1;
        }
index 3ccbaf791b48bfea34d3053d4d7d3cce6e165b22..4d5e33259ca894d66fe2edc997b8d3ed6580467b 100644 (file)
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index 777a578294bdc3ff35712b1a83261de7c46c24ce..fe47db9c20cd2428549b6c520920abed84140487 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index a27b14cfeaec05753bb64fe8708ec7c25065995c..02e8233ccf29865e988eed0be9036c7dfc2179c8 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <linux/lockdep.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
@@ -3746,10 +3745,10 @@ il_full_rxon_required(struct il_priv *il)
 
        /* These items are only settable from the full RXON command */
        CHK(!il_is_associated(il));
-       CHK(!ether_addr_equal(staging->bssid_addr, active->bssid_addr));
-       CHK(!ether_addr_equal(staging->node_addr, active->node_addr));
-       CHK(!ether_addr_equal(staging->wlap_bssid_addr,
-                             active->wlap_bssid_addr));
+       CHK(!ether_addr_equal_64bits(staging->bssid_addr, active->bssid_addr));
+       CHK(!ether_addr_equal_64bits(staging->node_addr, active->node_addr));
+       CHK(!ether_addr_equal_64bits(staging->wlap_bssid_addr,
+                                    active->wlap_bssid_addr));
        CHK_NEQ(staging->dev_type, active->dev_type);
        CHK_NEQ(staging->channel, active->channel);
        CHK_NEQ(staging->air_propagation, active->air_propagation);
index 23d5f0275ce98e1cde6c05e7b9a1654c870774ea..562772d851021e390575868ece4f3fbf04068ede 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1b0f0d502568700d096215b92fc1a1dce1afeb19..be1086c87157c158834d622546e8bfc2b25b7dff 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cfddde194940e2a183c1685bf4eb445a4550f9b9..aeae4e80ea402d475c5df89481a8e377ccf10397 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ebdac909f0cd750bffbe2b46bd49ea4975079340..751ae1d10b7f6d27650e1a1a966a65651dd2ca30 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f69301e505ee0e8968d5a9b90f9dcb3404c1f843..d2fe2596d54ec4525a7661a9b381f3e5352bae61 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 7434d9edf3b773566530b79eb542a8431bbfb24c..3441f70d0ff911594dfd4066e782f0ca042e02d6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 352c6cb7b4f17d5b85facf619839f93beaec5ade..7b140e487deb8da42a19d669e4428830516470c6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 33c7e15d24f5c64584e1f3c870a6d3a851258751..ca4d6692cc4eb94907cfe32acd227df07f57046a 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -27,7 +27,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
index 8749dcfe695fd22407fbeb653a5fa249c9832e36..6a0817d9c4fa05f15e1ceffd4272925451994f80 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 3d5bdc4217a8901a3c4fb46ad6ffc091809bf9b4..576f7ee38ca5894150cba0e54eff4bcc5ff2f079 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -29,7 +29,6 @@
 #include <linux/etherdevice.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <net/mac80211.h>
 
index 9f4239d31c088a8d58406b11283c83779cc4e4ea..40eb5e691475c5280c718893ec084fa2454e4d1c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -28,7 +28,6 @@
  *****************************************************************************/
 #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>
index fd9f6cf96cfdd29f199383927f82fb6f6624be8b..ba1b1ea54252c8d1ce9018263c42ef88fca9d50f 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
index 77cb59712235035c689034575bfd58794b933245..b4e61417013aff585bf8dcfa33b8fa9e3c5c84c6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <net/mac80211.h>
 #include "iwl-io.h"
 #include "iwl-debug.h"
index 7b03e1342d47076aa0ad8cf662e543c45b1e8be1..570d3a5e4670058dbb68b278e0b682e2a008ce9c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
index b647e506564cb78cd6117a70c0e09a3036c69d7b..0977d93b529d3ce11fde93ac1e1c4ff626415a13 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index 41988f4b8a5add9ec1c2f87617f8cc64913cd8dc..bdd5644a400bc780a2c7fed99dca5b482a1cdcd9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index d71776dd1e6adcc16a0a9baa7e557588b2e1b27c..b68bb2f4d2c22c08c3590ca2839f7912550bfa6a 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project, as well
  * as portionhelp of the ieee80211 subsystem header files.
index d7ce2f12a90724a4e4b046908311c3ff1a35a1f4..503a81e581855729fde646408a8ae33b0195539f 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 928f8640a0a7965aebfb5c429265ac71a4970f88..be98b913ed582046d6598d0cf7454cf3bd8278cc 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index c3c13ce96eb0f6217ae3971a389d0bcc7e041528..c0d070c5df5ed73e14a64e141d6a7d2f2a3133b6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
index fbeee081ee2fccde51f0a227f6d9053f472722af..058c5892c427afdf3df48038bf8e715017d379c6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <net/mac80211.h>
 #include "iwl-io.h"
 #include "iwl-modparams.h"
index 9356c4b908ca58b55652843e6b7c7e5a43895f9e..507726534b845674655be7469f4f8ca85ee29a87 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 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.
index e12b1a63c484635f64a23f0e27904045a8185cc2..a6839dfcb82dd75029c1e377bbebb078464a8792 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -29,7 +29,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ieee80211.h>
 #include "iwl-io.h"
index 63637949a146d65246f9d2da0381ec8697e6e4a9..f59709a9b79d6ba95ac26e6a8a1f9ee51586e3d5 100644 (file)
@@ -2,7 +2,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -28,7 +28,6 @@
  *****************************************************************************/
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 
 #include "iwl-io.h"
 #include "iwl-agn-hw.h"
index 0d2afe098afce81d1000d658bee9f788b632f797..854ba84ccb730995f0d786d26a85a1c2fc14c0dc 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index c727ec7c90a65ec1f760c6e0cc53b3af026850e4..3e63323637f3f593dd895528dac4e5fb794fdb4c 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index ecc01e1a61a1d14107ca523c6fd7339fe380c5d8..6674f2c4541c183fbae6c2a1bb0861d9eb3a966f 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 8ac305be68f489be533606cb8260dbfd4dc5cfda..8048de90233fa038545e9d752eaaffbfc3968c72 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 5fb37724c096fb879b601770356050a6b16f0d72..2a59da2ff87aaf278b65983e1735cbc1eeb49d2d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 6d73f943cefafb2dfb2489b4f1b31a846f833230..7f37fb86837b7a46569ba74f90df0a7bdb8d0271 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e05440ff5cd46d2c4add28faab7255b97c88b7f2..1ced525157dc20b6c5ed0546a4ee762cfbcd6784 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index da4eca8b3007feabb267a1710c95a70306224455..9d325516c42d80111eb2336c2ffe1a4b1f2c3d99 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
                                 CSR_INT_BIT_RF_KILL | \
                                 CSR_INT_BIT_SW_RX   | \
                                 CSR_INT_BIT_WAKEUP  | \
-                                CSR_INT_BIT_ALIVE)
+                                CSR_INT_BIT_ALIVE   | \
+                                CSR_INT_BIT_RX_PERIODIC)
 
 /* interrupt flags in FH (flow handler) (PCI busmaster DMA) */
 #define CSR_FH_INT_BIT_ERR       (1 << 31) /* Error */
index b2bb32a781ddd9675efe77da6e4d164de45d0b60..a75aac986a23ebd80872f9164ee45d1b1e96e4bd 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index 8f61c717f619c4fc0e979c6c57c005529550529e..23e7351e02decaa49026b8f628c67990f1607d2a 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 684c416d34936c5ecdb6451f2d3707babae6b180..78bd41bf34b0f04dac4d056d470ac30a80b212c8 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2009 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 4bebfb58fc7be083f72e0492b3b0aa4df7f34710..c3728163be463224b4e3eb38b5573aa85370e193 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 429337a2b9a15189c0c0fefc94389a884e3b43f3..592c01e11013c3ce74264f49951c29eff84610c4 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -67,7 +67,7 @@
 /* for all modules */
 #define DRV_NAME        "iwlwifi"
 #define IWLWIFI_VERSION "in-tree:"
-#define DRV_COPYRIGHT  "Copyright(c) 2003-2013 Intel Corporation"
+#define DRV_COPYRIGHT  "Copyright(c) 2003- 2014 Intel Corporation"
 #define DRV_AUTHOR     "<ilw@linux.intel.com>"
 
 
index 4380c16580ebe4303b6bd8a679686c2c6ef94cc4..c44cf1149648860e4e8faa4630140e8bb76ae6b3 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d73304a23ec203dbdf1df8cc65e7092b2d5aaa37..e3c7deafabe6e71abd012751a59655aa977ef980 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e5f2e362ab0b293665636aad41f844e29dfbf34e..25d0105741dbee2b1a292d10c1b6cc56ce3f41d5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8e941f8bd7d62158dc92e5a102b54b71b047e174..a6d3bdf82cdd47133686f647450dab3cd437c0cd 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 484d318245fb91e21705a7c11dad7c30d66d69d7..9564ae173d060a46bd34c60970ce77d6eb483a73 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4f95734b28118b93e3b144c58e1b41aa682b9890..88e2d6eb569f4f23ba7696178ffe96135dfdb508 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8704e3042ca137a8bd4e647c70411f964a8b47ff..5f1493c44097c5fc0543e0c886a96b9180522841 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ad8e19a56eca034bf231c001ba16c0775fa047a3..f98175a0d35b7e508c0e71b7fa10c8c0fc7c22e1 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index 63d10ec08dbc2f894ea769169d17d0be2027a4c4..c339c1bed08056fe217c54c0825404d9618b2768 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * Portions of this file are derived from the ipw3945 project.
  *
index a1f580c0c6c6e9e80164421e157eb82b67fa007c..0a84ade7edac25b01d28df63158669083c442b8c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 940b8a9d5285ad7a54ecd3cce7623bc19e59a0b6..b5bc959b1dfe0bed54cf9423c6f01c23e332062e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2e2f1c8c99f989023ab80a1244eb5b5b55164810..95af97a6c2cfa3886b6aa4fa5f1bb1213854cdf7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a48decc6c68f9d9291cf68bdf9e61d0a403c6218..1b61cb5299484d79aee36d27e9a4647b05bd1866 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 3325059c52d49d97c289fab319946fddd0a40c57..0c4399aba8c6bfcbbee990f964296543563dfbe1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2008 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2008 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f50e6c62ebc5b7dd7e6b009e3da82503a14794b5..b5be51f3cd3d15c669e92e9de2ef95749cdb33aa 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1a405ae6a9c59a00f95936f25bb2602abf1751d7..fa77d63a277a393e913e154a1323237801496cee 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index ce983af79644310050a11297813927e3ece3fecf..9ee18d0d2d01ab40693410cacfff9f50cc8dcff7 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f6412dae26590cbf2f66ae774b11aaf402721179..d69b0fb0a434086eff6cf0a5cb8ea34f69c81e6b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0c3647858909dc53ce1697072cce6d9947808633..8d1b5ed3502a486258b8e4bc384e07effb834b33 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -622,6 +622,10 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
 {
        int ret;
 
+       if (unlikely(!(cmd->flags & CMD_SEND_IN_RFKILL) &&
+                    test_bit(STATUS_RFKILL, &trans->status)))
+               return -ERFKILL;
+
        if (unlikely(test_bit(STATUS_FW_ERROR, &trans->status)))
                return -EIO;
 
@@ -684,9 +688,6 @@ static inline void iwl_trans_reclaim(struct iwl_trans *trans, int queue,
 
 static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue)
 {
-       if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
-               IWL_ERR(trans, "%s bad state = %d", __func__, trans->state);
-
        trans->ops->txq_disable(trans, queue);
 }
 
index 57d3eed86efa99edbf4c729f41db9d0fb6b89c5c..a1376539d2dc7a0af9563ff3716745e693f4384e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d126245c48dea219d2161221a56dd0709cfd35f8..76cde6ce6551dc0a9996a91edc36cad5b40e5588 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -294,9 +294,9 @@ static const __le64 iwl_ci_mask[][3] = {
                cpu_to_le64(0x0)
        },
        {
-               cpu_to_le64(0xFE00000000ULL),
+               cpu_to_le64(0xFFC0000000ULL),
                cpu_to_le64(0x0ULL),
-               cpu_to_le64(0x0)
+               cpu_to_le64(0x0ULL)
        },
 };
 
index 4b6d670c35092d18679e8437ce5dbeb14ecf7702..036857698565809b302b6043032cf0793c45d171 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 665f87e788d6ec2a78e9ab1ba6a3af8795c2c752..f04d2f4d80cde5bccf2a12b0ce000e15633dc16d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b8667575bc109046fae37001c7776958e664ab7c..0e29cd83a06a83c158860a5523549edf7e3c44db 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index e8f62a6a1b57098a3f456e9beff974f7caa3493c..76cdce9edf55de251eebf46b30d5d605de0cc250 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -123,51 +123,31 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 {
        struct iwl_mvm *mvm = file->private_data;
        const struct fw_img *img;
-       int ofs, len, pos = 0;
-       size_t bufsz, ret;
-       char *buf;
+       unsigned int ofs, len;
+       size_t ret;
        u8 *ptr;
 
        if (!mvm->ucode_loaded)
                return -EINVAL;
 
        /* default is to dump the entire data segment */
+       img = &mvm->fw->img[mvm->cur_ucode];
+       ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
+       len = img->sec[IWL_UCODE_SECTION_DATA].len;
+
        if (!mvm->dbgfs_sram_offset && !mvm->dbgfs_sram_len) {
-               img = &mvm->fw->img[mvm->cur_ucode];
-               ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
-               len = img->sec[IWL_UCODE_SECTION_DATA].len;
-       } else {
                ofs = mvm->dbgfs_sram_offset;
                len = mvm->dbgfs_sram_len;
        }
 
-       bufsz = len * 4 + 256;
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
        ptr = kzalloc(len, GFP_KERNEL);
-       if (!ptr) {
-               kfree(buf);
+       if (!ptr)
                return -ENOMEM;
-       }
-
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_len: 0x%x\n", len);
-       pos += scnprintf(buf + pos, bufsz - pos, "sram_offset: 0x%x\n", ofs);
 
        iwl_trans_read_mem_bytes(mvm->trans, ofs, ptr, len);
-       for (ofs = 0; ofs < len; ofs += 16) {
-               pos += scnprintf(buf + pos, bufsz - pos, "0x%.4x ", ofs);
-               hex_dump_to_buffer(ptr + ofs, 16, 16, 1, buf + pos,
-                                  bufsz - pos, false);
-               pos += strlen(buf + pos);
-               if (bufsz - pos > 0)
-                       buf[pos++] = '\n';
-       }
 
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       ret = simple_read_from_buffer(user_buf, count, ppos, ptr, len);
 
-       kfree(buf);
        kfree(ptr);
 
        return ret;
@@ -176,11 +156,24 @@ static ssize_t iwl_dbgfs_sram_read(struct file *file, char __user *user_buf,
 static ssize_t iwl_dbgfs_sram_write(struct iwl_mvm *mvm, char *buf,
                                    size_t count, loff_t *ppos)
 {
+       const struct fw_img *img;
        u32 offset, len;
+       u32 img_offset, img_len;
+
+       if (!mvm->ucode_loaded)
+               return -EINVAL;
+
+       img = &mvm->fw->img[mvm->cur_ucode];
+       img_offset = img->sec[IWL_UCODE_SECTION_DATA].offset;
+       img_len = img->sec[IWL_UCODE_SECTION_DATA].len;
 
        if (sscanf(buf, "%x,%x", &offset, &len) == 2) {
                if ((offset & 0x3) || (len & 0x3))
                        return -EINVAL;
+
+               if (offset + len > img_offset + img_len)
+                       return -EINVAL;
+
                mvm->dbgfs_sram_offset = offset;
                mvm->dbgfs_sram_len = len;
        } else {
index 85f9f958bfd2d1d0ee7bdb807c6b71b134a468fd..e3a9774af495d3ac814f24e923d10e124afbf2ca 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index af500996bbf140e8422f7e6b17e4cf12253c3f8f..1b4e54d416b044e2563e9e810f3a07b12ffee262 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4e7dd8cf87dce738cbe062d931dcabe49ce67a51..8415ff312d0eec8139bae02fcdb1e45e1ee49284 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 39c3148bdfa8eff2a09a7641b317f8a8a1648da9..c405cda1025fa4b745b541d65b679bca1dd01253 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index cb78e5539357646089e0db87d7470fcbe8fb681c..884c0872530883ae55646b0c177d9d2ae172e1da 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 532312c7b93718d3c3a245b893c999459ea90834..85057219cc43ff4c4edbd3e606a9254dae9772e5 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b3ed59237cbadfca46f609daec46812ee72ff7e3..73cbba7424f2be42e5278f85c4e3f54289d06280 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 8c73ba74b6fd1ec1f53cee998492951ccfa51783..6bbbad453a3b78359a8f2c435ca63cb6a685ba91 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 22864671d66c4115c415a1cf38460fc9d6ecffff..b674c2a2b51c8910b47811ad73ed876a58fb22f2 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 1c3079714c2b766f1fabe811027edf620afe6df6..989d7dbdca6c31f4a13bb9e70a6cf9a669cf9d33 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 27ba104a3540e36b23968e0f86f652ea93d0ab4b..c03d39541f9ee50d7f179982d4a688d3f90c4246 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2269a9e5cc6724832d384b031d5907dabcaf4597..6b4ea6bf8ffeaf13273b1f79ec46057290254e31 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -103,7 +103,7 @@ int iwl_mvm_leds_init(struct iwl_mvm *mvm)
                return 0;
        default:
                return -EINVAL;
-       };
+       }
 
        mvm->led.name = kasprintf(GFP_KERNEL, "%s-led",
                                   wiphy_name(mvm->hw->wiphy));
index fb93961da7500bf1ada5668fb86ef5d4b17c152a..ba723d50939a5582ea3aaf02c8d1fa4e9ae7388c 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "mvm.h"
 
 const u8 iwl_mvm_ac_to_tx_fifo[] = {
-       IWL_MVM_TX_FIFO_BK,
-       IWL_MVM_TX_FIFO_BE,
-       IWL_MVM_TX_FIFO_VI,
        IWL_MVM_TX_FIFO_VO,
+       IWL_MVM_TX_FIFO_VI,
+       IWL_MVM_TX_FIFO_BE,
+       IWL_MVM_TX_FIFO_BK,
 };
 
 struct iwl_mvm_mac_iface_iterator_data {
@@ -85,35 +85,15 @@ struct iwl_mvm_mac_iface_iterator_data {
        bool found_vif;
 };
 
-static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
-                                      struct ieee80211_vif *vif)
+static void iwl_mvm_mac_tsf_id_iter(void *_data, u8 *mac,
+                                   struct ieee80211_vif *vif)
 {
        struct iwl_mvm_mac_iface_iterator_data *data = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
-       u32 ac;
 
-       /* Iterator may already find the interface being added -- skip it */
-       if (vif == data->vif) {
-               data->found_vif = true;
+       /* Skip the interface for which we are trying to assign a tsf_id  */
+       if (vif == data->vif)
                return;
-       }
-
-       /* Mark the queues used by the vif */
-       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
-               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
-                       __set_bit(vif->hw_queue[ac], data->used_hw_queues);
-
-       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
-               __set_bit(vif->cab_queue, data->used_hw_queues);
-
-       /*
-        * Mark MAC IDs as used by clearing the available bit, and
-        * (below) mark TSFs as used if their existing use is not
-        * compatible with the new interface type.
-        * No locking or atomic bit operations are needed since the
-        * data is on the stack of the caller function.
-        */
-       __clear_bit(mvmvif->id, data->available_mac_ids);
 
        /*
         * The TSF is a hardware/firmware resource, there are 4 and
@@ -135,21 +115,26 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
        case NL80211_IFTYPE_STATION:
                /*
                 * The new interface is client, so if the existing one
-                * we're iterating is an AP, the TSF should be used to
+                * we're iterating is an AP, and both interfaces have the
+                * same beacon interval, the same TSF should be used to
                 * avoid drift between the new client and existing AP,
                 * the existing AP will get drift updates from the new
                 * client context in this case
                 */
                if (vif->type == NL80211_IFTYPE_AP) {
                        if (data->preferred_tsf == NUM_TSF_IDS &&
-                           test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+                           test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
+                           (vif->bss_conf.beacon_int ==
+                            data->vif->bss_conf.beacon_int)) {
                                data->preferred_tsf = mvmvif->tsf_id;
-                       return;
+                               return;
+                       }
                }
                break;
        case NL80211_IFTYPE_AP:
                /*
-                * The new interface is AP/GO, so should get drift
+                * The new interface is AP/GO, so in case both interfaces
+                * have the same beacon interval, it should get drift
                 * updates from an existing client or use the same
                 * TSF as an existing GO. There's no drift between
                 * TSFs internally but if they used different TSFs
@@ -159,9 +144,12 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
                if (vif->type == NL80211_IFTYPE_STATION ||
                    vif->type == NL80211_IFTYPE_AP) {
                        if (data->preferred_tsf == NUM_TSF_IDS &&
-                           test_bit(mvmvif->tsf_id, data->available_tsf_ids))
+                           test_bit(mvmvif->tsf_id, data->available_tsf_ids) &&
+                           (vif->bss_conf.beacon_int ==
+                            data->vif->bss_conf.beacon_int)) {
                                data->preferred_tsf = mvmvif->tsf_id;
-                       return;
+                               return;
+                       }
                }
                break;
        default:
@@ -187,6 +175,39 @@ static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
                data->preferred_tsf = NUM_TSF_IDS;
 }
 
+static void iwl_mvm_mac_iface_iterator(void *_data, u8 *mac,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_mac_iface_iterator_data *data = _data;
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       u32 ac;
+
+       /* Iterator may already find the interface being added -- skip it */
+       if (vif == data->vif) {
+               data->found_vif = true;
+               return;
+       }
+
+       /* Mark the queues used by the vif */
+       for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
+               if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+                       __set_bit(vif->hw_queue[ac], data->used_hw_queues);
+
+       if (vif->cab_queue != IEEE80211_INVAL_HW_QUEUE)
+               __set_bit(vif->cab_queue, data->used_hw_queues);
+
+       /* Mark MAC IDs as used by clearing the available bit, and
+        * (below) mark TSFs as used if their existing use is not
+        * compatible with the new interface type.
+        * No locking or atomic bit operations are needed since the
+        * data is on the stack of the caller function.
+        */
+       __clear_bit(mvmvif->id, data->available_mac_ids);
+
+       /* find a suitable tsf_id */
+       iwl_mvm_mac_tsf_id_iter(_data, mac, vif);
+}
+
 /*
  * Get the mask of the queus used by the vif
  */
@@ -205,6 +226,29 @@ u32 iwl_mvm_mac_get_queues_mask(struct iwl_mvm *mvm,
        return qmask;
 }
 
+void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       struct iwl_mvm_mac_iface_iterator_data data = {
+               .mvm = mvm,
+               .vif = vif,
+               .available_tsf_ids = { (1 << NUM_TSF_IDS) - 1 },
+               /* no preference yet */
+               .preferred_tsf = NUM_TSF_IDS,
+       };
+
+       ieee80211_iterate_active_interfaces_atomic(
+               mvm->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               iwl_mvm_mac_tsf_id_iter, &data);
+
+       if (data.preferred_tsf != NUM_TSF_IDS)
+               mvmvif->tsf_id = data.preferred_tsf;
+       else if (!test_bit(mvmvif->tsf_id, data.available_tsf_ids))
+               mvmvif->tsf_id = find_first_bit(data.available_tsf_ids,
+                                               NUM_TSF_IDS);
+}
+
 static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
                                               struct ieee80211_vif *vif)
 {
@@ -586,18 +630,23 @@ static void iwl_mvm_mac_ctxt_cmd_common(struct iwl_mvm *mvm,
                cpu_to_le32(vif->bss_conf.use_short_slot ?
                            MAC_FLG_SHORT_SLOT : 0);
 
-       for (i = 0; i < AC_NUM; i++) {
-               cmd->ac[i].cw_min = cpu_to_le16(mvmvif->queue_params[i].cw_min);
-               cmd->ac[i].cw_max = cpu_to_le16(mvmvif->queue_params[i].cw_max);
-               cmd->ac[i].aifsn = mvmvif->queue_params[i].aifs;
-               cmd->ac[i].edca_txop =
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               u8 txf = iwl_mvm_ac_to_tx_fifo[i];
+
+               cmd->ac[txf].cw_min =
+                       cpu_to_le16(mvmvif->queue_params[i].cw_min);
+               cmd->ac[txf].cw_max =
+                       cpu_to_le16(mvmvif->queue_params[i].cw_max);
+               cmd->ac[txf].edca_txop =
                        cpu_to_le16(mvmvif->queue_params[i].txop * 32);
-               cmd->ac[i].fifos_mask = BIT(iwl_mvm_ac_to_tx_fifo[i]);
+               cmd->ac[txf].aifsn = mvmvif->queue_params[i].aifs;
+               cmd->ac[txf].fifos_mask = BIT(txf);
        }
 
        /* in AP mode, the MCAST FIFO takes the EDCA params from VO */
        if (vif->type == NL80211_IFTYPE_AP)
-               cmd->ac[AC_VO].fifos_mask |= BIT(IWL_MVM_TX_FIFO_MCAST);
+               cmd->ac[IWL_MVM_TX_FIFO_VO].fifos_mask |=
+                       BIT(IWL_MVM_TX_FIFO_MCAST);
 
        if (vif->bss_conf.qos)
                cmd->qos_flags |= cpu_to_le32(MAC_QOS_FLG_UPDATE_EDCA);
@@ -1007,7 +1056,7 @@ static void iwl_mvm_mac_ctxt_cmd_fill_ap(struct iwl_mvm *mvm,
                        iwl_mvm_mac_ap_iterator, &data);
 
                if (data.beacon_device_ts) {
-                       u32 rand = (prandom_u32() % (80 - 20)) + 20;
+                       u32 rand = (prandom_u32() % (64 - 36)) + 36;
                        mvmvif->ap_beacon_time = data.beacon_device_ts +
                                ieee80211_tu_to_usec(data.beacon_int * rand /
                                                     100);
@@ -1186,10 +1235,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
 static void iwl_mvm_beacon_loss_iterator(void *_data, u8 *mac,
                                         struct ieee80211_vif *vif)
 {
-       u16 *id = _data;
+       struct iwl_missed_beacons_notif *missed_beacons = _data;
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
 
-       if (mvmvif->id == *id)
+       if (mvmvif->id != (u16)le32_to_cpu(missed_beacons->mac_id))
+               return;
+
+       /*
+        * TODO: the threshold should be adjusted based on latency conditions,
+        * and/or in case of a CS flow on one of the other AP vifs.
+        */
+       if (le32_to_cpu(missed_beacons->consec_missed_beacons_since_last_rx) >
+            IWL_MVM_MISSED_BEACONS_THRESHOLD)
                ieee80211_beacon_loss(vif);
 }
 
@@ -1198,12 +1255,19 @@ int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
-       struct iwl_missed_beacons_notif *missed_beacons = (void *)pkt->data;
-       u16 id = (u16)le32_to_cpu(missed_beacons->mac_id);
+       struct iwl_missed_beacons_notif *mb = (void *)pkt->data;
+
+       IWL_DEBUG_INFO(mvm,
+                      "missed bcn mac_id=%u, consecutive=%u (%u, %u, %u)\n",
+                      le32_to_cpu(mb->mac_id),
+                      le32_to_cpu(mb->consec_missed_beacons),
+                      le32_to_cpu(mb->consec_missed_beacons_since_last_rx),
+                      le32_to_cpu(mb->num_recvd_beacons),
+                      le32_to_cpu(mb->num_expected_beacons));
 
        ieee80211_iterate_active_interfaces_atomic(mvm->hw,
                                                   IEEE80211_IFACE_ITER_NORMAL,
                                                   iwl_mvm_beacon_loss_iterator,
-                                                  &id);
+                                                  mb);
        return 0;
 }
index 2f5269359dced3dd678f7e911c636be20a7a67cb..b41177eb48887213d238f06c132f04390e44fcf1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -262,7 +262,7 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
        mvm->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
 
        /* currently FW API supports only one optional cipher scheme */
-       if (mvm->fw->cs && mvm->fw->cs->cipher) {
+       if (mvm->fw->cs->cipher) {
                mvm->hw->n_cipher_schemes = 1;
                mvm->hw->cipher_schemes = mvm->fw->cs;
        }
@@ -866,6 +866,14 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        int ret;
 
+       /*
+        * Re-calculate the tsf id, as the master-slave relations depend on the
+        * beacon interval, which was not known when the station interface was
+        * added.
+        */
+       if (changes & BSS_CHANGED_ASSOC && bss_conf->assoc)
+               iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
+
        ret = iwl_mvm_mac_ctxt_changed(mvm, vif);
        if (ret)
                IWL_ERR(mvm, "failed to update MAC %pM\n", vif->addr);
@@ -979,6 +987,13 @@ static int iwl_mvm_start_ap_ibss(struct ieee80211_hw *hw,
        if (ret)
                goto out_unlock;
 
+       /*
+        * Re-calculate the tsf id, as the master-slave relations depend on the
+        * beacon interval, which was not known when the AP interface was added.
+        */
+       if (vif->type == NL80211_IFTYPE_AP)
+               iwl_mvm_mac_ctxt_recalc_tsf_id(mvm, vif);
+
        /* Add the mac context */
        ret = iwl_mvm_mac_ctxt_add(mvm, vif);
        if (ret)
@@ -1671,7 +1686,8 @@ static void iwl_mvm_change_chanctx(struct ieee80211_hw *hw,
        if (WARN_ONCE((phy_ctxt->ref > 1) &&
                      (changed & ~(IEEE80211_CHANCTX_CHANGE_WIDTH |
                                   IEEE80211_CHANCTX_CHANGE_RX_CHAINS |
-                                  IEEE80211_CHANCTX_CHANGE_RADAR)),
+                                  IEEE80211_CHANCTX_CHANGE_RADAR |
+                                  IEEE80211_CHANCTX_CHANGE_MIN_WIDTH)),
                      "Cannot change PHY. Ref=%d, changed=0x%X\n",
                      phy_ctxt->ref, changed))
                return;
index 84edf3649ad29bdafb21ff2fda366d1ce46b53dc..e4ead86f06d69a7ebb99d2ceede388035dd6c89e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -81,6 +81,7 @@
 #define IWL_MVM_MAX_ADDRESSES          5
 /* RSSI offset for WkP */
 #define IWL_RSSI_OFFSET 50
+#define IWL_MVM_MISSED_BEACONS_THRESHOLD 8
 
 enum iwl_mvm_tx_fifo {
        IWL_MVM_TX_FIFO_BK = 0,
@@ -711,6 +712,8 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm,
 int iwl_mvm_rx_missed_beacons_notif(struct iwl_mvm *mvm,
                                    struct iwl_rx_cmd_buffer *rxb,
                                    struct iwl_device_cmd *cmd);
+void iwl_mvm_mac_ctxt_recalc_tsf_id(struct iwl_mvm *mvm,
+                                   struct ieee80211_vif *vif);
 
 /* Bindings */
 int iwl_mvm_binding_add_vif(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
index 48089b1625fff7c1dfc804c6f84a9e68ae56d282..c6beb0f842d5358c25e612911baed6436331e479 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -367,16 +367,17 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
                        break;
                }
 
+               if (WARN(section_id >= NVM_NUM_OF_SECTIONS,
+                        "Invalid NVM section ID %d\n", section_id)) {
+                       ret = -EINVAL;
+                       break;
+               }
+
                temp = kmemdup(file_sec->data, section_size, GFP_KERNEL);
                if (!temp) {
                        ret = -ENOMEM;
                        break;
                }
-               if (WARN_ON(section_id >= NVM_NUM_OF_SECTIONS)) {
-                       IWL_ERR(mvm, "Invalid NVM section ID\n");
-                       ret = -EINVAL;
-                       break;
-               }
                mvm->nvm_sections[section_id].data = temp;
                mvm->nvm_sections[section_id].length = section_size;
 
index a362430477a006c01d69ade2ecbc7d916fc9c2ef..552c76a926ed7aee2a0d30b1c8a4f4df1385b353 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -665,6 +665,8 @@ static void iwl_mvm_set_hw_rfkill_state(struct iwl_op_mode *op_mode, bool state)
        else
                clear_bit(IWL_MVM_STATUS_HW_RFKILL, &mvm->status);
 
+       if (state && mvm->cur_ucode != IWL_UCODE_INIT)
+               iwl_trans_stop_device(mvm->trans);
        wiphy_rfkill_set_hw_state(mvm->hw->wiphy, iwl_mvm_is_radio_killed(mvm));
 }
 
index a8652ddd6bedb54ed7bd045d44fc414c618b5ce9..b7268c0b33339c975a93eca4450d145bfa27137b 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 483ecc67501fc359682599dbc4173c7cc5a59128..d9eab3b7bb9f871a37b818e5a63e1320a12d7189 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -64,7 +64,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 
 #include <net/mac80211.h>
 
index 2ce79bad5845d6325bb0fc512cbe034158acf701..ef712ae5bc621e46b0fb70e0c38ebe375cbea625 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 38165eba2a177da38eb564258a36d81f641e445a..ce5db6c4ef7e60e3ad557cd0e2d773738419d587 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d6d28d7b442b2373ef2660f8ae5b9c05c4a34508..ba078a3322b8014a7d9f31fcd443a0fb572b37ce 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -24,7 +24,6 @@
  *
  *****************************************************************************/
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
@@ -700,7 +699,7 @@ static int rs_rate_from_ucode_rate(const u32 ucode_rate,
        u8 num_of_ant = get_num_of_ant_from_rate(ucode_rate);
        u8 nss;
 
-       memset(rate, 0, sizeof(struct rs_rate));
+       memset(rate, 0, sizeof(*rate));
        rate->index = iwl_hwrate_to_plcp_idx(ucode_rate);
 
        if (rate->index == IWL_RATE_INVALID) {
@@ -2121,7 +2120,7 @@ static void rs_initialize_lq(struct iwl_mvm *mvm,
                tbl->column = RS_COLUMN_LEGACY_ANT_B;
 
        rs_set_expected_tpt_table(lq_sta, tbl);
-       rs_fill_lq_cmd(NULL, NULL, lq_sta, rate);
+       rs_fill_lq_cmd(mvm, sta, lq_sta, rate);
        /* TODO restore station should remember the lq cmd */
        iwl_mvm_send_lq_cmd(mvm, &lq_sta->lq, init);
 }
@@ -2446,10 +2445,9 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
        struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
        bool toggle_ant = false;
 
-       memcpy(&rate, initial_rate, sizeof(struct rs_rate));
+       memcpy(&rate, initial_rate, sizeof(rate));
 
-       if (mvm)
-               valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
+       valid_tx_ant = iwl_fw_valid_tx_ant(mvm->fw);
 
        if (is_siso(&rate)) {
                num_rates = RS_INITIAL_SISO_NUM_RATES;
@@ -2623,7 +2621,7 @@ static void rs_program_fix_rate(struct iwl_mvm *mvm,
                struct rs_rate rate;
                rs_rate_from_ucode_rate(lq_sta->dbg_fixed_rate,
                                        lq_sta->band, &rate);
-               rs_fill_lq_cmd(NULL, NULL, lq_sta, &rate);
+               rs_fill_lq_cmd(mvm, NULL, lq_sta, &rate);
                iwl_mvm_send_lq_cmd(lq_sta->drv, &lq_sta->lq, false);
        }
 }
index c31aa59728ea37afe8ae9a8fb1d16abd10b5c248..7bc6404f6986f4b0babca6c5d8c17bc94343e0f9 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
index 454341cc3b274c0a2c27ab6354d566a9c10d0a3a..a85b60f7e67e47e24c842f65f726794dd32dfddd 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 4ce9bb581144e4a64c8842980e41e0097a4da6e9..0e0007960612e7866b332e27a1f19af9c5847afc 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -473,13 +473,18 @@ void iwl_mvm_cancel_scan(struct iwl_mvm *mvm)
        if (mvm->scan_status == IWL_MVM_SCAN_NONE)
                return;
 
+       if (iwl_mvm_is_radio_killed(mvm)) {
+               ieee80211_scan_completed(mvm->hw, true);
+               mvm->scan_status = IWL_MVM_SCAN_NONE;
+               return;
+       }
+
        iwl_init_notification_wait(&mvm->notif_wait, &wait_scan_abort,
                                   scan_abort_notif,
                                   ARRAY_SIZE(scan_abort_notif),
                                   iwl_mvm_scan_abort_notif, NULL);
 
-       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD,
-                                  CMD_SYNC | CMD_SEND_IN_RFKILL, 0, NULL);
+       ret = iwl_mvm_send_cmd_pdu(mvm, SCAN_ABORT_CMD, CMD_SYNC, 0, NULL);
        if (ret) {
                IWL_ERR(mvm, "Couldn't send SCAN_ABORT_CMD: %d\n", ret);
                /* mac80211's state will be cleaned in the fw_restart flow */
index 97bb3c3e75ceba4a6ecc935d4dcc5199ff508bac..8401627c003098f04d020fc2fb242c48447ac1b0 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 0a8af2083ddc5653e8124a2148619d9b527236d7..ec1812133235d8834ab5a235b66794e20d6a9bbd 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index b34941148a9834161eea211bfb17e9c568e9aa6d..4968d0237dc5455d6aa29f3fa5f03e470effd596 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index eb74391d91cac9a7469277c3beab830427bbfa0f..0241665925f704037faeb73999989a2cadff21b2 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 95ce4b601fef3050085518e59a4e32036c57fbfc..50f3d7f560bc1a82094e5db23bdc3c0926b731e9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index d9c8d6cfa2db0c4a44a58b0ec2bc0eaf6fca94cc..4a61c8c02372824cd08b3901f2e26c2a0353f35d 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index a0ec7b3473bddac890d4940c6f511a1464da0243..3afa6b6bf83571734eae30e9042c798a0bdb65ed 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 735f86da79856d6a97180641f21468117c39c5d5..3c575a39987bc0ffed36c67c06c22cc336f86ff1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index f4aff56a36da6e02a420963a5516c9e94bd03415..487d61b25359bb54cb99aa00cd107b060d76ce16 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2012 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 2e97a39953339abdf436b90c2553c790b342ab07..e58b8af56c045f0095d6d41405b3bc3f2ce83dab 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
index 674c75b0d002f23244f12de07d66f35aa7254073..e851f26fd44c1644c81b24f9a91b690ab2fb418e 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -262,6 +262,7 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
  * @rx_page_order: page order for receive buffer size
  * @wd_timeout: queue watchdog timeout (jiffies)
  * @reg_lock: protect hw register access
+ * @cmd_in_flight: true when we have a host command in flight
  */
 struct iwl_trans_pcie {
        struct iwl_rxq rxq;
@@ -273,7 +274,6 @@ struct iwl_trans_pcie {
        __le32 *ict_tbl;
        dma_addr_t ict_tbl_dma;
        int ict_index;
-       u32 inta;
        bool use_ict;
        struct isr_statistics isr_stats;
 
@@ -311,6 +311,7 @@ struct iwl_trans_pcie {
 
        /*protect hw register */
        spinlock_t reg_lock;
+       bool cmd_in_flight;
 };
 
 #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
@@ -343,7 +344,7 @@ void iwl_pcie_rx_free(struct iwl_trans *trans);
 /*****************************************************
 * ICT - interrupt handling
 ******************************************************/
-irqreturn_t iwl_pcie_isr_ict(int irq, void *data);
+irqreturn_t iwl_pcie_isr(int irq, void *data);
 int iwl_pcie_alloc_ict(struct iwl_trans *trans);
 void iwl_pcie_free_ict(struct iwl_trans *trans);
 void iwl_pcie_reset_ict(struct iwl_trans *trans);
@@ -397,13 +398,17 @@ static inline void iwl_enable_interrupts(struct iwl_trans *trans)
 
        IWL_DEBUG_ISR(trans, "Enabling interrupts\n");
        set_bit(STATUS_INT_ENABLED, &trans->status);
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
        iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
 static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
        IWL_DEBUG_ISR(trans, "Enabling rfkill interrupt\n");
-       iwl_write32(trans, CSR_INT_MASK, CSR_INT_BIT_RF_KILL);
+       trans_pcie->inta_mask = CSR_INT_BIT_RF_KILL;
+       iwl_write32(trans, CSR_INT_MASK, trans_pcie->inta_mask);
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
@@ -456,4 +461,31 @@ static inline bool iwl_is_rfkill_set(struct iwl_trans *trans)
                CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW);
 }
 
+static inline void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
+                                                 u32 reg, u32 mask, u32 value)
+{
+       u32 v;
+
+#ifdef CONFIG_IWLWIFI_DEBUG
+       WARN_ON_ONCE(value & ~mask);
+#endif
+
+       v = iwl_read32(trans, reg);
+       v &= ~mask;
+       v |= value;
+       iwl_write32(trans, reg, v);
+}
+
+static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
+                                             u32 reg, u32 mask)
+{
+       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
+}
+
+static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
+                                           u32 reg, u32 mask)
+{
+       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
+}
+
 #endif /* __iwl_trans_int_pcie_h__ */
index 7aeec5ccefa5a34082a3115bed773ad279a236a4..1890ea29c264c2eeeedced38d8f033b5bae67c53 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -148,10 +148,9 @@ int iwl_pcie_rx_stop(struct iwl_trans *trans)
 static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
                                    struct iwl_rxq *rxq)
 {
-       unsigned long flags;
        u32 reg;
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
 
        if (rxq->need_update == 0)
                goto exit_unlock;
@@ -190,7 +189,7 @@ static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans,
        rxq->need_update = 0;
 
  exit_unlock:
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 }
 
 /*
@@ -209,7 +208,6 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
-       unsigned long flags;
 
        /*
         * If the device isn't enabled - not need to try to add buffers...
@@ -222,7 +220,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
                return;
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) {
                /* The overwritten rxb must be a used one */
                rxb = rxq->queue[rxq->write];
@@ -239,7 +237,7 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
                rxq->free_count--;
        }
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
        /* If the pre-allocated buffer pool is dropping low, schedule to
         * refill it */
        if (rxq->free_count <= RX_LOW_WATERMARK)
@@ -248,9 +246,9 @@ static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
        /* If we've added more space for the firmware to place data, tell it.
         * Increment device's write pointer in multiples of 8. */
        if (rxq->write_actual != (rxq->write & ~0x7)) {
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
                rxq->need_update = 1;
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
                iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
        }
 }
@@ -270,16 +268,15 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
-       unsigned long flags;
        gfp_t gfp_mask = priority;
 
        while (1) {
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
                if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        return;
                }
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
 
                if (rxq->free_count > RX_LOW_WATERMARK)
                        gfp_mask |= __GFP_NOWARN;
@@ -308,17 +305,17 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                        return;
                }
 
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
 
                if (list_empty(&rxq->rx_used)) {
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
                rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer,
                                       list);
                list_del(&rxb->list);
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
 
                BUG_ON(rxb->page);
                rxb->page = page;
@@ -329,9 +326,9 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                                     DMA_FROM_DEVICE);
                if (dma_mapping_error(trans->dev, rxb->page_dma)) {
                        rxb->page = NULL;
-                       spin_lock_irqsave(&rxq->lock, flags);
+                       spin_lock(&rxq->lock);
                        list_add(&rxb->list, &rxq->rx_used);
-                       spin_unlock_irqrestore(&rxq->lock, flags);
+                       spin_unlock(&rxq->lock);
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
@@ -340,12 +337,12 @@ static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
                /* and also 256 byte aligned! */
                BUG_ON(rxb->page_dma & DMA_BIT_MASK(8));
 
-               spin_lock_irqsave(&rxq->lock, flags);
+               spin_lock(&rxq->lock);
 
                list_add_tail(&rxb->list, &rxq->rx_free);
                rxq->free_count++;
 
-               spin_unlock_irqrestore(&rxq->lock, flags);
+               spin_unlock(&rxq->lock);
        }
 }
 
@@ -379,13 +376,12 @@ static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
 static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_pcie_rxq_restock(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
 static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans)
@@ -511,7 +507,6 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        int i, err;
-       unsigned long flags;
 
        if (!rxq->bd) {
                err = iwl_pcie_rx_alloc(trans);
@@ -519,7 +514,7 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
                        return err;
        }
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
 
        INIT_WORK(&trans_pcie->rx_replenish, iwl_pcie_rx_replenish_work);
 
@@ -535,16 +530,16 @@ int iwl_pcie_rx_init(struct iwl_trans *trans)
        rxq->read = rxq->write = 0;
        rxq->write_actual = 0;
        memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 
        iwl_pcie_rx_replenish(trans);
 
        iwl_pcie_rx_hw_init(trans, rxq);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        rxq->need_update = 1;
        iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        return 0;
 }
@@ -553,7 +548,6 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
-       unsigned long flags;
 
        /*if rxq->bd is NULL, it means that nothing has been allocated,
         * exit now */
@@ -564,9 +558,9 @@ void iwl_pcie_rx_free(struct iwl_trans *trans)
 
        cancel_work_sync(&trans_pcie->rx_replenish);
 
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        iwl_pcie_rxq_free_rbs(trans);
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 
        dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
                          rxq->bd, rxq->bd_dma);
@@ -589,7 +583,6 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
-       unsigned long flags;
        bool page_stolen = false;
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
        u32 offset = 0;
@@ -691,7 +684,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
        /* Reuse the page if possible. For notification packets and
         * SKBs that fail to Rx correctly, add them back into the
         * rx_free list for reuse later. */
-       spin_lock_irqsave(&rxq->lock, flags);
+       spin_lock(&rxq->lock);
        if (rxb->page != NULL) {
                rxb->page_dma =
                        dma_map_page(trans->dev, rxb->page, 0,
@@ -712,7 +705,7 @@ static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                }
        } else
                list_add_tail(&rxb->list, &rxq->rx_used);
-       spin_unlock_irqrestore(&rxq->lock, flags);
+       spin_unlock(&rxq->lock);
 }
 
 /*
@@ -807,6 +800,87 @@ static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
        wake_up(&trans_pcie->wait_command_queue);
 }
 
+static u32 iwl_pcie_int_cause_non_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 inta;
+
+       lockdep_assert_held(&trans_pcie->irq_lock);
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(trans, CSR_INT);
+
+       /* the thread will service interrupts and re-enable them */
+       return inta;
+}
+
+/* a device (PCI-E) page is 4096 bytes long */
+#define ICT_SHIFT      12
+#define ICT_SIZE       (1 << ICT_SHIFT)
+#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
+
+/* interrupt handler using ict table, with this interrupt driver will
+ * stop using INTA register to get device's interrupt, reading this register
+ * is expensive, device will write interrupts in ICT dram table, increment
+ * index then will fire interrupt to driver, driver will OR all ICT table
+ * entries from current index up to table entry with 0 value. the result is
+ * the interrupt we need to service, driver will set the entries back to 0 and
+ * set index.
+ */
+static u32 iwl_pcie_int_cause_ict(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 inta;
+       u32 val = 0;
+       u32 read;
+
+       trace_iwlwifi_dev_irq(trans->dev);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
+       if (!read)
+               return 0;
+
+       /*
+        * Collect all entries up to the first 0, starting from ict_index;
+        * note we already read at ict_index.
+        */
+       do {
+               val |= read;
+               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
+                               trans_pcie->ict_index, read);
+               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
+               trans_pcie->ict_index =
+                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
+
+               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
+               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
+                                          read);
+       } while (read);
+
+       /* We should not get this value, just ignore it. */
+       if (val == 0xffffffff)
+               val = 0;
+
+       /*
+        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
+        * (bit 15 before shifting it to 31) to clear when using interrupt
+        * coalescing. fortunately, bits 18 and 19 stay set when this happens
+        * so we use them to decide on the real state of the Rx bit.
+        * In order words, bit 15 is set if bit 18 or bit 19 are set.
+        */
+       if (val & 0xC0000)
+               val |= 0x8000;
+
+       inta = (0xff & val) | ((0xff00 & val) << 16);
+       return inta;
+}
+
 irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
 {
        struct iwl_trans *trans = dev_id;
@@ -814,12 +888,61 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
        u32 inta = 0;
        u32 handled = 0;
-       unsigned long flags;
        u32 i;
 
        lock_map_acquire(&trans->sync_cmd_lockdep_map);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
+
+       /* dram interrupt table not set yet,
+        * use legacy interrupt.
+        */
+       if (likely(trans_pcie->use_ict))
+               inta = iwl_pcie_int_cause_ict(trans);
+       else
+               inta = iwl_pcie_int_cause_non_ict(trans);
+
+       if (iwl_have_debug_level(IWL_DL_ISR)) {
+               IWL_DEBUG_ISR(trans,
+                             "ISR inta 0x%08x, enabled 0x%08x(sw), enabled(hw) 0x%08x, fh 0x%08x\n",
+                             inta, trans_pcie->inta_mask,
+                             iwl_read32(trans, CSR_INT_MASK),
+                             iwl_read32(trans, CSR_FH_INT_STATUS));
+               if (inta & (~trans_pcie->inta_mask))
+                       IWL_DEBUG_ISR(trans,
+                                     "We got a masked interrupt (0x%08x)\n",
+                                     inta & (~trans_pcie->inta_mask));
+       }
+
+       inta &= trans_pcie->inta_mask;
+
+       /*
+        * Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC.
+        */
+       if (unlikely(!inta)) {
+               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
+               /*
+                * Re-enable interrupts here since we don't
+                * have anything to service
+                */
+               if (test_bit(STATUS_INT_ENABLED, &trans->status))
+                       iwl_enable_interrupts(trans);
+               spin_unlock(&trans_pcie->irq_lock);
+               lock_map_release(&trans->sync_cmd_lockdep_map);
+               return IRQ_NONE;
+       }
+
+       if (unlikely(inta == 0xFFFFFFFF || (inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /*
+                * Hardware disappeared. It might have
+                * already raised an interrupt.
+                */
+               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               spin_unlock(&trans_pcie->irq_lock);
+               goto out;
+       }
 
        /* Ack/clear/reset pending uCode interrupts.
         * Note:  Some bits in CSR_INT are "OR" of bits in CSR_FH_INT_STATUS,
@@ -832,19 +955,13 @@ irqreturn_t iwl_pcie_irq_handler(int irq, void *dev_id)
         * hardware bugs here by ACKing all the possible interrupts so that
         * interrupt coalescing can still be achieved.
         */
-       iwl_write32(trans, CSR_INT,
-                   trans_pcie->inta | ~trans_pcie->inta_mask);
-
-       inta = trans_pcie->inta;
+       iwl_write32(trans, CSR_INT, inta | ~trans_pcie->inta_mask);
 
        if (iwl_have_debug_level(IWL_DL_ISR))
                IWL_DEBUG_ISR(trans, "inta 0x%08x, enabled 0x%08x\n",
                              inta, iwl_read32(trans, CSR_INT_MASK));
 
-       /* saved interrupt in inta variable now we can reset trans_pcie->inta */
-       trans_pcie->inta = 0;
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* Now service all interrupt bits discovered above. */
        if (inta & CSR_INT_BIT_HW_ERR) {
@@ -1019,11 +1136,6 @@ out:
  *
  ******************************************************************************/
 
-/* a device (PCI-E) page is 4096 bytes long */
-#define ICT_SHIFT      12
-#define ICT_SIZE       (1 << ICT_SHIFT)
-#define ICT_COUNT      (ICT_SIZE / sizeof(u32))
-
 /* Free dram table */
 void iwl_pcie_free_ict(struct iwl_trans *trans)
 {
@@ -1048,7 +1160,7 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
        trans_pcie->ict_tbl =
-               dma_alloc_coherent(trans->dev, ICT_SIZE,
+               dma_zalloc_coherent(trans->dev, ICT_SIZE,
                                   &trans_pcie->ict_tbl_dma,
                                   GFP_KERNEL);
        if (!trans_pcie->ict_tbl)
@@ -1060,17 +1172,10 @@ int iwl_pcie_alloc_ict(struct iwl_trans *trans)
                return -EINVAL;
        }
 
-       IWL_DEBUG_ISR(trans, "ict dma addr %Lx\n",
-                     (unsigned long long)trans_pcie->ict_tbl_dma);
-
-       IWL_DEBUG_ISR(trans, "ict vir addr %p\n", trans_pcie->ict_tbl);
+       IWL_DEBUG_ISR(trans, "ict dma addr %Lx ict vir addr %p\n",
+                     (unsigned long long)trans_pcie->ict_tbl_dma,
+                     trans_pcie->ict_tbl);
 
-       /* reset table and index to all 0 */
-       memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
-       trans_pcie->ict_index = 0;
-
-       /* add periodic RX interrupt */
-       trans_pcie->inta_mask |= CSR_INT_BIT_RX_PERIODIC;
        return 0;
 }
 
@@ -1081,12 +1186,11 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 val;
-       unsigned long flags;
 
        if (!trans_pcie->ict_tbl)
                return;
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
 
        memset(trans_pcie->ict_tbl, 0, ICT_SIZE);
@@ -1103,120 +1207,26 @@ void iwl_pcie_reset_ict(struct iwl_trans *trans)
        trans_pcie->ict_index = 0;
        iwl_write32(trans, CSR_INT, trans_pcie->inta_mask);
        iwl_enable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
 /* Device is going down disable ict interrupt usage */
 void iwl_pcie_disable_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        trans_pcie->use_ict = false;
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-}
-
-/* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */
-static irqreturn_t iwl_pcie_isr(int irq, void *data)
-{
-       struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 inta, inta_mask;
-
-       lockdep_assert_held(&trans_pcie->irq_lock);
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the irq thread will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(trans, CSR_INT_MASK);
-       iwl_write32(trans, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(trans, CSR_INT);
-
-       if (inta & (~inta_mask)) {
-               IWL_DEBUG_ISR(trans,
-                             "We got a masked interrupt (0x%08x)...Ack and ignore\n",
-                             inta & (~inta_mask));
-               iwl_write32(trans, CSR_INT, inta & (~inta_mask));
-               inta &= inta_mask;
-       }
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               /*
-                * Re-enable interrupts here since we don't have anything to
-                * service, but only in case the handler won't run. Note that
-                * the handler can be scheduled because of a previous
-                * interrupt.
-                */
-               if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
-                   !trans_pcie->inta)
-                       iwl_enable_interrupts(trans);
-               return IRQ_NONE;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared. It might have already raised
-                * an interrupt */
-               IWL_WARN(trans, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               return IRQ_HANDLED;
-       }
-
-       if (iwl_have_debug_level(IWL_DL_ISR))
-               IWL_DEBUG_ISR(trans,
-                             "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-                             inta, inta_mask,
-                             iwl_read32(trans, CSR_FH_INT_STATUS));
-
-       trans_pcie->inta |= inta;
-       /* the thread will service interrupts and re-enable them */
-       return IRQ_WAKE_THREAD;
+       spin_unlock(&trans_pcie->irq_lock);
 }
 
-/* interrupt handler using ict table, with this interrupt driver will
- * stop using INTA register to get device's interrupt, reading this register
- * is expensive, device will write interrupts in ICT dram table, increment
- * index then will fire interrupt to driver, driver will OR all ICT table
- * entries from current index up to table entry with 0 value. the result is
- * the interrupt we need to service, driver will set the entries back to 0 and
- * set index.
- */
-irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
+irqreturn_t iwl_pcie_isr(int irq, void *data)
 {
        struct iwl_trans *trans = data;
-       struct iwl_trans_pcie *trans_pcie;
-       u32 inta;
-       u32 val = 0;
-       u32 read;
-       unsigned long flags;
-       irqreturn_t ret = IRQ_NONE;
 
        if (!trans)
                return IRQ_NONE;
 
-       trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* dram interrupt table not set yet,
-        * use legacy interrupt.
-        */
-       if (unlikely(!trans_pcie->use_ict)) {
-               ret = iwl_pcie_isr(irq, data);
-               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-               return ret;
-       }
-
-       trace_iwlwifi_dev_irq(trans->dev);
-
        /* Disable (but don't clear!) interrupts here to avoid
         * back-to-back ISRs and sporadic interrupts from our NIC.
         * If we have something to service, the tasklet will re-enable ints.
@@ -1224,73 +1234,5 @@ irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
         */
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
 
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-       trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index, read);
-       if (!read) {
-               IWL_DEBUG_ISR(trans, "Ignore interrupt, inta == 0\n");
-               goto none;
-       }
-
-       /*
-        * Collect all entries up to the first 0, starting from ict_index;
-        * note we already read at ict_index.
-        */
-       do {
-               val |= read;
-               IWL_DEBUG_ISR(trans, "ICT index %d value 0x%08X\n",
-                               trans_pcie->ict_index, read);
-               trans_pcie->ict_tbl[trans_pcie->ict_index] = 0;
-               trans_pcie->ict_index =
-                       iwl_queue_inc_wrap(trans_pcie->ict_index, ICT_COUNT);
-
-               read = le32_to_cpu(trans_pcie->ict_tbl[trans_pcie->ict_index]);
-               trace_iwlwifi_dev_ict_read(trans->dev, trans_pcie->ict_index,
-                                          read);
-       } while (read);
-
-       /* We should not get this value, just ignore it. */
-       if (val == 0xffffffff)
-               val = 0;
-
-       /*
-        * this is a w/a for a h/w bug. the h/w bug may cause the Rx bit
-        * (bit 15 before shifting it to 31) to clear when using interrupt
-        * coalescing. fortunately, bits 18 and 19 stay set when this happens
-        * so we use them to decide on the real state of the Rx bit.
-        * In order words, bit 15 is set if bit 18 or bit 19 are set.
-        */
-       if (val & 0xC0000)
-               val |= 0x8000;
-
-       inta = (0xff & val) | ((0xff00 & val) << 16);
-       IWL_DEBUG_ISR(trans, "ISR inta 0x%08x, enabled(sw) 0x%08x ict 0x%08x\n",
-                     inta, trans_pcie->inta_mask, val);
-       if (iwl_have_debug_level(IWL_DL_ISR))
-               IWL_DEBUG_ISR(trans, "enabled(hw) 0x%08x\n",
-                             iwl_read32(trans, CSR_INT_MASK));
-
-       inta &= trans_pcie->inta_mask;
-       trans_pcie->inta |= inta;
-
-       /* iwl_pcie_tasklet() will service interrupts and re-enable them */
-       if (likely(inta)) {
-               spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-               return IRQ_WAKE_THREAD;
-       }
-
-       ret = IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service.
-        * only Re-enable if disabled by irq.
-        */
-       if (test_bit(STATUS_INT_ENABLED, &trans->status) &&
-           !trans_pcie->inta)
-               iwl_enable_interrupts(trans);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-       return ret;
+       return IRQ_WAKE_THREAD;
 }
index eecd38e3f15f3cac1bd09f56e39996fb1f255537..16f66c1a23def29b447b5c1dd4827ee7165483c9 100644 (file)
@@ -5,7 +5,7 @@
  *
  * GPL LICENSE SUMMARY
  *
- * Copyright(c) 2007 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
  *
  * 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
@@ -30,7 +30,7 @@
  *
  * BSD LICENSE
  *
- * Copyright(c) 2005 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "iwl-agn-hw.h"
 #include "internal.h"
 
-static void __iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans,
-                                                 u32 reg, u32 mask, u32 value)
-{
-       u32 v;
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       WARN_ON_ONCE(value & ~mask);
-#endif
-
-       v = iwl_read32(trans, reg);
-       v &= ~mask;
-       v |= value;
-       iwl_write32(trans, reg, v);
-}
-
-static inline void __iwl_trans_pcie_clear_bit(struct iwl_trans *trans,
-                                             u32 reg, u32 mask)
-{
-       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, 0);
-}
-
-static inline void __iwl_trans_pcie_set_bit(struct iwl_trans *trans,
-                                           u32 reg, u32 mask)
-{
-       __iwl_trans_pcie_set_bits_mask(trans, reg, mask, mask);
-}
-
 static void iwl_pcie_set_pwr(struct iwl_trans *trans, bool vaux)
 {
        if (vaux && pci_pme_capable(to_pci_dev(trans->dev), PCI_D3cold))
@@ -271,13 +244,12 @@ static void iwl_pcie_apm_stop(struct iwl_trans *trans)
 static int iwl_pcie_nic_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        /* nic_init */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_pcie_apm_init(trans);
 
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_set_pwr(trans, false);
 
@@ -635,13 +607,14 @@ static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
-       bool hw_rfkill;
+       bool hw_rfkill, was_hw_rfkill;
+
+       was_hw_rfkill = iwl_is_rfkill_set(trans);
 
        /* tell the device to stop sending interrupts */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* device going down, Stop using ICT table */
        iwl_pcie_disable_ict(trans);
@@ -673,9 +646,9 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        /* Upon stop, the APM issues an interrupt if HW RF kill is set.
         * Clean again the interrupt here
         */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* stop and reset the on-board processor */
        iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
@@ -698,13 +671,20 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         * all the interrupts were disabled, in this case we couldn't
         * receive the RF kill interrupt and update the state in the
         * op_mode.
+        * Don't call the op_mode if the rkfill state hasn't changed.
+        * This allows the op_mode to call stop_device from the rfkill
+        * notification without endless recursion. Under very rare
+        * circumstances, we might have a small recursion if the rfkill
+        * state changed exactly now while we were called from stop_device.
+        * This is very unlikely but can happen and is supported.
         */
        hw_rfkill = iwl_is_rfkill_set(trans);
        if (hw_rfkill)
                set_bit(STATUS_RFKILL, &trans->status);
        else
                clear_bit(STATUS_RFKILL, &trans->status);
-       iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+       if (hw_rfkill != was_hw_rfkill)
+               iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
 }
 
 static void iwl_trans_pcie_d3_suspend(struct iwl_trans *trans, bool test)
@@ -799,7 +779,7 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
        }
 
        /* Reset the entire device */
-       iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+       iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
 
        usleep_range(10, 15);
 
@@ -821,18 +801,17 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       unsigned long flags;
 
        /* disable interrupts - don't enable HW RF kill interrupt */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_apm_stop(trans);
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
        iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        iwl_pcie_disable_ict(trans);
 }
@@ -932,6 +911,9 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
 
        spin_lock_irqsave(&trans_pcie->reg_lock, *flags);
 
+       if (trans_pcie->cmd_in_flight)
+               goto out;
+
        /* this bit wakes up the NIC */
        __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
                                 CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
@@ -971,6 +953,7 @@ static bool iwl_trans_pcie_grab_nic_access(struct iwl_trans *trans, bool silent,
                }
        }
 
+out:
        /*
         * Fool sparse by faking we release the lock - sparse will
         * track nic_access anyway.
@@ -992,6 +975,9 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         */
        __acquire(&trans_pcie->reg_lock);
 
+       if (trans_pcie->cmd_in_flight)
+               goto out;
+
        __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
                                   CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
        /*
@@ -1001,6 +987,7 @@ static void iwl_trans_pcie_release_nic_access(struct iwl_trans *trans,
         * scheduled on different CPUs (after we drop reg_lock).
         */
        mmiowb();
+out:
        spin_unlock_irqrestore(&trans_pcie->reg_lock, *flags);
 }
 
@@ -1597,7 +1584,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        if (iwl_pcie_alloc_ict(trans))
                goto out_free_cmd_pool;
 
-       err = request_threaded_irq(pdev->irq, iwl_pcie_isr_ict,
+       err = request_threaded_irq(pdev->irq, iwl_pcie_isr,
                                   iwl_pcie_irq_handler,
                                   IRQF_SHARED, DRV_NAME, trans);
        if (err) {
index 8df24787c1416b30675c275d3a7082613303865b..3b14fa8abfc70461d6cd643b71a7997b3234ebe6 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2003 - 2013 Intel Corporation. All rights reserved.
+ * Copyright(c) 2003 - 2014 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.
@@ -737,10 +737,9 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ch, txq_id, ret;
-       unsigned long flags;
 
        /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
 
        iwl_pcie_txq_set_sched(trans, 0);
 
@@ -757,13 +756,19 @@ int iwl_pcie_tx_stop(struct iwl_trans *trans)
                                iwl_read_direct32(trans,
                                                  FH_TSSR_TX_STATUS_REG));
        }
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans,
-                        "Stopping tx queues that aren't allocated...\n");
+       /*
+        * This function can be called before the op_mode disabled the
+        * queues. This happens when we have an rfkill interrupt.
+        * Since we stop Tx altogether - mark the queues as stopped.
+        */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+       /* This can happen: start_hw, stop_device */
+       if (!trans_pcie->txq)
                return 0;
-       }
 
        /* Unmap DMA from host system and free skb's */
        for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
@@ -865,7 +870,6 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
        int txq_id, slots_num;
-       unsigned long flags;
        bool alloc = false;
 
        if (!trans_pcie->txq) {
@@ -875,7 +879,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
                alloc = true;
        }
 
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       spin_lock(&trans_pcie->irq_lock);
 
        /* Turn off all Tx DMA fifos */
        iwl_write_prph(trans, SCD_TXFACT, 0);
@@ -884,7 +888,7 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
        iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
                           trans_pcie->kw.dma >> 4);
 
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+       spin_unlock(&trans_pcie->irq_lock);
 
        /* Alloc and init all Tx queues, including the command queue (#4/#9) */
        for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
@@ -1003,6 +1007,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_txq *txq = &trans_pcie->txq[txq_id];
        struct iwl_queue *q = &txq->q;
+       unsigned long flags;
        int nfreed = 0;
 
        lockdep_assert_held(&txq->lock);
@@ -1025,6 +1030,16 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
                }
        }
 
+       if (q->read_ptr == q->write_ptr) {
+               spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+               WARN_ON(!trans_pcie->cmd_in_flight);
+               trans_pcie->cmd_in_flight = false;
+               __iwl_trans_pcie_clear_bit(trans,
+                                          CSR_GP_CNTRL,
+                                          CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+               spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+       }
+
        iwl_pcie_txq_progress(trans_pcie, txq);
 }
 
@@ -1141,8 +1156,15 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                        SCD_TX_STTS_QUEUE_OFFSET(txq_id);
        static const u32 zero_val[4] = {};
 
+       /*
+        * Upon HW Rfkill - we stop the device, and then stop the queues
+        * in the op_mode. Just for the sake of the simplicity of the op_mode,
+        * allow the op_mode to call txq_disable after it already called
+        * stop_device.
+        */
        if (!test_and_clear_bit(txq_id, trans_pcie->queue_used)) {
-               WARN_ONCE(1, "queue %d not used", txq_id);
+               WARN_ONCE(test_bit(STATUS_DEVICE_ENABLED, &trans->status),
+                         "queue %d not used", txq_id);
                return;
        }
 
@@ -1176,12 +1198,13 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
+       unsigned long flags;
        void *dup_buf = NULL;
        dma_addr_t phys_addr;
        int idx;
        u16 copy_size, cmd_size, scratch_size;
        bool had_nocopy = false;
-       int i;
+       int i, ret;
        u32 cmd_pos;
        const u8 *cmddata[IWL_MAX_CMD_TBS_PER_TFD];
        u16 cmdlen[IWL_MAX_CMD_TBS_PER_TFD];
@@ -1379,10 +1402,38 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
        if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
                mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
 
+       spin_lock_irqsave(&trans_pcie->reg_lock, flags);
+
+       /*
+        * wake up the NIC to make sure that the firmware will see the host
+        * command - we will let the NIC sleep once all the host commands
+        * returned.
+        */
+       if (!trans_pcie->cmd_in_flight) {
+               trans_pcie->cmd_in_flight = true;
+               __iwl_trans_pcie_set_bit(trans, CSR_GP_CNTRL,
+                                        CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+               ret = iwl_poll_bit(trans, CSR_GP_CNTRL,
+                                  CSR_GP_CNTRL_REG_VAL_MAC_ACCESS_EN,
+                                  (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
+                                   CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP),
+                                  15000);
+               if (ret < 0) {
+                       __iwl_trans_pcie_clear_bit(trans, CSR_GP_CNTRL,
+                                  CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+                       spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+                       trans_pcie->cmd_in_flight = false;
+                       idx = -EIO;
+                       goto out;
+               }
+       }
+
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
        iwl_pcie_txq_inc_wr_ptr(trans, txq);
 
+       spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
+
  out:
        spin_unlock_bh(&txq->lock);
  free_dup_buf:
@@ -1464,7 +1515,6 @@ void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
 }
 
 #define HOST_COMPLETE_TIMEOUT  (2 * HZ)
-#define COMMAND_POKE_TIMEOUT   (HZ / 10)
 
 static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
                                    struct iwl_host_cmd *cmd)
@@ -1492,7 +1542,6 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int cmd_idx;
        int ret;
-       int timeout = HOST_COMPLETE_TIMEOUT;
 
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                       get_cmd_string(trans_pcie, cmd->id));
@@ -1516,29 +1565,10 @@ static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
                return ret;
        }
 
-       while (timeout > 0) {
-               unsigned long flags;
-
-               timeout -= COMMAND_POKE_TIMEOUT;
-               ret = wait_event_timeout(trans_pcie->wait_command_queue,
-                                        !test_bit(STATUS_SYNC_HCMD_ACTIVE,
-                                                  &trans->status),
-                                        COMMAND_POKE_TIMEOUT);
-               if (ret)
-                       break;
-               /* poke the device - it may have lost the command */
-               if (iwl_trans_grab_nic_access(trans, true, &flags)) {
-                       iwl_trans_release_nic_access(trans, &flags);
-                       IWL_DEBUG_INFO(trans,
-                                      "Tried to wake NIC for command %s\n",
-                                      get_cmd_string(trans_pcie, cmd->id));
-               } else {
-                       IWL_ERR(trans, "Failed to poke NIC for command %s\n",
-                               get_cmd_string(trans_pcie, cmd->id));
-                       break;
-               }
-       }
-
+       ret = wait_event_timeout(trans_pcie->wait_command_queue,
+                                !test_bit(STATUS_SYNC_HCMD_ACTIVE,
+                                          &trans->status),
+                                HOST_COMPLETE_TIMEOUT);
        if (!ret) {
                struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
                struct iwl_queue *q = &txq->q;
index b994679abce0a2685dbe74098580e2efcef6076e..e7c81abf108eda9f438b810687bbdefcc60adcd0 100644 (file)
@@ -563,14 +563,7 @@ static void mwifiex_reg_notifier(struct wiphy *wiphy,
                memcpy(adapter->country_code, request->alpha2,
                       sizeof(request->alpha2));
                mwifiex_send_domain_info_cmd_fw(wiphy);
-
-               if (adapter->dt_node) {
-                       char txpwr[] = {"marvell,00_txpwrlimit"};
-
-                       memcpy(&txpwr[8], adapter->country_code, 2);
-                       mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
-                                               txpwr);
-               }
+               mwifiex_dnld_txpwr_table(priv);
        }
 }
 
index 6bf58aba51d20ca59253efb55ada327888615e5d..2d6f5e1721cfc5428823896a20f9963e9d843ce0 100644 (file)
@@ -749,7 +749,7 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
 static u16
 mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb)
 {
-       skb->priority = cfg80211_classify8021d(skb);
+       skb->priority = cfg80211_classify8021d(skb, NULL);
        return mwifiex_1d_to_wmm_queue[skb->priority];
 }
 
index ab3416449bfd3c0f2668d312df9854cb3281eb9d..d8ad554ce39f566cbf95221317fca751482d7e5c 100644 (file)
@@ -1155,6 +1155,7 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
 int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
 int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
                            struct device_node *node, const char *prefix);
+void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv);
 
 extern const struct ethtool_ops mwifiex_ethtool_ops;
 
index 9c2404cd755f34dcfd85922c4b7c9bf8a816dbb8..9208a8816b800f619426eb41403d4177ad2d0ad3 100644 (file)
@@ -1170,8 +1170,9 @@ int mwifiex_dnld_dt_cfgdata(struct mwifiex_private *priv,
                    strncmp(prop->name, prefix, len))
                        continue;
 
-               /* property header is 6 bytes */
-               if (prop && prop->value && prop->length > 6) {
+               /* property header is 6 bytes, data must fit in cmd buffer */
+               if (prop && prop->value && prop->length > 6 &&
+                   prop->length <= MWIFIEX_SIZE_OF_CMD_BUFFER - S_DS_GEN) {
                        ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_CFG_DATA,
                                                    HostCmd_ACT_GEN_SET, 0,
                                                    prop);
index 3edc92fad319ab21c4e1dd04aa9d65a0235e4c4c..c5cb2ed19ec2e240d6a65a7bb9ee4165ad181b68 100644 (file)
@@ -184,6 +184,16 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
 }
 
+void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
+{
+       if (priv->adapter->dt_node) {
+               char txpwr[] = {"marvell,00_txpwrlimit"};
+
+               memcpy(&txpwr[8], priv->adapter->country_code, 2);
+               mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
+       }
+}
+
 static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                                      struct cfg80211_bss *bss)
 {
@@ -234,12 +244,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
                return -1;
        }
 
-       if (priv->adapter->dt_node) {
-               char txpwr[] = {"marvell,00_txpwrlimit"};
-
-               memcpy(&txpwr[8], priv->adapter->country_code, 2);
-               mwifiex_dnld_dt_cfgdata(priv, priv->adapter->dt_node, txpwr);
-       }
+       mwifiex_dnld_txpwr_table(priv);
 
        return 0;
 }
index b953ad621e0b90ef23e9fbe009bc0c4cd5f66876..63dbde5c3713304e538890ba1aa90fef5caec400 100644 (file)
@@ -9,7 +9,6 @@
  * warranty of any kind, whether express or implied.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -1258,7 +1257,7 @@ mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh)
 {
        return priv->capture_beacon &&
                ieee80211_is_beacon(wh->frame_control) &&
-               ether_addr_equal(wh->addr3, priv->capture_bssid);
+               ether_addr_equal_64bits(wh->addr3, priv->capture_bssid);
 }
 
 static inline void mwl8k_save_beacon(struct ieee80211_hw *hw,
index 75c15bc7b34cabf7b59ed87f2c41af5f54242fbc..43790fbea0e00ab6c7d292ee71d9209e9cf36ba5 100644 (file)
@@ -40,7 +40,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 
 #include "hermes.h"
index d21d95939316ece9557d579226bdc2ef66896b50..c0a27377d9e26306ea7dc32b44efc6749723bcda 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
index bdfe637953f4d3a41270abafa9e174d04901879c..f9805c9353d2295f076d1f5cbe1eaaa5a1f0be72 100644 (file)
@@ -52,7 +52,6 @@
 #include <linux/signal.h>
 #include <linux/errno.h>
 #include <linux/poll.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/fcntl.h>
 #include <linux/spinlock.h>
index e2264bc12ebf30cf5119d997c70356dc2af1446c..b60048c95e0a852863f3e2f541bc283fd263f9ab 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <pcmcia/cistpl.h>
 #include <pcmcia/cisreg.h>
index d43e3740e45d95e4b55bc3af085747dcf346c04b..0fe67d2da20895373c6bcf1cad50356184494224 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <linux/sort.h>
index b3879fbf53688bcea74ba9b639d5b6c8ddab860d..bc065e8e348b264fad86bffa8450c31a96d0274e 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
index 3837e1eec5f4a56fdbf80a2b8f13984f3d15742b..1f6fd5ff55313731b034b565c358ac56b21bfaf7 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 
index 067e6f2fd050fcad0ddc4eb00565ba3324397894..80d93cba51502edc28806202af6c48f8c42485ff 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
index f9a07b0d83acd2f40df4755880fa1551e6276091..d411de4090509df56f9e51a7b268296d979dc59e 100644 (file)
@@ -13,7 +13,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/firmware.h>
index e328d3058c419a0c7c4c367fd7e62ada31ddded4..6e635cfa24c8dea70eb439f3724ee52adc01d27d 100644 (file)
@@ -12,7 +12,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index f95de0d162166e1de1e9035d1d3be9db238869fe..9c96831c0b5c8ded956451ebd7d41a4f22fd92a5 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/firmware.h>
 #include <linux/etherdevice.h>
 #include <asm/div64.h>
@@ -308,7 +307,7 @@ static void p54_pspoll_workaround(struct p54_common *priv, struct sk_buff *skb)
                return;
 
        /* only consider beacons from the associated BSSID */
-       if (!ether_addr_equal(hdr->addr3, priv->bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, priv->bssid))
                return;
 
        tim = p54_find_ie(skb, WLAN_EID_TIM);
index c3cdda1252defba9d9c27d25e0fdeca72bedf76e..5028557aa18adb1a22c74c7a59123f1bb52b0d5a 100644 (file)
@@ -26,7 +26,6 @@
 // #define     VERBOSE                 // more; success messages
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
index 4ad0de9d1d08b4a54bb8b87643be4e7c84ad6511..4ccfef5094e0b2ecec3c2633df2a22ac7d5747a5 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index 4f61ffbcd2f196a2b9fbe0354ab87b8e86f336e2..abc5f56f29fe1c96c3dc585af30f662c138c1cd7 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index 1bb76935da717c6fb15a46e9399407a2955b2531..9f16824cd1bccf80407633fa0864d1d7f0d6d257 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 49ff178a0b46eac88cd78156bb7263f4843991d2..5c5c4906c6b669517d043209685f476dd40cee02 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
index 00c3fae6fa3c1cfe2a7574a372e868432b073a85..2bde6729f5e61e4923c472bade9da057e850b0e0 100644 (file)
@@ -565,10 +565,10 @@ static void rt2x00lib_rxdone_check_ba(struct rt2x00_dev *rt2x00dev,
 
 #undef TID_CHECK
 
-               if (!ether_addr_equal(ba->ra, entry->ta))
+               if (!ether_addr_equal_64bits(ba->ra, entry->ta))
                        continue;
 
-               if (!ether_addr_equal(ba->ta, entry->ra))
+               if (!ether_addr_equal_64bits(ba->ta, entry->ra))
                        continue;
 
                /* Mark BAR since we received the according BA */
index b76f6049ad9a9f099e8293f23a403a8e79a0c69a..24402984ee5749f272609d82907cda4a68f750f6 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index ade88d7e089cc485fc0f0a9fafb9ac0000cbf217..a140170b1eb3e63625ecde7b4cc43ec6bf1b87b1 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/crc-itu-t.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index a91506b12a627f26a084aef5e6dcb9a4213ac5e4..8ec17aad0e520019fa0f93fbd50f1999885ea9ad 100644 (file)
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index dc845693f321ee39dbe1728aada582cccb609165..b1bfee73893703f89cc00720566e4a4fa631fdf0 100644 (file)
@@ -19,7 +19,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index a63c443c3c6fbc9cbf16dca89e20f34ac56d22ba..eebf23976524a3a8da9f51575f4d233e18235698 100644 (file)
@@ -18,7 +18,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index ee638d0749d601ac593a17fd1304753ad2203a2f..d60a5f399022447c81130e7edc9e60d45d59a3c0 100644 (file)
@@ -15,7 +15,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index 7614d9ccc72931edf0e41557c7882fd555ded246..959b049827de1e44df543940d68026f670cb787a 100644 (file)
@@ -19,7 +19,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <net/mac80211.h>
index ec9aa5b6738171f547dc50a45b977795de133486..fd78df813a8533911ffaeb7c08d53c0a440810f1 100644 (file)
@@ -20,7 +20,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index a26193a0444790286c625c3fae39d773698fb1b0..5ecf18ed67b88abc8627f2fd2dabfa06d8a7db13 100644 (file)
@@ -16,7 +16,6 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/usb.h>
 #include <net/mac80211.h>
 
index fcf9b621918c07ba2ab42e38622af9b56ac66682..d63a12cc5de8e6af64b3b9fef9650b42bbfcd6e5 100644 (file)
@@ -1293,7 +1293,7 @@ void rtl_beacon_statistic(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        rtlpriv->link_info.bcn_rx_inperiod++;
@@ -1781,7 +1781,7 @@ void rtl_recognize_peer(struct ieee80211_hw *hw, u8 *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        if (rtl_find_221_ie(hw, data, len))
index 8707d1a94995c740d11a5b6cd3dd5d4849616f53..d7aa165fe6776cb64e178f3ec6db0eeb7e9c255c 100644 (file)
@@ -738,6 +738,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
        };
        int index = rtlpci->rx_ring[rx_queue_idx].idx;
 
+       if (rtlpci->driver_is_goingto_unload)
+               return;
        /*RX NORMAL PKT */
        while (count--) {
                /*rx descriptor */
@@ -1634,6 +1636,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
         */
        set_hal_stop(rtlhal);
 
+       rtlpci->driver_is_goingto_unload = true;
        rtlpriv->cfg->ops->disable_interrupt(hw);
        cancel_work_sync(&rtlpriv->works.lps_change_work);
 
@@ -1651,7 +1654,6 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
        ppsc->rfchange_inprogress = true;
        spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
 
-       rtlpci->driver_is_goingto_unload = true;
        rtlpriv->cfg->ops->hw_disable(hw);
        /* some things are not needed if firmware not available */
        if (!rtlpriv->max_fw_size)
index 0d81f766fd0f9e27b6b60478ceae71d9629bfa9a..deedae3c54498370462ef4bc1bde40d7749ee0c8 100644 (file)
@@ -478,7 +478,7 @@ void rtl_swlps_beacon(struct ieee80211_hw *hw, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        rtlpriv->psc.last_beacon = jiffies;
@@ -923,7 +923,7 @@ void rtl_p2p_info(struct ieee80211_hw *hw, void *data, unsigned int len)
                return;
 
        /* and only beacons from the associated BSSID, please */
-       if (!ether_addr_equal(hdr->addr3, rtlpriv->mac80211.bssid))
+       if (!ether_addr_equal_64bits(hdr->addr3, rtlpriv->mac80211.bssid))
                return;
 
        /* check if this really is a beacon */
index 374268d5ac6a70e97355269489538ad31d802cbb..5a4ec56c83d0aa15e7e00226a6cfe69c9146696b 100644 (file)
@@ -194,7 +194,7 @@ out:
        return ret;
 }
 
-int wl1251_acx_feature_cfg(struct wl1251 *wl)
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options)
 {
        struct acx_feature_config *feature;
        int ret;
@@ -205,8 +205,8 @@ int wl1251_acx_feature_cfg(struct wl1251 *wl)
        if (!feature)
                return -ENOMEM;
 
-       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE are disabled */
-       feature->data_flow_options = 0;
+       /* DF_ENCRYPTION_DISABLE and DF_SNIFF_MODE_ENABLE can be set */
+       feature->data_flow_options = data_flow_options;
        feature->options = 0;
 
        ret = wl1251_cmd_configure(wl, ACX_FEATURE_CFG,
@@ -381,7 +381,8 @@ out:
        return ret;
 }
 
-int wl1251_acx_group_address_tbl(struct wl1251 *wl)
+int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
+                                void *mc_list, u32 mc_list_len)
 {
        struct acx_dot11_grp_addr_tbl *acx;
        int ret;
@@ -393,9 +394,9 @@ int wl1251_acx_group_address_tbl(struct wl1251 *wl)
                return -ENOMEM;
 
        /* MAC filtering */
-       acx->enabled = 0;
-       acx->num_groups = 0;
-       memset(acx->mac_table, 0, ADDRESS_GROUP_MAX_LEN);
+       acx->enabled = enable;
+       acx->num_groups = mc_list_len;
+       memcpy(acx->mac_table, mc_list, mc_list_len * ETH_ALEN);
 
        ret = wl1251_cmd_configure(wl, DOT11_GROUP_ADDRESS_TBL,
                                   acx, sizeof(*acx));
@@ -846,12 +847,18 @@ int wl1251_acx_rate_policies(struct wl1251 *wl)
                return -ENOMEM;
 
        /* configure one default (one-size-fits-all) rate class */
-       acx->rate_class_cnt = 1;
+       acx->rate_class_cnt = 2;
        acx->rate_class[0].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
        acx->rate_class[0].short_retry_limit = ACX_RATE_RETRY_LIMIT;
        acx->rate_class[0].long_retry_limit = ACX_RATE_RETRY_LIMIT;
        acx->rate_class[0].aflags = 0;
 
+       /* no-retry rate class */
+       acx->rate_class[1].enabled_rates = ACX_RATE_MASK_UNSPECIFIED;
+       acx->rate_class[1].short_retry_limit = 0;
+       acx->rate_class[1].long_retry_limit = 0;
+       acx->rate_class[1].aflags = 0;
+
        ret = wl1251_cmd_configure(wl, ACX_RATE_POLICY, acx, sizeof(*acx));
        if (ret < 0) {
                wl1251_warning("Setting of rate policies failed: %d", ret);
@@ -960,6 +967,32 @@ out:
        return ret;
 }
 
+int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address)
+{
+       struct wl1251_acx_arp_filter *acx;
+       int ret;
+
+       wl1251_debug(DEBUG_ACX, "acx arp ip filter, enable: %d", enable);
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx)
+               return -ENOMEM;
+
+       acx->version = ACX_IPV4_VERSION;
+       acx->enable = enable;
+
+       if (enable)
+               memcpy(acx->address, &address, ACX_IPV4_ADDR_SIZE);
+
+       ret = wl1251_cmd_configure(wl, ACX_ARP_IP_FILTER,
+                                  acx, sizeof(*acx));
+       if (ret < 0)
+               wl1251_warning("failed to set arp ip filter: %d", ret);
+
+       kfree(acx);
+       return ret;
+}
+
 int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
                      u8 aifs, u16 txop)
 {
index c2ba100f9b1ab3e659301f88328a4274beaf2047..2bdec38699f4f1a833e311020e0187a827c2ebcb 100644 (file)
@@ -350,8 +350,8 @@ struct acx_slot {
 } __packed;
 
 
-#define ADDRESS_GROUP_MAX      (8)
-#define ADDRESS_GROUP_MAX_LEN  (ETH_ALEN * ADDRESS_GROUP_MAX)
+#define ACX_MC_ADDRESS_GROUP_MAX       (8)
+#define ACX_MC_ADDRESS_GROUP_MAX_LEN   (ETH_ALEN * ACX_MC_ADDRESS_GROUP_MAX)
 
 struct acx_dot11_grp_addr_tbl {
        struct acx_header header;
@@ -359,7 +359,7 @@ struct acx_dot11_grp_addr_tbl {
        u8 enabled;
        u8 num_groups;
        u8 pad[2];
-       u8 mac_table[ADDRESS_GROUP_MAX_LEN];
+       u8 mac_table[ACX_MC_ADDRESS_GROUP_MAX_LEN];
 } __packed;
 
 
@@ -1232,6 +1232,20 @@ struct wl1251_acx_bet_enable {
        u8 padding[2];
 } __packed;
 
+#define ACX_IPV4_VERSION 4
+#define ACX_IPV6_VERSION 6
+#define ACX_IPV4_ADDR_SIZE 4
+struct wl1251_acx_arp_filter {
+       struct acx_header header;
+       u8 version;     /* The IP version: 4 - IPv4, 6 - IPv6.*/
+       u8 enable;      /* 1 - ARP filtering is enabled, 0 - disabled */
+       u8 padding[2];
+       u8 address[16]; /* The IP address used to filter ARP packets.
+                          ARP packets that do not match this address are
+                          dropped. When the IP Version is 4, the last 12
+                          bytes of the the address are ignored. */
+} __attribute__((packed));
+
 struct wl1251_acx_ac_cfg {
        struct acx_header header;
 
@@ -1440,7 +1454,7 @@ int wl1251_acx_wake_up_conditions(struct wl1251 *wl, u8 wake_up_event,
 int wl1251_acx_sleep_auth(struct wl1251 *wl, u8 sleep_auth);
 int wl1251_acx_fw_version(struct wl1251 *wl, char *buf, size_t len);
 int wl1251_acx_tx_power(struct wl1251 *wl, int power);
-int wl1251_acx_feature_cfg(struct wl1251 *wl);
+int wl1251_acx_feature_cfg(struct wl1251 *wl, u32 data_flow_options);
 int wl1251_acx_mem_map(struct wl1251 *wl,
                       struct acx_header *mem_map, size_t len);
 int wl1251_acx_data_path_params(struct wl1251 *wl,
@@ -1449,7 +1463,8 @@ int wl1251_acx_rx_msdu_life_time(struct wl1251 *wl, u32 life_time);
 int wl1251_acx_rx_config(struct wl1251 *wl, u32 config, u32 filter);
 int wl1251_acx_pd_threshold(struct wl1251 *wl);
 int wl1251_acx_slot(struct wl1251 *wl, enum acx_slot_type slot_time);
-int wl1251_acx_group_address_tbl(struct wl1251 *wl);
+int wl1251_acx_group_address_tbl(struct wl1251 *wl, bool enable,
+                                void *mc_list, u32 mc_list_len);
 int wl1251_acx_service_period_timeout(struct wl1251 *wl);
 int wl1251_acx_rts_threshold(struct wl1251 *wl, u16 rts_threshold);
 int wl1251_acx_beacon_filter_opt(struct wl1251 *wl, bool enable_filter);
@@ -1473,6 +1488,7 @@ int wl1251_acx_mem_cfg(struct wl1251 *wl);
 int wl1251_acx_wr_tbtt_and_dtim(struct wl1251 *wl, u16 tbtt, u8 dtim);
 int wl1251_acx_bet_enable(struct wl1251 *wl, enum wl1251_acx_bet_mode mode,
                          u8 max_consecutive);
+int wl1251_acx_arp_ip_filter(struct wl1251 *wl, bool enable, __be32 address);
 int wl1251_acx_ac_cfg(struct wl1251 *wl, u8 ac, u8 cw_min, u16 cw_max,
                      u8 aifs, u16 txop);
 int wl1251_acx_tid_cfg(struct wl1251 *wl, u8 queue,
index a2e5241382da3ddab3fd71920863a9cca12ea4d3..2000cd5360776470bc33a4ec76fa940ec79500e4 100644 (file)
@@ -299,7 +299,8 @@ int wl1251_boot_run_firmware(struct wl1251 *wl)
                ROAMING_TRIGGER_LOW_RSSI_EVENT_ID |
                ROAMING_TRIGGER_REGAINED_RSSI_EVENT_ID |
                REGAINED_BSS_EVENT_ID | BT_PTA_SENSE_EVENT_ID |
-               BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID;
+               BT_PTA_PREDICTION_EVENT_ID | JOIN_EVENT_COMPLETE_ID |
+               PS_REPORT_EVENT_ID;
 
        ret = wl1251_event_unmask(wl);
        if (ret < 0) {
index 6822b845efc15d5e2305bf468cf76c6bd83e1dce..223649bcaa5a6764cff615bd9f1716b16810cc00 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/crc7.h>
+#include <linux/etherdevice.h>
 
 #include "wl1251.h"
 #include "reg.h"
@@ -203,11 +204,11 @@ out:
        return ret;
 }
 
-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
+int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable)
 {
        struct cmd_enabledisable_path *cmd;
        int ret;
-       u16 cmd_rx, cmd_tx;
+       u16 cmd_rx;
 
        wl1251_debug(DEBUG_CMD, "cmd data path");
 
@@ -219,13 +220,10 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
 
        cmd->channel = channel;
 
-       if (enable) {
+       if (enable)
                cmd_rx = CMD_ENABLE_RX;
-               cmd_tx = CMD_ENABLE_TX;
-       } else {
+       else
                cmd_rx = CMD_DISABLE_RX;
-               cmd_tx = CMD_DISABLE_TX;
-       }
 
        ret = wl1251_cmd_send(wl, cmd_rx, cmd, sizeof(*cmd));
        if (ret < 0) {
@@ -237,17 +235,38 @@ int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable)
        wl1251_debug(DEBUG_BOOT, "rx %s cmd channel %d",
                     enable ? "start" : "stop", channel);
 
+out:
+       kfree(cmd);
+       return ret;
+}
+
+int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable)
+{
+       struct cmd_enabledisable_path *cmd;
+       int ret;
+       u16 cmd_tx;
+
+       wl1251_debug(DEBUG_CMD, "cmd data path");
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (!cmd)
+               return -ENOMEM;
+
+       cmd->channel = channel;
+
+       if (enable)
+               cmd_tx = CMD_ENABLE_TX;
+       else
+               cmd_tx = CMD_DISABLE_TX;
+
        ret = wl1251_cmd_send(wl, cmd_tx, cmd, sizeof(*cmd));
-       if (ret < 0) {
+       if (ret < 0)
                wl1251_error("tx %s cmd for channel %d failed",
                             enable ? "start" : "stop", channel);
-               goto out;
-       }
-
-       wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
-                    enable ? "start" : "stop", channel);
+       else
+               wl1251_debug(DEBUG_BOOT, "tx %s cmd channel %d",
+                            enable ? "start" : "stop", channel);
 
-out:
        kfree(cmd);
        return ret;
 }
@@ -410,7 +429,9 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
        struct wl1251_cmd_scan *cmd;
        int i, ret = 0;
 
-       wl1251_debug(DEBUG_CMD, "cmd scan");
+       wl1251_debug(DEBUG_CMD, "cmd scan channels %d", n_channels);
+
+       WARN_ON(n_channels > SCAN_MAX_NUM_OF_CHANNELS);
 
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        if (!cmd)
@@ -421,6 +442,13 @@ int wl1251_cmd_scan(struct wl1251 *wl, u8 *ssid, size_t ssid_len,
                                                    CFG_RX_MGMT_EN |
                                                    CFG_RX_BCN_EN);
        cmd->params.scan_options = 0;
+       /*
+        * Use high priority scan when not associated to prevent fw issue
+        * causing never-ending scans (sometimes 20+ minutes).
+        * Note: This bug may be caused by the fw's DTIM handling.
+        */
+       if (is_zero_ether_addr(wl->bssid))
+               cmd->params.scan_options |= WL1251_SCAN_OPT_PRIORITY_HIGH;
        cmd->params.num_channels = n_channels;
        cmd->params.num_probe_requests = n_probes;
        cmd->params.tx_rate = cpu_to_le16(1 << 1); /* 2 Mbps */
index ee4f2b391822ac7b58da04e5c6fa6e52daef0813..d824ff9783116ac3db04d18a3736312b3d565f35 100644 (file)
@@ -35,7 +35,8 @@ int wl1251_cmd_interrogate(struct wl1251 *wl, u16 id, void *buf, size_t len);
 int wl1251_cmd_configure(struct wl1251 *wl, u16 id, void *buf, size_t len);
 int wl1251_cmd_vbm(struct wl1251 *wl, u8 identity,
                   void *bitmap, u16 bitmap_len, u8 bitmap_control);
-int wl1251_cmd_data_path(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_data_path_rx(struct wl1251 *wl, u8 channel, bool enable);
+int wl1251_cmd_data_path_tx(struct wl1251 *wl, u8 channel, bool enable);
 int wl1251_cmd_join(struct wl1251 *wl, u8 bss_type, u8 channel,
                    u16 beacon_interval, u8 dtim_interval);
 int wl1251_cmd_ps_mode(struct wl1251 *wl, u8 ps_mode);
@@ -167,6 +168,11 @@ struct cmd_read_write_memory {
 #define CMDMBOX_HEADER_LEN 4
 #define CMDMBOX_INFO_ELEM_HEADER_LEN 4
 
+#define WL1251_SCAN_OPT_PASSIVE                1
+#define WL1251_SCAN_OPT_5GHZ_BAND      2
+#define WL1251_SCAN_OPT_TRIGGERD_SCAN  4
+#define WL1251_SCAN_OPT_PRIORITY_HIGH  8
+
 #define WL1251_SCAN_MIN_DURATION 30000
 #define WL1251_SCAN_MAX_DURATION 60000
 
index 74ae8e1c2e334a3f61071209a2e9b6fd952014d4..db0105313745f08a02c9d408564c5d8029aa05ca 100644 (file)
@@ -46,6 +46,43 @@ static int wl1251_event_scan_complete(struct wl1251 *wl,
        return ret;
 }
 
+#define WL1251_PSM_ENTRY_RETRIES  3
+static int wl1251_event_ps_report(struct wl1251 *wl,
+                                 struct event_mailbox *mbox)
+{
+       int ret = 0;
+
+       wl1251_debug(DEBUG_EVENT, "ps status: %x", mbox->ps_status);
+
+       switch (mbox->ps_status) {
+       case EVENT_ENTER_POWER_SAVE_FAIL:
+               wl1251_debug(DEBUG_PSM, "PSM entry failed");
+
+               if (wl->station_mode != STATION_POWER_SAVE_MODE) {
+                       /* remain in active mode */
+                       wl->psm_entry_retry = 0;
+                       break;
+               }
+
+               if (wl->psm_entry_retry < WL1251_PSM_ENTRY_RETRIES) {
+                       wl->psm_entry_retry++;
+                       ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
+               } else {
+                       wl1251_error("Power save entry failed, giving up");
+                       wl->psm_entry_retry = 0;
+               }
+               break;
+       case EVENT_ENTER_POWER_SAVE_SUCCESS:
+       case EVENT_EXIT_POWER_SAVE_FAIL:
+       case EVENT_EXIT_POWER_SAVE_SUCCESS:
+       default:
+               wl->psm_entry_retry = 0;
+               break;
+       }
+
+       return 0;
+}
+
 static void wl1251_event_mbox_dump(struct event_mailbox *mbox)
 {
        wl1251_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -80,7 +117,14 @@ static int wl1251_event_process(struct wl1251 *wl, struct event_mailbox *mbox)
                }
        }
 
-       if (vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
+       if (vector & PS_REPORT_EVENT_ID) {
+               wl1251_debug(DEBUG_EVENT, "PS_REPORT_EVENT");
+               ret = wl1251_event_ps_report(wl, mbox);
+               if (ret < 0)
+                       return ret;
+       }
+
+       if (wl->vif && vector & SYNCHRONIZATION_TIMEOUT_EVENT_ID) {
                wl1251_debug(DEBUG_EVENT, "SYNCHRONIZATION_TIMEOUT_EVENT");
 
                /* indicate to the stack, that beacons have been lost */
index 30eb5d150bf75d8ca8a653a4adc27f59f186d0a7..88570a5cd04210af6a890e0e39808fbc94e55e76 100644 (file)
@@ -112,6 +112,13 @@ struct event_mailbox {
        u8 padding[19];
 } __packed;
 
+enum {
+       EVENT_ENTER_POWER_SAVE_FAIL = 0,
+       EVENT_ENTER_POWER_SAVE_SUCCESS,
+       EVENT_EXIT_POWER_SAVE_FAIL,
+       EVENT_EXIT_POWER_SAVE_SUCCESS,
+};
+
 int wl1251_event_unmask(struct wl1251 *wl);
 void wl1251_event_mbox_config(struct wl1251 *wl);
 int wl1251_event_handle(struct wl1251 *wl, u8 mbox);
index 89b43d35473c662a6f5763c992dbb1f35e8f18c0..1d799bffaa9f35ab772057beae1ba067d8b406df 100644 (file)
@@ -33,7 +33,7 @@ int wl1251_hw_init_hwenc_config(struct wl1251 *wl)
 {
        int ret;
 
-       ret = wl1251_acx_feature_cfg(wl);
+       ret = wl1251_acx_feature_cfg(wl, 0);
        if (ret < 0) {
                wl1251_warning("couldn't set feature config");
                return ret;
@@ -127,7 +127,7 @@ int wl1251_hw_init_phy_config(struct wl1251 *wl)
        if (ret < 0)
                return ret;
 
-       ret = wl1251_acx_group_address_tbl(wl);
+       ret = wl1251_acx_group_address_tbl(wl, true, NULL, 0);
        if (ret < 0)
                return ret;
 
@@ -394,8 +394,13 @@ int wl1251_hw_init(struct wl1251 *wl)
        if (ret < 0)
                goto out_free_data_path;
 
-       /* Enable data path */
-       ret = wl1251_cmd_data_path(wl, wl->channel, 1);
+       /* Enable rx data path */
+       ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+       if (ret < 0)
+               goto out_free_data_path;
+
+       /* Enable tx data path */
+       ret = wl1251_cmd_data_path_tx(wl, wl->channel, 1);
        if (ret < 0)
                goto out_free_data_path;
 
index 3291ffa952736ac9f6ac2784c758db39b498d37c..80f92110a3bfd692ef53f0899cf8551fbc00b973 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/etherdevice.h>
 #include <linux/vmalloc.h>
 #include <linux/slab.h>
+#include <linux/netdevice.h>
 
 #include "wl1251.h"
 #include "wl12xx_80211.h"
@@ -479,10 +480,13 @@ static void wl1251_op_stop(struct ieee80211_hw *hw)
        wl->next_tx_complete = 0;
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
 
        wl1251_debugfs_reset(wl);
 
@@ -542,6 +546,7 @@ static void wl1251_op_remove_interface(struct ieee80211_hw *hw,
        mutex_lock(&wl->mutex);
        wl1251_debug(DEBUG_MAC80211, "mac80211 remove interface");
        wl->vif = NULL;
+       memset(wl->bssid, 0, ETH_ALEN);
        mutex_unlock(&wl->mutex);
 }
 
@@ -566,6 +571,11 @@ static int wl1251_build_qos_null_data(struct wl1251 *wl)
                                       sizeof(template));
 }
 
+static bool wl1251_can_do_pm(struct ieee80211_conf *conf, struct wl1251 *wl)
+{
+       return (conf->flags & IEEE80211_CONF_PS) && !wl->monitor_present;
+}
+
 static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct wl1251 *wl = hw->priv;
@@ -575,8 +585,10 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        channel = ieee80211_frequency_to_channel(
                        conf->chandef.chan->center_freq);
 
-       wl1251_debug(DEBUG_MAC80211, "mac80211 config ch %d psm %s power %d",
+       wl1251_debug(DEBUG_MAC80211,
+                    "mac80211 config ch %d monitor %s psm %s power %d",
                     channel,
+                    conf->flags & IEEE80211_CONF_MONITOR ? "on" : "off",
                     conf->flags & IEEE80211_CONF_PS ? "on" : "off",
                     conf->power_level);
 
@@ -586,16 +598,44 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
        if (ret < 0)
                goto out;
 
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
+               u32 mode;
+
+               if (conf->flags & IEEE80211_CONF_MONITOR) {
+                       wl->monitor_present = true;
+                       mode = DF_SNIFF_MODE_ENABLE | DF_ENCRYPTION_DISABLE;
+               } else {
+                       wl->monitor_present = false;
+                       mode = 0;
+               }
+
+               ret = wl1251_acx_feature_cfg(wl, mode);
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (channel != wl->channel) {
                wl->channel = channel;
 
-               ret = wl1251_join(wl, wl->bss_type, wl->channel,
-                                 wl->beacon_int, wl->dtim_period);
+               /*
+                * Use ENABLE_RX command for channel switching when no
+                * interface is present (monitor mode only).
+                * This leaves the tx path disabled in firmware, whereas
+                * the usual JOIN command seems to transmit some frames
+                * at firmware level.
+                */
+               if (wl->vif == NULL) {
+                       wl->joined = false;
+                       ret = wl1251_cmd_data_path_rx(wl, wl->channel, 1);
+               } else {
+                       ret = wl1251_join(wl, wl->bss_type, wl->channel,
+                                         wl->beacon_int, wl->dtim_period);
+               }
                if (ret < 0)
                        goto out_sleep;
        }
 
-       if (conf->flags & IEEE80211_CONF_PS && !wl->psm_requested) {
+       if (wl1251_can_do_pm(conf, wl) && !wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm enabled");
 
                wl->psm_requested = true;
@@ -611,8 +651,7 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                ret = wl1251_ps_set_mode(wl, STATION_POWER_SAVE_MODE);
                if (ret < 0)
                        goto out_sleep;
-       } else if (!(conf->flags & IEEE80211_CONF_PS) &&
-                  wl->psm_requested) {
+       } else if (!wl1251_can_do_pm(conf, wl) && wl->psm_requested) {
                wl1251_debug(DEBUG_PSM, "psm disabled");
 
                wl->psm_requested = false;
@@ -648,6 +687,16 @@ static int wl1251_op_config(struct ieee80211_hw *hw, u32 changed)
                wl->power_level = conf->power_level;
        }
 
+       /*
+        * Tell stack that connection is lost because hw encryption isn't
+        * supported in monitor mode.
+        * This requires temporary enabling of the hw connection monitor flag
+        */
+       if ((changed & IEEE80211_CONF_CHANGE_MONITOR) && wl->vif) {
+               wl->hw->flags |= IEEE80211_HW_CONNECTION_MONITOR;
+               ieee80211_connection_loss(wl->vif);
+       }
+
 out_sleep:
        wl1251_ps_elp_sleep(wl);
 
@@ -657,6 +706,44 @@ out:
        return ret;
 }
 
+struct wl1251_filter_params {
+       bool enabled;
+       int mc_list_length;
+       u8 mc_list[ACX_MC_ADDRESS_GROUP_MAX][ETH_ALEN];
+};
+
+static u64 wl1251_op_prepare_multicast(struct ieee80211_hw *hw,
+                                      struct netdev_hw_addr_list *mc_list)
+{
+       struct wl1251_filter_params *fp;
+       struct netdev_hw_addr *ha;
+       struct wl1251 *wl = hw->priv;
+
+       if (unlikely(wl->state == WL1251_STATE_OFF))
+               return 0;
+
+       fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+       if (!fp) {
+               wl1251_error("Out of memory setting filters.");
+               return 0;
+       }
+
+       /* update multicast filtering parameters */
+       fp->mc_list_length = 0;
+       if (netdev_hw_addr_list_count(mc_list) > ACX_MC_ADDRESS_GROUP_MAX) {
+               fp->enabled = false;
+       } else {
+               fp->enabled = true;
+               netdev_hw_addr_list_for_each(ha, mc_list) {
+                       memcpy(fp->mc_list[fp->mc_list_length],
+                                       ha->addr, ETH_ALEN);
+                       fp->mc_list_length++;
+               }
+       }
+
+       return (u64)(unsigned long)fp;
+}
+
 #define WL1251_SUPPORTED_FILTERS (FIF_PROMISC_IN_BSS | \
                                  FIF_ALLMULTI | \
                                  FIF_FCSFAIL | \
@@ -667,8 +754,9 @@ out:
 
 static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
                                       unsigned int changed,
-                                      unsigned int *total,u64 multicast)
+                                      unsigned int *total, u64 multicast)
 {
+       struct wl1251_filter_params *fp = (void *)(unsigned long)multicast;
        struct wl1251 *wl = hw->priv;
        int ret;
 
@@ -677,9 +765,11 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        *total &= WL1251_SUPPORTED_FILTERS;
        changed &= WL1251_SUPPORTED_FILTERS;
 
-       if (changed == 0)
+       if (changed == 0) {
                /* no filters which we support changed */
+               kfree(fp);
                return;
+       }
 
        mutex_lock(&wl->mutex);
 
@@ -716,6 +806,15 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
+       if (*total & FIF_ALLMULTI || *total & FIF_PROMISC_IN_BSS)
+               ret = wl1251_acx_group_address_tbl(wl, false, NULL, 0);
+       else if (fp)
+               ret = wl1251_acx_group_address_tbl(wl, fp->enabled,
+                                                  fp->mc_list,
+                                                  fp->mc_list_length);
+       if (ret < 0)
+               goto out;
+
        /* send filters to firmware */
        wl1251_acx_rx_config(wl, wl->rx_config, wl->rx_filter);
 
@@ -723,6 +822,7 @@ static void wl1251_op_configure_filter(struct ieee80211_hw *hw,
 
 out:
        mutex_unlock(&wl->mutex);
+       kfree(fp);
 }
 
 /* HW encryption */
@@ -802,12 +902,12 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 
        mutex_lock(&wl->mutex);
 
-       ret = wl1251_ps_elp_wakeup(wl);
-       if (ret < 0)
-               goto out_unlock;
-
        switch (cmd) {
        case SET_KEY:
+               if (wl->monitor_present) {
+                       ret = -EOPNOTSUPP;
+                       goto out_unlock;
+               }
                wl_cmd->key_action = KEY_ADD_OR_REPLACE;
                break;
        case DISABLE_KEY:
@@ -818,6 +918,10 @@ static int wl1251_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        }
 
+       ret = wl1251_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out_unlock;
+
        ret = wl1251_set_key_type(wl, wl_cmd, cmd, key, addr);
        if (ret < 0) {
                wl1251_error("Set KEY type failed");
@@ -930,6 +1034,7 @@ static int wl1251_op_hw_scan(struct ieee80211_hw *hw,
        ret = wl1251_cmd_scan(wl, ssid, ssid_len, req->channels,
                              req->n_channels, WL1251_SCAN_NUM_PROBES);
        if (ret < 0) {
+               wl1251_debug(DEBUG_SCAN, "scan failed %d", ret);
                wl->scanning = false;
                goto out_idle;
        }
@@ -977,6 +1082,7 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct wl1251 *wl = hw->priv;
        struct sk_buff *beacon, *skb;
+       bool enable;
        int ret;
 
        wl1251_debug(DEBUG_MAC80211, "mac80211 bss info changed");
@@ -1023,6 +1129,9 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_ASSOC) {
+               /* Disable temporary enabled hw connection monitor flag */
+               wl->hw->flags &= ~IEEE80211_HW_CONNECTION_MONITOR;
+
                if (bss_conf->assoc) {
                        wl->beacon_int = bss_conf->beacon_int;
 
@@ -1075,6 +1184,17 @@ static void wl1251_op_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
+       if (changed & BSS_CHANGED_ARP_FILTER) {
+               __be32 addr = bss_conf->arp_addr_list[0];
+               WARN_ON(wl->bss_type != BSS_TYPE_STA_BSS);
+
+               enable = bss_conf->arp_addr_cnt == 1 && bss_conf->assoc;
+               wl1251_acx_arp_ip_filter(wl, enable, addr);
+
+               if (ret < 0)
+                       goto out_sleep;
+       }
+
        if (changed & BSS_CHANGED_BEACON) {
                beacon = ieee80211_beacon_get(hw, vif);
                if (!beacon)
@@ -1245,6 +1365,7 @@ static const struct ieee80211_ops wl1251_ops = {
        .add_interface = wl1251_op_add_interface,
        .remove_interface = wl1251_op_remove_interface,
        .config = wl1251_op_config,
+       .prepare_multicast = wl1251_op_prepare_multicast,
        .configure_filter = wl1251_op_configure_filter,
        .tx = wl1251_op_tx,
        .set_key = wl1251_op_set_key,
@@ -1401,7 +1522,10 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
 
        INIT_DELAYED_WORK(&wl->elp_work, wl1251_elp_work);
        wl->channel = WL1251_DEFAULT_CHANNEL;
+       wl->monitor_present = false;
+       wl->joined = false;
        wl->scanning = false;
+       wl->bss_type = MAX_BSS_TYPE;
        wl->default_key = 0;
        wl->listen_int = 1;
        wl->rx_counter = 0;
@@ -1413,6 +1537,7 @@ struct ieee80211_hw *wl1251_alloc_hw(void)
        wl->elp = false;
        wl->station_mode = STATION_ACTIVE_MODE;
        wl->psm_requested = false;
+       wl->psm_entry_retry = 0;
        wl->tx_queue_stopped = false;
        wl->power_level = WL1251_DEFAULT_POWER_LEVEL;
        wl->rssi_thold = 0;
@@ -1478,3 +1603,4 @@ MODULE_DESCRIPTION("TI wl1251 Wireles LAN Driver Core");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Kalle Valo <kvalo@adurom.com>");
 MODULE_FIRMWARE(WL1251_FW_NAME);
+MODULE_FIRMWARE(WL1251_NVS_NAME);
index 23289d49dd31806210566fe2aa737154eecf482e..123c4bb50e0a0c2eff220c4509c2ece5aab7b365 100644 (file)
@@ -83,7 +83,7 @@ static void wl1251_rx_status(struct wl1251 *wl,
 
        status->flag |= RX_FLAG_MACTIME_START;
 
-       if (desc->flags & RX_DESC_ENCRYPTION_MASK) {
+       if (!wl->monitor_present && (desc->flags & RX_DESC_ENCRYPTION_MASK)) {
                status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
 
                if (likely(!(desc->flags & RX_DESC_DECRYPT_FAIL)))
index 28121c590a2b1a62effa4c17b335b83264c99acf..81de83c6fcf625108b9cdb5dcd7145f1a741d143 100644 (file)
@@ -28,6 +28,7 @@
 #include "tx.h"
 #include "ps.h"
 #include "io.h"
+#include "event.h"
 
 static bool wl1251_tx_double_buffer_busy(struct wl1251 *wl, u32 data_out_count)
 {
@@ -89,8 +90,12 @@ static void wl1251_tx_control(struct tx_double_buffer_desc *tx_hdr,
        /* 802.11 packets */
        tx_hdr->control.packet_type = 0;
 
-       if (control->flags & IEEE80211_TX_CTL_NO_ACK)
+       /* Also disable retry and ACK policy for injected packets */
+       if ((control->flags & IEEE80211_TX_CTL_NO_ACK) ||
+           (control->flags & IEEE80211_TX_CTL_INJECTED)) {
+               tx_hdr->control.rate_policy = 1;
                tx_hdr->control.ack_policy = 1;
+       }
 
        tx_hdr->control.tx_complete = 1;
 
@@ -277,6 +282,26 @@ static void wl1251_tx_trigger(struct wl1251 *wl)
                TX_STATUS_DATA_OUT_COUNT_MASK;
 }
 
+static void enable_tx_for_packet_injection(struct wl1251 *wl)
+{
+       int ret;
+
+       ret = wl1251_cmd_join(wl, BSS_TYPE_STA_BSS, wl->channel,
+                             wl->beacon_int, wl->dtim_period);
+       if (ret < 0) {
+               wl1251_warning("join failed");
+               return;
+       }
+
+       ret = wl1251_event_wait(wl, JOIN_EVENT_COMPLETE_ID, 100);
+       if (ret < 0) {
+               wl1251_warning("join timeout");
+               return;
+       }
+
+       wl->joined = true;
+}
+
 /* caller must hold wl->mutex */
 static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
 {
@@ -287,6 +312,9 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
        info = IEEE80211_SKB_CB(skb);
 
        if (info->control.hw_key) {
+               if (unlikely(wl->monitor_present))
+                       return -EINVAL;
+
                idx = info->control.hw_key->hw_key_idx;
                if (unlikely(wl->default_key != idx)) {
                        ret = wl1251_acx_default_key(wl, idx);
@@ -295,6 +323,10 @@ static int wl1251_tx_frame(struct wl1251 *wl, struct sk_buff *skb)
                }
        }
 
+       /* Enable tx path in monitor mode for packet injection */
+       if ((wl->vif == NULL) && !wl->joined)
+               enable_tx_for_packet_injection(wl);
+
        ret = wl1251_tx_path_status(wl);
        if (ret < 0)
                return ret;
@@ -394,6 +426,7 @@ static void wl1251_tx_packet_cb(struct wl1251 *wl,
        info = IEEE80211_SKB_CB(skb);
 
        if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) &&
+           !(info->flags & IEEE80211_TX_CTL_INJECTED) &&
            (result->status == TX_SUCCESS))
                info->flags |= IEEE80211_TX_STAT_ACK;
 
index 2c3bd1bff3f68e08de48b42101c52606a472fa6a..235617a7716d59ff4a699427540c1ecb4a612178 100644 (file)
@@ -93,6 +93,7 @@ enum {
        } while (0)
 
 #define WL1251_DEFAULT_RX_CONFIG (CFG_UNI_FILTER_EN |  \
+                                 CFG_MC_FILTER_EN |    \
                                  CFG_BSSID_FILTER_EN)
 
 #define WL1251_DEFAULT_RX_FILTER (CFG_RX_PRSP_EN |  \
@@ -303,6 +304,8 @@ struct wl1251 {
        u8 bss_type;
        u8 listen_int;
        int channel;
+       bool monitor_present;
+       bool joined;
 
        void *target_mem_map;
        struct acx_data_path_params_resp *data_path;
@@ -368,6 +371,9 @@ struct wl1251 {
        /* PSM mode requested */
        bool psm_requested;
 
+       /* retry counter for PSM entries */
+       u8 psm_entry_retry;
+
        u16 beacon_int;
        u8 dtim_period;
 
index 38d2089f338a3277d8ff77126f3dd166524f84b8..1f5987d142c1c56d71a184be9c1b8f6dba9352c4 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/delay.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/in.h>
 #include <linux/kernel.h>
index c1fb20603338299eb2eecfd085653480dd726428..fe20e1cc0545bf4bb9700f054bddea12fb1ec643 100644 (file)
@@ -58,5 +58,6 @@ config NFC_PORT100
 
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/microread/Kconfig"
+source "drivers/nfc/nfcmrvl/Kconfig"
 
 endmenu
index c715fe8582a8075503f7db5de758fa250d2905bb..56ab822ba03d9f1be61a544f975368de086b75ba 100644 (file)
@@ -9,5 +9,6 @@ obj-$(CONFIG_NFC_WILINK)        += nfcwilink.o
 obj-$(CONFIG_NFC_MEI_PHY)      += mei_phy.o
 obj-$(CONFIG_NFC_SIM)          += nfcsim.o
 obj-$(CONFIG_NFC_PORT100)      += port100.o
+obj-$(CONFIG_NFC_MRVL)         += nfcmrvl/
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
index 1d78605519850b5392c8c25ff51fc358f6dea308..11c7cbdade6663fe73e680a853df9908d1e18286 100644 (file)
@@ -127,7 +127,7 @@ void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
 
                reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
                if (reply_size < MEI_NFC_HEADER_SIZE) {
-                       kfree(skb);
+                       kfree_skb(skb);
                        return;
                }
 
diff --git a/drivers/nfc/nfcmrvl/Kconfig b/drivers/nfc/nfcmrvl/Kconfig
new file mode 100644 (file)
index 0000000..5e18afd
--- /dev/null
@@ -0,0 +1,23 @@
+config NFC_MRVL
+       tristate "Marvell NFC driver support"
+       depends on NFC_NCI
+       help
+         The core driver to support Marvell NFC devices.
+
+         This driver is required if you want to support
+         Marvell NFC device 8897.
+
+         Say Y here to compile Marvell NFC driver into the kernel or
+         say M to compile it as module.
+
+config NFC_MRVL_USB
+       tristate "Marvell NFC-over-USB driver"
+       depends on NFC_MRVL && USB
+       help
+         Marvell NFC-over-USB driver.
+
+         This driver provides support for Marvell NFC-over-USB devices:
+          8897.
+
+         Say Y here to compile support for Marvell NFC-over-USB driver
+         into the kernel or say M to compile it as module.
diff --git a/drivers/nfc/nfcmrvl/Makefile b/drivers/nfc/nfcmrvl/Makefile
new file mode 100644 (file)
index 0000000..97a0de7
--- /dev/null
@@ -0,0 +1,9 @@
+#
+# Makefile for NFCMRVL NCI based NFC driver
+#
+
+nfcmrvl-y += main.o
+obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
+
+nfcmrvl_usb-y += usb.o
+obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o
diff --git a/drivers/nfc/nfcmrvl/main.c b/drivers/nfc/nfcmrvl/main.c
new file mode 100644 (file)
index 0000000..85e8bcf
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Marvell NFC driver: major functions
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+#define VERSION "1.0"
+
+static int nfcmrvl_nci_open(struct nci_dev *ndev)
+{
+       struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+       int err;
+
+       if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+               return 0;
+
+       err = priv->if_ops->nci_open(priv);
+
+       if (err)
+               clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags);
+
+       return err;
+}
+
+static int nfcmrvl_nci_close(struct nci_dev *ndev)
+{
+       struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+
+       if (!test_and_clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+               return 0;
+
+       priv->if_ops->nci_close(priv);
+
+       return 0;
+}
+
+static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+
+       nfc_info(priv->dev, "send entry, len %d\n", skb->len);
+
+       skb->dev = (void *)ndev;
+
+       if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+               return -EBUSY;
+
+       return priv->if_ops->nci_send(priv, skb);
+}
+
+static int nfcmrvl_nci_setup(struct nci_dev *ndev)
+{
+       __u8 val;
+
+       val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
+       nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
+       val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
+       nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
+       val = NFCMRVL_EXT_COEX_ENABLE;
+       nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
+
+       return 0;
+}
+
+static struct nci_ops nfcmrvl_nci_ops = {
+       .open = nfcmrvl_nci_open,
+       .close = nfcmrvl_nci_close,
+       .send = nfcmrvl_nci_send,
+       .setup = nfcmrvl_nci_setup,
+};
+
+struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
+                                                struct nfcmrvl_if_ops *ops,
+                                                struct device *dev)
+{
+       struct nfcmrvl_private *priv;
+       int rc;
+       u32 protocols;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return ERR_PTR(-ENOMEM);
+
+       priv->drv_data = drv_data;
+       priv->if_ops = ops;
+       priv->dev = dev;
+
+       protocols = NFC_PROTO_JEWEL_MASK
+               | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+               | NFC_PROTO_ISO14443_MASK
+               | NFC_PROTO_ISO14443_B_MASK
+               | NFC_PROTO_NFC_DEP_MASK;
+
+       priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
+       if (!priv->ndev) {
+               nfc_err(dev, "nci_allocate_device failed");
+               rc = -ENOMEM;
+               goto error;
+       }
+
+       nci_set_drvdata(priv->ndev, priv);
+
+       rc = nci_register_device(priv->ndev);
+       if (rc) {
+               nfc_err(dev, "nci_register_device failed %d", rc);
+               nci_free_device(priv->ndev);
+               goto error;
+       }
+
+       nfc_info(dev, "registered with nci successfully\n");
+       return priv;
+
+error:
+       kfree(priv);
+       return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_register_dev);
+
+void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
+{
+       struct nci_dev *ndev = priv->ndev;
+
+       nci_unregister_device(ndev);
+       nci_free_device(ndev);
+       kfree(priv);
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
+
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
+{
+       struct sk_buff *skb;
+
+       skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       memcpy(skb_put(skb, count), data, count);
+       nci_recv_frame(priv->ndev, skb);
+
+       return count;
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/nfc/nfcmrvl/nfcmrvl.h b/drivers/nfc/nfcmrvl/nfcmrvl.h
new file mode 100644 (file)
index 0000000..54c4a95
--- /dev/null
@@ -0,0 +1,48 @@
+/**
+ * Marvell NFC driver
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+/* Define private flags: */
+#define NFCMRVL_NCI_RUNNING                    1
+
+#define NFCMRVL_EXT_COEX_ID                    0xE0
+#define NFCMRVL_NOT_ALLOWED_ID                 0xE1
+#define NFCMRVL_ACTIVE_ID                      0xE2
+#define NFCMRVL_EXT_COEX_ENABLE                        1
+#define NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED       0xA
+#define NFCMRVL_GPIO_PIN_NFC_ACTIVE            0xB
+#define NFCMRVL_NCI_MAX_EVENT_SIZE             260
+
+struct nfcmrvl_private {
+       struct nci_dev *ndev;
+       unsigned long flags;
+       void *drv_data;
+       struct device *dev;
+       struct nfcmrvl_if_ops *if_ops;
+};
+
+struct nfcmrvl_if_ops {
+       int (*nci_open) (struct nfcmrvl_private *priv);
+       int (*nci_close) (struct nfcmrvl_private *priv);
+       int (*nci_send) (struct nfcmrvl_private *priv, struct sk_buff *skb);
+};
+
+void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
+struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
+                                                struct nfcmrvl_if_ops *ops,
+                                                struct device *dev);
diff --git a/drivers/nfc/nfcmrvl/usb.c b/drivers/nfc/nfcmrvl/usb.c
new file mode 100644 (file)
index 0000000..3221ca3
--- /dev/null
@@ -0,0 +1,459 @@
+/**
+ * Marvell NFC-over-USB driver: USB interface related functions
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+#define VERSION "1.0"
+
+static struct usb_device_id nfcmrvl_table[] = {
+       { USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
+       { }     /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, nfcmrvl_table);
+
+#define NFCMRVL_USB_BULK_RUNNING       1
+#define NFCMRVL_USB_SUSPENDING         2
+
+struct nfcmrvl_usb_drv_data {
+       struct usb_device *udev;
+       struct usb_interface *intf;
+       unsigned long flags;
+       struct work_struct waker;
+       struct usb_anchor tx_anchor;
+       struct usb_anchor bulk_anchor;
+       struct usb_anchor deferred;
+       int tx_in_flight;
+       /* protects tx_in_flight */
+       spinlock_t txlock;
+       struct usb_endpoint_descriptor *bulk_tx_ep;
+       struct usb_endpoint_descriptor *bulk_rx_ep;
+       int suspend_count;
+       struct nfcmrvl_private *priv;
+};
+
+static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
+{
+       unsigned long flags;
+       int rv;
+
+       spin_lock_irqsave(&drv_data->txlock, flags);
+       rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+       if (!rv)
+               drv_data->tx_in_flight++;
+       spin_unlock_irqrestore(&drv_data->txlock, flags);
+
+       return rv;
+}
+
+static void nfcmrvl_bulk_complete(struct urb *urb)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = urb->context;
+       int err;
+
+       dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
+               urb, urb->status, urb->actual_length);
+
+       if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+               return;
+
+       if (!urb->status) {
+               if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
+                                          urb->actual_length) < 0)
+                       nfc_err(&drv_data->udev->dev, "corrupted Rx packet");
+       }
+
+       if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
+               return;
+
+       usb_anchor_urb(urb, &drv_data->bulk_anchor);
+       usb_mark_last_busy(drv_data->udev);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err) {
+               /* -EPERM: urb is being killed;
+                * -ENODEV: device got disconnected
+                */
+               if (err != -EPERM && err != -ENODEV)
+                       nfc_err(&drv_data->udev->dev,
+                               "urb %p failed to resubmit (%d)", urb, -err);
+               usb_unanchor_urb(urb);
+       }
+}
+
+static int
+nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
+{
+       struct urb *urb;
+       unsigned char *buf;
+       unsigned int pipe;
+       int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE;
+
+       if (!drv_data->bulk_rx_ep)
+               return -ENODEV;
+
+       urb = usb_alloc_urb(0, mem_flags);
+       if (!urb)
+               return -ENOMEM;
+
+       buf = kmalloc(size, mem_flags);
+       if (!buf) {
+               usb_free_urb(urb);
+               return -ENOMEM;
+       }
+
+       pipe = usb_rcvbulkpipe(drv_data->udev,
+                              drv_data->bulk_rx_ep->bEndpointAddress);
+
+       usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
+                         nfcmrvl_bulk_complete, drv_data);
+
+       urb->transfer_flags |= URB_FREE_BUFFER;
+
+       usb_mark_last_busy(drv_data->udev);
+       usb_anchor_urb(urb, &drv_data->bulk_anchor);
+
+       err = usb_submit_urb(urb, mem_flags);
+       if (err) {
+               if (err != -EPERM && err != -ENODEV)
+                       nfc_err(&drv_data->udev->dev,
+                               "urb %p submission failed (%d)", urb, -err);
+               usb_unanchor_urb(urb);
+       }
+
+       usb_free_urb(urb);
+
+       return err;
+}
+
+static void nfcmrvl_tx_complete(struct urb *urb)
+{
+       struct sk_buff *skb = urb->context;
+       struct nci_dev *ndev = (struct nci_dev *)skb->dev;
+       struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+       struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+
+       nfc_info(priv->dev, "urb %p status %d count %d",
+                urb, urb->status, urb->actual_length);
+
+       spin_lock(&drv_data->txlock);
+       drv_data->tx_in_flight--;
+       spin_unlock(&drv_data->txlock);
+
+       kfree(urb->setup_packet);
+       kfree_skb(skb);
+}
+
+static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+       int err;
+
+       err = usb_autopm_get_interface(drv_data->intf);
+       if (err)
+               return err;
+
+       drv_data->intf->needs_remote_wakeup = 1;
+
+       err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+       if (err)
+               goto failed;
+
+       set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+       nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+
+       usb_autopm_put_interface(drv_data->intf);
+       return 0;
+
+failed:
+       usb_autopm_put_interface(drv_data->intf);
+       return err;
+}
+
+static void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data)
+{
+       usb_kill_anchored_urbs(&drv_data->bulk_anchor);
+}
+
+static int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+       int err;
+
+       cancel_work_sync(&drv_data->waker);
+
+       clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+
+       nfcmrvl_usb_stop_traffic(drv_data);
+       usb_kill_anchored_urbs(&drv_data->tx_anchor);
+       err = usb_autopm_get_interface(drv_data->intf);
+       if (err)
+               goto failed;
+
+       drv_data->intf->needs_remote_wakeup = 0;
+       usb_autopm_put_interface(drv_data->intf);
+
+failed:
+       usb_scuttle_anchored_urbs(&drv_data->deferred);
+       return 0;
+}
+
+static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
+                               struct sk_buff *skb)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+       struct urb *urb;
+       unsigned int pipe;
+       int err;
+
+       if (!drv_data->bulk_tx_ep)
+               return -ENODEV;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+       if (!urb)
+               return -ENOMEM;
+
+       pipe = usb_sndbulkpipe(drv_data->udev,
+                               drv_data->bulk_tx_ep->bEndpointAddress);
+
+       usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len,
+                         nfcmrvl_tx_complete, skb);
+
+       err = nfcmrvl_inc_tx(drv_data);
+       if (err) {
+               usb_anchor_urb(urb, &drv_data->deferred);
+               schedule_work(&drv_data->waker);
+               err = 0;
+               goto done;
+       }
+
+       usb_anchor_urb(urb, &drv_data->tx_anchor);
+
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err) {
+               if (err != -EPERM && err != -ENODEV)
+                       nfc_err(&drv_data->udev->dev,
+                               "urb %p submission failed (%d)", urb, -err);
+               kfree(urb->setup_packet);
+               usb_unanchor_urb(urb);
+       } else {
+               usb_mark_last_busy(drv_data->udev);
+       }
+
+done:
+       usb_free_urb(urb);
+       return err;
+}
+
+static struct nfcmrvl_if_ops usb_ops = {
+       .nci_open = nfcmrvl_usb_nci_open,
+       .nci_close = nfcmrvl_usb_nci_close,
+       .nci_send = nfcmrvl_usb_nci_send,
+};
+
+static void nfcmrvl_waker(struct work_struct *work)
+{
+       struct nfcmrvl_usb_drv_data *drv_data =
+                       container_of(work, struct nfcmrvl_usb_drv_data, waker);
+       int err;
+
+       err = usb_autopm_get_interface(drv_data->intf);
+       if (err)
+               return;
+
+       usb_autopm_put_interface(drv_data->intf);
+}
+
+static int nfcmrvl_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct usb_endpoint_descriptor *ep_desc;
+       struct nfcmrvl_usb_drv_data *drv_data;
+       struct nfcmrvl_private *priv;
+       int i;
+       struct usb_device *udev = interface_to_usbdev(intf);
+
+       nfc_info(&udev->dev, "intf %p id %p", intf, id);
+
+       drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
+       if (!drv_data)
+               return -ENOMEM;
+
+       for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+               ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+               if (!drv_data->bulk_tx_ep &&
+                   usb_endpoint_is_bulk_out(ep_desc)) {
+                       drv_data->bulk_tx_ep = ep_desc;
+                       continue;
+               }
+
+               if (!drv_data->bulk_rx_ep &&
+                   usb_endpoint_is_bulk_in(ep_desc)) {
+                       drv_data->bulk_rx_ep = ep_desc;
+                       continue;
+               }
+       }
+
+       if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep)
+               return -ENODEV;
+
+       drv_data->udev = udev;
+       drv_data->intf = intf;
+
+       INIT_WORK(&drv_data->waker, nfcmrvl_waker);
+       spin_lock_init(&drv_data->txlock);
+
+       init_usb_anchor(&drv_data->tx_anchor);
+       init_usb_anchor(&drv_data->bulk_anchor);
+       init_usb_anchor(&drv_data->deferred);
+
+       priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
+                                       &drv_data->udev->dev);
+       if (IS_ERR(priv))
+               return PTR_ERR(priv);
+
+       drv_data->priv = priv;
+       priv->dev = &drv_data->udev->dev;
+
+       usb_set_intfdata(intf, drv_data);
+
+       return 0;
+}
+
+static void nfcmrvl_disconnect(struct usb_interface *intf)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+
+       if (!drv_data)
+               return;
+
+       nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+       nfcmrvl_nci_unregister_dev(drv_data->priv);
+
+       usb_set_intfdata(drv_data->intf, NULL);
+}
+
+#ifdef CONFIG_PM
+static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+
+       nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+       if (drv_data->suspend_count++)
+               return 0;
+
+       spin_lock_irq(&drv_data->txlock);
+       if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) {
+               set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+               spin_unlock_irq(&drv_data->txlock);
+       } else {
+               spin_unlock_irq(&drv_data->txlock);
+               drv_data->suspend_count--;
+               return -EBUSY;
+       }
+
+       nfcmrvl_usb_stop_traffic(drv_data);
+       usb_kill_anchored_urbs(&drv_data->tx_anchor);
+
+       return 0;
+}
+
+static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
+{
+       struct urb *urb;
+       int err;
+
+       while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err)
+                       break;
+
+               drv_data->tx_in_flight++;
+       }
+       usb_scuttle_anchored_urbs(&drv_data->deferred);
+}
+
+static int nfcmrvl_resume(struct usb_interface *intf)
+{
+       struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+       int err = 0;
+
+       nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+       if (--drv_data->suspend_count)
+               return 0;
+
+       if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+               goto done;
+
+       if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
+               err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+               if (err) {
+                       clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+                       goto failed;
+               }
+
+               nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+       }
+
+       spin_lock_irq(&drv_data->txlock);
+       nfcmrvl_play_deferred(drv_data);
+       clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+       spin_unlock_irq(&drv_data->txlock);
+
+       return 0;
+
+failed:
+       usb_scuttle_anchored_urbs(&drv_data->deferred);
+done:
+       spin_lock_irq(&drv_data->txlock);
+       clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+       spin_unlock_irq(&drv_data->txlock);
+
+       return err;
+}
+#endif
+
+static struct usb_driver nfcmrvl_usb_driver = {
+       .name           = "nfcmrvl",
+       .probe          = nfcmrvl_probe,
+       .disconnect     = nfcmrvl_disconnect,
+#ifdef CONFIG_PM
+       .suspend        = nfcmrvl_suspend,
+       .resume         = nfcmrvl_resume,
+       .reset_resume   = nfcmrvl_resume,
+#endif
+       .id_table       = nfcmrvl_table,
+       .supports_autosuspend = 1,
+       .disable_hub_initiated_lpm = 1,
+       .soft_unbind = 1,
+};
+module_usb_driver(nfcmrvl_usb_driver);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");
index 3df19e657bc1e23aea6b28baec9adeef3337ca13..cf1a87bb74f86b405d3edc73249155f51bfb661a 100644 (file)
@@ -521,6 +521,9 @@ static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
        if (frame->ccid.type != 0x83)
                return false;
 
+       if (!frame->ccid.datalen)
+               return false;
+
        if (frame->data[frame->ccid.datalen - 2] == 0x63)
                return false;
 
index 51e21a87cd847896754fece3b17f02293b8de86c..3df4a109cfadfb36a5ccd08e788feef43da0048e 100644 (file)
@@ -195,42 +195,42 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
 
                {{0x9e, 0xaa}, 0x01},
 
-               {{0x9b, 0xd1}, 0x0d},
-               {{0x9b, 0xd2}, 0x24},
-               {{0x9b, 0xd3}, 0x0a},
-               {{0x9b, 0xd4}, 0x22},
-               {{0x9b, 0xd5}, 0x08},
-               {{0x9b, 0xd6}, 0x1e},
-               {{0x9b, 0xdd}, 0x1c},
-
-               {{0x9b, 0x84}, 0x13},
-               {{0x99, 0x81}, 0x7f},
-               {{0x99, 0x31}, 0x70},
+               {{0x9b, 0xd1}, 0x17},
+               {{0x9b, 0xd2}, 0x58},
+               {{0x9b, 0xd3}, 0x10},
+               {{0x9b, 0xd4}, 0x47},
+               {{0x9b, 0xd5}, 0x0c},
+               {{0x9b, 0xd6}, 0x37},
+               {{0x9b, 0xdd}, 0x33},
+
+               {{0x9b, 0x84}, 0x00},
+               {{0x99, 0x81}, 0x79},
+               {{0x99, 0x31}, 0x79},
 
                {{0x98, 0x00}, 0x3f},
 
-               {{0x9f, 0x09}, 0x00},
+               {{0x9f, 0x09}, 0x02},
 
                {{0x9f, 0x0a}, 0x05},
 
                {{0x9e, 0xd1}, 0xa1},
-               {{0x99, 0x23}, 0x00},
-
-               {{0x9e, 0x74}, 0x80},
+               {{0x99, 0x23}, 0x01},
 
+               {{0x9e, 0x74}, 0x00},
+               {{0x9e, 0x90}, 0x00},
                {{0x9f, 0x28}, 0x10},
 
-               {{0x9f, 0x35}, 0x14},
+               {{0x9f, 0x35}, 0x04},
 
-               {{0x9f, 0x36}, 0x60},
+               {{0x9f, 0x36}, 0x11},
 
                {{0x9c, 0x31}, 0x00},
 
-               {{0x9c, 0x32}, 0xc8},
+               {{0x9c, 0x32}, 0x00},
 
-               {{0x9c, 0x19}, 0x40},
+               {{0x9c, 0x19}, 0x0a},
 
-               {{0x9c, 0x1a}, 0x40},
+               {{0x9c, 0x1a}, 0x0a},
 
                {{0x9c, 0x0c}, 0x00},
 
@@ -240,13 +240,13 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
 
                {{0x9c, 0x13}, 0x00},
 
-               {{0x98, 0xa2}, 0x0e},
+               {{0x98, 0xa2}, 0x09},
 
-               {{0x98, 0x93}, 0x40},
+               {{0x98, 0x93}, 0x00},
 
-               {{0x98, 0x7d}, 0x02},
+               {{0x98, 0x7d}, 0x08},
                {{0x98, 0x7e}, 0x00},
-               {{0x9f, 0xc8}, 0x01},
+               {{0x9f, 0xc8}, 0x00},
        };
        struct hw_config *p = hw_config;
        int count = ARRAY_SIZE(hw_config);
index 8a0571eb2627e42becfeb424e33d8099255037c7..a8555f81cbbac2ce4dac42c509d898228cc451f3 100644 (file)
@@ -1509,6 +1509,7 @@ static void port100_disconnect(struct usb_interface *interface)
 
        usb_free_urb(dev->in_urb);
        usb_free_urb(dev->out_urb);
+       usb_put_dev(dev->udev);
 
        kfree(dev->cmd);
 
index 50328de712fa6bb199fad05303bc28b05d46c6ed..937fc31971a785061e9273f849ed515360252063 100644 (file)
@@ -37,7 +37,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_st_tbl[] = {
        { "M25P32", 0x15, 0x10000, 64, },
        { "M25P64", 0x16, 0x10000, 128, },
        { "M25FL128", 0x17, 0x10000, 256, },
-       { 0 },
+       { NULL },
 };
 
 static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
@@ -55,7 +55,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_sst_tbl[] = {
        { "SST25VF016", 0x41, 0x1000, 512, },
        { "SST25VF032", 0x4a, 0x1000, 1024, },
        { "SST25VF064", 0x4b, 0x1000, 2048, },
-       { 0 },
+       { NULL },
 };
 
 static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
@@ -66,7 +66,7 @@ static const struct ssb_sflash_tbl_e ssb_sflash_at_tbl[] = {
        { "AT45DB161", 0x2c, 512, 4096, },
        { "AT45DB321", 0x34, 512, 8192, },
        { "AT45DB642", 0x3c, 1024, 8192, },
-       { 0 },
+       { NULL },
 };
 
 static void ssb_sflash_cmd(struct ssb_chipcommon *cc, u32 opcode)
index 9f03feedc8e71e044e66f60f3cf7c3b863676ad4..d8836623f36afcbd0aa88949c27a9f3c7000fa38 100644 (file)
 /*
  * Vendors and devices.  Sort key: vendor first, device next.
  */
+#define SDIO_VENDOR_ID_BROADCOM                        0x02d0
+#define SDIO_DEVICE_ID_BROADCOM_43143          43143
+#define SDIO_DEVICE_ID_BROADCOM_43241          0x4324
+#define SDIO_DEVICE_ID_BROADCOM_4329           0x4329
+#define SDIO_DEVICE_ID_BROADCOM_4330           0x4330
+#define SDIO_DEVICE_ID_BROADCOM_4334           0x4334
+#define SDIO_DEVICE_ID_BROADCOM_4335_4339      0x4335
+#define SDIO_DEVICE_ID_BROADCOM_43362          43362
+
 #define SDIO_VENDOR_ID_INTEL                   0x0089
 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX     0x1402
 #define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI      0x1403
index cc2da73055fadba14268593a9a7457c44b9f0c78..66c1cd87bfe7f9b9d117db340f736884f9d0c4c1 100644 (file)
@@ -83,7 +83,8 @@
 enum {
        HCI_QUIRK_RESET_ON_CLOSE,
        HCI_QUIRK_RAW_DEVICE,
-       HCI_QUIRK_FIXUP_BUFFER_SIZE
+       HCI_QUIRK_FIXUP_BUFFER_SIZE,
+       HCI_QUIRK_BROKEN_STORED_LINK_KEY,
 };
 
 /* HCI device flags */
@@ -131,6 +132,7 @@ enum {
        HCI_PERIODIC_INQ,
        HCI_FAST_CONNECTABLE,
        HCI_BREDR_ENABLED,
+       HCI_6LOWPAN_ENABLED,
 };
 
 /* A mask for the flags that are supposed to remain when a reset happens
index b796161fb04e8f02b0de6f398fee59d8d464150b..f2f0cf5865c40a9b92f7a98eb4c53c6834a34d29 100644 (file)
@@ -448,6 +448,7 @@ enum {
        HCI_CONN_SSP_ENABLED,
        HCI_CONN_POWER_SAVE,
        HCI_CONN_REMOTE_OOB,
+       HCI_CONN_6LOWPAN,
 };
 
 static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
index e149e992fdae9d9b113b349c1db5d062a72d5971..dbc4a89984ca67287715a8279b2d9793e7d2eebe 100644 (file)
@@ -136,6 +136,7 @@ struct l2cap_conninfo {
 #define L2CAP_FC_L2CAP         0x02
 #define L2CAP_FC_CONNLESS      0x04
 #define L2CAP_FC_A2MP          0x08
+#define L2CAP_FC_6LOWPAN        0x3e /* reserved and temporary value */
 
 /* L2CAP Control Field bit masks */
 #define L2CAP_CTRL_SAR                 0xC000
index 80a10212b1b9bee63eafcae9d3142e6aee18d9e2..56c597793d6d380cb90c80c5d17f73fe87a63eb6 100644 (file)
@@ -1971,6 +1971,50 @@ struct cfg80211_mgmt_tx_params {
        bool dont_wait_for_ack;
 };
 
+/**
+ * struct cfg80211_dscp_exception - DSCP exception
+ *
+ * @dscp: DSCP value that does not adhere to the user priority range definition
+ * @up: user priority value to which the corresponding DSCP value belongs
+ */
+struct cfg80211_dscp_exception {
+       u8 dscp;
+       u8 up;
+};
+
+/**
+ * struct cfg80211_dscp_range - DSCP range definition for user priority
+ *
+ * @low: lowest DSCP value of this user priority range, inclusive
+ * @high: highest DSCP value of this user priority range, inclusive
+ */
+struct cfg80211_dscp_range {
+       u8 low;
+       u8 high;
+};
+
+/* QoS Map Set element length defined in IEEE Std 802.11-2012, 8.4.2.97 */
+#define IEEE80211_QOS_MAP_MAX_EX       21
+#define IEEE80211_QOS_MAP_LEN_MIN      16
+#define IEEE80211_QOS_MAP_LEN_MAX \
+       (IEEE80211_QOS_MAP_LEN_MIN + 2 * IEEE80211_QOS_MAP_MAX_EX)
+
+/**
+ * struct cfg80211_qos_map - QoS Map Information
+ *
+ * This struct defines the Interworking QoS map setting for DSCP values
+ *
+ * @num_des: number of DSCP exceptions (0..21)
+ * @dscp_exception: optionally up to maximum of 21 DSCP exceptions from
+ *     the user priority DSCP range definition
+ * @up: DSCP range definition for a particular user priority
+ */
+struct cfg80211_qos_map {
+       u8 num_des;
+       struct cfg80211_dscp_exception dscp_exception[IEEE80211_QOS_MAP_MAX_EX];
+       struct cfg80211_dscp_range up[8];
+};
+
 /**
  * struct cfg80211_ops - backend description for wireless configuration
  *
@@ -2213,6 +2257,8 @@ struct cfg80211_mgmt_tx_params {
  * @set_coalesce: Set coalesce parameters.
  *
  * @channel_switch: initiate channel-switch procedure (with CSA)
+ *
+ * @set_qos_map: Set QoS mapping information to the driver
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
@@ -2454,6 +2500,9 @@ struct cfg80211_ops {
        int     (*channel_switch)(struct wiphy *wiphy,
                                  struct net_device *dev,
                                  struct cfg80211_csa_settings *params);
+       int     (*set_qos_map)(struct wiphy *wiphy,
+                              struct net_device *dev,
+                              struct cfg80211_qos_map *qos_map);
 };
 
 /*
@@ -2824,6 +2873,8 @@ struct wiphy_vendor_command {
  *
  * @vendor_commands: array of vendor commands supported by the hardware
  * @n_vendor_commands: number of vendor commands
+ * @vendor_events: array of vendor events supported by the hardware
+ * @n_vendor_events: number of vendor events
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -2936,7 +2987,8 @@ struct wiphy {
        const struct wiphy_coalesce_support *coalesce;
 
        const struct wiphy_vendor_command *vendor_commands;
-       int n_vendor_commands;
+       const struct nl80211_vendor_cmd_info *vendor_events;
+       int n_vendor_commands, n_vendor_events;
 
        char priv[0] __aligned(NETDEV_ALIGN);
 };
@@ -3429,9 +3481,11 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 /**
  * cfg80211_classify8021d - determine the 802.1p/1d tag for a data frame
  * @skb: the data frame
+ * @qos_map: Interworking QoS mapping or %NULL if not in use
  * Return: The 802.1p/1d tag.
  */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb);
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+                                   struct cfg80211_qos_map *qos_map);
 
 /**
  * cfg80211_find_ie - find information element in data
@@ -3907,6 +3961,14 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
                                           enum nl80211_attrs attr,
                                           int approxlen);
 
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int vendor_event_idx,
+                                          int approxlen, gfp_t gfp);
+
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp);
+
 /**
  * cfg80211_vendor_cmd_alloc_reply_skb - allocate vendor command reply
  * @wiphy: the wiphy
@@ -3951,6 +4013,44 @@ cfg80211_vendor_cmd_alloc_reply_skb(struct wiphy *wiphy, int approxlen)
  */
 int cfg80211_vendor_cmd_reply(struct sk_buff *skb);
 
+/**
+ * cfg80211_vendor_event_alloc - allocate vendor-specific event skb
+ * @wiphy: the wiphy
+ * @event_idx: index of the vendor event in the wiphy's vendor_events
+ * @approxlen: an upper bound of the length of the data that will
+ *     be put into the skb
+ * @gfp: allocation flags
+ *
+ * This function allocates and pre-fills an skb for an event on the
+ * vendor-specific multicast group.
+ *
+ * When done filling the skb, call cfg80211_vendor_event() with the
+ * skb to send the event.
+ *
+ * Return: An allocated and pre-filled skb. %NULL if any errors happen.
+ */
+static inline struct sk_buff *
+cfg80211_vendor_event_alloc(struct wiphy *wiphy, int approxlen,
+                           int event_idx, gfp_t gfp)
+{
+       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_VENDOR,
+                                         NL80211_ATTR_VENDOR_DATA,
+                                         event_idx, approxlen, gfp);
+}
+
+/**
+ * cfg80211_vendor_event - send the event
+ * @skb: The skb, must have been allocated with cfg80211_vendor_event_alloc()
+ * @gfp: allocation flags
+ *
+ * This function sends the given @skb, which must have been allocated
+ * by cfg80211_vendor_event_alloc(), as an event. It always consumes it.
+ */
+static inline void cfg80211_vendor_event(struct sk_buff *skb, gfp_t gfp)
+{
+       __cfg80211_send_event_skb(skb, gfp);
+}
+
 #ifdef CONFIG_NL80211_TESTMODE
 /**
  * DOC: Test mode
@@ -4031,8 +4131,13 @@ static inline int cfg80211_testmode_reply(struct sk_buff *skb)
  *
  * Return: An allocated and pre-filled skb. %NULL if any errors happen.
  */
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-                                                 int approxlen, gfp_t gfp);
+static inline struct sk_buff *
+cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy, int approxlen, gfp_t gfp)
+{
+       return __cfg80211_alloc_event_skb(wiphy, NL80211_CMD_TESTMODE,
+                                         NL80211_ATTR_TESTDATA, -1,
+                                         approxlen, gfp);
+}
 
 /**
  * cfg80211_testmode_event - send the event
@@ -4044,7 +4149,10 @@ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
  * by cfg80211_testmode_alloc_event_skb(), as an event. It always
  * consumes it.
  */
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
+static inline void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+{
+       __cfg80211_send_event_skb(skb, gfp);
+}
 
 #define CFG80211_TESTMODE_CMD(cmd)     .testmode_cmd = (cmd),
 #define CFG80211_TESTMODE_DUMP(cmd)    .testmode_dump = (cmd),
index 531785f5819ecb0ba0e665dd9be444ea8276b03d..f838af816b56cd26909752b650178450c9e47eef 100644 (file)
@@ -4652,4 +4652,51 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
                              struct ieee80211_vif *vif, struct sk_buff *skb,
                              int band, struct ieee80211_sta **sta);
 
+/**
+ * struct ieee80211_noa_data - holds temporary data for tracking P2P NoA state
+ *
+ * @next_tsf: TSF timestamp of the next absent state change
+ * @has_next_tsf: next absent state change event pending
+ *
+ * @absent: descriptor bitmask, set if GO is currently absent
+ *
+ * private:
+ *
+ * @count: count fields from the NoA descriptors
+ * @desc: adjusted data from the NoA
+ */
+struct ieee80211_noa_data {
+       u32 next_tsf;
+       bool has_next_tsf;
+
+       u8 absent;
+
+       u8 count[IEEE80211_P2P_NOA_DESC_MAX];
+       struct {
+               u32 start;
+               u32 duration;
+               u32 interval;
+       } desc[IEEE80211_P2P_NOA_DESC_MAX];
+};
+
+/**
+ * ieee80211_parse_p2p_noa - initialize NoA tracking data from P2P IE
+ *
+ * @attr: P2P NoA IE
+ * @data: NoA tracking data
+ * @tsf: current TSF timestamp
+ *
+ * Return: number of successfully parsed descriptors
+ */
+int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
+                           struct ieee80211_noa_data *data, u32 tsf);
+
+/**
+ * ieee80211_update_p2p_noa - get next pending P2P GO absent state change
+ *
+ * @data: NoA tracking data
+ * @tsf: current TSF timestamp
+ */
+void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf);
+
 #endif /* MAC80211_H */
index 36acecd5f06c17475d1cf21ff571155b2aaf0221..81af21e9bcd49b141f799fca231bbf7b1deb08ec 100644 (file)
@@ -122,6 +122,16 @@ typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev,
  *     switch_rf to turn the radio on. A call to in|tg_configure_hw must turn
  *     the device radio on.
  * @abort_cmd: Discard the last sent command.
+ *
+ * Notes: Asynchronous functions have a timeout parameter. It is the driver
+ *     responsibility to call the digital stack back through the
+ *     nfc_digital_cmd_complete_t callback when no RF respsonse has been
+ *     received within the specified time (in milliseconds). In that case the
+ *     driver must set the resp sk_buff to ERR_PTR(-ETIMEDOUT).
+ *     Since the digital stack serializes commands to be sent, it's mandatory
+ *     for the driver to handle the timeout correctly. Otherwise the stack
+ *     would not be able to send new commands, waiting for the reply of the
+ *     current one.
  */
 struct nfc_digital_ops {
        int (*in_configure_hw)(struct nfc_digital_dev *ddev, int type,
index 6126f1f992b40068923771cf0a7967395f88017e..2b93b77b210c9540d8a746d8239a6842cd798286 100644 (file)
@@ -68,6 +68,7 @@ struct nci_ops {
        int (*open)(struct nci_dev *ndev);
        int (*close)(struct nci_dev *ndev);
        int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
+       int (*setup)(struct nci_dev *ndev);
 };
 
 #define NCI_MAX_SUPPORTED_RF_INTERFACES                4
@@ -154,6 +155,7 @@ void nci_free_device(struct nci_dev *ndev);
 int nci_register_device(struct nci_dev *ndev);
 void nci_unregister_device(struct nci_dev *ndev);
 int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
+int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val);
 
 static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev,
                                            unsigned int len,
index d7fea3496f323078739fc6c6148be125f79797c3..4d024d75d64ba8b7831cdb1d61384e47ac14ef33 100644 (file)
@@ -94,6 +94,7 @@
 #define ARPHRD_CAIF    822             /* CAIF media type              */
 #define ARPHRD_IP6GRE  823             /* GRE over IPv6                */
 #define ARPHRD_NETLINK 824             /* Netlink header               */
+#define ARPHRD_6LOWPAN 825             /* IPv6 over LoWPAN             */
 
 #define ARPHRD_VOID      0xFFFF        /* Void type, nothing is known */
 #define ARPHRD_NONE      0xFFFE        /* zero header length */
index e1307909ecf118728434286aa2150da73d4d0225..91054fd660e083156f02b826f0a5b812d7faac26 100644 (file)
  *     (&struct nl80211_vendor_cmd_info) of the supported vendor commands.
  *     This may also be sent as an event with the same attributes.
  *
+ * @NL80211_CMD_SET_QOS_MAP: Set Interworking QoS mapping for IP DSCP values.
+ *     The QoS mapping information is included in %NL80211_ATTR_QOS_MAP. If
+ *     that attribute is not included, QoS mapping is disabled. Since this
+ *     QoS mapping is relevant for IP packets, it is only valid during an
+ *     association. This is cleared on disassociation and AP restart.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -871,6 +877,8 @@ enum nl80211_commands {
 
        NL80211_CMD_VENDOR,
 
+       NL80211_CMD_SET_QOS_MAP,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1540,6 +1548,12 @@ enum nl80211_commands {
  * @NL80211_ATTR_VENDOR_SUBCMD: vendor sub-command
  * @NL80211_ATTR_VENDOR_DATA: data for the vendor command, if any; this
  *     attribute is also used for vendor command feature advertisement
+ * @NL80211_ATTR_VENDOR_EVENTS: used for event list advertising in the wiphy
+ *     info, containing a nested array of possible events
+ *
+ * @NL80211_ATTR_QOS_MAP: IP DSCP mapping for Interworking QoS mapping. This
+ *     data is in the format defined for the payload of the QoS Map Set element
+ *     in IEEE Std 802.11-2012, 8.4.2.97.
  *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -1865,6 +1879,9 @@ enum nl80211_attrs {
        NL80211_ATTR_VENDOR_ID,
        NL80211_ATTR_VENDOR_SUBCMD,
        NL80211_ATTR_VENDOR_DATA,
+       NL80211_ATTR_VENDOR_EVENTS,
+
+       NL80211_ATTR_QOS_MAP,
 
        /* add attributes here, update the policy in nl80211.c */
 
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
new file mode 100644 (file)
index 0000000..adb3ea0
--- /dev/null
@@ -0,0 +1,860 @@
+/*
+   Copyright (c) 2013 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <net/af_ieee802154.h> /* to get the address type */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "6lowpan.h"
+
+#include "../ieee802154/6lowpan.h" /* for the compression support */
+
+#define IFACE_NAME_TEMPLATE "bt%d"
+#define EUI64_ADDR_LEN 8
+
+struct skb_cb {
+       struct in6_addr addr;
+       struct l2cap_conn *conn;
+};
+#define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb))
+
+/* The devices list contains those devices that we are acting
+ * as a proxy. The BT 6LoWPAN device is a virtual device that
+ * connects to the Bluetooth LE device. The real connection to
+ * BT device is done via l2cap layer. There exists one
+ * virtual device / one BT 6LoWPAN network (=hciX device).
+ * The list contains struct lowpan_dev elements.
+ */
+static LIST_HEAD(bt_6lowpan_devices);
+static DEFINE_RWLOCK(devices_lock);
+
+struct lowpan_peer {
+       struct list_head list;
+       struct l2cap_conn *conn;
+
+       /* peer addresses in various formats */
+       unsigned char eui64_addr[EUI64_ADDR_LEN];
+       struct in6_addr peer_addr;
+};
+
+struct lowpan_dev {
+       struct list_head list;
+
+       struct hci_dev *hdev;
+       struct net_device *netdev;
+       struct list_head peers;
+       atomic_t peer_count; /* number of items in peers list */
+
+       struct work_struct delete_netdev;
+       struct delayed_work notify_peers;
+};
+
+static inline struct lowpan_dev *lowpan_dev(const struct net_device *netdev)
+{
+       return netdev_priv(netdev);
+}
+
+static inline void peer_add(struct lowpan_dev *dev, struct lowpan_peer *peer)
+{
+       list_add(&peer->list, &dev->peers);
+       atomic_inc(&dev->peer_count);
+}
+
+static inline bool peer_del(struct lowpan_dev *dev, struct lowpan_peer *peer)
+{
+       list_del(&peer->list);
+
+       if (atomic_dec_and_test(&dev->peer_count)) {
+               BT_DBG("last peer");
+               return true;
+       }
+
+       return false;
+}
+
+static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_dev *dev,
+                                                bdaddr_t *ba, __u8 type)
+{
+       struct lowpan_peer *peer, *tmp;
+
+       BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
+              ba, type);
+
+       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+               BT_DBG("addr %pMR type %d",
+                      &peer->conn->hcon->dst, peer->conn->hcon->dst_type);
+
+               if (bacmp(&peer->conn->hcon->dst, ba))
+                       continue;
+
+               if (type == peer->conn->hcon->dst_type)
+                       return peer;
+       }
+
+       return NULL;
+}
+
+static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev,
+                                                  struct l2cap_conn *conn)
+{
+       struct lowpan_peer *peer, *tmp;
+
+       list_for_each_entry_safe(peer, tmp, &dev->peers, list) {
+               if (peer->conn == conn)
+                       return peer;
+       }
+
+       return NULL;
+}
+
+static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_peer *peer = NULL;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               peer = peer_lookup_conn(entry, conn);
+               if (peer)
+                       break;
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+
+       return peer;
+}
+
+static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *dev = NULL;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               if (conn->hcon->hdev == entry->hdev) {
+                       dev = entry;
+                       break;
+               }
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+
+       return dev;
+}
+
+static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff *skb_cp;
+       int ret;
+
+       skb_cp = skb_copy(skb, GFP_ATOMIC);
+       if (!skb_cp)
+               return -ENOMEM;
+
+       ret = netif_rx(skb_cp);
+
+       BT_DBG("receive skb %d", ret);
+       if (ret < 0)
+               return NET_RX_DROP;
+
+       return ret;
+}
+
+static int process_data(struct sk_buff *skb, struct net_device *netdev,
+                       struct l2cap_conn *conn)
+{
+       const u8 *saddr, *daddr;
+       u8 iphc0, iphc1;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       unsigned long flags;
+
+       dev = lowpan_dev(netdev);
+
+       read_lock_irqsave(&devices_lock, flags);
+       peer = peer_lookup_conn(dev, conn);
+       read_unlock_irqrestore(&devices_lock, flags);
+       if (!peer)
+               goto drop;
+
+       saddr = peer->eui64_addr;
+       daddr = dev->netdev->dev_addr;
+
+       /* at least two bytes will be used for the encoding */
+       if (skb->len < 2)
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc0))
+               goto drop;
+
+       if (lowpan_fetch_skb_u8(skb, &iphc1))
+               goto drop;
+
+       return lowpan_process_data(skb, netdev,
+                                  saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+                                  daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+                                  iphc0, iphc1, give_skb_to_upper);
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+
+static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
+                   struct l2cap_conn *conn)
+{
+       struct sk_buff *local_skb;
+       int ret;
+
+       if (!netif_running(dev))
+               goto drop;
+
+       if (dev->type != ARPHRD_6LOWPAN)
+               goto drop;
+
+       /* check that it's our buffer */
+       if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+               /* Copy the packet so that the IPv6 header is
+                * properly aligned.
+                */
+               local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
+                                           skb_tailroom(skb), GFP_ATOMIC);
+               if (!local_skb)
+                       goto drop;
+
+               local_skb->protocol = htons(ETH_P_IPV6);
+               local_skb->pkt_type = PACKET_HOST;
+
+               skb_reset_network_header(local_skb);
+               skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
+
+               if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
+                       kfree_skb(local_skb);
+                       goto drop;
+               }
+
+               dev->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+
+               kfree_skb(local_skb);
+               kfree_skb(skb);
+       } else {
+               switch (skb->data[0] & 0xe0) {
+               case LOWPAN_DISPATCH_IPHC:      /* ipv6 datagram */
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+                       if (!local_skb)
+                               goto drop;
+
+                       ret = process_data(local_skb, dev, conn);
+                       if (ret != NET_RX_SUCCESS)
+                               goto drop;
+
+                       dev->stats.rx_bytes += skb->len;
+                       dev->stats.rx_packets++;
+
+                       kfree_skb(skb);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return NET_RX_SUCCESS;
+
+drop:
+       kfree_skb(skb);
+       return NET_RX_DROP;
+}
+
+/* Packet from BT LE device */
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       int err;
+
+       peer = lookup_peer(conn);
+       if (!peer)
+               return -ENOENT;
+
+       dev = lookup_dev(conn);
+       if (!dev || !dev->netdev)
+               return -ENOENT;
+
+       err = recv_pkt(skb, dev->netdev, conn);
+       BT_DBG("recv pkt %d", err);
+
+       return err;
+}
+
+static inline int skbuff_copy(void *msg, int len, int count, int mtu,
+                             struct sk_buff *skb, struct net_device *dev)
+{
+       struct sk_buff **frag;
+       int sent = 0;
+
+       memcpy(skb_put(skb, count), msg, count);
+
+       sent += count;
+       msg  += count;
+       len  -= count;
+
+       dev->stats.tx_bytes += count;
+       dev->stats.tx_packets++;
+
+       raw_dump_table(__func__, "Sending", skb->data, skb->len);
+
+       /* Continuation fragments (no L2CAP header) */
+       frag = &skb_shinfo(skb)->frag_list;
+       while (len > 0) {
+               struct sk_buff *tmp;
+
+               count = min_t(unsigned int, mtu, len);
+
+               tmp = bt_skb_alloc(count, GFP_ATOMIC);
+               if (!tmp)
+                       return -ENOMEM;
+
+               *frag = tmp;
+
+               memcpy(skb_put(*frag, count), msg, count);
+
+               raw_dump_table(__func__, "Sending fragment",
+                              (*frag)->data, count);
+
+               (*frag)->priority = skb->priority;
+
+               sent += count;
+               msg  += count;
+               len  -= count;
+
+               skb->len += (*frag)->len;
+               skb->data_len += (*frag)->len;
+
+               frag = &(*frag)->next;
+
+               dev->stats.tx_bytes += count;
+               dev->stats.tx_packets++;
+       }
+
+       return sent;
+}
+
+static struct sk_buff *create_pdu(struct l2cap_conn *conn, void *msg,
+                                 size_t len, u32 priority,
+                                 struct net_device *dev)
+{
+       struct sk_buff *skb;
+       int err, count;
+       struct l2cap_hdr *lh;
+
+       /* FIXME: This mtu check should be not needed and atm is only used for
+        * testing purposes
+        */
+       if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE))
+               conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE;
+
+       count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
+
+       BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count);
+
+       skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_ATOMIC);
+       if (!skb)
+               return ERR_PTR(-ENOMEM);
+
+       skb->priority = priority;
+
+       lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE);
+       lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN);
+       lh->len = cpu_to_le16(len);
+
+       err = skbuff_copy(msg, len, count, conn->mtu, skb, dev);
+       if (unlikely(err < 0)) {
+               kfree_skb(skb);
+               BT_DBG("skbuff copy %d failed", err);
+               return ERR_PTR(err);
+       }
+
+       return skb;
+}
+
+static int conn_send(struct l2cap_conn *conn,
+                    void *msg, size_t len, u32 priority,
+                    struct net_device *dev)
+{
+       struct sk_buff *skb;
+
+       skb = create_pdu(conn, msg, len, priority, dev);
+       if (IS_ERR(skb))
+               return -EINVAL;
+
+       BT_DBG("conn %p skb %p len %d priority %u", conn, skb, skb->len,
+              skb->priority);
+
+       hci_send_acl(conn->hchan, skb, ACL_START);
+
+       return 0;
+}
+
+static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
+                           bdaddr_t *addr, u8 *addr_type)
+{
+       u8 *eui64;
+
+       eui64 = ip6_daddr->s6_addr + 8;
+
+       addr->b[0] = eui64[7];
+       addr->b[1] = eui64[6];
+       addr->b[2] = eui64[5];
+       addr->b[3] = eui64[2];
+       addr->b[4] = eui64[1];
+       addr->b[5] = eui64[0];
+
+       addr->b[5] ^= 2;
+
+       /* Set universal/local bit to 0 */
+       if (addr->b[5] & 1) {
+               addr->b[5] &= ~1;
+               *addr_type = ADDR_LE_DEV_PUBLIC;
+       } else {
+               *addr_type = ADDR_LE_DEV_RANDOM;
+       }
+}
+
+static int header_create(struct sk_buff *skb, struct net_device *netdev,
+                        unsigned short type, const void *_daddr,
+                        const void *_saddr, unsigned int len)
+{
+       struct ipv6hdr *hdr;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       bdaddr_t addr, *any = BDADDR_ANY;
+       u8 *saddr, *daddr = any->b;
+       u8 addr_type;
+
+       if (type != ETH_P_IPV6)
+               return -EINVAL;
+
+       hdr = ipv6_hdr(skb);
+
+       dev = lowpan_dev(netdev);
+
+       if (ipv6_addr_is_multicast(&hdr->daddr)) {
+               memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+                      sizeof(struct in6_addr));
+               lowpan_cb(skb)->conn = NULL;
+       } else {
+               unsigned long flags;
+
+               /* Get destination BT device from skb.
+                * If there is no such peer then discard the packet.
+                */
+               get_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
+
+               BT_DBG("dest addr %pMR type %d", &addr, addr_type);
+
+               read_lock_irqsave(&devices_lock, flags);
+               peer = peer_lookup_ba(dev, &addr, addr_type);
+               read_unlock_irqrestore(&devices_lock, flags);
+
+               if (!peer) {
+                       BT_DBG("no such peer %pMR found", &addr);
+                       return -ENOENT;
+               }
+
+               daddr = peer->eui64_addr;
+
+               memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+                      sizeof(struct in6_addr));
+               lowpan_cb(skb)->conn = peer->conn;
+       }
+
+       saddr = dev->netdev->dev_addr;
+
+       return lowpan_header_compress(skb, netdev, type, daddr, saddr, len);
+}
+
+/* Packet to BT LE device */
+static int send_pkt(struct l2cap_conn *conn, const void *saddr,
+                   const void *daddr, struct sk_buff *skb,
+                   struct net_device *netdev)
+{
+       raw_dump_table(__func__, "raw skb data dump before fragmentation",
+                      skb->data, skb->len);
+
+       return conn_send(conn, skb->data, skb->len, 0, netdev);
+}
+
+static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct sk_buff *local_skb;
+       struct lowpan_dev *entry, *tmp;
+       unsigned long flags;
+
+       read_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               struct lowpan_peer *pentry, *ptmp;
+               struct lowpan_dev *dev;
+
+               if (entry->netdev != netdev)
+                       continue;
+
+               dev = lowpan_dev(entry->netdev);
+
+               list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
+                       local_skb = skb_clone(skb, GFP_ATOMIC);
+
+                       send_pkt(pentry->conn, netdev->dev_addr,
+                                pentry->eui64_addr, local_skb, netdev);
+
+                       kfree_skb(local_skb);
+               }
+       }
+
+       read_unlock_irqrestore(&devices_lock, flags);
+}
+
+static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       int err = 0;
+       unsigned char *eui64_addr;
+       struct lowpan_dev *dev;
+       struct lowpan_peer *peer;
+       bdaddr_t addr;
+       u8 addr_type;
+
+       if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
+               /* We need to send the packet to every device
+                * behind this interface.
+                */
+               send_mcast_pkt(skb, netdev);
+       } else {
+               unsigned long flags;
+
+               get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
+               eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8;
+               dev = lowpan_dev(netdev);
+
+               read_lock_irqsave(&devices_lock, flags);
+               peer = peer_lookup_ba(dev, &addr, addr_type);
+               read_unlock_irqrestore(&devices_lock, flags);
+
+               BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name,
+                      &addr, &lowpan_cb(skb)->addr, peer);
+
+               if (peer && peer->conn)
+                       err = send_pkt(peer->conn, netdev->dev_addr,
+                                      eui64_addr, skb, netdev);
+       }
+       dev_kfree_skb(skb);
+
+       if (err)
+               BT_DBG("ERROR: xmit failed (%d)", err);
+
+       return (err < 0) ? NET_XMIT_DROP : err;
+}
+
+static const struct net_device_ops netdev_ops = {
+       .ndo_start_xmit         = bt_xmit,
+};
+
+static struct header_ops header_ops = {
+       .create = header_create,
+};
+
+static void netdev_setup(struct net_device *dev)
+{
+       dev->addr_len           = EUI64_ADDR_LEN;
+       dev->type               = ARPHRD_6LOWPAN;
+
+       dev->hard_header_len    = 0;
+       dev->needed_tailroom    = 0;
+       dev->mtu                = IPV6_MIN_MTU;
+       dev->tx_queue_len       = 0;
+       dev->flags              = IFF_RUNNING | IFF_POINTOPOINT;
+       dev->watchdog_timeo     = 0;
+
+       dev->netdev_ops         = &netdev_ops;
+       dev->header_ops         = &header_ops;
+       dev->destructor         = free_netdev;
+}
+
+static struct device_type bt_type = {
+       .name   = "bluetooth",
+};
+
+static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
+{
+       /* addr is the BT address in little-endian format */
+       eui[0] = addr[5];
+       eui[1] = addr[4];
+       eui[2] = addr[3];
+       eui[3] = 0xFF;
+       eui[4] = 0xFE;
+       eui[5] = addr[2];
+       eui[6] = addr[1];
+       eui[7] = addr[0];
+
+       eui[0] ^= 2;
+
+       /* Universal/local bit set, RFC 4291 */
+       if (addr_type == ADDR_LE_DEV_PUBLIC)
+               eui[0] |= 1;
+       else
+               eui[0] &= ~1;
+}
+
+static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
+                        u8 addr_type)
+{
+       netdev->addr_assign_type = NET_ADDR_PERM;
+       set_addr(netdev->dev_addr, addr->b, addr_type);
+       netdev->dev_addr[0] ^= 2;
+}
+
+static void ifup(struct net_device *netdev)
+{
+       int err;
+
+       rtnl_lock();
+       err = dev_open(netdev);
+       if (err < 0)
+               BT_INFO("iface %s cannot be opened (%d)", netdev->name, err);
+       rtnl_unlock();
+}
+
+static void do_notify_peers(struct work_struct *work)
+{
+       struct lowpan_dev *dev = container_of(work, struct lowpan_dev,
+                                             notify_peers.work);
+
+       netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
+}
+
+static bool is_bt_6lowpan(struct hci_conn *hcon)
+{
+       if (hcon->type != LE_LINK)
+               return false;
+
+       return test_bit(HCI_CONN_6LOWPAN, &hcon->flags);
+}
+
+static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev)
+{
+       struct lowpan_peer *peer;
+       unsigned long flags;
+
+       peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
+       if (!peer)
+               return -ENOMEM;
+
+       peer->conn = conn;
+       memset(&peer->peer_addr, 0, sizeof(struct in6_addr));
+
+       /* RFC 2464 ch. 5 */
+       peer->peer_addr.s6_addr[0] = 0xFE;
+       peer->peer_addr.s6_addr[1] = 0x80;
+       set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b,
+                conn->hcon->dst_type);
+
+       memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
+              EUI64_ADDR_LEN);
+       peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local)
+                                  * is done according RFC2464
+                                  */
+
+       raw_dump_inline(__func__, "peer IPv6 address",
+                       (unsigned char *)&peer->peer_addr, 16);
+       raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8);
+
+       write_lock_irqsave(&devices_lock, flags);
+       INIT_LIST_HEAD(&peer->list);
+       peer_add(dev, peer);
+       write_unlock_irqrestore(&devices_lock, flags);
+
+       /* Notifying peers about us needs to be done without locks held */
+       INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
+       schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100));
+
+       return 0;
+}
+
+/* This gets called when BT LE 6LoWPAN device is connected. We then
+ * create network device that acts as a proxy between BT LE device
+ * and kernel network stack.
+ */
+int bt_6lowpan_add_conn(struct l2cap_conn *conn)
+{
+       struct lowpan_peer *peer = NULL;
+       struct lowpan_dev *dev;
+       struct net_device *netdev;
+       int err = 0;
+       unsigned long flags;
+
+       if (!is_bt_6lowpan(conn->hcon))
+               return 0;
+
+       peer = lookup_peer(conn);
+       if (peer)
+               return -EEXIST;
+
+       dev = lookup_dev(conn);
+       if (dev)
+               return add_peer_conn(conn, dev);
+
+       netdev = alloc_netdev(sizeof(*dev), IFACE_NAME_TEMPLATE, netdev_setup);
+       if (!netdev)
+               return -ENOMEM;
+
+       set_dev_addr(netdev, &conn->hcon->src, conn->hcon->src_type);
+
+       netdev->netdev_ops = &netdev_ops;
+       SET_NETDEV_DEV(netdev, &conn->hcon->dev);
+       SET_NETDEV_DEVTYPE(netdev, &bt_type);
+
+       err = register_netdev(netdev);
+       if (err < 0) {
+               BT_INFO("register_netdev failed %d", err);
+               free_netdev(netdev);
+               goto out;
+       }
+
+       BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR",
+              netdev->ifindex, &conn->hcon->dst, &conn->hcon->src);
+       set_bit(__LINK_STATE_PRESENT, &netdev->state);
+
+       dev = netdev_priv(netdev);
+       dev->netdev = netdev;
+       dev->hdev = conn->hcon->hdev;
+       INIT_LIST_HEAD(&dev->peers);
+
+       write_lock_irqsave(&devices_lock, flags);
+       INIT_LIST_HEAD(&dev->list);
+       list_add(&dev->list, &bt_6lowpan_devices);
+       write_unlock_irqrestore(&devices_lock, flags);
+
+       ifup(netdev);
+
+       return add_peer_conn(conn, dev);
+
+out:
+       return err;
+}
+
+static void delete_netdev(struct work_struct *work)
+{
+       struct lowpan_dev *entry = container_of(work, struct lowpan_dev,
+                                               delete_netdev);
+
+       unregister_netdev(entry->netdev);
+
+       /* The entry pointer is deleted in device_event() */
+}
+
+int bt_6lowpan_del_conn(struct l2cap_conn *conn)
+{
+       struct lowpan_dev *entry, *tmp;
+       struct lowpan_dev *dev = NULL;
+       struct lowpan_peer *peer;
+       int err = -ENOENT;
+       unsigned long flags;
+       bool last = false;
+
+       if (!conn || !is_bt_6lowpan(conn->hcon))
+               return 0;
+
+       write_lock_irqsave(&devices_lock, flags);
+
+       list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+               dev = lowpan_dev(entry->netdev);
+               peer = peer_lookup_conn(dev, conn);
+               if (peer) {
+                       last = peer_del(dev, peer);
+                       err = 0;
+                       break;
+               }
+       }
+
+       if (!err && last && dev && !atomic_read(&dev->peer_count)) {
+               write_unlock_irqrestore(&devices_lock, flags);
+
+               cancel_delayed_work_sync(&dev->notify_peers);
+
+               /* bt_6lowpan_del_conn() is called with hci dev lock held which
+                * means that we must delete the netdevice in worker thread.
+                */
+               INIT_WORK(&entry->delete_netdev, delete_netdev);
+               schedule_work(&entry->delete_netdev);
+       } else {
+               write_unlock_irqrestore(&devices_lock, flags);
+       }
+
+       return err;
+}
+
+static int device_event(struct notifier_block *unused,
+                       unsigned long event, void *ptr)
+{
+       struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
+       struct lowpan_dev *entry, *tmp;
+       unsigned long flags;
+
+       if (netdev->type != ARPHRD_6LOWPAN)
+               return NOTIFY_DONE;
+
+       switch (event) {
+       case NETDEV_UNREGISTER:
+               write_lock_irqsave(&devices_lock, flags);
+               list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
+                                        list) {
+                       if (entry->netdev == netdev) {
+                               list_del(&entry->list);
+                               kfree(entry);
+                               break;
+                       }
+               }
+               write_unlock_irqrestore(&devices_lock, flags);
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block bt_6lowpan_dev_notifier = {
+       .notifier_call = device_event,
+};
+
+int bt_6lowpan_init(void)
+{
+       return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
+
+void bt_6lowpan_cleanup(void)
+{
+       unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h
new file mode 100644 (file)
index 0000000..680eac8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+   Copyright (c) 2013 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef __6LOWPAN_H
+#define __6LOWPAN_H
+
+#include <linux/skbuff.h>
+#include <net/bluetooth/l2cap.h>
+
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
+int bt_6lowpan_add_conn(struct l2cap_conn *conn);
+int bt_6lowpan_del_conn(struct l2cap_conn *conn);
+int bt_6lowpan_init(void);
+void bt_6lowpan_cleanup(void);
+
+#endif /* __6LOWPAN_H */
index 6a791e73e39d936f0d9958d506c540c5a2805727..cc6827e2ce68b093be549a1be17b7159b23c1ddc 100644 (file)
@@ -10,6 +10,10 @@ obj-$(CONFIG_BT_HIDP)        += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-       a2mp.o amp.o
+       a2mp.o amp.o 6lowpan.o
+
+ifeq ($(CONFIG_IEEE802154_6LOWPAN),)
+  bluetooth-y +=  ../ieee802154/6lowpan_iphc.o
+endif
 
 subdir-ccflags-y += -D__CHECK_ENDIAN__
index 8b8b5f80dd89e2aaa6a9e3bb67f0ad5f371eae1d..5e8663c194c18e3c29ab221efe667dd311944294 100644 (file)
@@ -636,6 +636,49 @@ static int conn_max_interval_get(void *data, u64 *val)
 DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get,
                        conn_max_interval_set, "%llu\n");
 
+static ssize_t lowpan_read(struct file *file, char __user *user_buf,
+                          size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[3];
+
+       buf[0] = test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags) ? 'Y' : 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t lowpan_write(struct file *fp, const char __user *user_buffer,
+                           size_t count, loff_t *position)
+{
+       struct hci_dev *hdev = fp->private_data;
+       bool enable;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf)-1));
+
+       if (copy_from_user(buf, user_buffer, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+
+       if (strtobool(buf, &enable) < 0)
+               return -EINVAL;
+
+       if (enable == test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+               return -EALREADY;
+
+       change_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags);
+
+       return count;
+}
+
+static const struct file_operations lowpan_debugfs_fops = {
+       .open           = simple_open,
+       .read           = lowpan_read,
+       .write          = lowpan_write,
+       .llseek         = default_llseek,
+};
+
 /* ---- HCI requests ---- */
 
 static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -1261,8 +1304,13 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
         * as supported send it. If not supported assume that the controller
         * does not have actual support for stored link keys which makes this
         * command redundant anyway.
+        *
+        * Some controllers indicate that they support handling deleting
+        * stored link keys, but they don't. The quirk lets a driver
+        * just disable this command.
         */
-       if (hdev->commands[6] & 0x80) {
+       if (hdev->commands[6] & 0x80 &&
+           !test_bit(HCI_QUIRK_BROKEN_STORED_LINK_KEY, &hdev->quirks)) {
                struct hci_cp_delete_stored_link_key cp;
 
                bacpy(&cp.bdaddr, BDADDR_ANY);
@@ -1406,6 +1454,8 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &conn_min_interval_fops);
                debugfs_create_file("conn_max_interval", 0644, hdev->debugfs,
                                    hdev, &conn_max_interval_fops);
+               debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
+                                   &lowpan_debugfs_fops);
        }
 
        return 0;
index 5fb3df66c2cd5bda5b0ba7fa6cfda11565dbcde3..5f812455a4504260927cb2dd5a3bdc018e0e20d4 100644 (file)
@@ -3533,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
        conn->handle = __le16_to_cpu(ev->handle);
        conn->state = BT_CONNECTED;
 
+       if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+               set_bit(HCI_CONN_6LOWPAN, &conn->flags);
+
        hci_conn_add_sysfs(conn);
 
        hci_proto_connect_cfm(conn, ev->status);
index 6a6c8bb4fd72d4f2d4294b9f7fed772d81e57b93..7552f9e3089ce790040268f1ce0a067d6ef728cb 100644 (file)
@@ -940,8 +940,22 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        bt_cb(skb)->pkt_type = *((unsigned char *) skb->data);
        skb_pull(skb, 1);
 
-       if (hci_pi(sk)->channel == HCI_CHANNEL_RAW &&
-           bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
+       if (hci_pi(sk)->channel == HCI_CHANNEL_USER) {
+               /* No permission check is needed for user channel
+                * since that gets enforced when binding the socket.
+                *
+                * However check that the packet type is valid.
+                */
+               if (bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
+                   bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
+                   bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
+                       err = -EINVAL;
+                       goto drop;
+               }
+
+               skb_queue_tail(&hdev->raw_q, skb);
+               queue_work(hdev->workqueue, &hdev->tx_work);
+       } else if (bt_cb(skb)->pkt_type == HCI_COMMAND_PKT) {
                u16 opcode = get_unaligned_le16(skb->data);
                u16 ogf = hci_opcode_ogf(opcode);
                u16 ocf = hci_opcode_ocf(opcode);
@@ -972,14 +986,6 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                        goto drop;
                }
 
-               if (hci_pi(sk)->channel == HCI_CHANNEL_USER &&
-                   bt_cb(skb)->pkt_type != HCI_COMMAND_PKT &&
-                   bt_cb(skb)->pkt_type != HCI_ACLDATA_PKT &&
-                   bt_cb(skb)->pkt_type != HCI_SCODATA_PKT) {
-                       err = -EINVAL;
-                       goto drop;
-               }
-
                skb_queue_tail(&hdev->raw_q, skb);
                queue_work(hdev->workqueue, &hdev->tx_work);
        }
index b6bca64b320d23ba786573598174e7d0a8b73d32..b0ad2c752d738039cff8ec32c028dd109a10388b 100644 (file)
@@ -40,6 +40,7 @@
 #include "smp.h"
 #include "a2mp.h"
 #include "amp.h"
+#include "6lowpan.h"
 
 bool disable_ertm;
 
@@ -1468,6 +1469,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
 
        BT_DBG("");
 
+       bt_6lowpan_add_conn(conn);
+
        /* Check if we have socket listening on cid */
        pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_ATT,
                                          &hcon->src, &hcon->dst);
@@ -7119,6 +7122,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
                        l2cap_conn_del(conn->hcon, EACCES);
                break;
 
+       case L2CAP_FC_6LOWPAN:
+               bt_6lowpan_recv(conn, skb);
+               break;
+
        default:
                l2cap_data_channel(conn, cid, skb);
                break;
@@ -7186,6 +7193,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
+       bt_6lowpan_del_conn(hcon->l2cap_data);
+
        l2cap_conn_del(hcon, bt_to_errno(reason));
 }
 
@@ -7467,11 +7476,14 @@ int __init l2cap_init(void)
        debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs,
                           &le_default_mps);
 
+       bt_6lowpan_init();
+
        return 0;
 }
 
 void l2cap_exit(void)
 {
+       bt_6lowpan_cleanup();
        debugfs_remove(l2cap_debugfs);
        l2cap_cleanup_sockets();
 }
index e7806e6d282c29af9c64f92aaee4632b50a6c8b6..20ef748b290602c0156833970193f490800e429a 100644 (file)
@@ -147,6 +147,9 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
                    __le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
                        chan->sec_level = BT_SECURITY_SDP;
                break;
+       case L2CAP_CHAN_RAW:
+               chan->sec_level = BT_SECURITY_SDP;
+               break;
        }
 
        bacpy(&chan->src, &la.l2_bdaddr);
index 84fcf9fff3ea52e4235b7e478deb487fb075b53c..f9c0980abeeac9eaf1d94d70f3e001fd6e1f0870 100644 (file)
@@ -58,6 +58,7 @@ struct rfcomm_dev {
        uint                    modem_status;
 
        struct rfcomm_dlc       *dlc;
+       wait_queue_head_t       conn_wait;
 
        struct device           *tty_dev;
 
@@ -103,20 +104,60 @@ static void rfcomm_dev_destruct(struct tty_port *port)
        module_put(THIS_MODULE);
 }
 
-/* device-specific initialization: open the dlc */
-static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
+static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
 {
-       struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
+       struct hci_dev *hdev;
+       struct hci_conn *conn;
 
-       return rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
+       hdev = hci_get_route(&dev->dst, &dev->src);
+       if (!hdev)
+               return NULL;
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
+
+       hci_dev_put(hdev);
+
+       return conn ? &conn->dev : NULL;
 }
 
-/* we block the open until the dlc->state becomes BT_CONNECTED */
-static int rfcomm_dev_carrier_raised(struct tty_port *port)
+/* device-specific initialization: open the dlc */
+static int rfcomm_dev_activate(struct tty_port *port, struct tty_struct *tty)
 {
        struct rfcomm_dev *dev = container_of(port, struct rfcomm_dev, port);
+       DEFINE_WAIT(wait);
+       int err;
+
+       err = rfcomm_dlc_open(dev->dlc, &dev->src, &dev->dst, dev->channel);
+       if (err)
+               return err;
+
+       while (1) {
+               prepare_to_wait(&dev->conn_wait, &wait, TASK_INTERRUPTIBLE);
+
+               if (dev->dlc->state == BT_CLOSED) {
+                       err = -dev->err;
+                       break;
+               }
+
+               if (dev->dlc->state == BT_CONNECTED)
+                       break;
+
+               if (signal_pending(current)) {
+                       err = -ERESTARTSYS;
+                       break;
+               }
+
+               tty_unlock(tty);
+               schedule();
+               tty_lock(tty);
+       }
+       finish_wait(&dev->conn_wait, &wait);
+
+       if (!err)
+               device_move(dev->tty_dev, rfcomm_get_device(dev),
+                           DPM_ORDER_DEV_AFTER_PARENT);
 
-       return (dev->dlc->state == BT_CONNECTED);
+       return err;
 }
 
 /* device-specific cleanup: close the dlc */
@@ -135,7 +176,6 @@ static const struct tty_port_operations rfcomm_port_ops = {
        .destruct = rfcomm_dev_destruct,
        .activate = rfcomm_dev_activate,
        .shutdown = rfcomm_dev_shutdown,
-       .carrier_raised = rfcomm_dev_carrier_raised,
 };
 
 static struct rfcomm_dev *__rfcomm_dev_get(int id)
@@ -169,22 +209,6 @@ static struct rfcomm_dev *rfcomm_dev_get(int id)
        return dev;
 }
 
-static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
-{
-       struct hci_dev *hdev;
-       struct hci_conn *conn;
-
-       hdev = hci_get_route(&dev->dst, &dev->src);
-       if (!hdev)
-               return NULL;
-
-       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &dev->dst);
-
-       hci_dev_put(hdev);
-
-       return conn ? &conn->dev : NULL;
-}
-
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
@@ -258,6 +282,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
 
        tty_port_init(&dev->port);
        dev->port.ops = &rfcomm_port_ops;
+       init_waitqueue_head(&dev->conn_wait);
 
        skb_queue_head_init(&dev->pending);
 
@@ -437,7 +462,8 @@ static int rfcomm_release_dev(void __user *arg)
                tty_kref_put(tty);
        }
 
-       if (!test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
+       if (!test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
+           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
                tty_port_put(&dev->port);
 
        tty_port_put(&dev->port);
@@ -575,12 +601,9 @@ static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err)
        BT_DBG("dlc %p dev %p err %d", dlc, dev, err);
 
        dev->err = err;
-       if (dlc->state == BT_CONNECTED) {
-               device_move(dev->tty_dev, rfcomm_get_device(dev),
-                           DPM_ORDER_DEV_AFTER_PARENT);
+       wake_up_interruptible(&dev->conn_wait);
 
-               wake_up_interruptible(&dev->port.open_wait);
-       } else if (dlc->state == BT_CLOSED)
+       if (dlc->state == BT_CLOSED)
                tty_port_tty_hangup(&dev->port, false);
 }
 
@@ -670,10 +693,20 @@ static int rfcomm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 
        /* install the tty_port */
        err = tty_port_install(&dev->port, driver, tty);
-       if (err)
+       if (err) {
                rfcomm_tty_cleanup(tty);
+               return err;
+       }
 
-       return err;
+       /* take over the tty_port reference if the port was created with the
+        * flag RFCOMM_RELEASE_ONHUP. This will force the release of the port
+        * when the last process closes the tty. The behaviour is expected by
+        * userspace.
+        */
+       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags))
+               tty_port_put(&dev->port);
+
+       return 0;
 }
 
 static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
@@ -1010,10 +1043,6 @@ static void rfcomm_tty_hangup(struct tty_struct *tty)
        BT_DBG("tty %p dev %p", tty, dev);
 
        tty_port_hangup(&dev->port);
-
-       if (test_bit(RFCOMM_RELEASE_ONHUP, &dev->flags) &&
-           !test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags))
-               tty_port_put(&dev->port);
 }
 
 static int rfcomm_tty_tiocmget(struct tty_struct *tty)
@@ -1096,7 +1125,7 @@ int __init rfcomm_init_ttys(void)
        rfcomm_tty_driver->subtype      = SERIAL_TYPE_NORMAL;
        rfcomm_tty_driver->flags        = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        rfcomm_tty_driver->init_termios = tty_std_termios;
-       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;
+       rfcomm_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
        rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
        tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
 
index 459e200c08a40e4e737798582524cd973064b143..48b25c0af4d082a5c3256f9844f62e12e1cc6f3c 100644 (file)
@@ -62,9 +62,6 @@
 
 #include "6lowpan.h"
 
-/* TTL uncompression values */
-static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
-
 static LIST_HEAD(lowpan_devices);
 
 /* private device info */
@@ -104,378 +101,14 @@ static inline void lowpan_address_flip(u8 *src, u8 *dest)
                (dest)[IEEE802154_ADDR_LEN - i - 1] = (src)[i];
 }
 
-/* list of all 6lowpan devices, uses for package delivering */
-/* print data in line */
-static inline void lowpan_raw_dump_inline(const char *caller, char *msg,
-                                  unsigned char *buf, int len)
-{
-#ifdef DEBUG
-       if (msg)
-               pr_debug("(%s) %s: ", caller, msg);
-       print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE,
-                      16, 1, buf, len, false);
-#endif /* DEBUG */
-}
-
-/*
- * print data in a table format:
- *
- * addr: xx xx xx xx xx xx
- * addr: xx xx xx xx xx xx
- * ...
- */
-static inline void lowpan_raw_dump_table(const char *caller, char *msg,
-                                  unsigned char *buf, int len)
-{
-#ifdef DEBUG
-       if (msg)
-               pr_debug("(%s) %s:\n", caller, msg);
-       print_hex_dump(KERN_DEBUG, "\t", DUMP_PREFIX_OFFSET,
-                      16, 1, buf, len, false);
-#endif /* DEBUG */
-}
-
-static u8
-lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
-                const unsigned char *lladdr)
-{
-       u8 val = 0;
-
-       if (is_addr_mac_addr_based(ipaddr, lladdr))
-               val = 3; /* 0-bits */
-       else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
-               /* compress IID to 16 bits xxxx::XXXX */
-               memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
-               *hc06_ptr += 2;
-               val = 2; /* 16-bits */
-       } else {
-               /* do not compress IID => xxxx::IID */
-               memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
-               *hc06_ptr += 8;
-               val = 1; /* 64-bits */
-       }
-
-       return rol8(val, shift);
-}
-
-/*
- * Uncompress address function for source and
- * destination address(non-multicast).
- *
- * address_mode is sam value or dam value.
- */
-static int
-lowpan_uncompress_addr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 address_mode,
-               const struct ieee802154_addr *lladdr)
-{
-       bool fail;
-
-       switch (address_mode) {
-       case LOWPAN_IPHC_ADDR_00:
-               /* for global link addresses */
-               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
-               break;
-       case LOWPAN_IPHC_ADDR_01:
-               /* fe:80::XXXX:XXXX:XXXX:XXXX */
-               ipaddr->s6_addr[0] = 0xFE;
-               ipaddr->s6_addr[1] = 0x80;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
-               break;
-       case LOWPAN_IPHC_ADDR_02:
-               /* fe:80::ff:fe00:XXXX */
-               ipaddr->s6_addr[0] = 0xFE;
-               ipaddr->s6_addr[1] = 0x80;
-               ipaddr->s6_addr[11] = 0xFF;
-               ipaddr->s6_addr[12] = 0xFE;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
-               break;
-       case LOWPAN_IPHC_ADDR_03:
-               fail = false;
-               switch (lladdr->addr_type) {
-               case IEEE802154_ADDR_LONG:
-                       /* fe:80::XXXX:XXXX:XXXX:XXXX
-                        *        \_________________/
-                        *              hwaddr
-                        */
-                       ipaddr->s6_addr[0] = 0xFE;
-                       ipaddr->s6_addr[1] = 0x80;
-                       memcpy(&ipaddr->s6_addr[8], lladdr->hwaddr,
-                                       IEEE802154_ADDR_LEN);
-                       /* second bit-flip (Universe/Local)
-                        * is done according RFC2464
-                        */
-                       ipaddr->s6_addr[8] ^= 0x02;
-                       break;
-               case IEEE802154_ADDR_SHORT:
-                       /* fe:80::ff:fe00:XXXX
-                        *                \__/
-                        *             short_addr
-                        *
-                        * Universe/Local bit is zero.
-                        */
-                       ipaddr->s6_addr[0] = 0xFE;
-                       ipaddr->s6_addr[1] = 0x80;
-                       ipaddr->s6_addr[11] = 0xFF;
-                       ipaddr->s6_addr[12] = 0xFE;
-                       ipaddr->s6_addr16[7] = htons(lladdr->short_addr);
-                       break;
-               default:
-                       pr_debug("Invalid addr_type set\n");
-                       return -EINVAL;
-               }
-               break;
-       default:
-               pr_debug("Invalid address mode value: 0x%x\n", address_mode);
-               return -EINVAL;
-       }
-
-       if (fail) {
-               pr_debug("Failed to fetch skb data\n");
-               return -EIO;
-       }
-
-       lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-/* Uncompress address function for source context
- * based address(non-multicast).
- */
-static int
-lowpan_uncompress_context_based_src_addr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 sam)
-{
-       switch (sam) {
-       case LOWPAN_IPHC_ADDR_00:
-               /* unspec address ::
-                * Do nothing, address is already ::
-                */
-               break;
-       case LOWPAN_IPHC_ADDR_01:
-               /* TODO */
-       case LOWPAN_IPHC_ADDR_02:
-               /* TODO */
-       case LOWPAN_IPHC_ADDR_03:
-               /* TODO */
-               netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
-               return -EINVAL;
-       default:
-               pr_debug("Invalid sam value: 0x%x\n", sam);
-               return -EINVAL;
-       }
-
-       lowpan_raw_dump_inline(NULL,
-                       "Reconstructed context based ipv6 src addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-/* Uncompress function for multicast destination address,
- * when M bit is set.
- */
-static int
-lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
-               struct in6_addr *ipaddr,
-               const u8 dam)
-{
-       bool fail;
-
-       switch (dam) {
-       case LOWPAN_IPHC_DAM_00:
-               /* 00:  128 bits.  The full address
-                * is carried in-line.
-                */
-               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
-               break;
-       case LOWPAN_IPHC_DAM_01:
-               /* 01:  48 bits.  The address takes
-                * the form ffXX::00XX:XXXX:XXXX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
-               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
-               break;
-       case LOWPAN_IPHC_DAM_10:
-               /* 10:  32 bits.  The address takes
-                * the form ffXX::00XX:XXXX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
-               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
-               break;
-       case LOWPAN_IPHC_DAM_11:
-               /* 11:  8 bits.  The address takes
-                * the form ff02::00XX.
-                */
-               ipaddr->s6_addr[0] = 0xFF;
-               ipaddr->s6_addr[1] = 0x02;
-               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
-               break;
-       default:
-               pr_debug("DAM value has a wrong value: 0x%x\n", dam);
-               return -EINVAL;
-       }
-
-       if (fail) {
-               pr_debug("Failed to fetch skb data\n");
-               return -EIO;
-       }
-
-       lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is:\n",
-                       ipaddr->s6_addr, 16);
-
-       return 0;
-}
-
-static void
-lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
-{
-       struct udphdr *uh = udp_hdr(skb);
-
-       if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
-                               LOWPAN_NHC_UDP_4BIT_PORT) &&
-           ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
-                               LOWPAN_NHC_UDP_4BIT_PORT)) {
-               pr_debug("UDP header: both ports compression to 4 bits\n");
-               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
-               **(hc06_ptr + 1) = /* subtraction is faster */
-                  (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
-                      ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4));
-               *hc06_ptr += 2;
-       } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
-                       LOWPAN_NHC_UDP_8BIT_PORT) {
-               pr_debug("UDP header: remove 8 bits of dest\n");
-               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
-               memcpy(*hc06_ptr + 1, &uh->source, 2);
-               **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
-               *hc06_ptr += 4;
-       } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
-                       LOWPAN_NHC_UDP_8BIT_PORT) {
-               pr_debug("UDP header: remove 8 bits of source\n");
-               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
-               memcpy(*hc06_ptr + 1, &uh->dest, 2);
-               **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
-               *hc06_ptr += 4;
-       } else {
-               pr_debug("UDP header: can't compress\n");
-               **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
-               memcpy(*hc06_ptr + 1, &uh->source, 2);
-               memcpy(*hc06_ptr + 3, &uh->dest, 2);
-               *hc06_ptr += 5;
-       }
-
-       /* checksum is always inline */
-       memcpy(*hc06_ptr, &uh->check, 2);
-       *hc06_ptr += 2;
-
-       /* skip the UDP header */
-       skb_pull(skb, sizeof(struct udphdr));
-}
-
-static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 1)))
-               return -EINVAL;
-
-       *val = skb->data[0];
-       skb_pull(skb, 1);
-
-       return 0;
-}
-
-static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
-{
-       if (unlikely(!pskb_may_pull(skb, 2)))
-               return -EINVAL;
-
-       *val = (skb->data[0] << 8) | skb->data[1];
-       skb_pull(skb, 2);
-
-       return 0;
-}
-
-static int
-lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
-{
-       u8 tmp;
-
-       if (!uh)
-               goto err;
-
-       if (lowpan_fetch_skb_u8(skb, &tmp))
-               goto err;
-
-       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
-               pr_debug("UDP header uncompression\n");
-               switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
-               case LOWPAN_NHC_UDP_CS_P_00:
-                       memcpy(&uh->source, &skb->data[0], 2);
-                       memcpy(&uh->dest, &skb->data[2], 2);
-                       skb_pull(skb, 4);
-                       break;
-               case LOWPAN_NHC_UDP_CS_P_01:
-                       memcpy(&uh->source, &skb->data[0], 2);
-                       uh->dest =
-                          skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
-                       skb_pull(skb, 3);
-                       break;
-               case LOWPAN_NHC_UDP_CS_P_10:
-                       uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
-                       memcpy(&uh->dest, &skb->data[1], 2);
-                       skb_pull(skb, 3);
-                       break;
-               case LOWPAN_NHC_UDP_CS_P_11:
-                       uh->source =
-                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
-                       uh->dest =
-                          LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
-                       skb_pull(skb, 1);
-                       break;
-               default:
-                       pr_debug("ERROR: unknown UDP format\n");
-                       goto err;
-               }
-
-               pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
-                        uh->source, uh->dest);
-
-               /* copy checksum */
-               memcpy(&uh->check, &skb->data[0], 2);
-               skb_pull(skb, 2);
-
-               /*
-                * UDP lenght needs to be infered from the lower layers
-                * here, we obtain the hint from the remaining size of the
-                * frame
-                */
-               uh->len = htons(skb->len + sizeof(struct udphdr));
-               pr_debug("uncompressed UDP length: src = %d", uh->len);
-       } else {
-               pr_debug("ERROR: unsupported NH format\n");
-               goto err;
-       }
-
-       return 0;
-err:
-       return -EINVAL;
-}
-
 static int lowpan_header_create(struct sk_buff *skb,
                           struct net_device *dev,
                           unsigned short type, const void *_daddr,
                           const void *_saddr, unsigned int len)
 {
-       u8 tmp, iphc0, iphc1, *hc06_ptr;
        struct ipv6hdr *hdr;
        const u8 *saddr = _saddr;
        const u8 *daddr = _daddr;
-       u8 head[100];
        struct ieee802154_addr sa, da;
 
        /* TODO:
@@ -485,181 +118,14 @@ static int lowpan_header_create(struct sk_buff *skb,
                return 0;
 
        hdr = ipv6_hdr(skb);
-       hc06_ptr = head + 2;
-
-       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
-                "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version,
-                ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit);
-
-       lowpan_raw_dump_table(__func__, "raw skb network header dump",
-               skb_network_header(skb), sizeof(struct ipv6hdr));
 
        if (!saddr)
                saddr = dev->dev_addr;
 
-       lowpan_raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
-
-       /*
-        * As we copy some bit-length fields, in the IPHC encoding bytes,
-        * we sometimes use |=
-        * If the field is 0, and the current bit value in memory is 1,
-        * this does not work. We therefore reset the IPHC encoding here
-        */
-       iphc0 = LOWPAN_DISPATCH_IPHC;
-       iphc1 = 0;
-
-       /* TODO: context lookup */
+       raw_dump_inline(__func__, "saddr", (unsigned char *)saddr, 8);
+       raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
 
-       lowpan_raw_dump_inline(__func__, "daddr", (unsigned char *)daddr, 8);
-
-       /*
-        * Traffic class, flow label
-        * If flow label is 0, compress it. If traffic class is 0, compress it
-        * We have to process both in the same time as the offset of traffic
-        * class depends on the presence of version and flow label
-        */
-
-       /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
-       tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
-       tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
-
-       if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
-            (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
-               /* flow label can be compressed */
-               iphc0 |= LOWPAN_IPHC_FL_C;
-               if ((hdr->priority == 0) &&
-                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
-                       /* compress (elide) all */
-                       iphc0 |= LOWPAN_IPHC_TC_C;
-               } else {
-                       /* compress only the flow label */
-                       *hc06_ptr = tmp;
-                       hc06_ptr += 1;
-               }
-       } else {
-               /* Flow label cannot be compressed */
-               if ((hdr->priority == 0) &&
-                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
-                       /* compress only traffic class */
-                       iphc0 |= LOWPAN_IPHC_TC_C;
-                       *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
-                       memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
-                       hc06_ptr += 3;
-               } else {
-                       /* compress nothing */
-                       memcpy(hc06_ptr, &hdr, 4);
-                       /* replace the top byte with new ECN | DSCP format */
-                       *hc06_ptr = tmp;
-                       hc06_ptr += 4;
-               }
-       }
-
-       /* NOTE: payload length is always compressed */
-
-       /* Next Header is compress if UDP */
-       if (hdr->nexthdr == UIP_PROTO_UDP)
-               iphc0 |= LOWPAN_IPHC_NH_C;
-
-       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
-               *hc06_ptr = hdr->nexthdr;
-               hc06_ptr += 1;
-       }
-
-       /*
-        * Hop limit
-        * if 1:   compress, encoding is 01
-        * if 64:  compress, encoding is 10
-        * if 255: compress, encoding is 11
-        * else do not compress
-        */
-       switch (hdr->hop_limit) {
-       case 1:
-               iphc0 |= LOWPAN_IPHC_TTL_1;
-               break;
-       case 64:
-               iphc0 |= LOWPAN_IPHC_TTL_64;
-               break;
-       case 255:
-               iphc0 |= LOWPAN_IPHC_TTL_255;
-               break;
-       default:
-               *hc06_ptr = hdr->hop_limit;
-               hc06_ptr += 1;
-               break;
-       }
-
-       /* source address compression */
-       if (is_addr_unspecified(&hdr->saddr)) {
-               pr_debug("source address is unspecified, setting SAC\n");
-               iphc1 |= LOWPAN_IPHC_SAC;
-       /* TODO: context lookup */
-       } else if (is_addr_link_local(&hdr->saddr)) {
-               pr_debug("source address is link-local\n");
-               iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
-                               LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
-       } else {
-               pr_debug("send the full source address\n");
-               memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
-               hc06_ptr += 16;
-       }
-
-       /* destination address compression */
-       if (is_addr_mcast(&hdr->daddr)) {
-               pr_debug("destination address is multicast: ");
-               iphc1 |= LOWPAN_IPHC_M;
-               if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
-                       pr_debug("compressed to 1 octet\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_11;
-                       /* use last byte */
-                       *hc06_ptr = hdr->daddr.s6_addr[15];
-                       hc06_ptr += 1;
-               } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
-                       pr_debug("compressed to 4 octets\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_10;
-                       /* second byte + the last three */
-                       *hc06_ptr = hdr->daddr.s6_addr[1];
-                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
-                       hc06_ptr += 4;
-               } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
-                       pr_debug("compressed to 6 octets\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_01;
-                       /* second byte + the last five */
-                       *hc06_ptr = hdr->daddr.s6_addr[1];
-                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
-                       hc06_ptr += 6;
-               } else {
-                       pr_debug("using full address\n");
-                       iphc1 |= LOWPAN_IPHC_DAM_00;
-                       memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
-                       hc06_ptr += 16;
-               }
-       } else {
-               /* TODO: context lookup */
-               if (is_addr_link_local(&hdr->daddr)) {
-                       pr_debug("dest address is unicast and link-local\n");
-                       iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
-                               LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
-               } else {
-                       pr_debug("dest address is unicast: using full one\n");
-                       memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
-                       hc06_ptr += 16;
-               }
-       }
-
-       /* UDP header compression */
-       if (hdr->nexthdr == UIP_PROTO_UDP)
-               lowpan_compress_udp_header(&hc06_ptr, skb);
-
-       head[0] = iphc0;
-       head[1] = iphc1;
-
-       skb_pull(skb, sizeof(struct ipv6hdr));
-       skb_reset_transport_header(skb);
-       memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
-       skb_reset_network_header(skb);
-
-       lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
-                               skb->len);
+       lowpan_header_compress(skb, dev, type, daddr, saddr, len);
 
        /*
         * NOTE1: I'm still unsure about the fact that compression and WPAN
@@ -671,39 +137,38 @@ static int lowpan_header_create(struct sk_buff *skb,
         * from MAC subif of the 'dev' and 'real_dev' network devices, but
         * this isn't implemented in mainline yet, so currently we assign 0xff
         */
-       {
-               mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
-               mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
+       mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA;
+       mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev);
 
-               /* prepare wpan address data */
-               sa.addr_type = IEEE802154_ADDR_LONG;
-               sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       /* prepare wpan address data */
+       sa.addr_type = IEEE802154_ADDR_LONG;
+       sa.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-               memcpy(&(sa.hwaddr), saddr, 8);
-               /* intra-PAN communications */
-               da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
+       memcpy(&(sa.hwaddr), saddr, 8);
+       /* intra-PAN communications */
+       da.pan_id = ieee802154_mlme_ops(dev)->get_pan_id(dev);
 
-               /*
-                * if the destination address is the broadcast address, use the
-                * corresponding short address
-                */
-               if (lowpan_is_addr_broadcast(daddr)) {
-                       da.addr_type = IEEE802154_ADDR_SHORT;
-                       da.short_addr = IEEE802154_ADDR_BROADCAST;
-               } else {
-                       da.addr_type = IEEE802154_ADDR_LONG;
-                       memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
-
-                       /* request acknowledgment */
-                       mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
-               }
+       /*
+        * if the destination address is the broadcast address, use the
+        * corresponding short address
+        */
+       if (lowpan_is_addr_broadcast(daddr)) {
+               da.addr_type = IEEE802154_ADDR_SHORT;
+               da.short_addr = IEEE802154_ADDR_BROADCAST;
+       } else {
+               da.addr_type = IEEE802154_ADDR_LONG;
+               memcpy(&(da.hwaddr), daddr, IEEE802154_ADDR_LEN);
 
-               return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
-                               type, (void *)&da, (void *)&sa, skb->len);
+               /* request acknowledgment */
+               mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ;
        }
+
+       return dev_hard_header(skb, lowpan_dev_info(dev)->real_dev,
+                       type, (void *)&da, (void *)&sa, skb->len);
 }
 
-static int lowpan_give_skb_to_devices(struct sk_buff *skb)
+static int lowpan_give_skb_to_devices(struct sk_buff *skb,
+                                       struct net_device *dev)
 {
        struct lowpan_dev_record *entry;
        struct sk_buff *skb_cp;
@@ -726,31 +191,6 @@ static int lowpan_give_skb_to_devices(struct sk_buff *skb)
        return stat;
 }
 
-static int lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr)
-{
-       struct sk_buff *new;
-       int stat = NET_RX_SUCCESS;
-
-       new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
-                                                               GFP_ATOMIC);
-       kfree_skb(skb);
-
-       if (!new)
-               return -ENOMEM;
-
-       skb_push(new, sizeof(struct ipv6hdr));
-       skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
-
-       new->protocol = htons(ETH_P_IPV6);
-       new->pkt_type = PACKET_HOST;
-
-       stat = lowpan_give_skb_to_devices(new);
-
-       kfree_skb(new);
-
-       return stat;
-}
-
 static void lowpan_fragment_timer_expired(unsigned long entry_addr)
 {
        struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
@@ -814,16 +254,12 @@ frame_err:
        return NULL;
 }
 
-static int
-lowpan_process_data(struct sk_buff *skb)
+static int process_data(struct sk_buff *skb)
 {
-       struct ipv6hdr hdr = {};
-       u8 tmp, iphc0, iphc1, num_context = 0;
+       u8 iphc0, iphc1;
        const struct ieee802154_addr *_saddr, *_daddr;
-       int err;
 
-       lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
-                               skb->len);
+       raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
        /* at least two bytes will be used for the encoding */
        if (skb->len < 2)
                goto drop;
@@ -925,162 +361,11 @@ lowpan_process_data(struct sk_buff *skb)
        _saddr = &mac_cb(skb)->sa;
        _daddr = &mac_cb(skb)->da;
 
-       pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1);
-
-       /* another if the CID flag is set */
-       if (iphc1 & LOWPAN_IPHC_CID) {
-               pr_debug("CID flag is set, increase header with one\n");
-               if (lowpan_fetch_skb_u8(skb, &num_context))
-                       goto drop;
-       }
-
-       hdr.version = 6;
-
-       /* Traffic Class and Flow Label */
-       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
-       /*
-        * Traffic Class and FLow Label carried in-line
-        * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
-        */
-       case 0: /* 00b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               memcpy(&hdr.flow_lbl, &skb->data[0], 3);
-               skb_pull(skb, 3);
-               hdr.priority = ((tmp >> 2) & 0x0f);
-               hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
-                                       (hdr.flow_lbl[0] & 0x0f);
-               break;
-       /*
-        * Traffic class carried in-line
-        * ECN + DSCP (1 byte), Flow Label is elided
-        */
-       case 2: /* 10b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               hdr.priority = ((tmp >> 2) & 0x0f);
-               hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
-               break;
-       /*
-        * Flow Label carried in-line
-        * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
-        */
-       case 1: /* 01b */
-               if (lowpan_fetch_skb_u8(skb, &tmp))
-                       goto drop;
-
-               hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
-               memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
-               skb_pull(skb, 2);
-               break;
-       /* Traffic Class and Flow Label are elided */
-       case 3: /* 11b */
-               break;
-       default:
-               break;
-       }
-
-       /* Next Header */
-       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
-               /* Next header is carried inline */
-               if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
-                       goto drop;
-
-               pr_debug("NH flag is set, next header carried inline: %02x\n",
-                        hdr.nexthdr);
-       }
-
-       /* Hop Limit */
-       if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
-               hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
-       else {
-               if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
-                       goto drop;
-       }
-
-       /* Extract SAM to the tmp variable */
-       tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
-
-       if (iphc1 & LOWPAN_IPHC_SAC) {
-               /* Source address context based uncompression */
-               pr_debug("SAC bit is set. Handle context based source address.\n");
-               err = lowpan_uncompress_context_based_src_addr(
-                               skb, &hdr.saddr, tmp);
-       } else {
-               /* Source address uncompression */
-               pr_debug("source address stateless compression\n");
-               err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr);
-       }
-
-       /* Check on error of previous branch */
-       if (err)
-               goto drop;
-
-       /* Extract DAM to the tmp variable */
-       tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
-
-       /* check for Multicast Compression */
-       if (iphc1 & LOWPAN_IPHC_M) {
-               if (iphc1 & LOWPAN_IPHC_DAC) {
-                       pr_debug("dest: context-based mcast compression\n");
-                       /* TODO: implement this */
-               } else {
-                       err = lowpan_uncompress_multicast_daddr(
-                                       skb, &hdr.daddr, tmp);
-                       if (err)
-                               goto drop;
-               }
-       } else {
-               pr_debug("dest: stateless compression\n");
-               err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr);
-               if (err)
-                       goto drop;
-       }
-
-       /* UDP data uncompression */
-       if (iphc0 & LOWPAN_IPHC_NH_C) {
-               struct udphdr uh;
-               struct sk_buff *new;
-               if (lowpan_uncompress_udp_header(skb, &uh))
-                       goto drop;
-
-               /*
-                * replace the compressed UDP head by the uncompressed UDP
-                * header
-                */
-               new = skb_copy_expand(skb, sizeof(struct udphdr),
-                                     skb_tailroom(skb), GFP_ATOMIC);
-               kfree_skb(skb);
-
-               if (!new)
-                       return -ENOMEM;
-
-               skb = new;
-
-               skb_push(skb, sizeof(struct udphdr));
-               skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
-
-               lowpan_raw_dump_table(__func__, "raw UDP header dump",
-                                     (u8 *)&uh, sizeof(uh));
-
-               hdr.nexthdr = UIP_PROTO_UDP;
-       }
-
-       /* Not fragmented package */
-       hdr.payload_len = htons(skb->len);
-
-       pr_debug("skb headroom size = %d, data length = %d\n",
-                skb_headroom(skb), skb->len);
-
-       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
-                "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version,
-                ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
-
-       lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
-                                                       sizeof(hdr));
-       return lowpan_skb_deliver(skb, &hdr);
+       return lowpan_process_data(skb, skb->dev, (u8 *)_saddr->hwaddr,
+                               _saddr->addr_type, IEEE802154_ADDR_LEN,
+                               (u8 *)_daddr->hwaddr, _daddr->addr_type,
+                               IEEE802154_ADDR_LEN, iphc0, iphc1,
+                               lowpan_give_skb_to_devices);
 
 unlock_and_drop:
        spin_unlock_bh(&flist_lock);
@@ -1112,7 +397,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
        hlen = (type == LOWPAN_DISPATCH_FRAG1) ?
                        LOWPAN_FRAG1_HEAD_SIZE : LOWPAN_FRAGN_HEAD_SIZE;
 
-       lowpan_raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
+       raw_dump_inline(__func__, "6lowpan fragment header", head, hlen);
 
        frag = netdev_alloc_skb(skb->dev,
                                hlen + mlen + plen + IEEE802154_MFR_SIZE);
@@ -1132,8 +417,7 @@ lowpan_fragment_xmit(struct sk_buff *skb, u8 *head,
        skb_copy_to_linear_data_offset(frag, mlen + hlen,
                                       skb_network_header(skb) + offset, plen);
 
-       lowpan_raw_dump_table(__func__, " raw fragment dump", frag->data,
-                                                               frag->len);
+       raw_dump_table(__func__, " raw fragment dump", frag->data, frag->len);
 
        return dev_queue_xmit(frag);
 }
@@ -1316,7 +600,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                /* Pull off the 1-byte of 6lowpan header. */
                skb_pull(local_skb, 1);
 
-               lowpan_give_skb_to_devices(local_skb);
+               lowpan_give_skb_to_devices(local_skb, NULL);
 
                kfree_skb(local_skb);
                kfree_skb(skb);
@@ -1328,7 +612,7 @@ static int lowpan_rcv(struct sk_buff *skb, struct net_device *dev,
                        local_skb = skb_clone(skb, GFP_ATOMIC);
                        if (!local_skb)
                                goto drop;
-                       lowpan_process_data(local_skb);
+                       process_data(local_skb);
 
                        kfree_skb(skb);
                        break;
index 2869c0526dad698b574ddd05f3f2175d5fb69455..2b835db3bda83477bc89e9212e18bf612e21b074 100644 (file)
 #define LOWPAN_NHC_UDP_CS_P_10 0xF2 /* source = 0xF0 + 8bit inline,
                                        dest = 16 bit inline */
 #define LOWPAN_NHC_UDP_CS_P_11 0xF3 /* source & dest = 0xF0B + 4bit inline */
+#define LOWPAN_NHC_UDP_CS_C    0x04 /* checksum elided */
+
+#ifdef DEBUG
+/* print data in line */
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s: ", caller, msg);
+
+       print_hex_dump_debug("", DUMP_PREFIX_NONE, 16, 1, buf, len, false);
+}
+
+/* print data in a table format:
+ *
+ * addr: xx xx xx xx xx xx
+ * addr: xx xx xx xx xx xx
+ * ...
+ */
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len)
+{
+       if (msg)
+               pr_debug("%s():%s:\n", caller, msg);
+
+       print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET, 16, 1, buf, len, false);
+}
+#else
+static inline void raw_dump_table(const char *caller, char *msg,
+                                 unsigned char *buf, int len) { }
+static inline void raw_dump_inline(const char *caller, char *msg,
+                                  unsigned char *buf, int len) { }
+#endif
+
+static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 1)))
+               return -EINVAL;
+
+       *val = skb->data[0];
+       skb_pull(skb, 1);
+
+       return 0;
+}
+
+static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
+{
+       if (unlikely(!pskb_may_pull(skb, 2)))
+               return -EINVAL;
+
+       *val = (skb->data[0] << 8) | skb->data[1];
+       skb_pull(skb, 2);
+
+       return 0;
+}
 
 static inline bool lowpan_fetch_skb(struct sk_buff *skb,
                void *data, const unsigned int len)
@@ -244,4 +299,21 @@ static inline bool lowpan_fetch_skb(struct sk_buff *skb,
        return false;
 }
 
+static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
+                                      const size_t len)
+{
+       memcpy(*hc_ptr, data, len);
+       *hc_ptr += len;
+}
+
+typedef int (*skb_delivery_cb)(struct sk_buff *skb, struct net_device *dev);
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb skb_deliver);
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len);
+
 #endif /* __6LOWPAN_H__ */
diff --git a/net/ieee802154/6lowpan_iphc.c b/net/ieee802154/6lowpan_iphc.c
new file mode 100644 (file)
index 0000000..11840f9
--- /dev/null
@@ -0,0 +1,799 @@
+/*
+ * Copyright 2011, Siemens AG
+ * written by Alexander Smirnov <alex.bluesman.smirnov@gmail.com>
+ */
+
+/*
+ * Based on patches from Jon Smirl <jonsmirl@gmail.com>
+ * Copyright (c) 2011 Jon Smirl <jonsmirl@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/* Jon's code is based on 6lowpan implementation for Contiki which is:
+ * Copyright (c) 2008, Swedish Institute of Computer Science.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the Institute nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/bitops.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <net/ipv6.h>
+#include <net/af_ieee802154.h>
+
+#include "6lowpan.h"
+
+/*
+ * Uncompress address function for source and
+ * destination address(non-multicast).
+ *
+ * address_mode is sam value or dam value.
+ */
+static int uncompress_addr(struct sk_buff *skb,
+                               struct in6_addr *ipaddr, const u8 address_mode,
+                               const u8 *lladdr, const u8 addr_type,
+                               const u8 addr_len)
+{
+       bool fail;
+
+       switch (address_mode) {
+       case LOWPAN_IPHC_ADDR_00:
+               /* for global link addresses */
+               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+               break;
+       case LOWPAN_IPHC_ADDR_01:
+               /* fe:80::XXXX:XXXX:XXXX:XXXX */
+               ipaddr->s6_addr[0] = 0xFE;
+               ipaddr->s6_addr[1] = 0x80;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
+               break;
+       case LOWPAN_IPHC_ADDR_02:
+               /* fe:80::ff:fe00:XXXX */
+               ipaddr->s6_addr[0] = 0xFE;
+               ipaddr->s6_addr[1] = 0x80;
+               ipaddr->s6_addr[11] = 0xFF;
+               ipaddr->s6_addr[12] = 0xFE;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
+               break;
+       case LOWPAN_IPHC_ADDR_03:
+               fail = false;
+               switch (addr_type) {
+               case IEEE802154_ADDR_LONG:
+                       /* fe:80::XXXX:XXXX:XXXX:XXXX
+                        *        \_________________/
+                        *              hwaddr
+                        */
+                       ipaddr->s6_addr[0] = 0xFE;
+                       ipaddr->s6_addr[1] = 0x80;
+                       memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
+                       /* second bit-flip (Universe/Local)
+                        * is done according RFC2464
+                        */
+                       ipaddr->s6_addr[8] ^= 0x02;
+                       break;
+               case IEEE802154_ADDR_SHORT:
+                       /* fe:80::ff:fe00:XXXX
+                        *                \__/
+                        *             short_addr
+                        *
+                        * Universe/Local bit is zero.
+                        */
+                       ipaddr->s6_addr[0] = 0xFE;
+                       ipaddr->s6_addr[1] = 0x80;
+                       ipaddr->s6_addr[11] = 0xFF;
+                       ipaddr->s6_addr[12] = 0xFE;
+                       ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
+                       break;
+               default:
+                       pr_debug("Invalid addr_type set\n");
+                       return -EINVAL;
+               }
+               break;
+       default:
+               pr_debug("Invalid address mode value: 0x%x\n", address_mode);
+               return -EINVAL;
+       }
+
+       if (fail) {
+               pr_debug("Failed to fetch skb data\n");
+               return -EIO;
+       }
+
+       raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
+                       ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+/*
+ * Uncompress address function for source context
+ * based address(non-multicast).
+ */
+static int uncompress_context_based_src_addr(struct sk_buff *skb,
+                                               struct in6_addr *ipaddr,
+                                               const u8 sam)
+{
+       switch (sam) {
+       case LOWPAN_IPHC_ADDR_00:
+               /* unspec address ::
+                * Do nothing, address is already ::
+                */
+               break;
+       case LOWPAN_IPHC_ADDR_01:
+               /* TODO */
+       case LOWPAN_IPHC_ADDR_02:
+               /* TODO */
+       case LOWPAN_IPHC_ADDR_03:
+               /* TODO */
+               netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
+               return -EINVAL;
+       default:
+               pr_debug("Invalid sam value: 0x%x\n", sam);
+               return -EINVAL;
+       }
+
+       raw_dump_inline(NULL,
+                       "Reconstructed context based ipv6 src addr is",
+                       ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
+               struct net_device *dev, skb_delivery_cb deliver_skb)
+{
+       struct sk_buff *new;
+       int stat;
+
+       new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
+                                                               GFP_ATOMIC);
+       kfree_skb(skb);
+
+       if (!new)
+               return -ENOMEM;
+
+       skb_push(new, sizeof(struct ipv6hdr));
+       skb_reset_network_header(new);
+       skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
+
+       new->protocol = htons(ETH_P_IPV6);
+       new->pkt_type = PACKET_HOST;
+       new->dev = dev;
+
+       raw_dump_table(__func__, "raw skb data dump before receiving",
+                       new->data, new->len);
+
+       stat = deliver_skb(new, dev);
+
+       kfree_skb(new);
+
+       return stat;
+}
+
+/* Uncompress function for multicast destination address,
+ * when M bit is set.
+ */
+static int
+lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
+               struct in6_addr *ipaddr,
+               const u8 dam)
+{
+       bool fail;
+
+       switch (dam) {
+       case LOWPAN_IPHC_DAM_00:
+               /* 00:  128 bits.  The full address
+                * is carried in-line.
+                */
+               fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+               break;
+       case LOWPAN_IPHC_DAM_01:
+               /* 01:  48 bits.  The address takes
+                * the form ffXX::00XX:XXXX:XXXX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
+               break;
+       case LOWPAN_IPHC_DAM_10:
+               /* 10:  32 bits.  The address takes
+                * the form ffXX::00XX:XXXX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+               fail |= lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
+               break;
+       case LOWPAN_IPHC_DAM_11:
+               /* 11:  8 bits.  The address takes
+                * the form ff02::00XX.
+                */
+               ipaddr->s6_addr[0] = 0xFF;
+               ipaddr->s6_addr[1] = 0x02;
+               fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
+               break;
+       default:
+               pr_debug("DAM value has a wrong value: 0x%x\n", dam);
+               return -EINVAL;
+       }
+
+       if (fail) {
+               pr_debug("Failed to fetch skb data\n");
+               return -EIO;
+       }
+
+       raw_dump_inline(NULL, "Reconstructed ipv6 multicast addr is",
+                               ipaddr->s6_addr, 16);
+
+       return 0;
+}
+
+static int
+uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
+{
+       bool fail;
+       u8 tmp = 0, val = 0;
+
+       if (!uh)
+               goto err;
+
+       fail = lowpan_fetch_skb(skb, &tmp, 1);
+
+       if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+               pr_debug("UDP header uncompression\n");
+               switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
+               case LOWPAN_NHC_UDP_CS_P_00:
+                       fail |= lowpan_fetch_skb(skb, &uh->source, 2);
+                       fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_01:
+                       fail |= lowpan_fetch_skb(skb, &uh->source, 2);
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->dest = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_10:
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->source = htons(val + LOWPAN_NHC_UDP_8BIT_PORT);
+                       fail |= lowpan_fetch_skb(skb, &uh->dest, 2);
+                       break;
+               case LOWPAN_NHC_UDP_CS_P_11:
+                       fail |= lowpan_fetch_skb(skb, &val, 1);
+                       uh->source = htons(LOWPAN_NHC_UDP_4BIT_PORT +
+                                          (val >> 4));
+                       uh->dest = htons(LOWPAN_NHC_UDP_4BIT_PORT +
+                                        (val & 0x0f));
+                       break;
+               default:
+                       pr_debug("ERROR: unknown UDP format\n");
+                       goto err;
+                       break;
+               }
+
+               pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
+                        ntohs(uh->source), ntohs(uh->dest));
+
+               /* checksum */
+               if (tmp & LOWPAN_NHC_UDP_CS_C) {
+                       pr_debug_ratelimited("checksum elided currently not supported\n");
+                       goto err;
+               } else {
+                       fail |= lowpan_fetch_skb(skb, &uh->check, 2);
+               }
+
+               /*
+                * UDP lenght needs to be infered from the lower layers
+                * here, we obtain the hint from the remaining size of the
+                * frame
+                */
+               uh->len = htons(skb->len + sizeof(struct udphdr));
+               pr_debug("uncompressed UDP length: src = %d", ntohs(uh->len));
+       } else {
+               pr_debug("ERROR: unsupported NH format\n");
+               goto err;
+       }
+
+       if (fail)
+               goto err;
+
+       return 0;
+err:
+       return -EINVAL;
+}
+
+/* TTL uncompression values */
+static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
+
+int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
+               const u8 *saddr, const u8 saddr_type, const u8 saddr_len,
+               const u8 *daddr, const u8 daddr_type, const u8 daddr_len,
+               u8 iphc0, u8 iphc1, skb_delivery_cb deliver_skb)
+{
+       struct ipv6hdr hdr = {};
+       u8 tmp, num_context = 0;
+       int err;
+
+       raw_dump_table(__func__, "raw skb data dump uncompressed",
+                               skb->data, skb->len);
+
+       /* another if the CID flag is set */
+       if (iphc1 & LOWPAN_IPHC_CID) {
+               pr_debug("CID flag is set, increase header with one\n");
+               if (lowpan_fetch_skb_u8(skb, &num_context))
+                       goto drop;
+       }
+
+       hdr.version = 6;
+
+       /* Traffic Class and Flow Label */
+       switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+       /*
+        * Traffic Class and FLow Label carried in-line
+        * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
+        */
+       case 0: /* 00b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               memcpy(&hdr.flow_lbl, &skb->data[0], 3);
+               skb_pull(skb, 3);
+               hdr.priority = ((tmp >> 2) & 0x0f);
+               hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
+                                       (hdr.flow_lbl[0] & 0x0f);
+               break;
+       /*
+        * Traffic class carried in-line
+        * ECN + DSCP (1 byte), Flow Label is elided
+        */
+       case 2: /* 10b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               hdr.priority = ((tmp >> 2) & 0x0f);
+               hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
+               break;
+       /*
+        * Flow Label carried in-line
+        * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
+        */
+       case 1: /* 01b */
+               if (lowpan_fetch_skb_u8(skb, &tmp))
+                       goto drop;
+
+               hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
+               memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
+               skb_pull(skb, 2);
+               break;
+       /* Traffic Class and Flow Label are elided */
+       case 3: /* 11b */
+               break;
+       default:
+               break;
+       }
+
+       /* Next Header */
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               /* Next header is carried inline */
+               if (lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
+                       goto drop;
+
+               pr_debug("NH flag is set, next header carried inline: %02x\n",
+                        hdr.nexthdr);
+       }
+
+       /* Hop Limit */
+       if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
+               hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
+       else {
+               if (lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
+                       goto drop;
+       }
+
+       /* Extract SAM to the tmp variable */
+       tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
+
+       if (iphc1 & LOWPAN_IPHC_SAC) {
+               /* Source address context based uncompression */
+               pr_debug("SAC bit is set. Handle context based source address.\n");
+               err = uncompress_context_based_src_addr(
+                               skb, &hdr.saddr, tmp);
+       } else {
+               /* Source address uncompression */
+               pr_debug("source address stateless compression\n");
+               err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
+                                       saddr_type, saddr_len);
+       }
+
+       /* Check on error of previous branch */
+       if (err)
+               goto drop;
+
+       /* Extract DAM to the tmp variable */
+       tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
+
+       /* check for Multicast Compression */
+       if (iphc1 & LOWPAN_IPHC_M) {
+               if (iphc1 & LOWPAN_IPHC_DAC) {
+                       pr_debug("dest: context-based mcast compression\n");
+                       /* TODO: implement this */
+               } else {
+                       err = lowpan_uncompress_multicast_daddr(
+                                               skb, &hdr.daddr, tmp);
+                       if (err)
+                               goto drop;
+               }
+       } else {
+               err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
+                                       daddr_type, daddr_len);
+               pr_debug("dest: stateless compression mode %d dest %pI6c\n",
+                       tmp, &hdr.daddr);
+               if (err)
+                       goto drop;
+       }
+
+       /* UDP data uncompression */
+       if (iphc0 & LOWPAN_IPHC_NH_C) {
+               struct udphdr uh;
+               struct sk_buff *new;
+               if (uncompress_udp_header(skb, &uh))
+                       goto drop;
+
+               /*
+                * replace the compressed UDP head by the uncompressed UDP
+                * header
+                */
+               new = skb_copy_expand(skb, sizeof(struct udphdr),
+                                     skb_tailroom(skb), GFP_ATOMIC);
+               kfree_skb(skb);
+
+               if (!new)
+                       return -ENOMEM;
+
+               skb = new;
+
+               skb_push(skb, sizeof(struct udphdr));
+               skb_reset_transport_header(skb);
+               skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
+
+               raw_dump_table(__func__, "raw UDP header dump",
+                                     (u8 *)&uh, sizeof(uh));
+
+               hdr.nexthdr = UIP_PROTO_UDP;
+       }
+
+       hdr.payload_len = htons(skb->len);
+
+       pr_debug("skb headroom size = %d, data length = %d\n",
+                skb_headroom(skb), skb->len);
+
+       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n\t"
+                "nexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
+               hdr.version, ntohs(hdr.payload_len), hdr.nexthdr,
+               hdr.hop_limit, &hdr.daddr);
+
+       raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
+                                                       sizeof(hdr));
+
+       return skb_deliver(skb, &hdr, dev, deliver_skb);
+
+drop:
+       kfree_skb(skb);
+       return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(lowpan_process_data);
+
+static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
+                               const struct in6_addr *ipaddr,
+                               const unsigned char *lladdr)
+{
+       u8 val = 0;
+
+       if (is_addr_mac_addr_based(ipaddr, lladdr)) {
+               val = 3; /* 0-bits */
+               pr_debug("address compression 0 bits\n");
+       } else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+               /* compress IID to 16 bits xxxx::XXXX */
+               memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
+               *hc06_ptr += 2;
+               val = 2; /* 16-bits */
+               raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
+                       *hc06_ptr - 2, 2);
+       } else {
+               /* do not compress IID => xxxx::IID */
+               memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
+               *hc06_ptr += 8;
+               val = 1; /* 64-bits */
+               raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
+                       *hc06_ptr - 8, 8);
+       }
+
+       return rol8(val, shift);
+}
+
+static void compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+{
+       struct udphdr *uh = udp_hdr(skb);
+       u8 tmp;
+
+       if (((ntohs(uh->source) & LOWPAN_NHC_UDP_4BIT_MASK) ==
+            LOWPAN_NHC_UDP_4BIT_PORT) &&
+           ((ntohs(uh->dest) & LOWPAN_NHC_UDP_4BIT_MASK) ==
+            LOWPAN_NHC_UDP_4BIT_PORT)) {
+               pr_debug("UDP header: both ports compression to 4 bits\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_11;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source and destination port */
+               tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_4BIT_PORT +
+                     ((ntohs(uh->source) - LOWPAN_NHC_UDP_4BIT_PORT) << 4);
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+       } else if ((ntohs(uh->dest) & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("UDP header: remove 8 bits of dest\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_01;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+               /* destination port */
+               tmp = ntohs(uh->dest) - LOWPAN_NHC_UDP_8BIT_PORT;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+       } else if ((ntohs(uh->source) & LOWPAN_NHC_UDP_8BIT_MASK) ==
+                       LOWPAN_NHC_UDP_8BIT_PORT) {
+               pr_debug("UDP header: remove 8 bits of source\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_10;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               tmp = ntohs(uh->source) - LOWPAN_NHC_UDP_8BIT_PORT;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* destination port */
+               lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+       } else {
+               pr_debug("UDP header: can't compress\n");
+               /* compression value */
+               tmp = LOWPAN_NHC_UDP_CS_P_00;
+               lowpan_push_hc_data(hc06_ptr, &tmp, sizeof(tmp));
+               /* source port */
+               lowpan_push_hc_data(hc06_ptr, &uh->source, sizeof(uh->source));
+               /* destination port */
+               lowpan_push_hc_data(hc06_ptr, &uh->dest, sizeof(uh->dest));
+       }
+
+       /* checksum is always inline */
+       lowpan_push_hc_data(hc06_ptr, &uh->check, sizeof(uh->check));
+
+       /* skip the UDP header */
+       skb_pull(skb, sizeof(struct udphdr));
+}
+
+int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
+                       unsigned short type, const void *_daddr,
+                       const void *_saddr, unsigned int len)
+{
+       u8 tmp, iphc0, iphc1, *hc06_ptr;
+       struct ipv6hdr *hdr;
+       u8 head[100] = {};
+
+       if (type != ETH_P_IPV6)
+               return -EINVAL;
+
+       hdr = ipv6_hdr(skb);
+       hc06_ptr = head + 2;
+
+       pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength  = %d\n"
+                "\tnexthdr = 0x%02x\n\thop_lim = %d\n\tdest    = %pI6c\n",
+               hdr->version, ntohs(hdr->payload_len), hdr->nexthdr,
+               hdr->hop_limit, &hdr->daddr);
+
+       raw_dump_table(__func__, "raw skb network header dump",
+               skb_network_header(skb), sizeof(struct ipv6hdr));
+
+       /*
+        * As we copy some bit-length fields, in the IPHC encoding bytes,
+        * we sometimes use |=
+        * If the field is 0, and the current bit value in memory is 1,
+        * this does not work. We therefore reset the IPHC encoding here
+        */
+       iphc0 = LOWPAN_DISPATCH_IPHC;
+       iphc1 = 0;
+
+       /* TODO: context lookup */
+
+       raw_dump_inline(__func__, "saddr",
+                       (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
+       raw_dump_inline(__func__, "daddr",
+                       (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
+
+       raw_dump_table(__func__,
+                       "sending raw skb network uncompressed packet",
+                       skb->data, skb->len);
+
+       /*
+        * Traffic class, flow label
+        * If flow label is 0, compress it. If traffic class is 0, compress it
+        * We have to process both in the same time as the offset of traffic
+        * class depends on the presence of version and flow label
+        */
+
+       /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
+       tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+       tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+       if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
+            (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
+               /* flow label can be compressed */
+               iphc0 |= LOWPAN_IPHC_FL_C;
+               if ((hdr->priority == 0) &&
+                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress (elide) all */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+               } else {
+                       /* compress only the flow label */
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 1;
+               }
+       } else {
+               /* Flow label cannot be compressed */
+               if ((hdr->priority == 0) &&
+                  ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+                       /* compress only traffic class */
+                       iphc0 |= LOWPAN_IPHC_TC_C;
+                       *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+                       memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
+                       hc06_ptr += 3;
+               } else {
+                       /* compress nothing */
+                       memcpy(hc06_ptr, &hdr, 4);
+                       /* replace the top byte with new ECN | DSCP format */
+                       *hc06_ptr = tmp;
+                       hc06_ptr += 4;
+               }
+       }
+
+       /* NOTE: payload length is always compressed */
+
+       /* Next Header is compress if UDP */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               iphc0 |= LOWPAN_IPHC_NH_C;
+
+       if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+               *hc06_ptr = hdr->nexthdr;
+               hc06_ptr += 1;
+       }
+
+       /*
+        * Hop limit
+        * if 1:   compress, encoding is 01
+        * if 64:  compress, encoding is 10
+        * if 255: compress, encoding is 11
+        * else do not compress
+        */
+       switch (hdr->hop_limit) {
+       case 1:
+               iphc0 |= LOWPAN_IPHC_TTL_1;
+               break;
+       case 64:
+               iphc0 |= LOWPAN_IPHC_TTL_64;
+               break;
+       case 255:
+               iphc0 |= LOWPAN_IPHC_TTL_255;
+               break;
+       default:
+               *hc06_ptr = hdr->hop_limit;
+               hc06_ptr += 1;
+               break;
+       }
+
+       /* source address compression */
+       if (is_addr_unspecified(&hdr->saddr)) {
+               pr_debug("source address is unspecified, setting SAC\n");
+               iphc1 |= LOWPAN_IPHC_SAC;
+       /* TODO: context lookup */
+       } else if (is_addr_link_local(&hdr->saddr)) {
+               iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+                               LOWPAN_IPHC_SAM_BIT, &hdr->saddr, _saddr);
+               pr_debug("source address unicast link-local %pI6c "
+                       "iphc1 0x%02x\n", &hdr->saddr, iphc1);
+       } else {
+               pr_debug("send the full source address\n");
+               memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
+               hc06_ptr += 16;
+       }
+
+       /* destination address compression */
+       if (is_addr_mcast(&hdr->daddr)) {
+               pr_debug("destination address is multicast: ");
+               iphc1 |= LOWPAN_IPHC_M;
+               if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
+                       pr_debug("compressed to 1 octet\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_11;
+                       /* use last byte */
+                       *hc06_ptr = hdr->daddr.s6_addr[15];
+                       hc06_ptr += 1;
+               } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
+                       pr_debug("compressed to 4 octets\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_10;
+                       /* second byte + the last three */
+                       *hc06_ptr = hdr->daddr.s6_addr[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
+                       hc06_ptr += 4;
+               } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
+                       pr_debug("compressed to 6 octets\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_01;
+                       /* second byte + the last five */
+                       *hc06_ptr = hdr->daddr.s6_addr[1];
+                       memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
+                       hc06_ptr += 6;
+               } else {
+                       pr_debug("using full address\n");
+                       iphc1 |= LOWPAN_IPHC_DAM_00;
+                       memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
+                       hc06_ptr += 16;
+               }
+       } else {
+               /* TODO: context lookup */
+               if (is_addr_link_local(&hdr->daddr)) {
+                       iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+                               LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
+                       pr_debug("dest address unicast link-local %pI6c "
+                               "iphc1 0x%02x\n", &hdr->daddr, iphc1);
+               } else {
+                       pr_debug("dest address unicast %pI6c\n", &hdr->daddr);
+                       memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
+                       hc06_ptr += 16;
+               }
+       }
+
+       /* UDP header compression */
+       if (hdr->nexthdr == UIP_PROTO_UDP)
+               compress_udp_header(&hc06_ptr, skb);
+
+       head[0] = iphc0;
+       head[1] = iphc1;
+
+       skb_pull(skb, sizeof(struct ipv6hdr));
+       skb_reset_transport_header(skb);
+       memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+       skb_reset_network_header(skb);
+
+       pr_debug("header len %d skb %u\n", (int)(hc06_ptr - head), skb->len);
+
+       raw_dump_table(__func__, "raw skb data dump compressed",
+                               skb->data, skb->len);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(lowpan_header_compress);
index d7716d64c6bb2c38848695378d6634bfa958afd6..951a83ee8af4fb35c8dabc459c5c2d257f452eb7 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_IEEE802154) += ieee802154.o af_802154.o
-obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o
+obj-$(CONFIG_IEEE802154_6LOWPAN) += 6lowpan.o 6lowpan_iphc.o
 
 ieee802154-y := netlink.o nl-mac.o nl-phy.o nl_policy.o wpan-class.o
 af_802154-y := af_ieee802154.o raw.o dgram.o
index 12c97d8aa6bbb31ff1519459b89b7b9fb33817f5..d125fcdefb74097b5f6eed867d8ff60428a1d63a 100644 (file)
@@ -1816,6 +1816,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
                return addrconf_ifid_sit(eui, dev);
        case ARPHRD_IPGRE:
                return addrconf_ifid_gre(eui, dev);
+       case ARPHRD_6LOWPAN:
        case ARPHRD_IEEE802154:
                return addrconf_ifid_eui64(eui, dev);
        case ARPHRD_IEEE1394:
@@ -2658,7 +2659,8 @@ static void addrconf_dev_config(struct net_device *dev)
            (dev->type != ARPHRD_INFINIBAND) &&
            (dev->type != ARPHRD_IEEE802154) &&
            (dev->type != ARPHRD_IEEE1394) &&
-           (dev->type != ARPHRD_TUNNEL6)) {
+           (dev->type != ARPHRD_TUNNEL6) &&
+           (dev->type != ARPHRD_6LOWPAN)) {
                /* Alas, we support only Ethernet autoconfiguration. */
                return;
        }
index 537488cbf941a3699ccaf533d8a9bb92c9788434..9b9009f99551bb18b9613b4c470361d7fded4eb3 100644 (file)
@@ -111,7 +111,7 @@ void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
 }
 
 
-struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[])
+struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[])
 {
        struct crypto_cipher *tfm;
 
index 20785a6472540efe147ebcfd1083221a08968db8..0ce6487af79536c03e7cae25639eeacd389f5f18 100644 (file)
@@ -11,7 +11,7 @@
 
 #include <linux/crypto.h>
 
-struct crypto_cipher * ieee80211_aes_cmac_key_setup(const u8 key[]);
+struct crypto_cipher *ieee80211_aes_cmac_key_setup(const u8 key[]);
 void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad,
                        const u8 *data, size_t data_len, u8 *mic);
 void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm);
index ac185286842d67de981da089b07edcde0ccaf87f..09d2e58a2ba70e50ff6489700565a3755358a3b0 100644 (file)
@@ -828,6 +828,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
        if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
                return 0;
 
+       mutex_lock(&local->mtx);
        mutex_lock(&local->iflist_mtx);
        if (local->use_chanctx) {
                sdata = rcu_dereference_protected(
@@ -846,6 +847,7 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
        if (ret == 0)
                local->monitor_chandef = *chandef;
        mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&local->mtx);
 
        return ret;
 }
@@ -951,6 +953,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                              struct cfg80211_ap_settings *params)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
        struct beacon_data *old;
        struct ieee80211_sub_if_data *vlan;
        u32 changed = BSS_CHANGED_BEACON_INT |
@@ -969,8 +972,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        sdata->needed_rx_chains = sdata->local->rx_chains;
        sdata->radar_required = params->radar_required;
 
+       mutex_lock(&local->mtx);
        err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&local->mtx);
        if (err)
                return err;
        ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
@@ -1121,7 +1126,9 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
        skb_queue_purge(&sdata->u.ap.ps.bc_buf);
 
        ieee80211_vif_copy_chanctx_to_vlans(sdata, true);
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        return 0;
 }
@@ -1944,8 +1951,10 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
+       mutex_lock(&sdata->local->mtx);
        err = ieee80211_vif_use_channel(sdata, &setup->chandef,
                                        IEEE80211_CHANCTX_SHARED);
+       mutex_unlock(&sdata->local->mtx);
        if (err)
                return err;
 
@@ -1957,7 +1966,9 @@ static int ieee80211_leave_mesh(struct wiphy *wiphy, struct net_device *dev)
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
        ieee80211_stop_mesh(sdata);
+       mutex_lock(&sdata->local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&sdata->local->mtx);
 
        return 0;
 }
@@ -2895,26 +2906,29 @@ static int ieee80211_start_radar_detection(struct wiphy *wiphy,
        unsigned long timeout;
        int err;
 
-       if (!list_empty(&local->roc_list) || local->scanning)
-               return -EBUSY;
+       mutex_lock(&local->mtx);
+       if (!list_empty(&local->roc_list) || local->scanning) {
+               err = -EBUSY;
+               goto out_unlock;
+       }
 
        /* whatever, but channel contexts should not complain about that one */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = local->rx_chains;
        sdata->radar_required = true;
 
-       mutex_lock(&local->iflist_mtx);
        err = ieee80211_vif_use_channel(sdata, chandef,
                                        IEEE80211_CHANCTX_SHARED);
-       mutex_unlock(&local->iflist_mtx);
        if (err)
-               return err;
+               goto out_unlock;
 
        timeout = msecs_to_jiffies(IEEE80211_DFS_MIN_CAC_TIME_MS);
        ieee80211_queue_delayed_work(&sdata->local->hw,
                                     &sdata->dfs_cac_timer_work, timeout);
 
-       return 0;
+ out_unlock:
+       mutex_unlock(&local->mtx);
+       return err;
 }
 
 static struct cfg80211_beacon_data *
@@ -2990,7 +3004,9 @@ void ieee80211_csa_finalize_work(struct work_struct *work)
                goto unlock;
 
        sdata->radar_required = sdata->csa_radar_required;
+       mutex_lock(&local->mtx);
        err = ieee80211_vif_change_channel(sdata, &changed);
+       mutex_unlock(&local->mtx);
        if (WARN_ON(err < 0))
                goto unlock;
 
@@ -3821,6 +3837,31 @@ static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
 }
 #endif
 
+static int ieee80211_set_qos_map(struct wiphy *wiphy,
+                                struct net_device *dev,
+                                struct cfg80211_qos_map *qos_map)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct mac80211_qos_map *new_qos_map, *old_qos_map;
+
+       if (qos_map) {
+               new_qos_map = kzalloc(sizeof(*new_qos_map), GFP_KERNEL);
+               if (!new_qos_map)
+                       return -ENOMEM;
+               memcpy(&new_qos_map->qos_map, qos_map, sizeof(*qos_map));
+       } else {
+               /* A NULL qos_map was passed to disable QoS mapping */
+               new_qos_map = NULL;
+       }
+
+       old_qos_map = rtnl_dereference(sdata->qos_map);
+       rcu_assign_pointer(sdata->qos_map, new_qos_map);
+       if (old_qos_map)
+               kfree_rcu(old_qos_map, rcu_head);
+
+       return 0;
+}
+
 struct cfg80211_ops mac80211_config_ops = {
        .add_virtual_intf = ieee80211_add_iface,
        .del_virtual_intf = ieee80211_del_iface,
@@ -3900,4 +3941,5 @@ struct cfg80211_ops mac80211_config_ops = {
        .get_channel = ieee80211_cfg_get_channel,
        .start_radar_detection = ieee80211_start_radar_detection,
        .channel_switch = ieee80211_channel_switch,
+       .set_qos_map = ieee80211_set_qos_map,
 };
index a57d5d9466bcbca1c8aa05276502ede6987783e7..f43613a97dd664e2daf1856b001d7bdee5708d4f 100644 (file)
@@ -232,8 +232,8 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        if (!local->use_chanctx)
                local->hw.conf.radar_enabled = ctx->conf.radar_enabled;
 
-       /* acquire mutex to prevent idle from changing */
-       mutex_lock(&local->mtx);
+       /* we hold the mutex to prevent idle from changing */
+       lockdep_assert_held(&local->mtx);
        /* turn idle off *before* setting channel -- some drivers need that */
        changed = ieee80211_idle_off(local);
        if (changed)
@@ -246,19 +246,14 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
                err = drv_add_chanctx(local, ctx);
                if (err) {
                        kfree(ctx);
-                       ctx = ERR_PTR(err);
-
                        ieee80211_recalc_idle(local);
-                       goto out;
+                       return ERR_PTR(err);
                }
        }
 
        /* and keep the mutex held until the new chanctx is on the list */
        list_add_rcu(&ctx->list, &local->chanctx_list);
 
- out:
-       mutex_unlock(&local->mtx);
-
        return ctx;
 }
 
@@ -294,9 +289,7 @@ static void ieee80211_free_chanctx(struct ieee80211_local *local,
        /* throw a warning if this wasn't the only channel context. */
        WARN_ON(check_single_channel && !list_empty(&local->chanctx_list));
 
-       mutex_lock(&local->mtx);
        ieee80211_recalc_idle(local);
-       mutex_unlock(&local->mtx);
 }
 
 static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -358,6 +351,31 @@ static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
        ieee80211_change_chanctx(local, ctx, compat);
 }
 
+static void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
+                                          struct ieee80211_chanctx *chanctx)
+{
+       bool radar_enabled;
+
+       lockdep_assert_held(&local->chanctx_mtx);
+       /* for setting local->radar_detect_enabled */
+       lockdep_assert_held(&local->mtx);
+
+       radar_enabled = ieee80211_is_radar_required(local);
+
+       if (radar_enabled == chanctx->conf.radar_enabled)
+               return;
+
+       chanctx->conf.radar_enabled = radar_enabled;
+       local->radar_detect_enabled = chanctx->conf.radar_enabled;
+
+       if (!local->use_chanctx) {
+               local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
+               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
+       }
+
+       drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
+}
+
 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
                                           struct ieee80211_chanctx *ctx)
 {
@@ -404,29 +422,6 @@ static void __ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
                ieee80211_free_chanctx(local, ctx);
 }
 
-void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
-                                   struct ieee80211_chanctx *chanctx)
-{
-       bool radar_enabled;
-
-       lockdep_assert_held(&local->chanctx_mtx);
-
-       radar_enabled = ieee80211_is_radar_required(local);
-
-       if (radar_enabled == chanctx->conf.radar_enabled)
-               return;
-
-       chanctx->conf.radar_enabled = radar_enabled;
-       local->radar_detect_enabled = chanctx->conf.radar_enabled;
-
-       if (!local->use_chanctx) {
-               local->hw.conf.radar_enabled = chanctx->conf.radar_enabled;
-               ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
-       }
-
-       drv_change_chanctx(local, chanctx, IEEE80211_CHANCTX_CHANGE_RADAR);
-}
-
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx)
 {
@@ -518,6 +513,8 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_chanctx *ctx;
        int ret;
 
+       lockdep_assert_held(&local->mtx);
+
        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
        mutex_lock(&local->chanctx_mtx);
@@ -558,6 +555,8 @@ int ieee80211_vif_change_channel(struct ieee80211_sub_if_data *sdata,
        int ret;
        u32 chanctx_changed = 0;
 
+       lockdep_assert_held(&local->mtx);
+
        /* should never be called if not performing a channel switch. */
        if (WARN_ON(!sdata->vif.csa_active))
                return -EINVAL;
@@ -655,6 +654,8 @@ void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata)
 {
        WARN_ON(sdata->dev && netif_carrier_ok(sdata->dev));
 
+       lockdep_assert_held(&sdata->local->mtx);
+
        mutex_lock(&sdata->local->chanctx_mtx);
        __ieee80211_vif_release_channel(sdata);
        mutex_unlock(&sdata->local->chanctx_mtx);
index d6ba841437b6e41986163976e71650a9c911bbbf..771080ec7212a43b5e3bb151a7e17ab392fe5557 100644 (file)
@@ -293,14 +293,17 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                radar_required = true;
        }
 
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
        if (ieee80211_vif_use_channel(sdata, &chandef,
                                      ifibss->fixed_channel ?
                                        IEEE80211_CHANCTX_SHARED :
                                        IEEE80211_CHANCTX_EXCLUSIVE)) {
                sdata_info(sdata, "Failed to join IBSS, no channel context\n");
+               mutex_unlock(&local->mtx);
                return;
        }
+       mutex_unlock(&local->mtx);
 
        memcpy(ifibss->bssid, bssid, ETH_ALEN);
 
@@ -363,7 +366,9 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                sdata->vif.bss_conf.ssid_len = 0;
                RCU_INIT_POINTER(ifibss->presp, NULL);
                kfree_rcu(presp, rcu_head);
+               mutex_lock(&local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&local->mtx);
                sdata_info(sdata, "Failed to join IBSS, driver failure: %d\n",
                           err);
                return;
@@ -747,7 +752,9 @@ static void ieee80211_ibss_disconnect(struct ieee80211_sub_if_data *sdata)
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED |
                                                BSS_CHANGED_IBSS);
        drv_leave_ibss(local, sdata);
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 }
 
 static void ieee80211_csa_connection_drop_work(struct work_struct *work)
index fb5dbcb79a12264295622603e6134f4ec12bede0..953b9e29454707b39460fb761a5ddba3e9377344 100644 (file)
@@ -246,7 +246,8 @@ struct ps_data {
        /* yes, this looks ugly, but guarantees that we can later use
         * bitmap_empty :)
         * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */
-       u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)];
+       u8 tim[sizeof(unsigned long) * BITS_TO_LONGS(IEEE80211_MAX_AID + 1)]
+                       __aligned(__alignof__(unsigned long));
        struct sk_buff_head bc_buf;
        atomic_t num_sta_ps; /* number of stations in PS mode */
        int dtim_count;
@@ -693,6 +694,11 @@ struct ieee80211_chanctx {
        struct ieee80211_chanctx_conf conf;
 };
 
+struct mac80211_qos_map {
+       struct cfg80211_qos_map qos_map;
+       struct rcu_head rcu_head;
+};
+
 struct ieee80211_sub_if_data {
        struct list_head list;
 
@@ -738,6 +744,7 @@ struct ieee80211_sub_if_data {
        int encrypt_headroom;
 
        struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
+       struct mac80211_qos_map __rcu *qos_map;
 
        struct work_struct csa_finalize_work;
        int csa_counter_offset_beacon;
@@ -1775,8 +1782,6 @@ void ieee80211_vif_copy_chanctx_to_vlans(struct ieee80211_sub_if_data *sdata,
 
 void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
                                   struct ieee80211_chanctx *chanctx);
-void ieee80211_recalc_radar_chanctx(struct ieee80211_local *local,
-                                   struct ieee80211_chanctx *chanctx);
 void ieee80211_recalc_chanctx_min_def(struct ieee80211_local *local,
                                      struct ieee80211_chanctx *ctx);
 
index 3d2168c3269ef40b10fa28c50496f369f8158af4..0aa9675319ef18beac12b7eca0290f2f15e27109 100644 (file)
@@ -418,8 +418,10 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
                return ret;
        }
 
+       mutex_lock(&local->mtx);
        ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
                                        IEEE80211_CHANCTX_EXCLUSIVE);
+       mutex_unlock(&local->mtx);
        if (ret) {
                drv_remove_interface(local, sdata);
                kfree(sdata);
@@ -456,7 +458,9 @@ void ieee80211_del_virtual_monitor(struct ieee80211_local *local)
 
        synchronize_net();
 
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        drv_remove_interface(local, sdata);
 
@@ -826,9 +830,9 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        if (sdata->wdev.cac_started) {
                chandef = sdata->vif.bss_conf.chandef;
                WARN_ON(local->suspended);
-               mutex_lock(&local->iflist_mtx);
+               mutex_lock(&local->mtx);
                ieee80211_vif_release_channel(sdata);
-               mutex_unlock(&local->iflist_mtx);
+               mutex_unlock(&local->mtx);
                cfg80211_cac_event(sdata->dev, &chandef,
                                   NL80211_RADAR_CAC_ABORTED,
                                   GFP_KERNEL);
index 9c2c7ee2cc30815e47014ddb47bcd6cf1d66caf2..fc1d82465b3ce1b1cdcc9edb4f5157618b70e8ce 100644 (file)
@@ -888,7 +888,9 @@ static void ieee80211_chswitch_work(struct work_struct *work)
        if (!ifmgd->associated)
                goto out;
 
+       mutex_lock(&local->mtx);
        ret = ieee80211_vif_change_channel(sdata, &changed);
+       mutex_unlock(&local->mtx);
        if (ret) {
                sdata_info(sdata,
                           "vif channel switch failed, disconnecting\n");
@@ -1401,10 +1403,14 @@ void ieee80211_dfs_cac_timer_work(struct work_struct *work)
                             dfs_cac_timer_work);
        struct cfg80211_chan_def chandef = sdata->vif.bss_conf.chandef;
 
-       ieee80211_vif_release_channel(sdata);
-       cfg80211_cac_event(sdata->dev, &chandef,
-                          NL80211_RADAR_CAC_FINISHED,
-                          GFP_KERNEL);
+       mutex_lock(&sdata->local->mtx);
+       if (sdata->wdev.cac_started) {
+               ieee80211_vif_release_channel(sdata);
+               cfg80211_cac_event(sdata->dev, &chandef,
+                                  NL80211_RADAR_CAC_FINISHED,
+                                  GFP_KERNEL);
+       }
+       mutex_unlock(&sdata->local->mtx);
 }
 
 /* MLME */
@@ -1747,7 +1753,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        ifmgd->have_beacon = false;
 
        ifmgd->flags = 0;
+       mutex_lock(&local->mtx);
        ieee80211_vif_release_channel(sdata);
+       mutex_unlock(&local->mtx);
 
        sdata->encrypt_headroom = IEEE80211_ENCRYPT_HEADROOM;
 }
@@ -2070,7 +2078,9 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+               mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        cfg80211_put_bss(sdata->local->hw.wiphy, auth_data->bss);
@@ -2319,7 +2329,9 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
                sdata->u.mgd.flags = 0;
+               mutex_lock(&sdata->local->mtx);
                ieee80211_vif_release_channel(sdata);
+               mutex_unlock(&sdata->local->mtx);
        }
 
        kfree(assoc_data);
@@ -3670,6 +3682,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        /* will change later if needed */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
 
+       mutex_lock(&local->mtx);
        /*
         * If this fails (possibly due to channel context sharing
         * on incompatible channels, e.g. 80+80 and 160 sharing the
@@ -3681,13 +3694,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        /* don't downgrade for 5 and 10 MHz channels, though. */
        if (chandef.width == NL80211_CHAN_WIDTH_5 ||
            chandef.width == NL80211_CHAN_WIDTH_10)
-               return ret;
+               goto out;
 
        while (ret && chandef.width != NL80211_CHAN_WIDTH_20_NOHT) {
                ifmgd->flags |= ieee80211_chandef_downgrade(&chandef);
                ret = ieee80211_vif_use_channel(sdata, &chandef,
                                                IEEE80211_CHANCTX_SHARED);
        }
+ out:
+       mutex_unlock(&local->mtx);
        return ret;
 }
 
index d2f19f7e7091b6e6b9111702f19b02f612fdb52c..f3d88b0c054c219fde20b907195c3bdb5a481c97 100644 (file)
@@ -135,7 +135,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
        u32 usecs;
        int i;
 
-       for (i=0; i < MAX_THR_RATES; i++)
+       for (i = 0; i < MAX_THR_RATES; i++)
            tmp_tp_rate[i] = 0;
 
        for (i = 0; i < mi->n_rates; i++) {
@@ -190,7 +190,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
                 * choose the maximum throughput rate as max_prob_rate
                 * (2) if all success probabilities < 95%, the rate with
                 * highest success probability is choosen as max_prob_rate */
-               if (mr->probability >= MINSTREL_FRAC(95,100)) {
+               if (mr->probability >= MINSTREL_FRAC(95, 100)) {
                        if (mr->cur_tp >= mi->r[tmp_prob_rate].cur_tp)
                                tmp_prob_rate = i;
                } else {
@@ -220,7 +220,7 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi)
 
 static void
 minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
-                   struct ieee80211_sta *sta, void *priv_sta,
+                  struct ieee80211_sta *sta, void *priv_sta,
                   struct sk_buff *skb)
 {
        struct minstrel_priv *mp = priv;
@@ -260,7 +260,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband,
 
 static inline unsigned int
 minstrel_get_retry_count(struct minstrel_rate *mr,
-                         struct ieee80211_tx_info *info)
+                        struct ieee80211_tx_info *info)
 {
        unsigned int retry = mr->adjusted_retry_count;
 
index d2ed18d82fe1dd1f55a2f5c13f319920bbb9b887..c1b5b73c5b91353597eb1dfcf7a0f70946c72562 100644 (file)
@@ -63,7 +63,7 @@
 
 #define CCK_DURATION(_bitrate, _short, _len)           \
        (1000 * (10 /* SIFS */ +                        \
-        (_short ? 72 + 24 : 144 + 48 ) +               \
+        (_short ? 72 + 24 : 144 + 48) +                \
         (8 * (_len + 4) * 10) / (_bitrate)))
 
 #define CCK_ACK_DURATION(_bitrate, _short)                     \
index 124b1fdc20d05531bccfa32e6ccc5f72c7cef1bb..0ae207771a5837ff73d359fe4032be26ac4ca358 100644 (file)
@@ -186,7 +186,7 @@ void ieee80211_get_tkip_p1k_iv(struct ieee80211_key_conf *keyconf,
 EXPORT_SYMBOL(ieee80211_get_tkip_p1k_iv);
 
 void ieee80211_get_tkip_rx_p1k(struct ieee80211_key_conf *keyconf,
-                               const u8 *ta, u32 iv32, u16 *p1k)
+                              const u8 *ta, u32 iv32, u16 *p1k)
 {
        const u8 *tk = &keyconf->key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
        struct tkip_ctx ctx;
index 3a669d7ec7adc423501539bd682ce705451b74c1..da9366632f378651d14c12d543aa80525d8a6ba8 100644 (file)
@@ -553,7 +553,7 @@ TRACE_EVENT(drv_update_tkip_key,
 
        TP_printk(
                LOCAL_PR_FMT VIF_PR_FMT STA_PR_FMT " iv32:%#x",
-               LOCAL_PR_ARG,VIF_PR_ARG,STA_PR_ARG, __entry->iv32
+               LOCAL_PR_ARG, VIF_PR_ARG, STA_PR_ARG, __entry->iv32
        )
 );
 
index 2f0e176e79897f36499f48e9418127e4cddd6c51..377cf974d97d15b41773b0ea7aed9ae7ebc1edba 100644 (file)
@@ -2161,7 +2161,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
        if (ieee80211_is_data_qos(fc)) {
                __le16 *qos_control;
 
-               qos_control = (__le16*) skb_push(skb, 2);
+               qos_control = (__le16 *) skb_push(skb, 2);
                memcpy(skb_push(skb, hdrlen - 2), &hdr, hdrlen - 2);
                /*
                 * Maybe we could actually set some fields here, for now just
@@ -2323,7 +2323,7 @@ static void __ieee80211_beacon_add_tim(struct ieee80211_sub_if_data *sdata,
        if (atomic_read(&ps->num_sta_ps) > 0)
                /* in the hope that this is faster than
                 * checking byte-for-byte */
-               have_bits = !bitmap_empty((unsigned long*)ps->tim,
+               have_bits = !bitmap_empty((unsigned long *)ps->tim,
                                          IEEE80211_MAX_AID+1);
 
        if (ps->dtim_count == 0)
index 591b46b724621dedfba73cedeb9791c0608339b8..df00f1978a77574857a9e8cf5c37cad66ce3e487 100644 (file)
@@ -76,7 +76,7 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
        }
 
        if (ieee80211_is_ctl(fc)) {
-               if(ieee80211_is_pspoll(fc))
+               if (ieee80211_is_pspoll(fc))
                        return hdr->addr1;
 
                if (ieee80211_is_back_req(fc)) {
@@ -2315,9 +2315,14 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
        struct ieee80211_sub_if_data *sdata;
        struct cfg80211_chan_def chandef;
 
+       mutex_lock(&local->mtx);
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
-               cancel_delayed_work_sync(&sdata->dfs_cac_timer_work);
+               /* it might be waiting for the local->mtx, but then
+                * by the time it gets it, sdata->wdev.cac_started
+                * will no longer be true
+                */
+               cancel_delayed_work(&sdata->dfs_cac_timer_work);
 
                if (sdata->wdev.cac_started) {
                        chandef = sdata->vif.bss_conf.chandef;
@@ -2329,6 +2334,7 @@ void ieee80211_dfs_cac_cancel(struct ieee80211_local *local)
                }
        }
        mutex_unlock(&local->iflist_mtx);
+       mutex_unlock(&local->mtx);
 }
 
 void ieee80211_dfs_radar_detected_work(struct work_struct *work)
@@ -2588,3 +2594,143 @@ int ieee80211_cs_headroom(struct ieee80211_local *local,
 
        return headroom;
 }
+
+static bool
+ieee80211_extend_noa_desc(struct ieee80211_noa_data *data, u32 tsf, int i)
+{
+       s32 end = data->desc[i].start + data->desc[i].duration - (tsf + 1);
+       int skip;
+
+       if (end > 0)
+               return false;
+
+       /* End time is in the past, check for repetitions */
+       skip = DIV_ROUND_UP(-end, data->desc[i].interval);
+       if (data->count[i] < 255) {
+               if (data->count[i] <= skip) {
+                       data->count[i] = 0;
+                       return false;
+               }
+
+               data->count[i] -= skip;
+       }
+
+       data->desc[i].start += skip * data->desc[i].interval;
+
+       return true;
+}
+
+static bool
+ieee80211_extend_absent_time(struct ieee80211_noa_data *data, u32 tsf,
+                            s32 *offset)
+{
+       bool ret = false;
+       int i;
+
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               s32 cur;
+
+               if (!data->count[i])
+                       continue;
+
+               if (ieee80211_extend_noa_desc(data, tsf + *offset, i))
+                       ret = true;
+
+               cur = data->desc[i].start - tsf;
+               if (cur > *offset)
+                       continue;
+
+               cur = data->desc[i].start + data->desc[i].duration - tsf;
+               if (cur > *offset)
+                       *offset = cur;
+       }
+
+       return ret;
+}
+
+static u32
+ieee80211_get_noa_absent_time(struct ieee80211_noa_data *data, u32 tsf)
+{
+       s32 offset = 0;
+       int tries = 0;
+       /*
+        * arbitrary limit, used to avoid infinite loops when combined NoA
+        * descriptors cover the full time period.
+        */
+       int max_tries = 5;
+
+       ieee80211_extend_absent_time(data, tsf, &offset);
+       do {
+               if (!ieee80211_extend_absent_time(data, tsf, &offset))
+                       break;
+
+               tries++;
+       } while (tries < max_tries);
+
+       return offset;
+}
+
+void ieee80211_update_p2p_noa(struct ieee80211_noa_data *data, u32 tsf)
+{
+       u32 next_offset = BIT(31) - 1;
+       int i;
+
+       data->absent = 0;
+       data->has_next_tsf = false;
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               s32 start;
+
+               if (!data->count[i])
+                       continue;
+
+               ieee80211_extend_noa_desc(data, tsf, i);
+               start = data->desc[i].start - tsf;
+               if (start <= 0)
+                       data->absent |= BIT(i);
+
+               if (next_offset > start)
+                       next_offset = start;
+
+               data->has_next_tsf = true;
+       }
+
+       if (data->absent)
+               next_offset = ieee80211_get_noa_absent_time(data, tsf);
+
+       data->next_tsf = tsf + next_offset;
+}
+EXPORT_SYMBOL(ieee80211_update_p2p_noa);
+
+int ieee80211_parse_p2p_noa(const struct ieee80211_p2p_noa_attr *attr,
+                           struct ieee80211_noa_data *data, u32 tsf)
+{
+       int ret = 0;
+       int i;
+
+       memset(data, 0, sizeof(*data));
+
+       for (i = 0; i < IEEE80211_P2P_NOA_DESC_MAX; i++) {
+               const struct ieee80211_p2p_noa_desc *desc = &attr->desc[i];
+
+               if (!desc->count || !desc->duration)
+                       continue;
+
+               data->count[i] = desc->count;
+               data->desc[i].start = le32_to_cpu(desc->start_time);
+               data->desc[i].duration = le32_to_cpu(desc->duration);
+               data->desc[i].interval = le32_to_cpu(desc->interval);
+
+               if (data->count[i] > 1 &&
+                   data->desc[i].interval < data->desc[i].duration)
+                       continue;
+
+               ieee80211_extend_noa_desc(data, tsf, i);
+               ret++;
+       }
+
+       if (ret)
+               ieee80211_update_p2p_noa(data, tsf);
+
+       return ret;
+}
+EXPORT_SYMBOL(ieee80211_parse_p2p_noa);
index afba19cb6f87af534f67904b96c0efcd7f421896..21211c60ca988992034bfc330977e846c3fc7010 100644 (file)
@@ -106,6 +106,7 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        struct sta_info *sta = NULL;
        const u8 *ra = NULL;
        bool qos = false;
+       struct mac80211_qos_map *qos_map;
 
        if (local->hw.queues < IEEE80211_NUM_ACS || skb->len < 6) {
                skb->priority = 0; /* required for correct WPA/11i MIC */
@@ -155,7 +156,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
 
        /* use the data classifier to determine what 802.1d tag the
         * data frame has */
-       skb->priority = cfg80211_classify8021d(skb);
+       rcu_read_lock();
+       qos_map = rcu_dereference(sdata->qos_map);
+       skb->priority = cfg80211_classify8021d(skb, qos_map ?
+                                              &qos_map->qos_map : NULL);
+       rcu_read_unlock();
 
        return ieee80211_downgrade_queue(sdata, skb);
 }
index 02ab34132157066d9a0def95276b7abe3f8d7f71..c1903f439aacb1d0e0ce8deac8e15ad54c3536b6 100644 (file)
@@ -133,11 +133,8 @@ int nfc_dev_up(struct nfc_dev *dev)
                dev->dev_up = true;
 
        /* We have to enable the device before discovering SEs */
-       if (dev->ops->discover_se) {
-               rc = dev->ops->discover_se(dev);
-               if (rc)
-                       pr_warn("SE discovery failed\n");
-       }
+       if (dev->ops->discover_se && dev->ops->discover_se(dev))
+               pr_err("SE discovery failed\n");
 
 error:
        device_unlock(&dev->dev);
index 09fc95439955052c2b2f6f178ae0ea421f3fab24..c129d1571ca6c55281807781aeb803d6f9f9415b 100644 (file)
@@ -339,7 +339,6 @@ int digital_target_found(struct nfc_digital_dev *ddev,
        pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol);
 
        ddev->curr_rf_tech = rf_tech;
-       ddev->curr_protocol = protocol;
 
        if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
                ddev->skb_add_crc = digital_skb_add_crc_none;
@@ -541,8 +540,14 @@ static int digital_dep_link_up(struct nfc_dev *nfc_dev,
                               __u8 comm_mode, __u8 *gb, size_t gb_len)
 {
        struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
+       int rc;
+
+       rc = digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
 
-       return digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
+       if (!rc)
+               ddev->curr_protocol = NFC_PROTO_NFC_DEP;
+
+       return rc;
 }
 
 static int digital_dep_link_down(struct nfc_dev *nfc_dev)
@@ -557,6 +562,20 @@ static int digital_dep_link_down(struct nfc_dev *nfc_dev)
 static int digital_activate_target(struct nfc_dev *nfc_dev,
                                   struct nfc_target *target, __u32 protocol)
 {
+       struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
+
+       if (ddev->poll_tech_count) {
+               pr_err("Can't activate a target while polling\n");
+               return -EBUSY;
+       }
+
+       if (ddev->curr_protocol) {
+               pr_err("A target is already active\n");
+               return -EBUSY;
+       }
+
+       ddev->curr_protocol = protocol;
+
        return 0;
 }
 
@@ -565,6 +584,11 @@ static void digital_deactivate_target(struct nfc_dev *nfc_dev,
 {
        struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
 
+       if (!ddev->curr_protocol) {
+               pr_err("No active target\n");
+               return;
+       }
+
        ddev->curr_protocol = 0;
 }
 
index 07bbc24fb4c73e39f79c8e5b70c34d95338b04c3..43e450f78d0a2dd034335cf5d3384ccd86940187 100644 (file)
@@ -32,7 +32,6 @@
 #define DIGITAL_ATR_REQ_MIN_SIZE 16
 #define DIGITAL_ATR_REQ_MAX_SIZE 64
 
-#define DIGITAL_NFCID3_LEN ((u8)8)
 #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
 #define DIGITAL_GB_BIT 0x02
 
@@ -206,10 +205,9 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
        atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
        atr_req->cmd = DIGITAL_CMD_ATR_REQ;
        if (target->nfcid2_len)
-               memcpy(atr_req->nfcid3, target->nfcid2,
-                      max(target->nfcid2_len, DIGITAL_NFCID3_LEN));
+               memcpy(atr_req->nfcid3, target->nfcid2, NFC_NFCID2_MAXSIZE);
        else
-               get_random_bytes(atr_req->nfcid3, DIGITAL_NFCID3_LEN);
+               get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE);
 
        atr_req->did = 0;
        atr_req->bs = 0;
@@ -382,6 +380,33 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
                                   data_exch);
 }
 
+static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech)
+{
+       ddev->curr_rf_tech = rf_tech;
+
+       ddev->skb_add_crc = digital_skb_add_crc_none;
+       ddev->skb_check_crc = digital_skb_check_crc_none;
+
+       if (DIGITAL_DRV_CAPS_TG_CRC(ddev))
+               return;
+
+       switch (ddev->curr_rf_tech) {
+       case NFC_DIGITAL_RF_TECH_106A:
+               ddev->skb_add_crc = digital_skb_add_crc_a;
+               ddev->skb_check_crc = digital_skb_check_crc_a;
+               break;
+
+       case NFC_DIGITAL_RF_TECH_212F:
+       case NFC_DIGITAL_RF_TECH_424F:
+               ddev->skb_add_crc = digital_skb_add_crc_f;
+               ddev->skb_check_crc = digital_skb_check_crc_f;
+               break;
+
+       default:
+               break;
+       }
+}
+
 static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
                                    struct sk_buff *resp)
 {
@@ -472,11 +497,13 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb)
 static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev,
                                             void *arg, struct sk_buff *resp)
 {
-       u8 rf_tech = PTR_ERR(arg);
+       u8 rf_tech = (unsigned long)arg;
 
        if (IS_ERR(resp))
                return;
 
+       digital_tg_set_rf_tech(ddev, rf_tech);
+
        digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
 
        digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL);
@@ -508,7 +535,7 @@ static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did,
        ddev->skb_add_crc(skb);
 
        rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete,
-                                ERR_PTR(rf_tech));
+                                (void *)(unsigned long)rf_tech);
 
        if (rc)
                kfree_skb(skb);
@@ -661,16 +688,10 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
 
        if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) {
                min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2;
-
-               ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_106A;
-               ddev->skb_add_crc = digital_skb_add_crc_a;
-               ddev->skb_check_crc = digital_skb_check_crc_a;
+               digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_106A);
        } else {
                min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1;
-
-               ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_212F;
-               ddev->skb_add_crc = digital_skb_add_crc_f;
-               ddev->skb_check_crc = digital_skb_check_crc_f;
+               digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_212F);
        }
 
        if (resp->len < min_size) {
@@ -678,10 +699,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
                goto exit;
        }
 
-       if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) {
-               ddev->skb_add_crc = digital_skb_add_crc_none;
-               ddev->skb_check_crc = digital_skb_check_crc_none;
-       }
+       ddev->curr_protocol = NFC_PROTO_NFC_DEP_MASK;
 
        rc = ddev->skb_check_crc(resp);
        if (rc) {
index 3b9610031baa2271fd7b00648b00709bdc483b95..d45b638e77c78ec25b8228eacf2ea0ac754ad8d7 100644 (file)
@@ -335,11 +335,8 @@ exit:
        kfree_skb(skb);
 
 exit_noskb:
-       if (r) {
-               /* TODO: There was an error dispatching the event,
-                * how to propagate up to nfc core?
-                */
-       }
+       if (r)
+               nfc_hci_driver_failure(hdev, r);
 }
 
 static void nfc_hci_cmd_timeout(unsigned long data)
index 693cd1aad582314a81accc30d60e528eb0ad2335..bec6ed15f5037ef9ffbc75f93e450e9ef1fd81b7 100644 (file)
@@ -675,7 +675,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
        do {
                remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
-                               local->remote_miu : sock->remote_miu;
+                               LLCP_DEFAULT_MIU : sock->remote_miu;
 
                frag_len = min_t(size_t, remote_miu, remaining_len);
 
@@ -684,8 +684,10 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
                pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
                                        frag_len + LLCP_SEQUENCE_SIZE);
-               if (pdu == NULL)
+               if (pdu == NULL) {
+                       kfree(msg_data);
                        return -ENOMEM;
+               }
 
                skb_put(pdu, LLCP_SEQUENCE_SIZE);
 
index 1349074e1ffc09458cd307f063324d83423d4e46..6184bd1fba3a05c92fcefb45782d07ffbabac8ff 100644 (file)
@@ -943,7 +943,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
        new_sock->local = nfc_llcp_local_get(local);
        new_sock->rw = sock->rw;
        new_sock->miux = sock->miux;
-       new_sock->remote_miu = local->remote_miu;
        new_sock->nfc_protocol = sock->nfc_protocol;
        new_sock->dsap = ssap;
        new_sock->target_idx = local->target_idx;
index 69fbc8dadba745c5bf077d0b79be853cc2fde545..4a53bb58a46356606d1276d6e62c19e851feff3b 100644 (file)
@@ -700,7 +700,6 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 
        llcp_sock->dev = dev;
        llcp_sock->local = nfc_llcp_local_get(local);
-       llcp_sock->remote_miu = llcp_sock->local->remote_miu;
        llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
        if (llcp_sock->ssap == LLCP_SAP_MAX) {
                ret = -ENOMEM;
index f0e955e3a3853ee0dabc1daa6f35318dd68fab51..46bda010bf11740c1a2fcd9002a193a7ab70801a 100644 (file)
@@ -301,6 +301,9 @@ static int nci_open_device(struct nci_dev *ndev)
        rc = __nci_request(ndev, nci_reset_req, 0,
                           msecs_to_jiffies(NCI_RESET_TIMEOUT));
 
+       if (ndev->ops->setup(ndev))
+               ndev->ops->setup(ndev);
+
        if (!rc) {
                rc = __nci_request(ndev, nci_init_req, 0,
                                   msecs_to_jiffies(NCI_INIT_TIMEOUT));
@@ -361,6 +364,8 @@ static int nci_close_device(struct nci_dev *ndev)
                      msecs_to_jiffies(NCI_RESET_TIMEOUT));
        clear_bit(NCI_INIT, &ndev->flags);
 
+       del_timer_sync(&ndev->cmd_timer);
+
        /* Flush cmd wq */
        flush_workqueue(ndev->cmd_wq);
 
@@ -408,12 +413,26 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
        return nci_close_device(ndev);
 }
 
+int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val)
+{
+       struct nci_set_config_param param;
+
+       if (!val || !len)
+               return 0;
+
+       param.id = id;
+       param.len = len;
+       param.val = val;
+
+       return __nci_request(ndev, nci_set_config_req, (unsigned long)&param,
+                            msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
+}
+EXPORT_SYMBOL(nci_set_config);
+
 static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
 {
        struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
        struct nci_set_config_param param;
-       __u8 local_gb[NFC_MAX_GT_LEN];
-       int i;
 
        param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
        if ((param.val == NULL) || (param.len == 0))
@@ -422,11 +441,7 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
        if (param.len > NFC_MAX_GT_LEN)
                return -EINVAL;
 
-       for (i = 0; i < param.len; i++)
-               local_gb[param.len-1-i] = param.val[i];
-
        param.id = NCI_PN_ATR_REQ_GEN_BYTES;
-       param.val = local_gb;
 
        return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
                           msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
index 324e8d851dc4ca67fd0ded84a927e782c3647c8c..11ee4ed04f73ea2ae0dd1ae6293837785d8fd5f8 100644 (file)
@@ -29,6 +29,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
                wdev->beacon_interval = 0;
                wdev->channel = NULL;
                wdev->ssid_len = 0;
+               rdev_set_qos_map(rdev, dev, NULL);
        }
 
        return err;
index 730147ed8e652c625cb035309df687ca08fd5b49..f911c5f9f903d8ccdd791aaf26d950b19ad6dd9f 100644 (file)
@@ -183,6 +183,8 @@ static void __cfg80211_clear_ibss(struct net_device *dev, bool nowext)
        kfree(wdev->connect_keys);
        wdev->connect_keys = NULL;
 
+       rdev_set_qos_map(rdev, dev, NULL);
+
        /*
         * Delete all the keys ... pairwise keys can't really
         * exist any more anyway, but default keys might.
index 9c7a11ae79368894899ce9e4d2b84c0b0d133c68..885862447b63c3434c0784924de2b984fcfedc25 100644 (file)
@@ -277,6 +277,7 @@ static int __cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
        if (!err) {
                wdev->mesh_id_len = 0;
                wdev->channel = NULL;
+               rdev_set_qos_map(rdev, dev, NULL);
        }
 
        return err;
index 04681a46eda8fc974997041e52b2709882755720..b4f40fe84a0121381d221fd0c18a65043428fc17 100644 (file)
@@ -53,6 +53,7 @@ enum nl80211_multicast_groups {
        NL80211_MCGRP_SCAN,
        NL80211_MCGRP_REGULATORY,
        NL80211_MCGRP_MLME,
+       NL80211_MCGRP_VENDOR,
        NL80211_MCGRP_TESTMODE /* keep last - ifdef! */
 };
 
@@ -61,6 +62,7 @@ static const struct genl_multicast_group nl80211_mcgrps[] = {
        [NL80211_MCGRP_SCAN] = { .name = "scan", },
        [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
        [NL80211_MCGRP_MLME] = { .name = "mlme", },
+       [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
 #ifdef CONFIG_NL80211_TESTMODE
        [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
 #endif
@@ -380,6 +382,8 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_VENDOR_ID] = { .type = NLA_U32 },
        [NL80211_ATTR_VENDOR_SUBCMD] = { .type = NLA_U32 },
        [NL80211_ATTR_VENDOR_DATA] = { .type = NLA_BINARY },
+       [NL80211_ATTR_QOS_MAP] = { .type = NLA_BINARY,
+                                  .len = IEEE80211_QOS_MAP_LEN_MAX },
 };
 
 /* policy for the key attributes */
@@ -1188,7 +1192,6 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
        struct nlattr *nl_bands, *nl_band;
        struct nlattr *nl_freqs, *nl_freq;
        struct nlattr *nl_cmds;
-       struct nlattr *nl_vendor_cmds;
        enum ieee80211_band band;
        struct ieee80211_channel *chan;
        int i;
@@ -1455,6 +1458,7 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                        if (dev->wiphy.flags & WIPHY_FLAG_HAS_CHANNEL_SWITCH)
                                CMD(channel_switch, CHANNEL_SWITCH);
                }
+               CMD(set_qos_map, SET_QOS_MAP);
 
 #ifdef CONFIG_NL80211_TESTMODE
                CMD(testmode_cmd, TESTMODE);
@@ -1587,16 +1591,38 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *dev,
                state->split_start++;
                break;
        case 11:
-               nl_vendor_cmds = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
-               if (!nl_vendor_cmds)
-                       goto nla_put_failure;
+               if (dev->wiphy.n_vendor_commands) {
+                       const struct nl80211_vendor_cmd_info *info;
+                       struct nlattr *nested;
+
+                       nested = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
+                       if (!nested)
+                               goto nla_put_failure;
+
+                       for (i = 0; i < dev->wiphy.n_vendor_commands; i++) {
+                               info = &dev->wiphy.vendor_commands[i].info;
+                               if (nla_put(msg, i + 1, sizeof(*info), info))
+                                       goto nla_put_failure;
+                       }
+                       nla_nest_end(msg, nested);
+               }
+
+               if (dev->wiphy.n_vendor_events) {
+                       const struct nl80211_vendor_cmd_info *info;
+                       struct nlattr *nested;
 
-               for (i = 0; i < dev->wiphy.n_vendor_commands; i++)
-                       if (nla_put(msg, i + 1,
-                                   sizeof(struct nl80211_vendor_cmd_info),
-                                   &dev->wiphy.vendor_commands[i].info))
+                       nested = nla_nest_start(msg,
+                                               NL80211_ATTR_VENDOR_EVENTS);
+                       if (!nested)
                                goto nla_put_failure;
-               nla_nest_end(msg, nl_vendor_cmds);
+
+                       for (i = 0; i < dev->wiphy.n_vendor_events; i++) {
+                               info = &dev->wiphy.vendor_events[i];
+                               if (nla_put(msg, i + 1, sizeof(*info), info))
+                                       goto nla_put_failure;
+                       }
+                       nla_nest_end(msg, nested);
+               }
 
                /* done */
                state->split_start = 0;
@@ -6726,7 +6752,9 @@ static struct sk_buff *
 __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
                            int approxlen, u32 portid, u32 seq,
                            enum nl80211_commands cmd,
-                           enum nl80211_attrs attr, gfp_t gfp)
+                           enum nl80211_attrs attr,
+                           const struct nl80211_vendor_cmd_info *info,
+                           gfp_t gfp)
 {
        struct sk_buff *skb;
        void *hdr;
@@ -6744,6 +6772,16 @@ __cfg80211_alloc_vendor_skb(struct cfg80211_registered_device *rdev,
 
        if (nla_put_u32(skb, NL80211_ATTR_WIPHY, rdev->wiphy_idx))
                goto nla_put_failure;
+
+       if (info) {
+               if (nla_put_u32(skb, NL80211_ATTR_VENDOR_ID,
+                               info->vendor_id))
+                       goto nla_put_failure;
+               if (nla_put_u32(skb, NL80211_ATTR_VENDOR_SUBCMD,
+                               info->subcmd))
+                       goto nla_put_failure;
+       }
+
        data = nla_nest_start(skb, attr);
 
        ((void **)skb->cb)[0] = rdev;
@@ -6884,29 +6922,54 @@ static int nl80211_testmode_dump(struct sk_buff *skb,
        return err;
 }
 
-struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
-                                                 int approxlen, gfp_t gfp)
+struct sk_buff *__cfg80211_alloc_event_skb(struct wiphy *wiphy,
+                                          enum nl80211_commands cmd,
+                                          enum nl80211_attrs attr,
+                                          int vendor_event_idx,
+                                          int approxlen, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+       const struct nl80211_vendor_cmd_info *info;
+
+       switch (cmd) {
+       case NL80211_CMD_TESTMODE:
+               if (WARN_ON(vendor_event_idx != -1))
+                       return NULL;
+               info = NULL;
+               break;
+       case NL80211_CMD_VENDOR:
+               if (WARN_ON(vendor_event_idx < 0 ||
+                           vendor_event_idx >= wiphy->n_vendor_events))
+                       return NULL;
+               info = &wiphy->vendor_events[vendor_event_idx];
+               break;
+       default:
+               WARN_ON(1);
+               return NULL;
+       }
 
        return __cfg80211_alloc_vendor_skb(rdev, approxlen, 0, 0,
-                                          NL80211_CMD_TESTMODE,
-                                          NL80211_ATTR_TESTDATA, gfp);
+                                          cmd, attr, info, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_alloc_event_skb);
+EXPORT_SYMBOL(__cfg80211_alloc_event_skb);
 
-void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp)
+void __cfg80211_send_event_skb(struct sk_buff *skb, gfp_t gfp)
 {
        struct cfg80211_registered_device *rdev = ((void **)skb->cb)[0];
        void *hdr = ((void **)skb->cb)[1];
        struct nlattr *data = ((void **)skb->cb)[2];
+       enum nl80211_multicast_groups mcgrp = NL80211_MCGRP_TESTMODE;
 
        nla_nest_end(skb, data);
        genlmsg_end(skb, hdr);
+
+       if (data->nla_type == NL80211_ATTR_VENDOR_DATA)
+               mcgrp = NL80211_MCGRP_VENDOR;
+
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), skb, 0,
-                               NL80211_MCGRP_TESTMODE, gfp);
+                               mcgrp, gfp);
 }
-EXPORT_SYMBOL(cfg80211_testmode_event);
+EXPORT_SYMBOL(__cfg80211_send_event_skb);
 #endif
 
 static int nl80211_connect(struct sk_buff *skb, struct genl_info *info)
@@ -9039,7 +9102,7 @@ struct sk_buff *__cfg80211_alloc_reply_skb(struct wiphy *wiphy,
        return __cfg80211_alloc_vendor_skb(rdev, approxlen,
                                           rdev->cur_cmd_info->snd_portid,
                                           rdev->cur_cmd_info->snd_seq,
-                                          cmd, attr, GFP_KERNEL);
+                                          cmd, attr, NULL, GFP_KERNEL);
 }
 EXPORT_SYMBOL(__cfg80211_alloc_reply_skb);
 
@@ -9061,6 +9124,57 @@ int cfg80211_vendor_cmd_reply(struct sk_buff *skb)
 EXPORT_SYMBOL_GPL(cfg80211_vendor_cmd_reply);
 
 
+static int nl80211_set_qos_map(struct sk_buff *skb,
+                              struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_qos_map *qos_map = NULL;
+       struct net_device *dev = info->user_ptr[1];
+       u8 *pos, len, num_des, des_len, des;
+       int ret;
+
+       if (!rdev->ops->set_qos_map)
+               return -EOPNOTSUPP;
+
+       if (info->attrs[NL80211_ATTR_QOS_MAP]) {
+               pos = nla_data(info->attrs[NL80211_ATTR_QOS_MAP]);
+               len = nla_len(info->attrs[NL80211_ATTR_QOS_MAP]);
+
+               if (len % 2 || len < IEEE80211_QOS_MAP_LEN_MIN ||
+                   len > IEEE80211_QOS_MAP_LEN_MAX)
+                       return -EINVAL;
+
+               qos_map = kzalloc(sizeof(struct cfg80211_qos_map), GFP_KERNEL);
+               if (!qos_map)
+                       return -ENOMEM;
+
+               num_des = (len - IEEE80211_QOS_MAP_LEN_MIN) >> 1;
+               if (num_des) {
+                       des_len = num_des *
+                               sizeof(struct cfg80211_dscp_exception);
+                       memcpy(qos_map->dscp_exception, pos, des_len);
+                       qos_map->num_des = num_des;
+                       for (des = 0; des < num_des; des++) {
+                               if (qos_map->dscp_exception[des].up > 7) {
+                                       kfree(qos_map);
+                                       return -EINVAL;
+                               }
+                       }
+                       pos += des_len;
+               }
+               memcpy(qos_map->up, pos, IEEE80211_QOS_MAP_LEN_MIN);
+       }
+
+       wdev_lock(dev->ieee80211_ptr);
+       ret = nl80211_key_allowed(dev->ieee80211_ptr);
+       if (!ret)
+               ret = rdev_set_qos_map(rdev, dev, qos_map);
+       wdev_unlock(dev->ieee80211_ptr);
+
+       kfree(qos_map);
+       return ret;
+}
+
 #define NL80211_FLAG_NEED_WIPHY                0x01
 #define NL80211_FLAG_NEED_NETDEV       0x02
 #define NL80211_FLAG_NEED_RTNL         0x04
@@ -9793,6 +9907,14 @@ static const struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_SET_QOS_MAP,
+               .doit = nl80211_set_qos_map,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 /* notification functions */
index a271c27fac774ce987c0db6f1330ffbfca6dc7f7..722da616438cd1e933fb4d5e60a2c4846f44d186 100644 (file)
@@ -124,6 +124,10 @@ int ieee80211_radiotap_iterator_init(
        /* find payload start allowing for extended bitmap(s) */
 
        if (iterator->_bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT)) {
+               if ((unsigned long)iterator->_arg -
+                   (unsigned long)iterator->_rtheader + sizeof(uint32_t) >
+                   (unsigned long)iterator->_max_length)
+                       return -EINVAL;
                while (get_unaligned_le32(iterator->_arg) &
                                        (1 << IEEE80211_RADIOTAP_EXT)) {
                        iterator->_arg += sizeof(uint32_t);
index a6c03ab14a0d47ea9a7f676dec76301804ab809b..c8e225947adb2601d31dbb0f4a1aa5a4392d8bc5 100644 (file)
@@ -932,4 +932,19 @@ static inline int rdev_channel_switch(struct cfg80211_registered_device *rdev,
        return ret;
 }
 
+static inline int rdev_set_qos_map(struct cfg80211_registered_device *rdev,
+                                  struct net_device *dev,
+                                  struct cfg80211_qos_map *qos_map)
+{
+       int ret = -EOPNOTSUPP;
+
+       if (rdev->ops->set_qos_map) {
+               trace_rdev_set_qos_map(&rdev->wiphy, dev, qos_map);
+               ret = rdev->ops->set_qos_map(&rdev->wiphy, dev, qos_map);
+               trace_rdev_return_int(&rdev->wiphy, ret);
+       }
+
+       return ret;
+}
+
 #endif /* __CFG80211_RDEV_OPS */
index 65f800890d70d857c9b42d379caad887f5a98c74..5d6e7bb2fc89a2fc1e4a1034f44beadb76b53e5a 100644 (file)
@@ -632,6 +632,16 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
        }
 #endif
 
+       if (!bss && (status == WLAN_STATUS_SUCCESS)) {
+               WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
+               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
+                                      wdev->ssid, wdev->ssid_len,
+                                      WLAN_CAPABILITY_ESS,
+                                      WLAN_CAPABILITY_ESS);
+               if (bss)
+                       cfg80211_hold_bss(bss_from_pub(bss));
+       }
+
        if (wdev->current_bss) {
                cfg80211_unhold_bss(wdev->current_bss);
                cfg80211_put_bss(wdev->wiphy, &wdev->current_bss->pub);
@@ -649,16 +659,8 @@ void __cfg80211_connect_result(struct net_device *dev, const u8 *bssid,
                return;
        }
 
-       if (!bss) {
-               WARN_ON_ONCE(!wiphy_to_dev(wdev->wiphy)->ops->connect);
-               bss = cfg80211_get_bss(wdev->wiphy, NULL, bssid,
-                                      wdev->ssid, wdev->ssid_len,
-                                      WLAN_CAPABILITY_ESS,
-                                      WLAN_CAPABILITY_ESS);
-               if (WARN_ON(!bss))
-                       return;
-               cfg80211_hold_bss(bss_from_pub(bss));
-       }
+       if (WARN_ON(!bss))
+               return;
 
        wdev->current_bss = bss_from_pub(bss);
 
@@ -870,6 +872,8 @@ void __cfg80211_disconnected(struct net_device *dev, const u8 *ie,
                for (i = 0; i < 6; i++)
                        rdev_del_key(rdev, dev, i, false, NULL);
 
+       rdev_set_qos_map(rdev, dev, NULL);
+
 #ifdef CONFIG_CFG80211_WEXT
        memset(&wrqu, 0, sizeof(wrqu));
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
index f7aa7a72d9bc928aa7d24153d709e13634773b06..fbcc23edee5474459950b8566ecffd541ad4ed7d 100644 (file)
 
 #define BOOL_TO_STR(bo) (bo) ? "true" : "false"
 
+#define QOS_MAP_ENTRY __field(u8, num_des)                     \
+                     __array(u8, dscp_exception,               \
+                             2 * IEEE80211_QOS_MAP_MAX_EX)     \
+                     __array(u8, up, IEEE80211_QOS_MAP_LEN_MIN)
+#define QOS_MAP_ASSIGN(qos_map)                                        \
+       do {                                                    \
+               if ((qos_map)) {                                \
+                       __entry->num_des = (qos_map)->num_des;  \
+                       memcpy(__entry->dscp_exception,         \
+                              &(qos_map)->dscp_exception,      \
+                              2 * IEEE80211_QOS_MAP_MAX_EX);   \
+                       memcpy(__entry->up, &(qos_map)->up,     \
+                              IEEE80211_QOS_MAP_LEN_MIN);      \
+               } else {                                        \
+                       __entry->num_des = 0;                   \
+                       memset(__entry->dscp_exception, 0,      \
+                              2 * IEEE80211_QOS_MAP_MAX_EX);   \
+                       memset(__entry->up, 0,                  \
+                              IEEE80211_QOS_MAP_LEN_MIN);      \
+               }                                               \
+       } while (0)
+
 /*************************************************************
  *                     rdev->ops traces                     *
  *************************************************************/
@@ -1875,6 +1897,24 @@ TRACE_EVENT(rdev_channel_switch,
                  __entry->counter_offset_presp)
 );
 
+TRACE_EVENT(rdev_set_qos_map,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev,
+                struct cfg80211_qos_map *qos_map),
+       TP_ARGS(wiphy, netdev, qos_map),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               QOS_MAP_ENTRY
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               QOS_MAP_ASSIGN(qos_map);
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", num_des: %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->num_des)
+);
+
 /*************************************************************
  *          cfg80211 exported functions traces              *
  *************************************************************/
index 935dea9485da01f7a0fb82cacc6e187058ff1ce0..5618888853b24ffdac2853509a1528f70ac1661b 100644 (file)
@@ -689,7 +689,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
 EXPORT_SYMBOL(ieee80211_amsdu_to_8023s);
 
 /* Given a data frame determine the 802.1p/1d tag to use. */
-unsigned int cfg80211_classify8021d(struct sk_buff *skb)
+unsigned int cfg80211_classify8021d(struct sk_buff *skb,
+                                   struct cfg80211_qos_map *qos_map)
 {
        unsigned int dscp;
        unsigned char vlan_priority;
@@ -720,6 +721,21 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb)
                return 0;
        }
 
+       if (qos_map) {
+               unsigned int i, tmp_dscp = dscp >> 2;
+
+               for (i = 0; i < qos_map->num_des; i++) {
+                       if (tmp_dscp == qos_map->dscp_exception[i].dscp)
+                               return qos_map->dscp_exception[i].up;
+               }
+
+               for (i = 0; i < 8; i++) {
+                       if (tmp_dscp >= qos_map->up[i].low &&
+                           tmp_dscp <= qos_map->up[i].high)
+                               return i;
+               }
+       }
+
        return dscp >> 5;
 }
 EXPORT_SYMBOL(cfg80211_classify8021d);
@@ -863,6 +879,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 
                dev->ieee80211_ptr->use_4addr = false;
                dev->ieee80211_ptr->mesh_id_up_len = 0;
+               rdev_set_qos_map(rdev, dev, NULL);
 
                switch (otype) {
                case NL80211_IFTYPE_AP:
This page took 0.705523 seconds and 5 git commands to generate.