]> Pileus Git - ~andy/linux/commitdiff
Merge branch 'master' of git://git.infradead.org/users/linville/wireless-next into...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 30 Sep 2011 18:52:16 +0000 (14:52 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 30 Sep 2011 18:52:29 +0000 (14:52 -0400)
Conflicts:
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/wl12xx/main.c

186 files changed:
MAINTAINERS
drivers/bcma/driver_chipcommon_pmu.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath9k/ani.c
drivers/net/wireless/ath/ath9k/ani.h
drivers/net/wireless/ath/ath9k/ar5008_phy.c
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9003_2p2_initvals.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom_4k.c
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw-ops.h
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/mac.c
drivers/net/wireless/ath/ath9k/mac.h
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_lcn.c
drivers/net/wireless/b43/phy_lcn.h
drivers/net/wireless/b43/tables_phy_lcn.c
drivers/net/wireless/iwlegacy/iwl-core.c
drivers/net/wireless/iwlegacy/iwl-core.h
drivers/net/wireless/iwlegacy/iwl-hcmd.c
drivers/net/wireless/iwlegacy/iwl-tx.c
drivers/net/wireless/iwlegacy/iwl3945-base.c
drivers/net/wireless/iwlegacy/iwl4965-base.c
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000-hw.h
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-calib.c
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c [deleted file]
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-tt.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-bus.h
drivers/net/wireless/iwlwifi/iwl-cfg.h [moved from drivers/net/wireless/iwlwifi/iwl-pci.h with 97% similarity]
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-debugfs.c
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/iwlwifi/iwl-led.c
drivers/net/wireless/iwlwifi/iwl-pci.c
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-shared.h
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h [moved from drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h with 94% similarity]
drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c [moved from drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c with 97% similarity]
drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c [moved from drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c with 94% similarity]
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c [new file with mode: 0644]
drivers/net/wireless/iwlwifi/iwl-trans.c
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/scan.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.h
drivers/net/wireless/rtlwifi/rtl8192cu/mac.h
drivers/net/wireless/rtlwifi/rtl8192de/sw.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.h
drivers/net/wireless/rtlwifi/rtl8192se/def.h
drivers/net/wireless/rtlwifi/rtl8192se/sw.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/usb.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/wl12xx/Kconfig
drivers/net/wireless/wl12xx/Makefile
drivers/net/wireless/wl12xx/acx.c
drivers/net/wireless/wl12xx/acx.h
drivers/net/wireless/wl12xx/cmd.c
drivers/net/wireless/wl12xx/cmd.h
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/debugfs.c
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/ps.c
drivers/net/wireless/wl12xx/rx.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/sdio_test.c
drivers/net/wireless/wl12xx/tx.c
drivers/net/wireless/wl12xx/tx.h
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/nfcwilink.c [new file with mode: 0644]
drivers/nfc/pn533.c
drivers/staging/brcm80211/brcmsmac/mac80211_if.c
drivers/staging/winbond/wbusb.c
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/ieee80211.h
include/linux/nfc.h
include/linux/nl80211.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/mgmt.h
include/net/bluetooth/smp.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/nci.h [new file with mode: 0644]
include/net/nfc/nci_core.h [new file with mode: 0644]
include/net/nfc/nfc.h [moved from include/net/nfc.h with 97% similarity]
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/mgmt.c
net/bluetooth/smp.c
net/mac80211/cfg.c
net/mac80211/debugfs.c
net/mac80211/debugfs_netdev.c
net/mac80211/driver-ops.h
net/mac80211/driver-trace.h
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/mesh_plink.c
net/mac80211/mlme.c
net/mac80211/rate.c
net/mac80211/scan.c
net/mac80211/util.c
net/mac80211/work.c
net/nfc/Kconfig
net/nfc/Makefile
net/nfc/core.c
net/nfc/nci/Kconfig [new file with mode: 0644]
net/nfc/nci/Makefile [new file with mode: 0644]
net/nfc/nci/core.c [new file with mode: 0644]
net/nfc/nci/data.c [new file with mode: 0644]
net/nfc/nci/lib.c [new file with mode: 0644]
net/nfc/nci/ntf.c [new file with mode: 0644]
net/nfc/nci/rsp.c [new file with mode: 0644]
net/nfc/netlink.c
net/nfc/nfc.h
net/rfkill/core.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/scan.c
net/wireless/sme.c
net/wireless/util.c

index 5faf685ee6c250a05c47e607d1c3d8a9a4a8ddd0..65ca7eae62769e1443b503a6da9c966557a9ea2e 100644 (file)
@@ -3426,7 +3426,7 @@ M:        Wey-Yi Guy <wey-yi.w.guy@intel.com>
 M:     Intel Linux Wireless <ilw@linux.intel.com>
 L:     linux-wireless@vger.kernel.org
 W:     http://intellinuxwireless.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-2.6.git
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
 S:     Supported
 F:     drivers/net/wireless/iwlwifi/
 
@@ -4528,7 +4528,7 @@ L:        linux-wireless@vger.kernel.org
 S:     Maintained
 F:     net/nfc/
 F:     include/linux/nfc.h
-F:     include/net/nfc.h
+F:     include/net/nfc/
 F:     drivers/nfc/
 
 NFS, SUNRPC, AND LOCKD CLIENTS
index 4bc10aa57bd425cf61cb0cb65f1e8f064b169e38..2968d809d49f8357cae15ef644cdd5a81cbe0a5a 100644 (file)
@@ -18,20 +18,40 @@ static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
        return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
 }
 
-static void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
-                                       u32 offset, u32 mask, u32 set)
+void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
 {
-       u32 value;
+       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+       bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
 
-       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
+void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+                            u32 set)
+{
+       bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
+       bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
+
+void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+                                u32 offset, u32 mask, u32 set)
+{
        bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
        bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
-       value = bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
-       value &= mask;
-       value |= set;
-       bcma_cc_write32(cc, BCMA_CC_CHIPCTL_DATA, value);
-       bcma_cc_read32(cc, BCMA_CC_CHIPCTL_DATA);
+       bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
+}
+EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
+
+void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
+                               u32 set)
+{
+       bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
+       bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
+       bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
 }
+EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
 
 static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
 {
index 43ebc44fc82cdc24d0cff2cb7a3af4cd24267f6f..3b752d9fb3cd7bd9f72264cdf8f003cecebacaaf 100644 (file)
@@ -1249,7 +1249,8 @@ static int adm8211_hw_reset(struct ieee80211_hw *dev)
        return 0;
 }
 
-static u64 adm8211_get_tsft(struct ieee80211_hw *dev)
+static u64 adm8211_get_tsft(struct ieee80211_hw *dev,
+                           struct ieee80211_vif *vif)
 {
        struct adm8211_priv *priv = dev->priv;
        u32 tsftl;
index 0560234ec3f648603e5159dc1f2aa3d9e6425df0..bba4f6fcf7e2c3641db9fe61cd9c5d05e8fcd09a 100644 (file)
@@ -602,7 +602,7 @@ ath5k_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
 
 static u64
-ath5k_get_tsf(struct ieee80211_hw *hw)
+ath5k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = hw->priv;
 
@@ -611,7 +611,7 @@ ath5k_get_tsf(struct ieee80211_hw *hw)
 
 
 static void
-ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+ath5k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif, u64 tsf)
 {
        struct ath5k_hw *ah = hw->priv;
 
@@ -620,7 +620,7 @@ ath5k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 
 static void
-ath5k_reset_tsf(struct ieee80211_hw *hw)
+ath5k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath5k_hw *ah = hw->priv;
 
index d969a11e342584f71be1abe9e9cceacd9d4ae026..01240d63896ed27d08c7948bc1b49e6f2e658370 100644 (file)
@@ -273,7 +273,8 @@ static void ath9k_hw_set_ofdm_nil(struct ath_hw *ah, u8 immunityLevel)
                immunityLevel, aniState->noiseFloor,
                aniState->rssiThrLow, aniState->rssiThrHigh);
 
-       aniState->ofdmNoiseImmunityLevel = immunityLevel;
+       if (aniState->update_ani)
+               aniState->ofdmNoiseImmunityLevel = immunityLevel;
 
        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -346,7 +347,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel)
            immunityLevel > ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI)
                immunityLevel = ATH9K_ANI_CCK_MAX_LEVEL_LOW_RSSI;
 
-       aniState->cckNoiseImmunityLevel = immunityLevel;
+       if (aniState->update_ani)
+               aniState->cckNoiseImmunityLevel = immunityLevel;
 
        entry_ofdm = &ofdm_level_table[aniState->ofdmNoiseImmunityLevel];
        entry_cck = &cck_level_table[aniState->cckNoiseImmunityLevel];
@@ -593,6 +595,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                                aniState->ofdmNoiseImmunityLevel,
                                aniState->cckNoiseImmunityLevel);
 
+                       aniState->update_ani = false;
                        ath9k_hw_set_ofdm_nil(ah, ATH9K_ANI_OFDM_DEF_LEVEL);
                        ath9k_hw_set_cck_nil(ah, ATH9K_ANI_CCK_DEF_LEVEL);
                }
@@ -609,6 +612,7 @@ void ath9k_ani_reset(struct ath_hw *ah, bool is_scanning)
                        aniState->ofdmNoiseImmunityLevel,
                        aniState->cckNoiseImmunityLevel);
 
+                       aniState->update_ani = true;
                        ath9k_hw_set_ofdm_nil(ah,
                                              aniState->ofdmNoiseImmunityLevel);
                        ath9k_hw_set_cck_nil(ah,
@@ -892,6 +896,8 @@ void ath9k_hw_ani_init(struct ath_hw *ah)
                ani->ofdmWeakSigDetectOff =
                        !ATH9K_ANI_USE_OFDM_WEAK_SIG;
                ani->cckNoiseImmunityLevel = ATH9K_ANI_CCK_DEF_LEVEL;
+               ani->ofdmNoiseImmunityLevel = ATH9K_ANI_OFDM_DEF_LEVEL;
+               ani->update_ani = false;
        }
 
        /*
index a547005572e7f4a7edcccf9957ab9b6aac53cabf..83029d6c7b2258ae1e59ca8a2483fbe85a4f26a8 100644 (file)
@@ -122,6 +122,7 @@ struct ar5416AniState {
        u8 firstepLevel;
        u8 ofdmWeakSigDetectOff;
        u8 cckWeakSigThreshold;
+       bool update_ani;
        u32 listenTime;
        int32_t rssiThrLow;
        int32_t rssiThrHigh;
index fac2c6da6ca4d14986120e0c8079d27ac584fda1..0a749c8fa634830cbb90239e13ebc7ed8a343685 100644 (file)
@@ -704,8 +704,10 @@ static void ar5008_hw_override_ini(struct ath_hw *ah,
                REG_WRITE(ah, AR_PCU_MISC_MODE2, val);
        }
 
-       if (!AR_SREV_5416_20_OR_LATER(ah) ||
-           AR_SREV_9280_20_OR_LATER(ah))
+       REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+                   AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
+
+       if (AR_SREV_9280_20_OR_LATER(ah))
                return;
        /*
         * Disable BB clock gating
@@ -802,7 +804,8 @@ static int ar5008_hw_process_ini(struct ath_hw *ah,
 
        /* Write ADDAC shifts */
        REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
-       ah->eep_ops->set_addac(ah, chan);
+       if (ah->eep_ops->set_addac)
+               ah->eep_ops->set_addac(ah, chan);
 
        if (AR_SREV_5416_22_OR_LATER(ah)) {
                REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
@@ -1007,24 +1010,6 @@ static void ar5008_restore_chainmask(struct ath_hw *ah)
        }
 }
 
-static void ar5008_set_diversity(struct ath_hw *ah, bool value)
-{
-       u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
-       if (value)
-               v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-       else
-               v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-       REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-}
-
-static u32 ar9100_hw_compute_pll_control(struct ath_hw *ah,
-                                        struct ath9k_channel *chan)
-{
-       if (chan && IS_CHAN_5GHZ(chan))
-               return 0x1450;
-       return 0x1458;
-}
-
 static u32 ar9160_hw_compute_pll_control(struct ath_hw *ah,
                                         struct ath9k_channel *chan)
 {
@@ -1654,7 +1639,6 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
        priv_ops->rfbus_req = ar5008_hw_rfbus_req;
        priv_ops->rfbus_done = ar5008_hw_rfbus_done;
        priv_ops->restore_chainmask = ar5008_restore_chainmask;
-       priv_ops->set_diversity = ar5008_set_diversity;
        priv_ops->do_getnf = ar5008_hw_do_getnf;
        priv_ops->set_radar_params = ar5008_hw_set_radar_params;
 
@@ -1664,9 +1648,7 @@ void ar5008_hw_attach_phy_ops(struct ath_hw *ah)
        } else
                priv_ops->ani_control = ar5008_hw_ani_control_old;
 
-       if (AR_SREV_9100(ah))
-               priv_ops->compute_pll_control = ar9100_hw_compute_pll_control;
-       else if (AR_SREV_9160_10_OR_LATER(ah))
+       if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah))
                priv_ops->compute_pll_control = ar9160_hw_compute_pll_control;
        else
                priv_ops->compute_pll_control = ar5008_hw_compute_pll_control;
index 2d394af82171fe4031e1c1797fbb7db158879e8c..e0ab0657cc3a8808379ae0cc93e32e0863e13305 100644 (file)
@@ -869,6 +869,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
        ar9002_hw_pa_cal(ah, true);
 
        /* Do NF Calibration after DC offset and other calibrations */
+       ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
        if (ah->caldata)
index f2c6f2316a3b5edad25f18604fe1200216598b19..08e9341f636825097f5f4bcc1a0ed29209ef8fc4 100644 (file)
@@ -1514,7 +1514,7 @@ static const u32 ar9300_2p2_mac_core[][2] = {
        {0x00008258, 0x00000000},
        {0x0000825c, 0x40000000},
        {0x00008260, 0x00080922},
-       {0x00008264, 0x9bc00010},
+       {0x00008264, 0x9d400010},
        {0x00008268, 0xffffffff},
        {0x0000826c, 0x0000ffff},
        {0x00008270, 0x00000000},
index 3319a676c0fbc25062a7acd5e6da7ecea5100fb3..e4b1a83008547cbe053b18af6f2119bd95486e58 100644 (file)
@@ -652,8 +652,9 @@ static void ar9003_hw_detect_outlier(int *mp_coeff, int nmeasurement,
                        outlier_idx = max_idx;
                else
                        outlier_idx = min_idx;
+
+               mp_coeff[outlier_idx] = mp_avg;
        }
-       mp_coeff[outlier_idx] = mp_avg;
 }
 
 static void ar9003_hw_tx_iqcal_load_avg_2_passes(struct ath_hw *ah,
@@ -884,6 +885,7 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
        if (txiqcal_done)
                ar9003_hw_tx_iq_cal_post_proc(ah);
 
+       ath9k_hw_loadnf(ah, chan);
        ath9k_hw_start_nfcal(ah, true);
 
        /* Initialize list pointers */
index 4956d09cb58904a5458ae4aa5852ddb1b1d63ded..7db6e8647a01ffc2bfb952ba34eedb5bb0008f5f 100644 (file)
@@ -595,6 +595,9 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
        val = REG_READ(ah, AR_PCU_MISC_MODE2) & (~AR_ADHOC_MCAST_KEYID_ENABLE);
        REG_WRITE(ah, AR_PCU_MISC_MODE2,
                  val | AR_AGG_WEP_ENABLE_FIX | AR_AGG_WEP_ENABLE);
+
+       REG_SET_BIT(ah, AR_PHY_CCK_DETECT,
+                   AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV);
 }
 
 static void ar9003_hw_prog_ini(struct ath_hw *ah,
@@ -795,16 +798,6 @@ static void ar9003_hw_rfbus_done(struct ath_hw *ah)
        REG_WRITE(ah, AR_PHY_RFBUS_REQ, 0);
 }
 
-static void ar9003_hw_set_diversity(struct ath_hw *ah, bool value)
-{
-       u32 v = REG_READ(ah, AR_PHY_CCK_DETECT);
-       if (value)
-               v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-       else
-               v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV;
-       REG_WRITE(ah, AR_PHY_CCK_DETECT, v);
-}
-
 static bool ar9003_hw_ani_control(struct ath_hw *ah,
                                  enum ath9k_ani_cmd cmd, int param)
 {
@@ -1287,7 +1280,6 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
        priv_ops->set_delta_slope = ar9003_hw_set_delta_slope;
        priv_ops->rfbus_req = ar9003_hw_rfbus_req;
        priv_ops->rfbus_done = ar9003_hw_rfbus_done;
-       priv_ops->set_diversity = ar9003_hw_set_diversity;
        priv_ops->ani_control = ar9003_hw_ani_control;
        priv_ops->do_getnf = ar9003_hw_do_getnf;
        priv_ops->ani_cache_ini_regs = ar9003_hw_ani_cache_ini_regs;
index 179da20992703fc99af3840d6e51349de5c5c5a3..a5329c98f9ea53858772503669ba4c50e9e4cd6a 100644 (file)
@@ -876,6 +876,15 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
        TX_SAMP_DBG(rssi) = ts->ts_rssi;
        TX_SAMP_DBG(tid) = ts->tid;
        TX_SAMP_DBG(qid) = ts->qid;
+
+       if (ts->ts_flags & ATH9K_TX_BA) {
+               TX_SAMP_DBG(ba_low) = ts->ba_low;
+               TX_SAMP_DBG(ba_high) = ts->ba_high;
+       } else {
+               TX_SAMP_DBG(ba_low) = 0;
+               TX_SAMP_DBG(ba_high) = 0;
+       }
+
        sc->debug.tsidx = (sc->debug.tsidx + 1) % ATH_DBG_MAX_SAMPLES;
        spin_unlock(&sc->debug.samp_lock);
 
@@ -1516,14 +1525,15 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
        len += snprintf(buf + len, size - len, "Tx status Dump :\n");
        len += snprintf(buf + len, size - len,
                        "Sample rssi:- ctl0 ctl1 ctl2 ext0 ext1 ext2 comb "
-                       "isok rts_fail data_fail rate tid qid tx_before(ms)\n");
+                       "isok rts_fail data_fail rate tid qid "
+                                       "ba_low  ba_high tx_before(ms)\n");
        for (sampidx = 0; sampidx < ATH_DBG_MAX_SAMPLES; sampidx++) {
                for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
                        if (!ATH_SAMP_DBG(ts[i].jiffies))
                                continue;
-                       len += snprintf(buf + len, size - len, "%4d \t"
-                               "%8d %4d %4d %4d %4d %4d %4d %4d %4d "
-                               "%4d %4d %2d %2d %d\n",
+                       len += snprintf(buf + len, size - len, "%-14d"
+                               "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-4d %-8d "
+                               "%-9d %-4d %-3d %-3d %08x %08x %-11d\n",
                                sampidx,
                                ATH_SAMP_DBG(ts[i].rssi_ctl0),
                                ATH_SAMP_DBG(ts[i].rssi_ctl1),
@@ -1538,6 +1548,8 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
                                ATH_SAMP_DBG(ts[i].rateindex),
                                ATH_SAMP_DBG(ts[i].tid),
                                ATH_SAMP_DBG(ts[i].qid),
+                               ATH_SAMP_DBG(ts[i].ba_low),
+                               ATH_SAMP_DBG(ts[i].ba_high),
                                jiffies_to_msecs(jiffies -
                                        ATH_SAMP_DBG(ts[i].jiffies)));
                }
@@ -1550,8 +1562,8 @@ static int open_file_bb_mac_samps(struct inode *inode, struct file *file)
                for (i = 0; i < ATH_DBG_MAX_SAMPLES; i++) {
                        if (!ATH_SAMP_DBG(rs[i].jiffies))
                                continue;
-                       len += snprintf(buf + len, size - len, "%4d \t"
-                               "%8d %4d %4d %4d %4d %4d %4d %s %4d %02x %d\n",
+                       len += snprintf(buf + len, size - len, "%-14d"
+                               "%-4d %-4d %-4d %-4d %-4d %-4d %-4d %-9s %-2d %02x %-13d\n",
                                sampidx,
                                ATH_SAMP_DBG(rs[i].rssi_ctl0),
                                ATH_SAMP_DBG(rs[i].rssi_ctl1),
index 39f89bc9abcddfcf45ad6615425ddcafbf48f06b..b93e88bd8c5890aa3fbd111b4025cd121201332b 100644 (file)
@@ -196,6 +196,8 @@ struct ath_dbg_bb_mac_samp {
                u8 rateindex;
                u8 qid;
                u8 tid;
+               u32 ba_low;
+               u32 ba_high;
        } ts[ATH_DBG_MAX_SAMPLES];
        struct {
                u64 jiffies;
index e61404dda8c59b36be9766dada75b3c16ae3560e..e46f751ab50818d1c30d31a6f271c67409192eef 100644 (file)
@@ -456,12 +456,7 @@ void ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hw *ah,
                pPdGainBoundaries[i] =
                        min((u16)MAX_RATE_POWER, pPdGainBoundaries[i]);
 
-               if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
-                       minDelta = pPdGainBoundaries[0] - 23;
-                       pPdGainBoundaries[0] = 23;
-               } else {
-                       minDelta = 0;
-               }
+               minDelta = 0;
 
                if (i == 0) {
                        if (AR_SREV_9280_20_OR_LATER(ah))
index ea658e794cbdf70f8dc8c1f016afb96a59f5d106..303560e49ac88f399f4a25f197bc7609d9e7065e 100644 (file)
@@ -405,12 +405,7 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
        REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
 
        for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
-               if (AR_SREV_5416_20_OR_LATER(ah) &&
-                   (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
-                   (i != 0)) {
-                       regChainOffset = (i == 1) ? 0x2000 : 0x1000;
-               } else
-                       regChainOffset = i * 0x1000;
+               regChainOffset = i * 0x1000;
 
                if (pEepData->baseEepHeader.txMask & (1 << i)) {
                        pRawDataset = pEepData->calPierData2G[i];
@@ -423,19 +418,17 @@ static void ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
 
                        ENABLE_REGWRITE_BUFFER(ah);
 
-                       if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
-                               REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
-                                         SM(pdGainOverlap_t2,
-                                            AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
-                                         | SM(gainBoundaries[0],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
-                                         | SM(gainBoundaries[1],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
-                                         | SM(gainBoundaries[2],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
-                                         | SM(gainBoundaries[3],
-                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
-                       }
+                       REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
+                                 SM(pdGainOverlap_t2,
+                                    AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
+                                 | SM(gainBoundaries[0],
+                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
+                                 | SM(gainBoundaries[1],
+                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
+                                 | SM(gainBoundaries[2],
+                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
+                                 | SM(gainBoundaries[3],
+                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
 
                        regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
                        for (j = 0; j < 32; j++) {
@@ -715,10 +708,8 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
        if (test)
            return;
 
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               for (i = 0; i < Ar5416RateSize; i++)
-                       ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
-       }
+       for (i = 0; i < Ar5416RateSize; i++)
+               ratesArray[i] -= AR5416_PWR_TABLE_OFFSET_DB * 2;
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -788,28 +779,6 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
        REGWRITE_BUFFER_FLUSH(ah);
 }
 
-static void ath9k_hw_4k_set_addac(struct ath_hw *ah,
-                                 struct ath9k_channel *chan)
-{
-       struct modal_eep_4k_header *pModal;
-       struct ar5416_eeprom_4k *eep = &ah->eeprom.map4k;
-       u8 biaslevel;
-
-       if (ah->hw_version.macVersion != AR_SREV_VERSION_9160)
-               return;
-
-       if (ah->eep_ops->get_eeprom_rev(ah) < AR5416_EEP_MINOR_VER_7)
-               return;
-
-       pModal = &eep->modalHeader;
-
-       if (pModal->xpaBiasLvl != 0xff) {
-               biaslevel = pModal->xpaBiasLvl;
-               INI_RA(&ah->iniAddac, 7, 1) =
-                 (INI_RA(&ah->iniAddac, 7, 1) & (~0x18)) | biaslevel << 3;
-       }
-}
-
 static void ath9k_hw_4k_set_gain(struct ath_hw *ah,
                                 struct modal_eep_4k_header *pModal,
                                 struct ar5416_eeprom_4k *eep,
@@ -877,6 +846,7 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
        u8 txRxAttenLocal;
        u8 ob[5], db1[5], db2[5];
        u8 ant_div_control1, ant_div_control2;
+       u8 bb_desired_scale;
        u32 regVal;
 
        pModal = &eep->modalHeader;
@@ -1096,30 +1066,29 @@ static void ath9k_hw_4k_set_board_values(struct ath_hw *ah,
                                      AR_PHY_SETTLING_SWITCH,
                                      pModal->swSettleHt40);
        }
-       if (AR_SREV_9271(ah) || AR_SREV_9285(ah)) {
-               u8 bb_desired_scale = (pModal->bb_scale_smrt_antenna &
-                               EEP_4K_BB_DESIRED_SCALE_MASK);
-               if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
-                       u32 pwrctrl, mask, clr;
-
-                       mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
-                       pwrctrl = mask * bb_desired_scale;
-                       clr = mask * 0x1f;
-                       REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
-                       REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
-                       REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
-
-                       mask = BIT(0)|BIT(5)|BIT(15);
-                       pwrctrl = mask * bb_desired_scale;
-                       clr = mask * 0x1f;
-                       REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
-
-                       mask = BIT(0)|BIT(5);
-                       pwrctrl = mask * bb_desired_scale;
-                       clr = mask * 0x1f;
-                       REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
-                       REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
-               }
+
+       bb_desired_scale = (pModal->bb_scale_smrt_antenna &
+                       EEP_4K_BB_DESIRED_SCALE_MASK);
+       if ((pBase->txGainType == 0) && (bb_desired_scale != 0)) {
+               u32 pwrctrl, mask, clr;
+
+               mask = BIT(0)|BIT(5)|BIT(10)|BIT(15)|BIT(20)|BIT(25);
+               pwrctrl = mask * bb_desired_scale;
+               clr = mask * 0x1f;
+               REG_RMW(ah, AR_PHY_TX_PWRCTRL8, pwrctrl, clr);
+               REG_RMW(ah, AR_PHY_TX_PWRCTRL10, pwrctrl, clr);
+               REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL12, pwrctrl, clr);
+
+               mask = BIT(0)|BIT(5)|BIT(15);
+               pwrctrl = mask * bb_desired_scale;
+               clr = mask * 0x1f;
+               REG_RMW(ah, AR_PHY_TX_PWRCTRL9, pwrctrl, clr);
+
+               mask = BIT(0)|BIT(5);
+               pwrctrl = mask * bb_desired_scale;
+               clr = mask * 0x1f;
+               REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL11, pwrctrl, clr);
+               REG_RMW(ah, AR_PHY_CH0_TX_PWRCTRL13, pwrctrl, clr);
        }
 }
 
@@ -1161,7 +1130,6 @@ const struct eeprom_ops eep_4k_ops = {
        .get_eeprom_ver         = ath9k_hw_4k_get_eeprom_ver,
        .get_eeprom_rev         = ath9k_hw_4k_get_eeprom_rev,
        .set_board_values       = ath9k_hw_4k_set_board_values,
-       .set_addac              = ath9k_hw_4k_set_addac,
        .set_txpower            = ath9k_hw_4k_set_txpower,
        .get_spur_channel       = ath9k_hw_4k_get_spur_channel
 };
index 21f180db23810dddf52ffd2eed2364d75e3cb82d..6698b722b604e8a4c9b5f1c29b50ec8a6584c7a1 100644 (file)
@@ -851,10 +851,8 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
        if (test)
                return;
 
-       if (AR_SREV_9280_20_OR_LATER(ah)) {
-               for (i = 0; i < Ar5416RateSize; i++)
-                       ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
-       }
+       for (i = 0; i < Ar5416RateSize; i++)
+               ratesArray[i] -= AR9287_PWR_TABLE_OFFSET_DB * 2;
 
        ENABLE_REGWRITE_BUFFER(ah);
 
@@ -944,11 +942,6 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
        REGWRITE_BUFFER_FLUSH(ah);
 }
 
-static void ath9k_hw_ar9287_set_addac(struct ath_hw *ah,
-                                     struct ath9k_channel *chan)
-{
-}
-
 static void ath9k_hw_ar9287_set_board_values(struct ath_hw *ah,
                                             struct ath9k_channel *chan)
 {
@@ -1100,7 +1093,6 @@ const struct eeprom_ops eep_ar9287_ops = {
        .get_eeprom_ver         = ath9k_hw_ar9287_get_eeprom_ver,
        .get_eeprom_rev         = ath9k_hw_ar9287_get_eeprom_rev,
        .set_board_values       = ath9k_hw_ar9287_set_board_values,
-       .set_addac              = ath9k_hw_ar9287_set_addac,
        .set_txpower            = ath9k_hw_ar9287_set_txpower,
        .get_spur_channel       = ath9k_hw_ar9287_get_spur_channel
 };
index e7e84be8beed32d2768d08888a7083427338997b..eda681fc7ba6d8bd00283bea564b263305d2a2aa 100644 (file)
@@ -547,8 +547,7 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
                                break;
                }
 
-               if (AR_SREV_5416_20_OR_LATER(ah) &&
-                   (ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
+               if ((ah->rxchainmask == 5 || ah->txchainmask == 5) && (i != 0))
                        regChainOffset = (i == 1) ? 0x2000 : 0x1000;
                else
                        regChainOffset = i * 0x1000;
@@ -565,9 +564,8 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
                          SM(pModal->iqCalQCh[i],
                             AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
 
-               if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah))
-                       ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
-                                             regChainOffset, i);
+               ath9k_hw_def_set_gain(ah, pModal, eep, txRxAttenLocal,
+                                     regChainOffset, i);
        }
 
        if (AR_SREV_9280_20_OR_LATER(ah)) {
@@ -893,8 +891,7 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
                      xpdGainValues[2]);
 
        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               if (AR_SREV_5416_20_OR_LATER(ah) &&
-                   (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
+               if ((ah->rxchainmask == 5 || ah->txchainmask == 5) &&
                    (i != 0)) {
                        regChainOffset = (i == 1) ? 0x2000 : 0x1000;
                } else
@@ -935,27 +932,24 @@ static void ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
 
                        ENABLE_REGWRITE_BUFFER(ah);
 
-                       if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
-                               if (OLC_FOR_AR9280_20_LATER) {
-                                       REG_WRITE(ah,
-                                               AR_PHY_TPCRG5 + regChainOffset,
-                                               SM(0x6,
-                                               AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
-                                               SM_PD_GAIN(1) | SM_PD_GAIN(2) |
-                                               SM_PD_GAIN(3) | SM_PD_GAIN(4));
-                               } else {
-                                       REG_WRITE(ah,
-                                               AR_PHY_TPCRG5 + regChainOffset,
-                                               SM(pdGainOverlap_t2,
-                                               AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
-                                               SM_PDGAIN_B(0, 1) |
-                                               SM_PDGAIN_B(1, 2) |
-                                               SM_PDGAIN_B(2, 3) |
-                                               SM_PDGAIN_B(3, 4));
-                               }
+                       if (OLC_FOR_AR9280_20_LATER) {
+                               REG_WRITE(ah,
+                                       AR_PHY_TPCRG5 + regChainOffset,
+                                       SM(0x6,
+                                       AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+                                       SM_PD_GAIN(1) | SM_PD_GAIN(2) |
+                                       SM_PD_GAIN(3) | SM_PD_GAIN(4));
+                       } else {
+                               REG_WRITE(ah,
+                                       AR_PHY_TPCRG5 + regChainOffset,
+                                       SM(pdGainOverlap_t2,
+                                       AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
+                                       SM_PDGAIN_B(0, 1) |
+                                       SM_PDGAIN_B(1, 2) |
+                                       SM_PDGAIN_B(2, 3) |
+                                       SM_PDGAIN_B(3, 4));
                        }
 
-
                        ath9k_adjust_pdadc_values(ah, pwr_table_offset,
                                                  diff, pdadcValues);
 
index 495fdf680a6c5269245ef49672c85a52b5bc057b..17dbbd9d2f53c13a2e4366c0dd4da497c83c6711 100644 (file)
@@ -1563,7 +1563,8 @@ static void ath9k_htc_bss_info_changed(struct ieee80211_hw *hw,
        mutex_unlock(&priv->mutex);
 }
 
-static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct ath9k_htc_priv *priv = hw->priv;
        u64 tsf;
@@ -1577,7 +1578,8 @@ static u64 ath9k_htc_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_htc_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
@@ -1588,7 +1590,8 @@ static void ath9k_htc_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        mutex_unlock(&priv->mutex);
 }
 
-static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_htc_reset_tsf(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif)
 {
        struct ath9k_htc_priv *priv = hw->priv;
 
index 41f4bf363d3d0dcaee749c055c6ee61111a6f030..e9782d164962ab450474a4a9475d8f9a757534b6 100644 (file)
@@ -181,11 +181,6 @@ static inline void ath9k_hw_restore_chainmask(struct ath_hw *ah)
        return ath9k_hw_private_ops(ah)->restore_chainmask(ah);
 }
 
-static inline void ath9k_hw_set_diversity(struct ath_hw *ah, bool value)
-{
-       return ath9k_hw_private_ops(ah)->set_diversity(ah, value);
-}
-
 static inline bool ath9k_hw_ani_control(struct ath_hw *ah,
                                        enum ath9k_ani_cmd cmd, int param)
 {
index bf38e2fc8f78f508ada85b5c48eb0c9345be40ac..24889f78a0536426d593ed0da3bd950e99f358f0 100644 (file)
@@ -584,7 +584,6 @@ struct ath_hw_private_ops {
        bool (*rfbus_req)(struct ath_hw *ah);
        void (*rfbus_done)(struct ath_hw *ah);
        void (*restore_chainmask)(struct ath_hw *ah);
-       void (*set_diversity)(struct ath_hw *ah, bool value);
        u32 (*compute_pll_control)(struct ath_hw *ah,
                                   struct ath9k_channel *chan);
        bool (*ani_control)(struct ath_hw *ah, enum ath9k_ani_cmd cmd,
index 9b34c4bab9372621dba1b82d4eb340b80b5e1e71..39514de044efea39f966e2a6d111600e8fb3344d 100644 (file)
@@ -506,7 +506,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
                sc->sc_flags |= SC_OP_RXAGGR;
        }
 
-       ath9k_hw_set_diversity(sc->sc_ah, true);
        sc->rx.defant = ath9k_hw_getdefantenna(sc->sc_ah);
 
        memcpy(common->bssidmask, ath_bcast_mac, ETH_ALEN);
index 786587ac40a7d221eee633538f22bf3198a6c61e..22f23eafe8bac12f132c501eb43674ef245cab02 100644 (file)
@@ -584,7 +584,7 @@ int ath9k_hw_rxprocdesc(struct ath_hw *ah, struct ath_desc *ds,
        else
                rs->rs_keyix = ATH9K_RXKEYIX_INVALID;
 
-       rs->rs_rate = RXSTATUS_RATE(ah, (&ads));
+       rs->rs_rate = MS(ads.ds_rxstatus0, AR_RxRate);
        rs->rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0;
 
        rs->rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0;
index ac5a1d265d3950889b36a48377a8ca730b9b2c50..91c96546c0cde73c395646819e552a65272bcab6 100644 (file)
 #ifndef MAC_H
 #define MAC_H
 
-#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ?         \
-                               MS(ads->ds_rxstatus0, AR_RxRate) :      \
-                               (ads->ds_rxstatus3 >> 2) & 0xFF)
-
 #define set11nTries(_series, _index) \
        (SM((_series)[_index].Tries, AR_XmitDataTries##_index))
 
index a16f53994a7e4987612d4adc0b2ae59a0b5b79ac..edaa7843bf4c7767f275e7ce1a7553f600cb7038 100644 (file)
@@ -133,7 +133,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
        ath_hw_cycle_counters_update(common);
        spin_unlock(&common->cc_lock);
 
-       ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_NETWORK_SLEEP);
+       ath9k_hw_setpower(sc->sc_ah, mode);
 
  unlock:
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
@@ -2021,6 +2021,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
                /* Stop ANI */
                sc->sc_flags &= ~SC_OP_ANI_RUN;
                del_timer_sync(&common->ani.timer);
+               memset(&sc->caldata, 0, sizeof(sc->caldata));
        }
 }
 
@@ -2142,7 +2143,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
        ath9k_ps_restore(sc);
 }
 
-static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
+static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = hw->priv;
        u64 tsf;
@@ -2156,7 +2157,9 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void ath9k_set_tsf(struct ieee80211_hw *hw,
+                         struct ieee80211_vif *vif,
+                         u64 tsf)
 {
        struct ath_softc *sc = hw->priv;
 
@@ -2167,7 +2170,7 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        mutex_unlock(&sc->mutex);
 }
 
-static void ath9k_reset_tsf(struct ieee80211_hw *hw)
+static void ath9k_reset_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct ath_softc *sc = hw->priv;
 
index bcc0b222ec18b7a0091fc913b6269510e3f3d14c..49843500fe7cd5faafd5f809fcf5515b2e50b4ab 100644 (file)
@@ -205,14 +205,22 @@ static void ath_rx_remove_buffer(struct ath_softc *sc,
 
 static void ath_rx_edma_cleanup(struct ath_softc *sc)
 {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath_buf *bf;
 
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_LP);
        ath_rx_remove_buffer(sc, ATH9K_RX_QUEUE_HP);
 
        list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-               if (bf->bf_mpdu)
+               if (bf->bf_mpdu) {
+                       dma_unmap_single(sc->dev, bf->bf_buf_addr,
+                                       common->rx_bufsize,
+                                       DMA_BIDIRECTIONAL);
                        dev_kfree_skb_any(bf->bf_mpdu);
+                       bf->bf_buf_addr = 0;
+                       bf->bf_mpdu = NULL;
+               }
        }
 
        INIT_LIST_HEAD(&sc->rx.rxbuf);
index 0846654b57efdf2c191f035c5c4fa8acd4cb961c..b76c49d9c503937fa2bf3a15e41e6405428a7657 100644 (file)
 #define AR_SREV_5416(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
         ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE))
-#define AR_SREV_5416_20_OR_LATER(_ah) \
-       (((AR_SREV_5416(_ah)) && \
-        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \
-        ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
 #define AR_SREV_5416_22_OR_LATER(_ah) \
        (((AR_SREV_5416(_ah)) && \
         ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \
index 2c6aefad3728f9dc7fe05a93b06862e9ba38704a..fa3dcfdf71743255771dd4c6f314687ff2ca0b0b 100644 (file)
@@ -262,6 +262,7 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
                             struct sk_buff *skb)
 {
        struct ath_frame_info *fi = get_frame_info(skb);
+       struct ath_buf *bf = fi->bf;
        struct ieee80211_hdr *hdr;
 
        TX_STAT_INC(txq->axq_qnum, a_retries);
@@ -270,6 +271,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
 
        hdr = (struct ieee80211_hdr *)skb->data;
        hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
+       dma_sync_single_for_device(sc->dev, bf->bf_buf_addr,
+               sizeof(*hdr), DMA_TO_DEVICE);
 }
 
 static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc)
@@ -1017,8 +1020,6 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
        while (bf) {
                struct sk_buff *skb = bf->bf_mpdu;
                struct ath_frame_info *fi = get_frame_info(skb);
-               struct ieee80211_hdr *hdr;
-               int padpos, padsize;
 
                info.type = get_hw_packet_type(skb);
                if (bf->bf_next)
@@ -1026,20 +1027,8 @@ static void ath_tx_fill_desc(struct ath_softc *sc, struct ath_buf *bf,
                else
                        info.link = 0;
 
-               if (ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-                       hdr = (struct ieee80211_hdr *)skb->data;
-                       padpos = ath9k_cmn_padpos(hdr->frame_control);
-                       padsize = padpos & 3;
-
-                       info.buf_addr[0] = bf->bf_buf_addr;
-                       info.buf_len[0] = padpos + padsize;
-                       info.buf_addr[1] = info.buf_addr[0] + padpos;
-                       info.buf_len[1] = skb->len - padpos;
-               } else {
-                       info.buf_addr[0] = bf->bf_buf_addr;
-                       info.buf_len[0] = skb->len;
-               }
-
+               info.buf_addr[0] = bf->bf_buf_addr;
+               info.buf_len[0] = skb->len;
                info.pkt_len = fi->framelen;
                info.keyix = fi->keyix;
                info.keytype = fi->keytype;
@@ -1892,17 +1881,16 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no);
        }
 
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
-               /* Add the padding after the header if this is not already done */
-               padpos = ath9k_cmn_padpos(hdr->frame_control);
-               padsize = padpos & 3;
-               if (padsize && skb->len > padpos) {
-                       if (skb_headroom(skb) < padsize)
-                               return -ENOMEM;
+       /* Add the padding after the header if this is not already done */
+       padpos = ath9k_cmn_padpos(hdr->frame_control);
+       padsize = padpos & 3;
+       if (padsize && skb->len > padpos) {
+               if (skb_headroom(skb) < padsize)
+                       return -ENOMEM;
 
-                       skb_push(skb, padsize);
-                       memmove(skb->data, skb->data + padsize, padpos);
-               }
+               skb_push(skb, padsize);
+               memmove(skb->data, skb->data + padsize, padpos);
+               hdr = (struct ieee80211_hdr *) skb->data;
        }
 
        if ((vif && vif->type != NL80211_IFTYPE_AP &&
@@ -1952,17 +1940,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                /* Frame was ACKed */
                tx_info->flags |= IEEE80211_TX_STAT_ACK;
 
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)) {
-               padpos = ath9k_cmn_padpos(hdr->frame_control);
-               padsize = padpos & 3;
-               if (padsize && skb->len>padpos+padsize) {
-                       /*
-                        * Remove MAC header padding before giving the frame back to
-                        * mac80211.
-                        */
-                       memmove(skb->data + padsize, skb->data, padpos);
-                       skb_pull(skb, padsize);
-               }
+       padpos = ath9k_cmn_padpos(hdr->frame_control);
+       padsize = padpos & 3;
+       if (padsize && skb->len>padpos+padsize) {
+               /*
+                * Remove MAC header padding before giving the frame back to
+                * mac80211.
+                */
+               memmove(skb->data + padsize, skb->data, padpos);
+               skb_pull(skb, padsize);
        }
 
        if (sc->ps_flags & PS_WAIT_FOR_TX_ACK) {
index af351ecd87c40810ad2c0102b9a3a112a5cbea6d..8b780d6d470f4f4cfb9315382e82811d8cb5c3db 100644 (file)
@@ -1078,7 +1078,8 @@ out:
        mutex_unlock(&ar->mutex);
 }
 
-static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw)
+static u64 carl9170_op_get_tsf(struct ieee80211_hw *hw,
+                              struct ieee80211_vif *vif)
 {
        struct ar9170 *ar = hw->priv;
        struct carl9170_tsf_rsp tsf;
index f8615cdf1075b7102403a1f352821ef756adb505..447a2307c9d9ae2bdb7657c2f0160f978c8e55e9 100644 (file)
 #define B43_MMIO_RADIO_HWENABLED_LO    0x49A
 #define B43_MMIO_GPIO_CONTROL          0x49C
 #define B43_MMIO_GPIO_MASK             0x49E
+#define B43_MMIO_TXE0_CTL              0x500
+#define B43_MMIO_TXE0_AUX              0x502
+#define B43_MMIO_TXE0_TS_LOC           0x504
+#define B43_MMIO_TXE0_TIME_OUT         0x506
+#define B43_MMIO_TXE0_WM_0             0x508
+#define B43_MMIO_TXE0_WM_1             0x50A
+#define B43_MMIO_TXE0_PHYCTL           0x50C
+#define B43_MMIO_TXE0_STATUS           0x50E
+#define B43_MMIO_TXE0_MMPLCP0          0x510
+#define B43_MMIO_TXE0_MMPLCP1          0x512
+#define B43_MMIO_TXE0_PHYCTL1          0x514
+#define B43_MMIO_XMTFIFODEF            0x520
+#define B43_MMIO_XMTFIFO_FRAME_CNT     0x522   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_BYTE_CNT      0x524   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_HEAD          0x526   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_RD_PTR                0x528   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFO_WR_PTR                0x52A   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFODEF1           0x52C   /* core rev>= 16 only */
+#define B43_MMIO_XMTFIFOCMD            0x540
+#define B43_MMIO_XMTFIFOFLUSH          0x542
+#define B43_MMIO_XMTFIFOTHRESH         0x544
+#define B43_MMIO_XMTFIFORDY            0x546
+#define B43_MMIO_XMTFIFOPRIRDY         0x548
+#define B43_MMIO_XMTFIFORQPRI          0x54A
+#define B43_MMIO_XMTTPLATETXPTR                0x54C
+#define B43_MMIO_XMTTPLATEPTR          0x550
+#define B43_MMIO_SMPL_CLCT_STRPTR      0x552   /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_STPPTR      0x554   /* core rev>= 22 only */
+#define B43_MMIO_SMPL_CLCT_CURPTR      0x556   /* core rev>= 22 only */
+#define B43_MMIO_XMTTPLATEDATALO       0x560
+#define B43_MMIO_XMTTPLATEDATAHI       0x562
+#define B43_MMIO_XMTSEL                        0x568
+#define B43_MMIO_XMTTXCNT              0x56A
+#define B43_MMIO_XMTTXSHMADDR          0x56C
 #define B43_MMIO_TSF_CFP_START_LOW     0x604
 #define B43_MMIO_TSF_CFP_START_HIGH    0x606
 #define B43_MMIO_TSF_CFP_PRETBTT       0x612
 #define B43_MMIO_TSF_3                 0x638   /* core rev < 3 only */
 #define B43_MMIO_RNG                   0x65A
 #define B43_MMIO_IFSSLOT               0x684   /* Interframe slot time */
-#define B43_MMIO_IFSCTL                        0x688 /* Interframe space control */
+#define B43_MMIO_IFSCTL                        0x688   /* Interframe space control */
+#define B43_MMIO_IFSSTAT               0x690
+#define B43_MMIO_IFSMEDBUSYCTL         0x692
+#define B43_MMIO_IFTXDUR               0x694
 #define  B43_MMIO_IFSCTL_USE_EDCF      0x0004
 #define B43_MMIO_POWERUP_DELAY         0x6A8
 #define B43_MMIO_BTCOEX_CTL            0x6B4 /* Bluetooth Coexistence Control */
 #define B43_MMIO_BTCOEX_STAT           0x6B6 /* Bluetooth Coexistence Status */
 #define B43_MMIO_BTCOEX_TXCTL          0x6B8 /* Bluetooth Coexistence Transmit Control */
+#define B43_MMIO_WEPCTL                        0x7C0
 
 /* SPROM boardflags_lo values */
 #define B43_BFL_BTCOEXIST              0x0001  /* implements Bluetooth coexistance */
index 56fa3a3648c43dbc32a015ece857a0f3f5bcaeac..43400fb62e1cf5e7b68cec1bebf0c6c892b81908 100644 (file)
@@ -729,52 +729,59 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
        for (i = 0; i < 5; i++)
                b43_ram_write(dev, i * 4, buffer[i]);
 
-       b43_write16(dev, 0x0568, 0x0000);
+       b43_write16(dev, B43_MMIO_XMTSEL, 0x0000);
+
        if (dev->dev->core_rev < 11)
-               b43_write16(dev, 0x07C0, 0x0000);
+               b43_write16(dev, B43_MMIO_WEPCTL, 0x0000);
        else
-               b43_write16(dev, 0x07C0, 0x0100);
+               b43_write16(dev, B43_MMIO_WEPCTL, 0x0100);
+
        value = (ofdm ? 0x41 : 0x40);
-       b43_write16(dev, 0x050C, value);
-       if ((phy->type == B43_PHYTYPE_N) || (phy->type == B43_PHYTYPE_LP))
-               b43_write16(dev, 0x0514, 0x1A02);
-       b43_write16(dev, 0x0508, 0x0000);
-       b43_write16(dev, 0x050A, 0x0000);
-       b43_write16(dev, 0x054C, 0x0000);
-       b43_write16(dev, 0x056A, 0x0014);
-       b43_write16(dev, 0x0568, 0x0826);
-       b43_write16(dev, 0x0500, 0x0000);
-       if (!pa_on && (phy->type == B43_PHYTYPE_N)) {
-               //SPEC TODO
-       }
+       b43_write16(dev, B43_MMIO_TXE0_PHYCTL, value);
+       if (phy->type == B43_PHYTYPE_N || phy->type == B43_PHYTYPE_LP ||
+           phy->type == B43_PHYTYPE_LCN)
+               b43_write16(dev, B43_MMIO_TXE0_PHYCTL1, 0x1A02);
+
+       b43_write16(dev, B43_MMIO_TXE0_WM_0, 0x0000);
+       b43_write16(dev, B43_MMIO_TXE0_WM_1, 0x0000);
+
+       b43_write16(dev, B43_MMIO_XMTTPLATETXPTR, 0x0000);
+       b43_write16(dev, B43_MMIO_XMTTXCNT, 0x0014);
+       b43_write16(dev, B43_MMIO_XMTSEL, 0x0826);
+       b43_write16(dev, B43_MMIO_TXE0_CTL, 0x0000);
+
+       if (!pa_on && phy->type == B43_PHYTYPE_N)
+               ; /*b43_nphy_pa_override(dev, false) */
 
        switch (phy->type) {
        case B43_PHYTYPE_N:
-               b43_write16(dev, 0x0502, 0x00D0);
+       case B43_PHYTYPE_LCN:
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x00D0);
                break;
        case B43_PHYTYPE_LP:
-               b43_write16(dev, 0x0502, 0x0050);
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0050);
                break;
        default:
-               b43_write16(dev, 0x0502, 0x0030);
+               b43_write16(dev, B43_MMIO_TXE0_AUX, 0x0030);
        }
+       b43_read16(dev, B43_MMIO_TXE0_AUX);
 
        if (phy->radio_ver == 0x2050 && phy->radio_rev <= 0x5)
                b43_radio_write16(dev, 0x0051, 0x0017);
        for (i = 0x00; i < max_loop; i++) {
-               value = b43_read16(dev, 0x050E);
+               value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
                if (value & 0x0080)
                        break;
                udelay(10);
        }
        for (i = 0x00; i < 0x0A; i++) {
-               value = b43_read16(dev, 0x050E);
+               value = b43_read16(dev, B43_MMIO_TXE0_STATUS);
                if (value & 0x0400)
                        break;
                udelay(10);
        }
        for (i = 0x00; i < 0x19; i++) {
-               value = b43_read16(dev, 0x0690);
+               value = b43_read16(dev, B43_MMIO_IFSSTAT);
                if (!(value & 0x0100))
                        break;
                udelay(10);
@@ -3599,7 +3606,7 @@ static int b43_op_get_stats(struct ieee80211_hw *hw,
        return 0;
 }
 
-static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
+static u64 b43_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -3618,7 +3625,8 @@ static u64 b43_op_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void b43_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void b43_op_set_tsf(struct ieee80211_hw *hw,
+                          struct ieee80211_vif *vif, u64 tsf)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
index d1dfeec7bc28d681659453d70d69e8bc0b3c5488..a13e28ef6246af2dd344025d1b394403572fd5f3 100644 (file)
   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
   Boston, MA 02110-1301, USA.
 
+  This file incorporates work covered by the following copyright and
+  permission notice:
+
+      Copyright (c) 2010 Broadcom Corporation
+
+      Permission to use, copy, modify, and/or distribute this software for any
+      purpose with or without fee is hereby granted, provided that the above
+      copyright notice and this permission notice appear in all copies.
 */
 
 #include <linux/slab.h>
 #include "tables_phy_lcn.h"
 #include "main.h"
 
+struct lcn_tx_gains {
+       u16 gm_gain;
+       u16 pga_gain;
+       u16 pad_gain;
+       u16 dac_gain;
+};
+
+struct lcn_tx_iir_filter {
+       u8 type;
+       u16 values[16];
+};
+
+enum lcn_sense_type {
+       B43_SENSE_TEMP,
+       B43_SENSE_VBAT,
+};
+
+/* In theory it's PHY common function, move if needed */
+/* brcms_b_switch_macfreq */
+static void b43_phy_switch_macfreq(struct b43_wldev *dev, u8 spurmode)
+{
+       if (dev->dev->chip_id == 43224 || dev->dev->chip_id == 43225) {
+               switch (spurmode) {
+               case 2:         /* 126 Mhz */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x2082);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+                       break;
+               case 1:         /* 123 Mhz */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x5341);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+                       break;
+               default:        /* 120 Mhz */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x8889);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0x8);
+                       break;
+               }
+       } else if (dev->phy.type == B43_PHYTYPE_LCN) {
+               switch (spurmode) {
+               case 1:         /* 82 Mhz */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0x7CE0);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+                       break;
+               default:        /* 80 Mhz */
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_LOW, 0xCCCD);
+                       b43_write16(dev, B43_MMIO_TSF_CLK_FRAC_HIGH, 0xC);
+                       break;
+               }
+       }
+}
+
 /**************************************************
  * Radio 2064.
  **************************************************/
@@ -152,6 +210,29 @@ static void b43_phy_lcn_afe_set_unset(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_LCN_AFE_CTL1, afe_ctl1);
 }
 
+/* wlc_lcnphy_get_pa_gain */
+static u16 b43_phy_lcn_get_pa_gain(struct b43_wldev *dev)
+{
+       return (b43_phy_read(dev, 0x4fb) & 0x7f00) >> 8;
+}
+
+/* wlc_lcnphy_set_dac_gain */
+static void b43_phy_lcn_set_dac_gain(struct b43_wldev *dev, u16 dac_gain)
+{
+       u16 dac_ctrl;
+
+       dac_ctrl = b43_phy_read(dev, 0x439);
+       dac_ctrl = dac_ctrl & 0xc7f;
+       dac_ctrl = dac_ctrl | (dac_gain << 7);
+       b43_phy_maskset(dev, 0x439, ~0xfff, dac_ctrl);
+}
+
+/* wlc_lcnphy_set_bbmult */
+static void b43_phy_lcn_set_bbmult(struct b43_wldev *dev, u8 m0)
+{
+       b43_lcntab_write(dev, B43_LCNTAB16(0x00, 0x57), m0 << 8);
+}
+
 /* wlc_lcnphy_clear_tx_power_offsets */
 static void b43_phy_lcn_clear_tx_power_offsets(struct b43_wldev *dev)
 {
@@ -231,18 +312,40 @@ static void b43_phy_lcn_bu_tweaks(struct b43_wldev *dev)
 
        b43_phy_write(dev, 0x7d6, 0x0902);
 
-       /* TODO: more ops */
+       b43_phy_maskset(dev, 0x429, ~0xf, 0x9);
+       b43_phy_maskset(dev, 0x429, ~(0x3f << 4), 0xe << 4);
 
        if (dev->phy.rev == 1) {
-               /* TODO: more ops */
+               b43_phy_maskset(dev, 0x423, ~0xff, 0x46);
+               b43_phy_maskset(dev, 0x411, ~0xff, 1);
+               b43_phy_set(dev, 0x434, 0xff); /* FIXME: update to wl */
+
+               /* TODO: wl operates on PHY 0x416, brcmsmac is outdated here */
+
+               b43_phy_maskset(dev, 0x656, ~0xf, 2);
+               b43_phy_set(dev, 0x44d, 4);
+
+               b43_radio_set(dev, 0x0f7, 0x4);
+               b43_radio_mask(dev, 0x0f1, ~0x3);
+               b43_radio_maskset(dev, 0x0f2, ~0xf8, 0x90);
+               b43_radio_maskset(dev, 0x0f3, ~0x3, 0x2);
+               b43_radio_maskset(dev, 0x0f3, ~0xf0, 0xa0);
+
+               b43_radio_set(dev, 0x11f, 0x2);
 
                b43_phy_lcn_clear_tx_power_offsets(dev);
+
+               /* TODO: something more? */
        }
 }
 
 /* wlc_lcnphy_vbat_temp_sense_setup */
-static void b43_phy_lcn_sense_setup(struct b43_wldev *dev)
+static void b43_phy_lcn_sense_setup(struct b43_wldev *dev,
+                                   enum lcn_sense_type sense_type)
 {
+       u8 auxpga_vmidcourse, auxpga_vmidfine, auxpga_gain;
+       u16 auxpga_vmid;
+       u8 tx_pwr_idx;
        u8 i;
 
        u16 save_radio_regs[6][2] = {
@@ -257,35 +360,312 @@ static void b43_phy_lcn_sense_setup(struct b43_wldev *dev)
        };
        u16 save_radio_4a4;
 
+       msleep(1);
+
+       /* Save */
        for (i = 0; i < 6; i++)
                save_radio_regs[i][1] = b43_radio_read(dev,
                                                       save_radio_regs[i][0]);
        for (i = 0; i < 14; i++)
                save_phy_regs[i][1] = b43_phy_read(dev, save_phy_regs[i][0]);
+       b43_mac_suspend(dev);
        save_radio_4a4 = b43_radio_read(dev, 0x4a4);
+       /* wlc_lcnphy_set_tx_pwr_ctrl(pi, LCNPHY_TX_PWR_CTRL_OFF); */
+       tx_pwr_idx = dev->phy.lcn->tx_pwr_curr_idx;
+
+       /* Setup */
+       /* TODO: wlc_lcnphy_set_tx_pwr_by_index(pi, 127); */
+       b43_radio_set(dev, 0x007, 0x1);
+       b43_radio_set(dev, 0x0ff, 0x10);
+       b43_radio_set(dev, 0x11f, 0x4);
+
+       b43_phy_mask(dev, 0x503, ~0x1);
+       b43_phy_mask(dev, 0x503, ~0x4);
+       b43_phy_mask(dev, 0x4a4, ~0x4000);
+       b43_phy_mask(dev, 0x4a4, (u16) ~0x8000);
+       b43_phy_mask(dev, 0x4d0, ~0x20);
+       b43_phy_set(dev, 0x4a5, 0xff);
+       b43_phy_maskset(dev, 0x4a5, ~0x7000, 0x5000);
+       b43_phy_mask(dev, 0x4a5, ~0x700);
+       b43_phy_maskset(dev, 0x40d, ~0xff, 64);
+       b43_phy_maskset(dev, 0x40d, ~0x700, 0x600);
+       b43_phy_maskset(dev, 0x4a2, ~0xff, 64);
+       b43_phy_maskset(dev, 0x4a2, ~0x700, 0x600);
+       b43_phy_maskset(dev, 0x4d9, ~0x70, 0x20);
+       b43_phy_maskset(dev, 0x4d9, ~0x700, 0x300);
+       b43_phy_maskset(dev, 0x4d9, ~0x7000, 0x1000);
+       b43_phy_mask(dev, 0x4da, ~0x1000);
+       b43_phy_set(dev, 0x4da, 0x2000);
+       b43_phy_set(dev, 0x4a6, 0x8000);
+
+       b43_radio_write(dev, 0x025, 0xc);
+       b43_radio_set(dev, 0x005, 0x8);
+       b43_phy_set(dev, 0x938, 0x4);
+       b43_phy_set(dev, 0x939, 0x4);
+       b43_phy_set(dev, 0x4a4, 0x1000);
+
+       /* FIXME: don't hardcode */
+       b43_lcntab_write(dev, B43_LCNTAB16(0x8, 0x6), 0x640);
+
+       switch (sense_type) {
+       case B43_SENSE_TEMP:
+               b43_phy_set(dev, 0x4d7, 0x8);
+               b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x1000);
+               auxpga_vmidcourse = 8;
+               auxpga_vmidfine = 0x4;
+               auxpga_gain = 2;
+               b43_radio_set(dev, 0x082, 0x20);
+               break;
+       case B43_SENSE_VBAT:
+               b43_phy_set(dev, 0x4d7, 0x8);
+               b43_phy_maskset(dev, 0x4d7, ~0x7000, 0x3000);
+               auxpga_vmidcourse = 7;
+               auxpga_vmidfine = 0xa;
+               auxpga_gain = 2;
+               break;
+       }
+       auxpga_vmid = (0x200 | (auxpga_vmidcourse << 4) | auxpga_vmidfine);
+
+       b43_phy_set(dev, 0x4d8, 0x1);
+       b43_phy_maskset(dev, 0x4d8, ~(0x3ff << 2), auxpga_vmid << 2);
+       b43_phy_set(dev, 0x4d8, 0x2);
+       b43_phy_maskset(dev, 0x4d8, ~(0x7 << 12), auxpga_gain << 12);
+       b43_phy_set(dev, 0x4d0, 0x20);
+       b43_radio_write(dev, 0x112, 0x6);
 
-       /* TODO: config sth */
+       b43_dummy_transmission(dev, true, false);
+       /* Wait if not done */
+       if (!(b43_phy_read(dev, 0x476) & 0x8000))
+               udelay(10);
 
+       /* Restore */
        for (i = 0; i < 6; i++)
                b43_radio_write(dev, save_radio_regs[i][0],
                                save_radio_regs[i][1]);
        for (i = 0; i < 14; i++)
                b43_phy_write(dev, save_phy_regs[i][0], save_phy_regs[i][1]);
+       /* TODO: wlc_lcnphy_set_tx_pwr_by_index(tx_pwr_idx) */
        b43_radio_write(dev, 0x4a4, save_radio_4a4);
+
+       b43_mac_enable(dev);
+
+       msleep(1);
+}
+
+static bool b43_phy_lcn_load_tx_iir_cck_filter(struct b43_wldev *dev,
+                                              u8 filter_type)
+{
+       int i, j;
+       u16 phy_regs[] = { 0x910, 0x91e, 0x91f, 0x924, 0x925, 0x926, 0x920,
+                          0x921, 0x927, 0x928, 0x929, 0x922, 0x923, 0x930,
+                          0x931, 0x932 };
+       /* Table is from brcmsmac, values for type 25 were outdated, probably
+        * others need updating too */
+       struct lcn_tx_iir_filter tx_iir_filters_cck[] = {
+               { 0,  { 1, 415, 1874, 64, 128, 64, 792, 1656, 64, 128, 64, 778,
+                       1582, 64, 128, 64 } },
+               { 1,  { 1, 402, 1847, 259, 59, 259, 671, 1794, 68, 54, 68, 608,
+                       1863, 93, 167, 93 } },
+               { 2,  { 1, 415, 1874, 64, 128, 64, 792, 1656, 192, 384, 192,
+                       778, 1582, 64, 128, 64 } },
+               { 3,  { 1, 302, 1841, 129, 258, 129, 658, 1720, 205, 410, 205,
+                       754, 1760, 170, 340, 170 } },
+               { 20, { 1, 360, 1884, 242, 1734, 242, 752, 1720, 205, 1845, 205,
+                       767, 1760, 256, 185, 256 } },
+               { 21, { 1, 360, 1884, 149, 1874, 149, 752, 1720, 205, 1883, 205,
+                       767, 1760, 256, 273, 256 } },
+               { 22, { 1, 360, 1884, 98, 1948, 98, 752, 1720, 205, 1924, 205,
+                       767, 1760, 256, 352, 256 } },
+               { 23, { 1, 350, 1884, 116, 1966, 116, 752, 1720, 205, 2008, 205,
+                       767, 1760, 128, 233, 128 } },
+               { 24, { 1, 325, 1884, 32, 40, 32, 756, 1720, 256, 471, 256, 766,
+                       1760, 256, 1881, 256 } },
+               { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720, 256, 471, 256, 765,
+                       1760, 262, 1878, 262 } },
+               /* brcmsmac version { 25, { 1, 299, 1884, 51, 64, 51, 736, 1720,
+                * 256, 471, 256, 765, 1760, 256, 1881, 256 } }, */
+               { 26, { 1, 277, 1943, 39, 117, 88, 637, 1838, 64, 192, 144, 614,
+                       1864, 128, 384, 288 } },
+               { 27, { 1, 245, 1943, 49, 147, 110, 626, 1838, 256, 768, 576,
+                       613, 1864, 128, 384, 288 } },
+               { 30, { 1, 302, 1841, 61, 122, 61, 658, 1720, 205, 410, 205,
+                       754, 1760, 170, 340, 170 } },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(tx_iir_filters_cck); i++) {
+               if (tx_iir_filters_cck[i].type == filter_type) {
+                       for (j = 0; j < 16; j++)
+                               b43_phy_write(dev, phy_regs[j],
+                                             tx_iir_filters_cck[i].values[j]);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+static bool b43_phy_lcn_load_tx_iir_ofdm_filter(struct b43_wldev *dev,
+                                               u8 filter_type)
+{
+       int i, j;
+       u16 phy_regs[] = { 0x90f, 0x900, 0x901, 0x906, 0x907, 0x908, 0x902,
+                          0x903, 0x909, 0x90a, 0x90b, 0x904, 0x905, 0x90c,
+                          0x90d, 0x90e };
+       struct lcn_tx_iir_filter tx_iir_filters_ofdm[] = {
+               { 0, { 0, 0xa2, 0x0, 0x100, 0x100, 0x0, 0x0, 0x0, 0x100, 0x0,
+                      0x0, 0x278, 0xfea0, 0x80, 0x100, 0x80 } },
+               { 1, { 0, 374, 0xFF79, 16, 32, 16, 799, 0xFE74, 50, 32, 50, 750,
+                      0xFE2B, 212, 0xFFCE, 212 } },
+               { 2, { 0, 375, 0xFF16, 37, 76, 37, 799, 0xFE74, 32, 20, 32, 748,
+                      0xFEF2, 128, 0xFFE2, 128 } },
+       };
+
+       for (i = 0; i < ARRAY_SIZE(tx_iir_filters_ofdm); i++) {
+               if (tx_iir_filters_ofdm[i].type == filter_type) {
+                       for (j = 0; j < 16; j++)
+                               b43_phy_write(dev, phy_regs[j],
+                                             tx_iir_filters_ofdm[i].values[j]);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+/* wlc_lcnphy_set_tx_gain_override */
+static void b43_phy_lcn_set_tx_gain_override(struct b43_wldev *dev, bool enable)
+{
+       b43_phy_maskset(dev, 0x4b0, ~(0x1 << 7), enable << 7);
+       b43_phy_maskset(dev, 0x4b0, ~(0x1 << 14), enable << 14);
+       b43_phy_maskset(dev, 0x43b, ~(0x1 << 6), enable << 6);
+}
+
+/* wlc_lcnphy_set_tx_gain */
+static void b43_phy_lcn_set_tx_gain(struct b43_wldev *dev,
+                                   struct lcn_tx_gains *target_gains)
+{
+       u16 pa_gain = b43_phy_lcn_get_pa_gain(dev);
+
+       b43_phy_write(dev, 0x4b5,
+                     (target_gains->gm_gain | (target_gains->pga_gain << 8)));
+       b43_phy_maskset(dev, 0x4fb, ~0x7fff,
+                       (target_gains->pad_gain | (pa_gain << 8)));
+       b43_phy_write(dev, 0x4fc,
+                     (target_gains->gm_gain | (target_gains->pga_gain << 8)));
+       b43_phy_maskset(dev, 0x4fd, ~0x7fff,
+                       (target_gains->pad_gain | (pa_gain << 8)));
+
+       b43_phy_lcn_set_dac_gain(dev, target_gains->dac_gain);
+       b43_phy_lcn_set_tx_gain_override(dev, true);
+}
+
+/* wlc_lcnphy_tx_pwr_ctrl_init */
+static void b43_phy_lcn_tx_pwr_ctl_init(struct b43_wldev *dev)
+{
+       struct lcn_tx_gains tx_gains;
+       u8 bbmult;
+
+       b43_mac_suspend(dev);
+
+       if (!dev->phy.lcn->hw_pwr_ctl_capable) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       tx_gains.gm_gain = 4;
+                       tx_gains.pga_gain = 12;
+                       tx_gains.pad_gain = 12;
+                       tx_gains.dac_gain = 0;
+                       bbmult = 150;
+               } else {
+                       tx_gains.gm_gain = 7;
+                       tx_gains.pga_gain = 15;
+                       tx_gains.pad_gain = 14;
+                       tx_gains.dac_gain = 0;
+                       bbmult = 150;
+               }
+               b43_phy_lcn_set_tx_gain(dev, &tx_gains);
+               b43_phy_lcn_set_bbmult(dev, bbmult);
+               b43_phy_lcn_sense_setup(dev, B43_SENSE_TEMP);
+       } else {
+               b43err(dev->wl, "TX power control not supported for this HW\n");
+       }
+
+       b43_mac_enable(dev);
+}
+
+/* wlc_lcnphy_txrx_spur_avoidance_mode */
+static void b43_phy_lcn_txrx_spur_avoidance_mode(struct b43_wldev *dev,
+                                                bool enable)
+{
+       if (enable) {
+               b43_phy_write(dev, 0x942, 0x7);
+               b43_phy_write(dev, 0x93b, ((1 << 13) + 23));
+               b43_phy_write(dev, 0x93c, ((1 << 13) + 1989));
+
+               b43_phy_write(dev, 0x44a, 0x084);
+               b43_phy_write(dev, 0x44a, 0x080);
+               b43_phy_write(dev, 0x6d3, 0x2222);
+               b43_phy_write(dev, 0x6d3, 0x2220);
+       } else {
+               b43_phy_write(dev, 0x942, 0x0);
+               b43_phy_write(dev, 0x93b, ((0 << 13) + 23));
+               b43_phy_write(dev, 0x93c, ((0 << 13) + 1989));
+       }
+       b43_phy_switch_macfreq(dev, enable);
 }
 
 /**************************************************
  * Channel switching ops.
  **************************************************/
 
+/* wlc_lcnphy_set_chanspec_tweaks */
+static void b43_phy_lcn_set_channel_tweaks(struct b43_wldev *dev, int channel)
+{
+       struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
+
+       b43_phy_maskset(dev, 0x448, ~0x300, (channel == 14) ? 0x200 : 0x100);
+
+       if (channel == 1 || channel == 2 || channel == 3 || channel == 4 ||
+           channel == 9 || channel == 10 || channel == 11 || channel == 12) {
+               bcma_chipco_pll_write(cc, 0x2, 0x03000c04);
+               bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x0);
+               bcma_chipco_pll_write(cc, 0x4, 0x200005c0);
+
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
+
+               b43_phy_write(dev, 0x942, 0);
+
+               b43_phy_lcn_txrx_spur_avoidance_mode(dev, false);
+               b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1b00);
+               b43_phy_write(dev, 0x425, 0x5907);
+       } else {
+               bcma_chipco_pll_write(cc, 0x2, 0x03140c04);
+               bcma_chipco_pll_maskset(cc, 0x3, 0x00ffffff, 0x333333);
+               bcma_chipco_pll_write(cc, 0x4, 0x202c2820);
+
+               bcma_cc_set32(cc, BCMA_CC_PMU_CTL, 0x400);
+
+               b43_phy_write(dev, 0x942, 0);
+
+               b43_phy_lcn_txrx_spur_avoidance_mode(dev, true);
+               b43_phy_maskset(dev, 0x424, (u16) ~0xff00, 0x1f00);
+               b43_phy_write(dev, 0x425, 0x590a);
+       }
+
+       b43_phy_set(dev, 0x44a, 0x44);
+       b43_phy_write(dev, 0x44a, 0x80);
+}
+
+/* wlc_phy_chanspec_set_lcnphy */
 static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
                                   struct ieee80211_channel *channel,
                                   enum nl80211_channel_type channel_type)
 {
-       /* TODO: PLL and PHY ops */
+       static const u16 sfo_cfg[14][2] = {
+               {965, 1087}, {967, 1085}, {969, 1082}, {971, 1080}, {973, 1078},
+               {975, 1076}, {977, 1073}, {979, 1071}, {981, 1069}, {983, 1067},
+               {985, 1065}, {987, 1063}, {989, 1060}, {994, 1055},
+       };
 
-       b43_phy_set(dev, 0x44a, 0x44);
-       b43_phy_write(dev, 0x44a, 0x80);
+       b43_phy_lcn_set_channel_tweaks(dev, channel->hw_value);
 
        b43_phy_set(dev, 0x44a, 0x44);
        b43_phy_write(dev, 0x44a, 0x80);
@@ -295,7 +675,21 @@ static int b43_phy_lcn_set_channel(struct b43_wldev *dev,
 
        b43_phy_lcn_afe_set_unset(dev);
 
-       /* TODO */
+       b43_phy_write(dev, 0x657, sfo_cfg[channel->hw_value - 1][0]);
+       b43_phy_write(dev, 0x658, sfo_cfg[channel->hw_value - 1][1]);
+
+       if (channel->hw_value == 14) {
+               b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (2) << 8);
+               b43_phy_lcn_load_tx_iir_cck_filter(dev, 3);
+       } else {
+               b43_phy_maskset(dev, 0x448, ~(0x3 << 8), (1) << 8);
+               /* brcmsmac uses filter_type 2, we follow wl with 25 */
+               b43_phy_lcn_load_tx_iir_cck_filter(dev, 25);
+       }
+       /* brcmsmac uses filter_type 2, we follow wl with 0 */
+       b43_phy_lcn_load_tx_iir_ofdm_filter(dev, 0);
+
+       b43_phy_maskset(dev, 0x4eb, ~(0x7 << 3), 0x1 << 3);
 
        return 0;
 }
@@ -336,6 +730,8 @@ static void b43_phy_lcn_op_prepare_structs(struct b43_wldev *dev)
 /* wlc_phy_init_lcnphy */
 static int b43_phy_lcn_op_init(struct b43_wldev *dev)
 {
+       struct bcma_drv_cc *cc = &dev->dev->bdev->bus->drv_cc;
+
        b43_phy_set(dev, 0x44a, 0x80);
        b43_phy_mask(dev, 0x44a, 0x7f);
        b43_phy_set(dev, 0x6d1, 0x80);
@@ -357,7 +753,21 @@ static int b43_phy_lcn_op_init(struct b43_wldev *dev)
        else
                B43_WARN_ON(1);
 
-       b43_phy_lcn_sense_setup(dev);
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               b43_phy_lcn_tx_pwr_ctl_init(dev);
+
+       b43_switch_channel(dev, dev->phy.channel);
+
+       bcma_chipco_regctl_maskset(cc, 0, 0xf, 0x9);
+       bcma_chipco_chipctl_maskset(cc, 0, 0, 0x03cddddd);
+
+       /* TODO */
+
+       b43_phy_set(dev, 0x448, 0x4000);
+       udelay(100);
+       b43_phy_mask(dev, 0x448, ~0x4000);
+
+       /* TODO */
 
        return 0;
 }
index 25f06e8d453186e73aaa1d7939c6a3c4eb549b1c..6a7092e13fff95244bbc9c11ff688f9d5686f38f 100644 (file)
@@ -19,6 +19,9 @@
 
 
 struct b43_phy_lcn {
+       bool hw_pwr_ctl;
+       bool hw_pwr_ctl_capable;
+       u8 tx_pwr_curr_idx;
 };
 
 
index 9d484e2f79bfd96f5ad2dd60b25c1334ce173e7f..5176363cadf297f720d7ddca09293a8c96cb5f8e 100644 (file)
@@ -657,8 +657,25 @@ void b43_phy_lcn_load_tx_gain_tab(struct b43_wldev *dev,
        }
 }
 
+/* wlc_lcnphy_load_rfpower */
+static void b43_phy_lcn_load_rfpower(struct b43_wldev *dev)
+{
+       u32 bbmult, rfgain;
+       u8 i;
+
+       for (i = 0; i < 128; i++) {
+               bbmult = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0x140 + i));
+               bbmult >>= 20;
+               rfgain = b43_lcntab_read(dev, B43_LCNTAB32(0x7, 0xc0 + i));
+
+               /* TODO: calculate value for 0x240 + i table offset
+                * b43_lcntab_write(dev, B43_LCNTAB32(0x7, 0x240 + i), val);
+                */
+       }
+}
+
 /* Not implemented in brcmsmac, noticed in wl in MMIO dump */
-static void b43_phy_lcn_rewrite_tables(struct b43_wldev *dev)
+static void b43_phy_lcn_rewrite_rfpower_table(struct b43_wldev *dev)
 {
        int i;
        u32 tmp;
@@ -685,7 +702,7 @@ void b43_phy_lcn_tables_init(struct b43_wldev *dev)
        b43_phy_lcn_upload_static_tables(dev);
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               if (sprom->boardflags_lo & B43_BFL_EXTLNA)
+               if (sprom->boardflags_lo & B43_BFL_FEM)
                        b43_phy_lcn_load_tx_gain_tab(dev,
                                b43_lcntab_tx_gain_tbl_2ghz_ext_pa_rev0);
                else
@@ -701,7 +718,7 @@ void b43_phy_lcn_tables_init(struct b43_wldev *dev)
        else
                b43err(dev->wl, "SW ctl table is unknown for this card\n");
 
-       /* TODO: various tables ops here */
-       b43_phy_lcn_rewrite_tables(dev);
+       b43_phy_lcn_load_rfpower(dev);
+       b43_phy_lcn_rewrite_rfpower_table(dev);
        b43_phy_lcn_clean_papd_comp_table(dev);
 }
index 35cd2537e7fd2cf13bdf8ff185498b108beaee7f..8928d47432df95ba1869831c0bfa42d1114de943 100644 (file)
@@ -937,7 +937,7 @@ void iwl_legacy_irq_handle_error(struct iwl_priv *priv)
                                        &priv->contexts[IWL_RXON_CTX_BSS]);
 #endif
 
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        /* Keep the restart process from trying to send host
         * commands by clearing the INIT status bit */
@@ -1746,7 +1746,7 @@ int iwl_legacy_force_reset(struct iwl_priv *priv, bool external)
 
        /* Set the FW error flag -- cleared on iwl_down */
        set_bit(STATUS_FW_ERROR, &priv->status);
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
        /*
         * Keep the restart process from trying to send host
         * commands by clearing the INIT status bit
@@ -2220,7 +2220,8 @@ out:
 }
 EXPORT_SYMBOL(iwl_legacy_mac_config);
 
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw)
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif)
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
index 84da79376ef8c16c835c533d056aa9ea4ca940be..b2df01c8f8f5d64dc0cab2571742c4de9be0bd0a 100644 (file)
@@ -620,7 +620,8 @@ static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
 
 /* mac80211 handlers */
 int iwl_legacy_mac_config(struct ieee80211_hw *hw, u32 changed);
-void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw);
+void iwl_legacy_mac_reset_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif);
 void iwl_legacy_mac_bss_info_changed(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_bss_conf *bss_conf,
index 62b4b09122cbac4489561a0a1428cc70d7a5b538..ce1fc9feb61f68487d3bc2f043d9feefa4fc8b72 100644 (file)
@@ -167,7 +167,7 @@ int iwl_legacy_send_cmd_sync(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                goto out;
        }
 
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        !test_bit(STATUS_HCMD_ACTIVE, &priv->status),
                        HOST_COMPLETE_TIMEOUT);
        if (!ret) {
index 4fff995c6f3e2f4cbb97139d52625fa5ccce2321..ef9e268bf8a074ea3707b04992e758f52dc0eb8d 100644 (file)
@@ -625,6 +625,8 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        cmd = txq->cmd[cmd_index];
        meta = &txq->meta[cmd_index];
 
+       txq->time_stamp = jiffies;
+
        pci_unmap_single(priv->pci_dev,
                         dma_unmap_addr(meta, mapping),
                         dma_unmap_len(meta, len),
@@ -645,7 +647,7 @@ iwl_legacy_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
                IWL_DEBUG_INFO(priv, "Clearing HCMD_ACTIVE for command %s\n",
                               iwl_legacy_get_cmd_string(cmd->hdr.cmd));
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        /* Mark as unmapped */
index 015739d204f225bafecc4cf7222c4be6d3ee130d..b282d869a546a79dcdc52fca43788e9069785eb9 100644 (file)
@@ -840,7 +840,7 @@ static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                                test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -2268,7 +2268,7 @@ static void iwl3945_alive_start(struct iwl_priv *priv)
        iwl3945_reg_txpower_periodic(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        return;
 
@@ -2299,7 +2299,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2852,7 +2852,7 @@ static int iwl3945_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index 6bc5575c8dff67dfe242b035b7a2ec11c005028f..d2fba9eae1536a00b4f7b833617b1f83ccf11062 100644 (file)
@@ -575,7 +575,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->status));
        else
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
 }
 
 /**
@@ -925,7 +925,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv)
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
                priv->ucode_write_complete = 1;
-               wake_up_interruptible(&priv->wait_command_queue);
+               wake_up(&priv->wait_command_queue);
        }
 
        if (inta & ~handled) {
@@ -1794,7 +1794,7 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
        iwl4965_rf_kill_ct_config(priv);
 
        IWL_DEBUG_INFO(priv, "ALIVE processing complete.\n");
-       wake_up_interruptible(&priv->wait_command_queue);
+       wake_up(&priv->wait_command_queue);
 
        iwl_legacy_power_update_mode(priv, true);
        IWL_DEBUG_INFO(priv, "Updated power mode\n");
@@ -1827,7 +1827,7 @@ static void __iwl4965_down(struct iwl_priv *priv)
        iwl_legacy_clear_driver_stations(priv);
 
        /* Unblock any waiting calls */
-       wake_up_interruptible_all(&priv->wait_command_queue);
+       wake_up_all(&priv->wait_command_queue);
 
        /* Wipe out the EXIT_PENDING status bit if we are not actually
         * exiting the module */
@@ -2265,7 +2265,7 @@ int iwl4965_mac_start(struct ieee80211_hw *hw)
 
        /* Wait for START_ALIVE from Run Time ucode. Otherwise callbacks from
         * mac80211 will not be run successfully. */
-       ret = wait_event_interruptible_timeout(priv->wait_command_queue,
+       ret = wait_event_timeout(priv->wait_command_queue,
                        test_bit(STATUS_READY, &priv->status),
                        UCODE_READY_TIMEOUT);
        if (!ret) {
index 48ab9142af387437858498166154182d48dc19ed..8fa59cdb3b49992e6a0380d655fb7f68d94ea006 100644 (file)
@@ -3,18 +3,19 @@ obj-$(CONFIG_IWLAGN)  += iwlagn.o
 iwlagn-objs            := iwl-agn.o iwl-agn-rs.o
 iwlagn-objs            += iwl-agn-ucode.o iwl-agn-tx.o
 iwlagn-objs            += iwl-agn-lib.o iwl-agn-calib.o iwl-io.o
-iwlagn-objs            += iwl-agn-tt.o iwl-agn-sta.o iwl-agn-eeprom.o
+iwlagn-objs            += iwl-agn-tt.o iwl-agn-sta.o
 
-iwlagn-objs            += iwl-core.o iwl-eeprom.o iwl-power.o
-iwlagn-objs            += iwl-rx.o iwl-sta.o
-iwlagn-objs            += iwl-scan.o iwl-led.o
-iwlagn-objs             += iwl-agn-rxon.o
-iwlagn-objs             += iwl-5000.o
-iwlagn-objs             += iwl-6000.o
-iwlagn-objs             += iwl-1000.o
-iwlagn-objs             += iwl-2000.o
-iwlagn-objs             += iwl-pci.o
-iwlagn-objs             += iwl-trans.o iwl-trans-rx-pcie.o iwl-trans-tx-pcie.o
+iwlagn-objs            += iwl-core.o iwl-eeprom.o iwl-power.o
+iwlagn-objs            += iwl-rx.o iwl-sta.o
+iwlagn-objs            += iwl-scan.o iwl-led.o
+iwlagn-objs            += iwl-agn-rxon.o
+iwlagn-objs            += iwl-5000.o
+iwlagn-objs            += iwl-6000.o
+iwlagn-objs            += iwl-1000.o
+iwlagn-objs            += iwl-2000.o
+iwlagn-objs            += iwl-pci.o
+iwlagn-objs            += iwl-trans.o
+iwlagn-objs            += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
 
 iwlagn-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlagn-$(CONFIG_IWLWIFI_DEVICE_TRACING) += iwl-devtrace.o
index 4766c3a1a2f6669c890fa8beadc33ab4e3a1a8aa..887f9ac434c2797afd903bca340a3e5fcf2a04b0 100644 (file)
@@ -44,7 +44,7 @@
 #include "iwl-helpers.h"
 #include "iwl-agn-hw.h"
 #include "iwl-shared.h"
-#include "iwl-pci.h"
+#include "iwl-cfg.h"
 
 /* Highest firmware API version supported */
 #define IWL1000_UCODE_API_MAX 6
@@ -161,8 +161,6 @@ static int iwl1000_hw_set_hw_params(struct iwl_priv *priv)
        if (priv->cfg->need_dc_calib)
                hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
 
-       hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
        return 0;
 }
 
@@ -191,7 +189,6 @@ static struct iwl_base_params iwl1000_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_1000,
        .shadow_ram_support = false,
        .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_EXT_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
index 913f2a22852727b6b17e976b4f43bc9a835a3097..db889581c0e5dabe3d47e2f3d9a54bd234b93b82 100644 (file)
@@ -45,7 +45,7 @@
 #include "iwl-agn-hw.h"
 #include "iwl-6000-hw.h"
 #include "iwl-shared.h"
-#include "iwl-pci.h"
+#include "iwl-cfg.h"
 
 /* Highest firmware API version supported */
 #define IWL2030_UCODE_API_MAX 6
@@ -75,7 +75,7 @@
 #define IWL105_MODULE_FIRMWARE(api) IWL105_FW_PRE __stringify(api) ".ucode"
 
 #define IWL135_FW_PRE "iwlwifi-135-"
-#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE #api ".ucode"
+#define IWL135_MODULE_FIRMWARE(api) IWL135_FW_PRE __stringify(api) ".ucode"
 
 static void iwl2000_set_ct_threshold(struct iwl_priv *priv)
 {
@@ -159,8 +159,6 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
        if (priv->cfg->need_temp_offset_calib)
                hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
 
-       hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
        return 0;
 }
 
@@ -211,7 +209,6 @@ static struct iwl_base_params iwl2000_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
        .shadow_ram_support = true,
        .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -231,7 +228,6 @@ static struct iwl_base_params iwl2030_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_2x00,
        .shadow_ram_support = true,
        .led_compensation = 57,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -268,6 +264,7 @@ static struct iwl_bt_params iwl2030_bt_params = {
        .base_params = &iwl2000_base_params,                    \
        .need_dc_calib = true,                                  \
        .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
        .led_mode = IWL_LED_RF_STATE,                           \
        .iq_invert = true                                       \
 
@@ -300,6 +297,7 @@ struct iwl_cfg iwl2000_2bgn_d_cfg = {
        .bt_params = &iwl2030_bt_params,                        \
        .need_dc_calib = true,                                  \
        .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
        .led_mode = IWL_LED_RF_STATE,                           \
        .adv_pm = true,                                         \
        .iq_invert = true                                       \
@@ -326,6 +324,7 @@ struct iwl_cfg iwl2030_2bg_cfg = {
        .base_params = &iwl2000_base_params,                    \
        .need_dc_calib = true,                                  \
        .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
        .led_mode = IWL_LED_RF_STATE,                           \
        .adv_pm = true,                                         \
        .rx_with_siso_diversity = true,                         \
@@ -354,6 +353,7 @@ struct iwl_cfg iwl105_bgn_cfg = {
        .bt_params = &iwl2030_bt_params,                        \
        .need_dc_calib = true,                                  \
        .need_temp_offset_calib = true,                         \
+       .temp_offset_v2 = true,                                 \
        .led_mode = IWL_LED_RF_STATE,                           \
        .adv_pm = true,                                         \
        .rx_with_siso_diversity = true,                         \
index f9630a3c79fe996c26093954f2938129cd6e2a89..c0135988e777140ff6ef1770bd74a580c3d55a8f 100644 (file)
@@ -74,8 +74,8 @@
 static inline s32 iwl_temp_calib_to_offset(struct iwl_priv *priv)
 {
        u16 temperature, voltage;
-       __le16 *temp_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE);
+       __le16 *temp_calib = (__le16 *)iwl_eeprom_query_addr(priv,
+                               EEPROM_KELVIN_TEMPERATURE);
 
        temperature = le16_to_cpu(temp_calib[0]);
        voltage = le16_to_cpu(temp_calib[1]);
index 7cb4d69e0c37a8d872d604dabec2a2b4a601f521..290701620f03dd8c73cf350b45afc46de673a153 100644 (file)
@@ -47,7 +47,7 @@
 #include "iwl-5000-hw.h"
 #include "iwl-trans.h"
 #include "iwl-shared.h"
-#include "iwl-pci.h"
+#include "iwl-cfg.h"
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 5
@@ -184,8 +184,6 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv)
                BIT(IWL_CALIB_TX_IQ_PERD)       |
                BIT(IWL_CALIB_BASE_BAND);
 
-       hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
        return 0;
 }
 
@@ -223,8 +221,6 @@ static int iwl5150_hw_set_hw_params(struct iwl_priv *priv)
        if (priv->cfg->need_dc_calib)
                hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_DC);
 
-       hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
        return 0;
 }
 
@@ -353,7 +349,6 @@ static struct iwl_base_params iwl5000_base_params = {
        .num_of_ampdu_queues = IWLAGN_NUM_AMPDU_QUEUES,
        .pll_cfg_val = CSR50_ANA_PLL_CFG_VAL,
        .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_LONG_THRESHOLD_DEF,
        .chain_noise_scale = 1000,
        .wd_timeout = IWL_LONG_WD_TIMEOUT,
index 2a98e65ca84cb8eebf4119342a4f90ceaca6d97f..37837f7b6990cfe0b0d74e15b511cf2e15d1b41b 100644 (file)
@@ -46,7 +46,7 @@
 #include "iwl-6000-hw.h"
 #include "iwl-trans.h"
 #include "iwl-shared.h"
-#include "iwl-pci.h"
+#include "iwl-cfg.h"
 
 /* Highest firmware API version supported */
 #define IWL6000_UCODE_API_MAX 4
@@ -180,8 +180,6 @@ static int iwl6000_hw_set_hw_params(struct iwl_priv *priv)
        if (priv->cfg->need_temp_offset_calib)
                hw_params(priv).calib_init_cfg |= BIT(IWL_CALIB_TEMP_OFFSET);
 
-       hw_params(priv).beacon_time_tsf_bits = IWLAGN_EXT_BEACON_TIME_POS;
-
        return 0;
 }
 
@@ -305,7 +303,6 @@ static struct iwl_base_params iwl6000_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
        .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -323,7 +320,6 @@ static struct iwl_base_params iwl6050_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_6x50,
        .shadow_ram_support = true,
        .led_compensation = 51,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
@@ -340,7 +336,6 @@ static struct iwl_base_params iwl6000_g2_base_params = {
        .max_ll_items = OTP_MAX_LL_ITEMS_6x00,
        .shadow_ram_support = true,
        .led_compensation = 57,
-       .chain_noise_num_beacons = IWL_CAL_NUM_BEACONS,
        .adv_thermal_throttle = true,
        .support_ct_kill_exit = true,
        .plcp_delta_threshold = IWL_MAX_PLCP_ERR_THRESHOLD_DEF,
index b725f6970dee81883416b0d95ff8d0d5f43d59be..03bac48558b25be81e810963f6c82f32dc9b89d7 100644 (file)
@@ -766,12 +766,9 @@ static void iwl_find_disconn_antenna(struct iwl_priv *priv, u32* average_sig,
        u8 first_chain;
        u16 i = 0;
 
-       average_sig[0] = data->chain_signal_a /
-                        priv->cfg->base_params->chain_noise_num_beacons;
-       average_sig[1] = data->chain_signal_b /
-                        priv->cfg->base_params->chain_noise_num_beacons;
-       average_sig[2] = data->chain_signal_c /
-                        priv->cfg->base_params->chain_noise_num_beacons;
+       average_sig[0] = data->chain_signal_a / IWL_CAL_NUM_BEACONS;
+       average_sig[1] = data->chain_signal_b / IWL_CAL_NUM_BEACONS;
+       average_sig[2] = data->chain_signal_c / IWL_CAL_NUM_BEACONS;
 
        if (average_sig[0] >= average_sig[1]) {
                max_average_sig = average_sig[0];
@@ -1038,8 +1035,7 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
        /* If this is the "chain_noise_num_beacons", determine:
         * 1)  Disconnected antennas (using signal strengths)
         * 2)  Differential gain (using silence noise) to balance receivers */
-       if (data->beacon_count !=
-               priv->cfg->base_params->chain_noise_num_beacons)
+       if (data->beacon_count != IWL_CAL_NUM_BEACONS)
                return;
 
        /* Analyze signal for disconnected antenna */
@@ -1055,12 +1051,9 @@ void iwl_chain_noise_calibration(struct iwl_priv *priv)
                iwl_find_disconn_antenna(priv, average_sig, data);
 
        /* Analyze noise for rx balance */
-       average_noise[0] = data->chain_noise_a /
-                          priv->cfg->base_params->chain_noise_num_beacons;
-       average_noise[1] = data->chain_noise_b /
-                          priv->cfg->base_params->chain_noise_num_beacons;
-       average_noise[2] = data->chain_noise_c /
-                          priv->cfg->base_params->chain_noise_num_beacons;
+       average_noise[0] = data->chain_noise_a / IWL_CAL_NUM_BEACONS;
+       average_noise[1] = data->chain_noise_b / IWL_CAL_NUM_BEACONS;
+       average_noise[2] = data->chain_noise_c / IWL_CAL_NUM_BEACONS;
 
        for (i = 0; i < NUM_RX_CHAINS; i++) {
                if (!(data->disconn_array[i]) &&
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
deleted file mode 100644 (file)
index c62ddc2..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/******************************************************************************
- *
- * This file is provided under a dual BSD/GPLv2 license.  When using or
- * redistributing this file, you may do so under either license.
- *
- * GPL LICENSE SUMMARY
- *
- * Copyright(c) 2008 - 2011 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
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
- * USA
- *
- * The full GNU General Public License is included in this distribution
- * in the file called LICENSE.GPL.
- *
- * Contact Information:
- *  Intel Linux Wireless <ilw@linux.intel.com>
- * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
- *
- * BSD LICENSE
- *
- * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- *  * Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *  * 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.
- *  * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT
- * OWNER 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-
-#include <net/mac80211.h>
-
-#include "iwl-commands.h"
-#include "iwl-dev.h"
-#include "iwl-core.h"
-#include "iwl-debug.h"
-#include "iwl-agn.h"
-#include "iwl-io.h"
-
-/******************************************************************************
- *
- * EEPROM related functions
- *
-******************************************************************************/
-
-int iwl_eeprom_check_version(struct iwl_priv *priv)
-{
-       u16 eeprom_ver;
-       u16 calib_ver;
-
-       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
-       calib_ver = iwlagn_eeprom_calib_version(priv);
-
-       if (eeprom_ver < priv->cfg->eeprom_ver ||
-           calib_ver < priv->cfg->eeprom_calib_ver)
-               goto err;
-
-       IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
-                eeprom_ver, calib_ver);
-
-       return 0;
-err:
-       IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
-                 "CALIB=0x%x < 0x%x\n",
-                 eeprom_ver, priv->cfg->eeprom_ver,
-                 calib_ver,  priv->cfg->eeprom_calib_ver);
-       return -EINVAL;
-
-}
-
-int iwl_eeprom_check_sku(struct iwl_priv *priv)
-{
-       u16 radio_cfg;
-
-       if (!priv->cfg->sku) {
-               /* not using sku overwrite */
-               priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
-               if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE &&
-                   !priv->cfg->ht_params) {
-                       IWL_ERR(priv, "Invalid 11n configuration\n");
-                       return -EINVAL;
-               }
-       }
-       if (!priv->cfg->sku) {
-               IWL_ERR(priv, "Invalid device sku\n");
-               return -EINVAL;
-       }
-
-       IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
-
-       if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
-               /* not using .cfg overwrite */
-               radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
-               priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
-               priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
-               if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
-                       IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
-                               priv->cfg->valid_tx_ant,
-                               priv->cfg->valid_rx_ant);
-                       return -EINVAL;
-               }
-               IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
-                        priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
-       }
-       /*
-        * for some special cases,
-        * EEPROM did not reflect the correct antenna setting
-        * so overwrite the valid tx/rx antenna from .cfg
-        */
-       return 0;
-}
-
-void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
-{
-       const u8 *addr = iwl_eeprom_query_addr(priv,
-                                       EEPROM_MAC_ADDRESS);
-       memcpy(mac, addr, ETH_ALEN);
-}
-
-/**
- * iwl_get_max_txpower_avg - get the highest tx power from all chains.
- *     find the highest tx power from all chains for the channel
- */
-static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
-               struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
-               int element, s8 *max_txpower_in_half_dbm)
-{
-       s8 max_txpower_avg = 0; /* (dBm) */
-
-       /* Take the highest tx power from any valid chains */
-       if ((priv->cfg->valid_tx_ant & ANT_A) &&
-           (enhanced_txpower[element].chain_a_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_a_max;
-       if ((priv->cfg->valid_tx_ant & ANT_B) &&
-           (enhanced_txpower[element].chain_b_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_b_max;
-       if ((priv->cfg->valid_tx_ant & ANT_C) &&
-           (enhanced_txpower[element].chain_c_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].chain_c_max;
-       if (((priv->cfg->valid_tx_ant == ANT_AB) |
-           (priv->cfg->valid_tx_ant == ANT_BC) |
-           (priv->cfg->valid_tx_ant == ANT_AC)) &&
-           (enhanced_txpower[element].mimo2_max > max_txpower_avg))
-               max_txpower_avg =  enhanced_txpower[element].mimo2_max;
-       if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
-           (enhanced_txpower[element].mimo3_max > max_txpower_avg))
-               max_txpower_avg = enhanced_txpower[element].mimo3_max;
-
-       /*
-        * max. tx power in EEPROM is in 1/2 dBm format
-        * convert from 1/2 dBm to dBm (round-up convert)
-        * but we also do not want to loss 1/2 dBm resolution which
-        * will impact performance
-        */
-       *max_txpower_in_half_dbm = max_txpower_avg;
-       return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
-}
-
-static void
-iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
-                                   struct iwl_eeprom_enhanced_txpwr *txp,
-                                   s8 max_txpower_avg)
-{
-       int ch_idx;
-       bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
-       enum ieee80211_band band;
-
-       band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
-               IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
-
-       for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
-               struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
-
-               /* update matching channel or from common data only */
-               if (txp->channel != 0 && ch_info->channel != txp->channel)
-                       continue;
-
-               /* update matching band only */
-               if (band != ch_info->band)
-                       continue;
-
-               if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
-                       ch_info->max_power_avg = max_txpower_avg;
-                       ch_info->curr_txpow = max_txpower_avg;
-                       ch_info->scan_power = max_txpower_avg;
-               }
-
-               if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
-                       ch_info->ht40_max_power_avg = max_txpower_avg;
-       }
-}
-
-#define EEPROM_TXP_OFFS        (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
-#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
-#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
-
-#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
-                           ? # x " " : "")
-
-void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
-{
-       struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
-       int idx, entries;
-       __le16 *txp_len;
-       s8 max_txp_avg, max_txp_avg_halfdbm;
-
-       BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
-
-       /* the length is in 16-bit words, but we want entries */
-       txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
-       entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
-
-       txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
-
-       for (idx = 0; idx < entries; idx++) {
-               txp = &txp_array[idx];
-               /* skip invalid entries */
-               if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
-                       continue;
-
-               IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
-                                (txp->channel && (txp->flags &
-                                       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
-                                       "Common " : (txp->channel) ?
-                                       "Channel" : "Common",
-                                (txp->channel),
-                                TXP_CHECK_AND_PRINT(VALID),
-                                TXP_CHECK_AND_PRINT(BAND_52G),
-                                TXP_CHECK_AND_PRINT(OFDM),
-                                TXP_CHECK_AND_PRINT(40MHZ),
-                                TXP_CHECK_AND_PRINT(HT_AP),
-                                TXP_CHECK_AND_PRINT(RES1),
-                                TXP_CHECK_AND_PRINT(RES2),
-                                TXP_CHECK_AND_PRINT(COMMON_TYPE),
-                                txp->flags);
-               IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
-                                "chain_B: 0X%02x chain_C: 0X%02x\n",
-                                txp->chain_a_max, txp->chain_b_max,
-                                txp->chain_c_max);
-               IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
-                                "MIMO3: 0x%02x High 20_on_40: 0x%02x "
-                                "Low 20_on_40: 0x%02x\n",
-                                txp->mimo2_max, txp->mimo3_max,
-                                ((txp->delta_20_in_40 & 0xf0) >> 4),
-                                (txp->delta_20_in_40 & 0x0f));
-
-               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
-                                                     &max_txp_avg_halfdbm);
-
-               /*
-                * Update the user limit values values to the highest
-                * power supported by any channel
-                */
-               if (max_txp_avg > priv->tx_power_user_lmt)
-                       priv->tx_power_user_lmt = max_txp_avg;
-               if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
-                       priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
-
-               iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
-       }
-}
index 13018872f776e759b4fae748e1141b330e785642..d30714be515b38249028337f59d6238b7deff305 100644 (file)
@@ -96,11 +96,7 @@ void iwlagn_temperature(struct iwl_priv *priv)
 
 u16 iwlagn_eeprom_calib_version(struct iwl_priv *priv)
 {
-       struct iwl_eeprom_calib_hdr {
-               u8 version;
-               u8 pa_type;
-               u16 voltage;
-       } *hdr;
+       struct iwl_eeprom_calib_hdr *hdr;
 
        hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
                                                        EEPROM_CALIB_ALL);
@@ -194,433 +190,6 @@ int iwlagn_hwrate_to_mac80211_idx(u32 rate_n_flags, enum ieee80211_band band)
        return -1;
 }
 
-static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
-                                          struct ieee80211_vif *vif,
-                                          enum ieee80211_band band,
-                                          struct iwl_scan_channel *scan_ch)
-{
-       const struct ieee80211_supported_band *sband;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added = 0;
-       u16 channel = 0;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband) {
-               IWL_ERR(priv, "invalid band\n");
-               return added;
-       }
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       channel = iwl_get_single_channel_number(priv, band);
-       if (channel) {
-               scan_ch->channel = cpu_to_le16(channel);
-               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-               added++;
-       } else
-               IWL_ERR(priv, "no valid channel found\n");
-       return added;
-}
-
-static int iwl_get_channels_for_scan(struct iwl_priv *priv,
-                                    struct ieee80211_vif *vif,
-                                    enum ieee80211_band band,
-                                    u8 is_active, u8 n_probes,
-                                    struct iwl_scan_channel *scan_ch)
-{
-       struct ieee80211_channel *chan;
-       const struct ieee80211_supported_band *sband;
-       const struct iwl_channel_info *ch_info;
-       u16 passive_dwell = 0;
-       u16 active_dwell = 0;
-       int added, i;
-       u16 channel;
-
-       sband = iwl_get_hw_mode(priv, band);
-       if (!sband)
-               return 0;
-
-       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
-       passive_dwell = iwl_get_passive_dwell_time(priv, band, vif);
-
-       if (passive_dwell <= active_dwell)
-               passive_dwell = active_dwell + 1;
-
-       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
-               chan = priv->scan_request->channels[i];
-
-               if (chan->band != band)
-                       continue;
-
-               channel = chan->hw_value;
-               scan_ch->channel = cpu_to_le16(channel);
-
-               ch_info = iwl_get_channel_info(priv, band, channel);
-               if (!is_channel_valid(ch_info)) {
-                       IWL_DEBUG_SCAN(priv, "Channel %d is INVALID for this band.\n",
-                                       channel);
-                       continue;
-               }
-
-               if (!is_active || is_channel_passive(ch_info) ||
-                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
-                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               else
-                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
-
-               if (n_probes)
-                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
-
-               scan_ch->active_dwell = cpu_to_le16(active_dwell);
-               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
-
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-
-               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                * power level:
-                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                */
-               if (band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-
-               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
-                              channel, le32_to_cpu(scan_ch->type),
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                               "ACTIVE" : "PASSIVE",
-                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
-                              active_dwell : passive_dwell);
-
-               scan_ch++;
-               added++;
-       }
-
-       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
-       return added;
-}
-
-int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
-{
-       struct iwl_host_cmd cmd = {
-               .id = REPLY_SCAN_CMD,
-               .len = { sizeof(struct iwl_scan_cmd), },
-               .flags = CMD_SYNC,
-       };
-       struct iwl_scan_cmd *scan;
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       u32 rate_flags = 0;
-       u16 cmd_len;
-       u16 rx_chain = 0;
-       enum ieee80211_band band;
-       u8 n_probes = 0;
-       u8 rx_ant = hw_params(priv).valid_rx_ant;
-       u8 rate;
-       bool is_active = false;
-       int  chan_mod;
-       u8 active_chains;
-       u8 scan_tx_antennas = hw_params(priv).valid_tx_ant;
-       int ret;
-
-       lockdep_assert_held(&priv->shrd->mutex);
-
-       if (vif)
-               ctx = iwl_rxon_ctx_from_vif(vif);
-
-       if (!priv->scan_cmd) {
-               priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
-                                        IWL_MAX_SCAN_SIZE, GFP_KERNEL);
-               if (!priv->scan_cmd) {
-                       IWL_DEBUG_SCAN(priv,
-                                      "fail to allocate memory for scan\n");
-                       return -ENOMEM;
-               }
-       }
-       scan = priv->scan_cmd;
-       memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
-
-       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
-       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
-
-       if (priv->scan_type != IWL_SCAN_ROC &&
-           iwl_is_any_associated(priv)) {
-               u16 interval = 0;
-               u32 extra;
-               u32 suspend_time = 100;
-               u32 scan_suspend_time = 100;
-
-               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
-               switch (priv->scan_type) {
-               case IWL_SCAN_ROC:
-                       WARN_ON(1);
-                       break;
-               case IWL_SCAN_RADIO_RESET:
-                       interval = 0;
-                       break;
-               case IWL_SCAN_NORMAL:
-                       interval = vif->bss_conf.beacon_int;
-                       break;
-               }
-
-               scan->suspend_time = 0;
-               scan->max_out_time = cpu_to_le32(200 * 1024);
-               if (!interval)
-                       interval = suspend_time;
-
-               extra = (suspend_time / interval) << 22;
-               scan_suspend_time = (extra |
-                   ((suspend_time % interval) * 1024));
-               scan->suspend_time = cpu_to_le32(scan_suspend_time);
-               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
-                              scan_suspend_time, interval);
-       } else if (priv->scan_type == IWL_SCAN_ROC) {
-               scan->suspend_time = 0;
-               scan->max_out_time = 0;
-               scan->quiet_time = 0;
-               scan->quiet_plcp_th = 0;
-       }
-
-       switch (priv->scan_type) {
-       case IWL_SCAN_RADIO_RESET:
-               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
-               break;
-       case IWL_SCAN_NORMAL:
-               if (priv->scan_request->n_ssids) {
-                       int i, p = 0;
-                       IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
-                       for (i = 0; i < priv->scan_request->n_ssids; i++) {
-                               /* always does wildcard anyway */
-                               if (!priv->scan_request->ssids[i].ssid_len)
-                                       continue;
-                               scan->direct_scan[p].id = WLAN_EID_SSID;
-                               scan->direct_scan[p].len =
-                                       priv->scan_request->ssids[i].ssid_len;
-                               memcpy(scan->direct_scan[p].ssid,
-                                      priv->scan_request->ssids[i].ssid,
-                                      priv->scan_request->ssids[i].ssid_len);
-                               n_probes++;
-                               p++;
-                       }
-                       is_active = true;
-               } else
-                       IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
-               break;
-       case IWL_SCAN_ROC:
-               IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
-               break;
-       }
-
-       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
-       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
-       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
-
-       switch (priv->scan_band) {
-       case IEEE80211_BAND_2GHZ:
-               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
-               chan_mod = le32_to_cpu(
-                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
-                                               RXON_FLG_CHANNEL_MODE_MSK)
-                                      >> RXON_FLG_CHANNEL_MODE_POS;
-               if (chan_mod == CHANNEL_MODE_PURE_40) {
-                       rate = IWL_RATE_6M_PLCP;
-               } else {
-                       rate = IWL_RATE_1M_PLCP;
-                       rate_flags = RATE_MCS_CCK_MSK;
-               }
-               /*
-                * Internal scans are passive, so we can indiscriminately set
-                * the BT ignore flag on 2.4 GHz since it applies to TX only.
-                */
-               if (priv->cfg->bt_params &&
-                   priv->cfg->bt_params->advanced_bt_coexist)
-                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
-               break;
-       case IEEE80211_BAND_5GHZ:
-               rate = IWL_RATE_6M_PLCP;
-               break;
-       default:
-               IWL_WARN(priv, "Invalid scan band\n");
-               return -EIO;
-       }
-
-       /*
-        * If active scanning is requested but a certain channel is
-        * marked passive, we can do active scanning if we detect
-        * transmissions.
-        *
-        * There is an issue with some firmware versions that triggers
-        * a sysassert on a "good CRC threshold" of zero (== disabled),
-        * on a radar channel even though this means that we should NOT
-        * send probes.
-        *
-        * The "good CRC threshold" is the number of frames that we
-        * need to receive during our dwell time on a channel before
-        * sending out probes -- setting this to a huge value will
-        * mean we never reach it, but at the same time work around
-        * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
-        * here instead of IWL_GOOD_CRC_TH_DISABLED.
-        *
-        * This was fixed in later versions along with some other
-        * scan changes, and the threshold behaves as a flag in those
-        * versions.
-        */
-       if (priv->new_scan_threshold_behaviour)
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-                                               IWL_GOOD_CRC_TH_DISABLED;
-       else
-               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
-                                               IWL_GOOD_CRC_TH_NEVER;
-
-       band = priv->scan_band;
-
-       if (priv->cfg->scan_rx_antennas[band])
-               rx_ant = priv->cfg->scan_rx_antennas[band];
-
-       if (band == IEEE80211_BAND_2GHZ &&
-           priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist) {
-               /* transmit 2.4 GHz probes only on first antenna */
-               scan_tx_antennas = first_antenna(scan_tx_antennas);
-       }
-
-       priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band],
-                                                   scan_tx_antennas);
-       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
-       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
-
-       /* In power save mode use one chain, otherwise use all chains */
-       if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) {
-               /* rx_ant has been set to all valid chains previously */
-               active_chains = rx_ant &
-                               ((u8)(priv->chain_noise_data.active_chains));
-               if (!active_chains)
-                       active_chains = rx_ant;
-
-               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
-                               priv->chain_noise_data.active_chains);
-
-               rx_ant = first_antenna(active_chains);
-       }
-       if (priv->cfg->bt_params &&
-           priv->cfg->bt_params->advanced_bt_coexist &&
-           priv->bt_full_concurrent) {
-               /* operated as 1x1 in full concurrency mode */
-               rx_ant = first_antenna(rx_ant);
-       }
-
-       /* MIMO is not used here, but value is required */
-       rx_chain |=
-               hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
-       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
-       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
-       scan->rx_chain = cpu_to_le16(rx_chain);
-       switch (priv->scan_type) {
-       case IWL_SCAN_NORMAL:
-               cmd_len = iwl_fill_probe_req(priv,
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       vif->addr,
-                                       priv->scan_request->ie,
-                                       priv->scan_request->ie_len,
-                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
-               break;
-       case IWL_SCAN_RADIO_RESET:
-       case IWL_SCAN_ROC:
-               /* use bcast addr, will not be transmitted but must be valid */
-               cmd_len = iwl_fill_probe_req(priv,
-                                       (struct ieee80211_mgmt *)scan->data,
-                                       iwl_bcast_addr, NULL, 0,
-                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
-               break;
-       default:
-               BUG();
-       }
-       scan->tx_cmd.len = cpu_to_le16(cmd_len);
-
-       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
-                              RXON_FILTER_BCON_AWARE_MSK);
-
-       switch (priv->scan_type) {
-       case IWL_SCAN_RADIO_RESET:
-               scan->channel_count =
-                       iwl_get_single_channel_for_scan(priv, vif, band,
-                               (void *)&scan->data[cmd_len]);
-               break;
-       case IWL_SCAN_NORMAL:
-               scan->channel_count =
-                       iwl_get_channels_for_scan(priv, vif, band,
-                               is_active, n_probes,
-                               (void *)&scan->data[cmd_len]);
-               break;
-       case IWL_SCAN_ROC: {
-               struct iwl_scan_channel *scan_ch;
-
-               scan->channel_count = 1;
-
-               scan_ch = (void *)&scan->data[cmd_len];
-               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
-               scan_ch->channel =
-                       cpu_to_le16(priv->hw_roc_channel->hw_value);
-               scan_ch->active_dwell =
-               scan_ch->passive_dwell =
-                       cpu_to_le16(priv->hw_roc_duration);
-
-               /* Set txpower levels to defaults */
-               scan_ch->dsp_atten = 110;
-
-               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
-                * power level:
-                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
-                */
-               if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
-                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
-               else
-                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
-               }
-               break;
-       }
-
-       if (scan->channel_count == 0) {
-               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
-               return -EIO;
-       }
-
-       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
-           scan->channel_count * sizeof(struct iwl_scan_channel);
-       cmd.data[0] = scan;
-       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
-       scan->len = cpu_to_le16(cmd.len[0]);
-
-       /* set scan bit here for PAN params */
-       set_bit(STATUS_SCAN_HW, &priv->shrd->status);
-
-       ret = iwlagn_set_pan_params(priv);
-       if (ret)
-               return ret;
-
-       ret = iwl_trans_send_cmd(trans(priv), &cmd);
-       if (ret) {
-               clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-               iwlagn_set_pan_params(priv);
-       }
-
-       return ret;
-}
-
 int iwlagn_manage_ibss_station(struct iwl_priv *priv,
                               struct ieee80211_vif *vif, bool add)
 {
@@ -1136,8 +705,9 @@ static void iwlagn_set_kill_msk(struct iwl_priv *priv,
        }
 }
 
-void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb)
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
 {
        unsigned long flags;
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -1146,7 +716,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
 
        if (priv->bt_enable_flag == IWLAGN_BT_FLAG_COEX_MODE_DISABLED) {
                /* bt coex disabled */
-               return;
+               return 0;
        }
 
        IWL_DEBUG_COEX(priv, "BT Coex notification:\n");
@@ -1188,6 +758,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
        spin_lock_irqsave(&priv->shrd->lock, flags);
        priv->bt_ci_compliance = coex->bt_ci_compliance;
        spin_unlock_irqrestore(&priv->shrd->lock, flags);
+       return 0;
 }
 
 void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv)
index ffee15ba06a8a53abf6c051713d6950f4011cad2..c14f8d6fd7d8d36878f071ba907ebe0661f5c848 100644 (file)
@@ -346,7 +346,7 @@ static void rs_program_fix_rate(struct iwl_priv *priv,
 {
        struct iwl_station_priv *sta_priv =
                container_of(lq_sta, struct iwl_station_priv, lq_sta);
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        lq_sta->active_legacy_rate = 0x0FFF;    /* 1 - 54 MBits, includes CCK */
        lq_sta->active_siso_rate   = 0x1FD0;    /* 6 - 60 MBits, no 9, no CCK */
@@ -710,7 +710,7 @@ static int rs_toggle_antenna(u32 valid_ant, u32 *rate_n_flags,
 static bool rs_use_green(struct ieee80211_sta *sta)
 {
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        return (sta->ht_cap.cap & IEEE80211_HT_CAP_GRN_FLD) &&
                !(ctx->ht.non_gf_sta_present);
@@ -917,7 +917,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        struct iwl_scale_tbl_info tbl_type;
        struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
 
@@ -1283,7 +1283,7 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv,
        s32 rate;
        s8 is_green = lq_sta->is_green;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1339,7 +1339,7 @@ static int rs_switch_to_mimo3(struct iwl_priv *priv,
        s32 rate;
        s8 is_green = lq_sta->is_green;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -1396,7 +1396,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv,
        u8 is_green = lq_sta->is_green;
        s32 rate;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        if (!conf_is_ht(conf) || !sta->ht_cap.ht_supported)
                return -1;
@@ -2263,7 +2263,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        u8 tid = IWL_MAX_TID_COUNT;
        struct iwl_tid_data *tid_data;
        struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
-       struct iwl_rxon_context *ctx = sta_priv->common.ctx;
+       struct iwl_rxon_context *ctx = sta_priv->ctx;
 
        IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
 
@@ -2706,7 +2706,7 @@ static void rs_initialize_lq(struct iwl_priv *priv,
                return;
 
        sta_priv = (void *)sta->drv_priv;
-       ctx = sta_priv->common.ctx;
+       ctx = sta_priv->ctx;
 
        i = lq_sta->last_txrate_idx;
 
index 00e6fc59e4590967625ef963c5ab58d4325b210b..ca632f9b1cc879bdc0ee69605db5590ca55bdd93 100644 (file)
@@ -370,7 +370,7 @@ int iwlagn_set_pan_params(struct iwl_priv *priv)
                        slot1 = IWL_MIN_SLOT_TIME;
                } else if (!ctx_pan->vif->bss_conf.idle &&
                           !ctx_pan->vif->bss_conf.assoc) {
-                       slot1 = bcnint * 3 - IWL_MIN_SLOT_TIME;
+                       slot1 = dtim * bcnint * 3 - IWL_MIN_SLOT_TIME;
                        slot0 = IWL_MIN_SLOT_TIME;
                }
        } else if (ctx_pan->vif) {
index 92ba8cd0ecd50f12196def3916a6df7e3a2119c0..c27180a73351752b59015900f90f174b34c0929d 100644 (file)
@@ -114,9 +114,6 @@ static bool iwl_within_ct_kill_margin(struct iwl_priv *priv)
        s32 temp = priv->temperature; /* degrees CELSIUS except specified */
        bool within_margin = false;
 
-       if (priv->cfg->base_params->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
        if (!priv->thermal_throttle.advanced_tt)
                within_margin = ((temp + IWL_TT_CT_KILL_MARGIN) >=
                                CT_KILL_THRESHOLD_LEGACY) ? true : false;
@@ -209,7 +206,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
 {
        if (stop) {
                IWL_DEBUG_TEMP(priv, "Stop all queues\n");
-               if (priv->shrd->mac80211_registered)
+               if (priv->mac80211_registered)
                        ieee80211_stop_queues(priv->hw);
                IWL_DEBUG_TEMP(priv,
                                "Schedule 5 seconds CT_KILL Timer\n");
@@ -217,7 +214,7 @@ static void iwl_perform_ct_kill_task(struct iwl_priv *priv,
                          jiffies + CT_KILL_EXIT_DURATION * HZ);
        } else {
                IWL_DEBUG_TEMP(priv, "Wake all queues\n");
-               if (priv->shrd->mac80211_registered)
+               if (priv->mac80211_registered)
                        ieee80211_wake_queues(priv->hw);
        }
 }
@@ -591,9 +588,6 @@ static void iwl_bg_tt_work(struct work_struct *work)
        if (test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
                return;
 
-       if (priv->cfg->base_params->temperature_kelvin)
-               temp = KELVIN_TO_CELSIUS(priv->temperature);
-
        if (!priv->thermal_throttle.advanced_tt)
                iwl_legacy_tt_handler(priv, temp, false);
        else
@@ -641,11 +635,13 @@ void iwl_tt_initialize(struct iwl_priv *priv)
 
        if (priv->cfg->base_params->adv_thermal_throttle) {
                IWL_DEBUG_TEMP(priv, "Advanced Thermal Throttling\n");
-               tt->restriction = kzalloc(sizeof(struct iwl_tt_restriction) *
-                                        IWL_TI_STATE_MAX, GFP_KERNEL);
-               tt->transaction = kzalloc(sizeof(struct iwl_tt_trans) *
-                       IWL_TI_STATE_MAX * (IWL_TI_STATE_MAX - 1),
-                       GFP_KERNEL);
+               tt->restriction = kcalloc(IWL_TI_STATE_MAX,
+                                         sizeof(struct iwl_tt_restriction),
+                                         GFP_KERNEL);
+               tt->transaction = kcalloc(IWL_TI_STATE_MAX *
+                                         (IWL_TI_STATE_MAX - 1),
+                                         sizeof(struct iwl_tt_trans),
+                                         GFP_KERNEL);
                if (!tt->restriction || !tt->transaction) {
                        IWL_ERR(priv, "Fallback to Legacy Throttling\n");
                        priv->thermal_throttle.advanced_tt = false;
index ba5c514c4a431cc33c9c0341be13342f1c076137..0e5d6498be21b7aa5600a1b065925f533411b136 100644 (file)
@@ -313,6 +313,9 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                iwl_sta_modify_sleep_tx_count(priv, sta_id, 1);
        }
 
+       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               is_agg = true;
+
        /* irqs already disabled/saved above when locking priv->shrd->lock */
        spin_lock(&priv->shrd->sta_lock);
 
@@ -322,10 +325,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                goto drop_unlock_sta;
 
        memset(dev_cmd, 0, sizeof(*dev_cmd));
-       tx_cmd = &dev_cmd->cmd.tx;
-
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
+       tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
 
        /* Total # bytes to be transmitted */
        len = (u16)skb->len;
@@ -342,6 +342,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
 
        iwl_update_stats(priv, true, fc, len);
 
+       memset(&info->status, 0, sizeof(info->status));
+
        info->driver_data[0] = ctx;
        info->driver_data[1] = dev_cmd;
 
@@ -580,6 +582,9 @@ static void iwl_rx_reply_tx_agg(struct iwl_priv *priv,
                IWL_DEBUG_COEX(priv, "receive reply tx w/ bt_kill\n");
        }
 
+       if (tx_resp->frame_count == 1)
+               return;
+
        /* Construct bit-map of pending frames within Tx window */
        for (i = 0; i < tx_resp->frame_count; i++) {
                u16 fstatus = le16_to_cpu(frame_status[i].status);
@@ -736,7 +741,8 @@ static void iwl_check_abort_status(struct iwl_priv *priv,
        }
 }
 
-void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -824,6 +830,7 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
 
        iwl_check_abort_status(priv, tx_resp->frame_count, status);
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       return 0;
 }
 
 /**
@@ -832,8 +839,9 @@ void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
  * Handles block-acknowledge notification from device, which reports success
  * of frames sent via aggregation.
  */
-void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                                          struct iwl_rx_mem_buffer *rxb)
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                  struct iwl_rx_mem_buffer *rxb,
+                                  struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
@@ -857,7 +865,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
        if (scd_flow >= hw_params(priv).max_txq_num) {
                IWL_ERR(priv,
                        "BUG_ON scd_flow is bigger than number of queues\n");
-               return;
+               return 0;
        }
 
        sta_id = ba_resp->sta_id;
@@ -877,14 +885,14 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                        "BA scd_flow %d does not match txq_id %d\n",
                        scd_flow, agg->txq_id);
                spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-               return;
+               return 0;
        }
 
        if (unlikely(!agg->wait_for_ba)) {
                if (unlikely(ba_resp->bitmap))
                        IWL_ERR(priv, "Received BA when not expected\n");
                spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
-               return;
+               return 0;
        }
 
        IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
@@ -901,7 +909,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                           ba_resp->scd_ssn);
 
        /* Mark that the expected block-ack response arrived */
-       agg->wait_for_ba = 0;
+       agg->wait_for_ba = false;
 
        /* Sanity check values reported by uCode */
        if (ba_resp->txed_2_done > ba_resp->txed) {
@@ -935,7 +943,10 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                else
                        WARN_ON_ONCE(1);
 
-               if (freed == 0) {
+               info = IEEE80211_SKB_CB(skb);
+               kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+
+               if (freed == 1) {
                        /* this is the first skb we deliver in this batch */
                        /* put the rate scaling data there */
                        info = IEEE80211_SKB_CB(skb);
@@ -948,11 +959,9 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
                                                    info);
                }
 
-               info = IEEE80211_SKB_CB(skb);
-               kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
-
                ieee80211_tx_status_irqsafe(priv->hw, skb);
        }
 
        spin_unlock_irqrestore(&priv->shrd->sta_lock, flags);
+       return 0;
 }
index a7b8914538690b30dbcef4abc979895c1deb10bc..b4e1e7c4c3148af02c1405bec1fe21003b2003d1 100644 (file)
@@ -114,13 +114,8 @@ static int iwlagn_load_section(struct iwl_priv *priv, const char *name,
                FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD);
 
        IWL_DEBUG_FW(priv, "%s uCode section being loaded...\n", name);
-       ret = wait_event_interruptible_timeout(priv->shrd->wait_command_queue,
-                                       priv->ucode_write_complete, 5 * HZ);
-       if (ret == -ERESTARTSYS) {
-               IWL_ERR(priv, "Could not load the %s uCode section due "
-                       "to interrupt\n", name);
-               return ret;
-       }
+       ret = wait_event_timeout(priv->shrd->wait_command_queue,
+                                priv->ucode_write_complete, 5 * HZ);
        if (!ret) {
                IWL_ERR(priv, "Could not load the %s uCode section\n",
                        name);
@@ -164,7 +159,7 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
 {
        struct iwl_calib_temperature_offset_cmd cmd;
        __le16 *offset_calib =
-               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_TEMPERATURE);
+               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
 
        memset(&cmd, 0, sizeof(cmd));
        iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
@@ -178,6 +173,42 @@ static int iwlagn_set_temperature_offset_calib(struct iwl_priv *priv)
                             (u8 *)&cmd, sizeof(cmd));
 }
 
+static int iwlagn_set_temperature_offset_calib_v2(struct iwl_priv *priv)
+{
+       struct iwl_calib_temperature_offset_v2_cmd cmd;
+       __le16 *offset_calib_high = (__le16 *)iwl_eeprom_query_addr(priv,
+                                    EEPROM_KELVIN_TEMPERATURE);
+       __le16 *offset_calib_low =
+               (__le16 *)iwl_eeprom_query_addr(priv, EEPROM_RAW_TEMPERATURE);
+       struct iwl_eeprom_calib_hdr *hdr;
+
+       memset(&cmd, 0, sizeof(cmd));
+       iwl_set_calib_hdr(&cmd.hdr, IWL_PHY_CALIBRATE_TEMP_OFFSET_CMD);
+       hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv,
+                                                       EEPROM_CALIB_ALL);
+       memcpy(&cmd.radio_sensor_offset_high, offset_calib_high,
+               sizeof(*offset_calib_high));
+       memcpy(&cmd.radio_sensor_offset_low, offset_calib_low,
+               sizeof(*offset_calib_low));
+       if (!(cmd.radio_sensor_offset_low)) {
+               IWL_DEBUG_CALIB(priv, "no info in EEPROM, use default\n");
+               cmd.radio_sensor_offset_low = DEFAULT_RADIO_SENSOR_OFFSET;
+               cmd.radio_sensor_offset_high = DEFAULT_RADIO_SENSOR_OFFSET;
+       }
+       memcpy(&cmd.burntVoltageRef, &hdr->voltage,
+               sizeof(hdr->voltage));
+
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset high: %d\n",
+                       le16_to_cpu(cmd.radio_sensor_offset_high));
+       IWL_DEBUG_CALIB(priv, "Radio sensor offset low: %d\n",
+                       le16_to_cpu(cmd.radio_sensor_offset_low));
+       IWL_DEBUG_CALIB(priv, "Voltage Ref: %d\n",
+                       le16_to_cpu(cmd.burntVoltageRef));
+
+       return iwl_calib_set(&priv->calib_results[IWL_CALIB_TEMP_OFFSET],
+                            (u8 *)&cmd, sizeof(cmd));
+}
+
 static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
 {
        struct iwl_calib_cfg_cmd calib_cfg_cmd;
@@ -197,8 +228,9 @@ static int iwlagn_send_calib_cfg(struct iwl_priv *priv)
        return iwl_trans_send_cmd(trans(priv), &cmd);
 }
 
-void iwlagn_rx_calib_result(struct iwl_priv *priv,
-                            struct iwl_rx_mem_buffer *rxb)
+int iwlagn_rx_calib_result(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw;
@@ -231,9 +263,10 @@ void iwlagn_rx_calib_result(struct iwl_priv *priv,
        default:
                IWL_ERR(priv, "Unknown calibration notification %d\n",
                          hdr->op_code);
-               return;
+               return -1;
        }
        iwl_calib_set(&priv->calib_results[index], pkt->u.raw, len);
+       return 0;
 }
 
 int iwlagn_init_alive_start(struct iwl_priv *priv)
@@ -263,8 +296,12 @@ int iwlagn_init_alive_start(struct iwl_priv *priv)
         * temperature offset calibration is only needed for runtime ucode,
         * so prepare the value now.
         */
-       if (priv->cfg->need_temp_offset_calib)
-               return iwlagn_set_temperature_offset_calib(priv);
+       if (priv->cfg->need_temp_offset_calib) {
+               if (priv->cfg->temp_offset_v2)
+                       return iwlagn_set_temperature_offset_calib_v2(priv);
+               else
+                       return iwlagn_set_temperature_offset_calib(priv);
+       }
 
        return 0;
 }
index 6057e18f688c0226a57fdf38aadea15a381f1355..baaf48616cc7afc11e4e9131e8ad2482f53f8996 100644 (file)
@@ -453,122 +453,6 @@ static void iwl_bg_tx_flush(struct work_struct *work)
        iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
 }
 
-/*****************************************************************************
- *
- * sysfs attributes
- *
- *****************************************************************************/
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-
-/*
- * The following adds a new attribute to the sysfs representation
- * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/)
- * used for controlling the debug level.
- *
- * See the level definitions in iwl for details.
- *
- * The debug_level being managed using sysfs below is a per device debug
- * level that is used instead of the global debug level if it (the per
- * device debug level) is set.
- */
-static ssize_t show_debug_level(struct device *d,
-                               struct device_attribute *attr, char *buf)
-{
-       struct iwl_shared *shrd = dev_get_drvdata(d);
-       return sprintf(buf, "0x%08X\n", iwl_get_debug_level(shrd));
-}
-static ssize_t store_debug_level(struct device *d,
-                               struct device_attribute *attr,
-                                const char *buf, size_t count)
-{
-       struct iwl_shared *shrd = dev_get_drvdata(d);
-       struct iwl_priv *priv = shrd->priv;
-       unsigned long val;
-       int ret;
-
-       ret = strict_strtoul(buf, 0, &val);
-       if (ret)
-               IWL_ERR(priv, "%s is not in hex or decimal form.\n", buf);
-       else {
-               shrd->dbg_level_dev = val;
-               if (iwl_alloc_traffic_mem(priv))
-                       IWL_ERR(shrd->priv,
-                               "Not enough memory to generate traffic log\n");
-       }
-       return strnlen(buf, count);
-}
-
-static DEVICE_ATTR(debug_level, S_IWUSR | S_IRUGO,
-                       show_debug_level, store_debug_level);
-
-
-#endif /* CONFIG_IWLWIFI_DEBUG */
-
-
-static ssize_t show_temperature(struct device *d,
-                               struct device_attribute *attr, char *buf)
-{
-       struct iwl_shared *shrd = dev_get_drvdata(d);
-       struct iwl_priv *priv = shrd->priv;
-
-       if (!iwl_is_alive(priv->shrd))
-               return -EAGAIN;
-
-       return sprintf(buf, "%d\n", priv->temperature);
-}
-
-static DEVICE_ATTR(temperature, S_IRUGO, show_temperature, NULL);
-
-static ssize_t show_tx_power(struct device *d,
-                            struct device_attribute *attr, char *buf)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-
-       if (!iwl_is_ready_rf(priv->shrd))
-               return sprintf(buf, "off\n");
-       else
-               return sprintf(buf, "%d\n", priv->tx_power_user_lmt);
-}
-
-static ssize_t store_tx_power(struct device *d,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       struct iwl_priv *priv = dev_get_drvdata(d);
-       unsigned long val;
-       int ret;
-
-       ret = strict_strtoul(buf, 10, &val);
-       if (ret)
-               IWL_INFO(priv, "%s is not in decimal form.\n", buf);
-       else {
-               ret = iwl_set_tx_power(priv, val, false);
-               if (ret)
-                       IWL_ERR(priv, "failed setting tx power (0x%d).\n",
-                               ret);
-               else
-                       ret = count;
-       }
-       return ret;
-}
-
-static DEVICE_ATTR(tx_power, S_IWUSR | S_IRUGO, show_tx_power, store_tx_power);
-
-static struct attribute *iwl_sysfs_entries[] = {
-       &dev_attr_temperature.attr,
-       &dev_attr_tx_power.attr,
-#ifdef CONFIG_IWLWIFI_DEBUG
-       &dev_attr_debug_level.attr,
-#endif
-       NULL
-};
-
-static struct attribute_group iwl_attribute_group = {
-       .name = NULL,           /* put in device directory */
-       .attrs = iwl_sysfs_entries,
-};
-
 /******************************************************************************
  *
  * uCode download functions
@@ -1259,13 +1143,6 @@ static void iwl_ucode_callback(const struct firmware *ucode_raw, void *context)
        if (err)
                IWL_ERR(priv, "failed to create debugfs files. Ignoring error: %d\n", err);
 
-       err = sysfs_create_group(&(priv->bus->dev->kobj),
-                                       &iwl_attribute_group);
-       if (err) {
-               IWL_ERR(priv, "failed to create sysfs device attributes\n");
-               goto out_unbind;
-       }
-
        /* We have our copies now, allow OS release its copies */
        release_firmware(ucode_raw);
        complete(&priv->firmware_loading_complete);
@@ -1519,9 +1396,11 @@ static void __iwl_down(struct iwl_priv *priv)
        if (!exit_pending)
                clear_bit(STATUS_EXIT_PENDING, &priv->shrd->status);
 
-       if (priv->shrd->mac80211_registered)
+       if (priv->mac80211_registered)
                ieee80211_stop_queues(priv->hw);
 
+       iwl_trans_stop_device(trans(priv));
+
        /* Clear out all status bits but a few that are stable across reset */
        priv->shrd->status &=
                        test_bit(STATUS_RF_KILL_HW, &priv->shrd->status) <<
@@ -1533,8 +1412,6 @@ static void __iwl_down(struct iwl_priv *priv)
                        test_bit(STATUS_EXIT_PENDING, &priv->shrd->status) <<
                                STATUS_EXIT_PENDING;
 
-       iwl_trans_stop_device(trans(priv));
-
        dev_kfree_skb(priv->beacon_skb);
        priv->beacon_skb = NULL;
 }
@@ -1868,7 +1745,7 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
                IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
                return ret;
        }
-       priv->shrd->mac80211_registered = 1;
+       priv->mac80211_registered = 1;
 
        return 0;
 }
@@ -1924,7 +1801,7 @@ static void iwlagn_mac_stop(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static int iwlagn_send_patterns(struct iwl_priv *priv,
                                struct cfg80211_wowlan *wowlan)
 {
@@ -1999,7 +1876,7 @@ struct wowlan_key_data {
        bool error, use_rsc_tsc, use_tkip;
 };
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 static void iwlagn_convert_p1k(u16 *p1k, __le16 *out)
 {
        int i;
@@ -2636,7 +2513,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
        mutex_lock(&priv->shrd->mutex);
        IWL_DEBUG_INFO(priv, "proceeding to add station %pM\n",
                        sta->addr);
-       sta_priv->common.sta_id = IWL_INVALID_STATION;
+       sta_priv->sta_id = IWL_INVALID_STATION;
 
        atomic_set(&sta_priv->pending_frames, 0);
        if (vif->type == NL80211_IFTYPE_AP)
@@ -2652,7 +2529,7 @@ static int iwlagn_mac_sta_add(struct ieee80211_hw *hw,
                return ret;
        }
 
-       sta_priv->common.sta_id = sta_id;
+       sta_priv->sta_id = sta_id;
 
        /* Initialize rate scaling */
        IWL_DEBUG_INFO(priv, "Initializing rate scaling for station %pM\n",
@@ -2893,15 +2770,6 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->shrd->mutex);
 
-       /*
-        * TODO: Remove this hack! Firmware needs to be updated
-        * to allow longer off-channel periods in scanning for
-        * this use case, based on a flag (and we'll need an API
-        * flag in the firmware when it has that).
-        */
-       if (iwl_is_associated(priv, IWL_RXON_CTX_BSS) && duration > 80)
-               duration = 80;
-
        if (test_bit(STATUS_SCAN_HW, &priv->shrd->status)) {
                err = -EBUSY;
                goto out;
@@ -2910,6 +2778,7 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
        priv->hw_roc_channel = channel;
        priv->hw_roc_chantype = channel_type;
        priv->hw_roc_duration = duration;
+       priv->hw_roc_start_notified = false;
        cancel_delayed_work(&priv->hw_roc_disable_work);
 
        if (!ctx->is_active) {
@@ -3208,7 +3077,7 @@ struct ieee80211_ops iwlagn_hw_ops = {
        .tx = iwlagn_mac_tx,
        .start = iwlagn_mac_start,
        .stop = iwlagn_mac_stop,
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
        .suspend = iwlagn_mac_suspend,
        .resume = iwlagn_mac_resume,
 #endif
@@ -3314,10 +3183,9 @@ int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
        priv = hw->priv;
        priv->bus = bus;
        priv->shrd = &priv->_shrd;
+       bus->shrd = priv->shrd;
        priv->shrd->bus = bus;
        priv->shrd->priv = priv;
-       priv->shrd->hw = hw;
-       bus_set_drv_data(priv->bus, priv->shrd);
 
        priv->shrd->trans = trans_ops->alloc(priv->shrd);
        if (priv->shrd->trans == NULL) {
@@ -3480,8 +3348,6 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        IWL_DEBUG_INFO(priv, "*** UNLOAD DRIVER ***\n");
 
        iwl_dbgfs_unregister(priv);
-       sysfs_remove_group(&priv->bus->dev->kobj,
-                          &iwl_attribute_group);
 
        /* ieee80211_unregister_hw call wil cause iwl_mac_stop to
         * to be called and iwl_down since we are removing the device
@@ -3492,9 +3358,9 @@ void __devexit iwl_remove(struct iwl_priv * priv)
        iwl_testmode_cleanup(priv);
        iwl_leds_exit(priv);
 
-       if (priv->shrd->mac80211_registered) {
+       if (priv->mac80211_registered) {
                ieee80211_unregister_hw(priv->hw);
-               priv->shrd->mac80211_registered = 0;
+               priv->mac80211_registered = 0;
        }
 
        iwl_tt_exit(priv);
@@ -3518,8 +3384,6 @@ void __devexit iwl_remove(struct iwl_priv * priv)
 
        iwl_trans_free(trans(priv));
 
-       bus_set_drv_data(priv->bus, NULL);
-
        iwl_uninit_drv(priv);
 
        dev_kfree_skb(priv->beacon_skb);
index 4bc1f4669e5a1afe873bd6ba08e174c84970e6cc..2a297d1e6bc7b0db59051036590a421fe4ac7a27 100644 (file)
@@ -88,8 +88,9 @@ void iwlagn_bss_info_changed(struct ieee80211_hw *hw,
                             u32 changes);
 
 /* uCode */
-void iwlagn_rx_calib_result(struct iwl_priv *priv,
-                        struct iwl_rx_mem_buffer *rxb);
+int iwlagn_rx_calib_result(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_device_cmd *cmd);
 int iwlagn_send_bt_env(struct iwl_priv *priv, u8 action, u8 type);
 void iwlagn_send_prio_tbl(struct iwl_priv *priv);
 int iwlagn_run_init_ucode(struct iwl_priv *priv);
@@ -116,9 +117,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn);
 int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
                       struct ieee80211_sta *sta, u16 tid);
-void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb);
-void iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
+                                  struct iwl_rx_mem_buffer *rxb,
+                                  struct iwl_device_cmd *cmd);
+int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
 
 static inline u32 iwl_tx_status_to_mac80211(u32 status)
 {
@@ -146,7 +149,6 @@ static inline bool iwl_is_tx_success(u32 status)
 u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx, u8 valid);
 
 /* scan */
-int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif);
 void iwlagn_post_scan(struct iwl_priv *priv);
 void iwlagn_disable_roc(struct iwl_priv *priv);
 
@@ -156,8 +158,9 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
 
 /* bt coex */
 void iwlagn_send_advance_bt_config(struct iwl_priv *priv);
-void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb);
+int iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_device_cmd *cmd);
 void iwlagn_bt_rx_handler_setup(struct iwl_priv *priv);
 void iwlagn_bt_setup_deferred_work(struct iwl_priv *priv);
 void iwlagn_bt_cancel_deferred_work(struct iwl_priv *priv);
index 83aed46673e17d0ad6f9b51ec5e4ef541f15a7a5..08b97594e3057c303237fda4846ea3b92240ee43 100644 (file)
 #ifndef __iwl_bus_h__
 #define __iwl_bus_h__
 
-/*This file includes the declaration that are exported from the bus layer */
-
 #include <linux/types.h>
 #include <linux/spinlock.h>
 
+/**
+ * DOC: Bus layer - role and goal
+ *
+ * iwl-bus.h defines the API to the bus layer of the iwlwifi driver.
+ * The bus layer is responsible for doing very basic bus operations that are
+ * listed in the iwl_bus_ops structure.
+ * The bus layer registers to the bus driver, advertises the supported HW and
+ * gets notifications about enumeration, suspend, resume.
+ * For the moment, the bus layer is not a linux kernel module as itself, and
+ * the module_init function of the driver must call the bus specific
+ * registration functions. These functions are listed at the end of this file.
+ * For the moment, there is only one implementation of this interface: PCI-e.
+ * This implementation is iwl-pci.c
+ */
+
+/**
+ * DOC: encapsulation and type safety
+ *
+ * The iwl_bus describes the data that is shared amongst all the bus layer
+ * implementations. This data is visible to other layers. Data in the bus
+ * specific area is not visible outside the bus specific implementation.
+ * iwl_bus holds a pointer to iwl_shared which holds pointer to all the other
+ * layers of the driver (iwl_priv, iwl_trans). In fact, this is the way to go
+ * when the transport layer needs to call a function of another layer.
+ *
+ * In order to achieve encapsulation, iwl_priv cannot be dereferenced from the
+ * bus layer. Type safety is still kept since functions that gets iwl_priv gets
+ * a typed pointer (as opposed to void *).
+ */
+
+/**
+ * DOC: probe flow
+ *
+ * The module_init calls the bus specific registration function. The
+ * registration to the bus layer will trigger an enumeration of the bus which
+ * will call the bus specific probe function.
+ * The first thing this function must do is to allocate the memory needed by
+ * iwl_bus + the bus_specific data.
+ * Once the bus specific probe function has configured the hardware, it
+ * chooses the appropriate transport layer and calls iwl_probe that will run
+ * the bus independent probe flow.
+ *
+ * Note: The bus specific code must set the following data in iwl_bus before it
+ *       calls iwl_probe:
+ *     * bus->dev
+ *     * bus->irq
+ *     * bus->ops
+ */
+
 struct iwl_shared;
 struct iwl_bus;
 
 /**
  * struct iwl_bus_ops - bus specific operations
  * @get_pm_support: must returns true if the bus can go to sleep
- * @apm_config: will be called during the config of the APM configuration
- * @set_drv_data: set the shared data pointer to the bus layer
+ * @apm_config: will be called during the config of the APM
  * @get_hw_id: prints the hw_id in the provided buffer
  * @write8: write a byte to register at offset ofs
  * @write32: write a dword to register at offset ofs
@@ -84,7 +130,6 @@ struct iwl_bus;
 struct iwl_bus_ops {
        bool (*get_pm_support)(struct iwl_bus *bus);
        void (*apm_config)(struct iwl_bus *bus);
-       void (*set_drv_data)(struct iwl_bus *bus, struct iwl_shared *shrd);
        void (*get_hw_id)(struct iwl_bus *bus, char buf[], int buf_len);
        void (*write8)(struct iwl_bus *bus, u32 ofs, u8 val);
        void (*write32)(struct iwl_bus *bus, u32 ofs, u32 val);
@@ -93,14 +138,18 @@ struct iwl_bus_ops {
 
 /**
  * struct iwl_bus - bus common data
- * @dev - pointer to struct device * that represent the device
+ *
+ * This data is common to all bus layer implementations.
+ *
+ * @dev - pointer to struct device * that represents the device
  * @ops - pointer to iwl_bus_ops
  * @shrd - pointer to iwl_shared which holds shared data from the upper layer
+ *     NB: for the time being this needs to be set by the upper layer since
+ *     it allocates the shared data
  * @irq - the irq number for the device
  * @reg_lock - protect hw register access
  */
 struct iwl_bus {
-       /* Common data to all buses */
        struct device *dev;
        const struct iwl_bus_ops *ops;
        struct iwl_shared *shrd;
@@ -123,12 +172,6 @@ static inline void bus_apm_config(struct iwl_bus *bus)
        bus->ops->apm_config(bus);
 }
 
-static inline void bus_set_drv_data(struct iwl_bus *bus,
-                               struct iwl_shared *shrd)
-{
-       bus->ops->set_drv_data(bus, shrd);
-}
-
 static inline void bus_get_hw_id(struct iwl_bus *bus, char buf[], int buf_len)
 {
        bus->ops->get_hw_id(bus, buf, buf_len);
@@ -149,6 +192,9 @@ static inline u32 bus_read32(struct iwl_bus *bus, u32 ofs)
        return bus->ops->read32(bus, ofs);
 }
 
+/*****************************************************
+* Bus layer registration functions
+******************************************************/
 int __must_check iwl_pci_register_driver(void);
 void iwl_pci_unregister_driver(void);
 
similarity index 97%
rename from drivers/net/wireless/iwlwifi/iwl-pci.h
rename to drivers/net/wireless/iwlwifi/iwl-cfg.h
index c0aea9e092cbaad904228fcede9d048123673419..d4f317cfe8b5608f2801bd841f6a74f527e041f9 100644 (file)
 #define __iwl_pci_h__
 
 
-/* This file includes the declaration that are internal to the PCI
- * implementation of the bus layer
+/*
+ * This file declares the config structures for all devices.
  */
 
-/* configuration for the _agn devices */
 extern struct iwl_cfg iwl5300_agn_cfg;
 extern struct iwl_cfg iwl5100_agn_cfg;
 extern struct iwl_cfg iwl5350_agn_cfg;
index 82bfef4730d50f9dadb33d3324287f79b6f1a70e..64593aa03ad6892b0ff5ce10374beeecce233c6f 100644 (file)
@@ -3263,6 +3263,14 @@ struct iwl_calib_temperature_offset_cmd {
        __le16 reserved;
 } __packed;
 
+struct iwl_calib_temperature_offset_v2_cmd {
+       struct iwl_calib_hdr hdr;
+       __le16 radio_sensor_offset_high;
+       __le16 radio_sensor_offset_low;
+       __le16 burntVoltageRef;
+       __le16 reserved;
+} __packed;
+
 /* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */
 struct iwl_calib_chain_noise_reset_cmd {
        struct iwl_calib_hdr hdr;
index 9270f990b2dd1ab9634b0e69ea5f44fe1ff02d93..fc400bb2bdffa8b0c4e646b601a927d608534543 100644 (file)
@@ -125,12 +125,12 @@ int iwl_init_geos(struct iwl_priv *priv)
                return 0;
        }
 
-       channels = kzalloc(sizeof(struct ieee80211_channel) *
-                          priv->channel_count, GFP_KERNEL);
+       channels = kcalloc(priv->channel_count,
+                          sizeof(struct ieee80211_channel), GFP_KERNEL);
        if (!channels)
                return -ENOMEM;
 
-       rates = kzalloc((sizeof(struct ieee80211_rate) * IWL_RATE_COUNT_LEGACY),
+       rates = kcalloc(IWL_RATE_COUNT_LEGACY, sizeof(struct ieee80211_rate),
                        GFP_KERNEL);
        if (!rates) {
                kfree(channels);
@@ -817,7 +817,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv, u8 ctxid)
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            enum iwl_rxon_context_id ctxid)
 {
        struct iwl_rxon_context *ctx = &priv->contexts[ctxid];
        struct iwl_rxon_cmd *rxon = &ctx->staging;
@@ -868,7 +869,7 @@ void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
         * commands by clearing the ready bit */
        clear_bit(STATUS_READY, &priv->shrd->status);
 
-       wake_up_interruptible(&priv->shrd->wait_command_queue);
+       wake_up(&priv->shrd->wait_command_queue);
 
        if (!ondemand) {
                /*
@@ -1327,7 +1328,13 @@ void iwl_mac_remove_interface(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->shrd->mutex);
 
-       WARN_ON(ctx->vif != vif);
+       if (WARN_ON(ctx->vif != vif)) {
+               struct iwl_rxon_context *tmp;
+               IWL_ERR(priv, "ctx->vif = %p, vif = %p\n", ctx->vif, vif);
+               for_each_context(priv, tmp)
+                       IWL_ERR(priv, "\tID = %d:\tctx = %p\tctx->vif = %p\n",
+                               tmp->ctxid, tmp, tmp->vif);
+       }
        ctx->vif = NULL;
 
        iwl_teardown_interface(priv, vif, false);
@@ -1802,13 +1809,12 @@ u32 iwl_usecs_to_beacons(struct iwl_priv *priv, u32 usec, u32 beacon_interval)
                return 0;
 
        quot = (usec / interval) &
-               (iwl_beacon_time_mask_high(priv,
-               hw_params(priv).beacon_time_tsf_bits) >>
-               hw_params(priv).beacon_time_tsf_bits);
+               (iwl_beacon_time_mask_high(priv, IWLAGN_EXT_BEACON_TIME_POS) >>
+               IWLAGN_EXT_BEACON_TIME_POS);
        rem = (usec % interval) & iwl_beacon_time_mask_low(priv,
-                                  hw_params(priv).beacon_time_tsf_bits);
+                                  IWLAGN_EXT_BEACON_TIME_POS);
 
-       return (quot << hw_params(priv).beacon_time_tsf_bits) + rem;
+       return (quot << IWLAGN_EXT_BEACON_TIME_POS) + rem;
 }
 
 /* base is usually what we get from ucode with each received frame,
@@ -1818,22 +1824,22 @@ __le32 iwl_add_beacon_time(struct iwl_priv *priv, u32 base,
                           u32 addon, u32 beacon_interval)
 {
        u32 base_low = base & iwl_beacon_time_mask_low(priv,
-                               hw_params(priv).beacon_time_tsf_bits);
+                               IWLAGN_EXT_BEACON_TIME_POS);
        u32 addon_low = addon & iwl_beacon_time_mask_low(priv,
-                               hw_params(priv).beacon_time_tsf_bits);
+                               IWLAGN_EXT_BEACON_TIME_POS);
        u32 interval = beacon_interval * TIME_UNIT;
        u32 res = (base & iwl_beacon_time_mask_high(priv,
-                               hw_params(priv).beacon_time_tsf_bits)) +
+                               IWLAGN_EXT_BEACON_TIME_POS)) +
                                (addon & iwl_beacon_time_mask_high(priv,
-                               hw_params(priv).beacon_time_tsf_bits));
+                               IWLAGN_EXT_BEACON_TIME_POS));
 
        if (base_low > addon_low)
                res += base_low - addon_low;
        else if (base_low < addon_low) {
                res += interval + base_low - addon_low;
-               res += (1 << hw_params(priv).beacon_time_tsf_bits);
+               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
        } else
-               res += (1 << hw_params(priv).beacon_time_tsf_bits);
+               res += (1 << IWLAGN_EXT_BEACON_TIME_POS);
 
        return cpu_to_le32(res);
 }
@@ -1876,3 +1882,22 @@ void iwl_nic_config(struct iwl_priv *priv)
        priv->cfg->lib->nic_config(priv);
 
 }
+
+void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb)
+{
+       struct ieee80211_tx_info *info;
+
+       info = IEEE80211_SKB_CB(skb);
+       kmem_cache_free(priv->tx_cmd_pool, (info->driver_data[1]));
+       dev_kfree_skb_any(skb);
+}
+
+void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac)
+{
+       ieee80211_stop_queue(priv->hw, ac);
+}
+
+void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac)
+{
+       ieee80211_wake_queue(priv->hw, ac);
+}
index 56b554c43fde75bb4cd85dd7bd77995067dc916f..e55ffad83950110e44326873935b6a1c14a5edcb 100644 (file)
@@ -108,7 +108,6 @@ struct iwl_lib_ops {
  *     radio tuning when there is a high receiving plcp error rate
  * @chain_noise_scale: default chain noise scale used for gain computation
  * @wd_timeout: TX queues watchdog timeout
- * @temperature_kelvin: temperature report by uCode in kelvin
  * @max_event_log_size: size of event log buffer size for ucode event logging
  * @shadow_reg_enable: HW shadhow register bit
  * @no_idle_support: do not support idle mode
@@ -124,14 +123,12 @@ struct iwl_base_params {
        const u16 max_ll_items;
        const bool shadow_ram_support;
        u16 led_compensation;
-       int chain_noise_num_beacons;
        bool adv_thermal_throttle;
        bool support_ct_kill_exit;
        const bool support_wimax_coexist;
        u8 plcp_delta_threshold;
        s32 chain_noise_scale;
        unsigned int wd_timeout;
-       bool temperature_kelvin;
        u32 max_event_log_size;
        const bool shadow_reg_enable;
        const bool no_idle_support;
@@ -194,6 +191,7 @@ struct iwl_ht_params {
  * @rx_with_siso_diversity: 1x1 device with rx antenna diversity
  * @internal_wimax_coex: internal wifi/wimax combo device
  * @iq_invert: I/Q inversion
+ * @temp_offset_v2: support v2 of temperature offset calibration
  *
  * We enable the driver to be backward compatible wrt API version. The
  * driver specifies which APIs it supports (with @ucode_api_max being the
@@ -231,6 +229,7 @@ struct iwl_cfg {
        const bool rx_with_siso_diversity;
        const bool internal_wimax_coex;
        const bool iq_invert;
+       const bool temp_offset_v2;
 };
 
 /***************************
@@ -319,7 +318,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force);
  ******************************************************************************/
 void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 void iwl_force_scan_end(struct iwl_priv *priv);
 int iwl_mac_hw_scan(struct ieee80211_hw *hw,
                    struct ieee80211_vif *vif,
@@ -329,12 +328,6 @@ int iwl_force_reset(struct iwl_priv *priv, int mode, bool external);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, struct ieee80211_mgmt *frame,
                       const u8 *ta, const u8 *ie, int ie_len, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
-u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-                             enum ieee80211_band band,
-                             u8 n_probes);
-u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band,
-                              struct ieee80211_vif *vif);
 void iwl_setup_scan_deferred_work(struct iwl_priv *priv);
 void iwl_cancel_scan_deferred_work(struct iwl_priv *priv);
 int __must_check iwl_scan_initiate(struct iwl_priv *priv,
index d0c63cfee15c144946e7f6517e88e51427cb1534..6d49dfbee964888685b1e2b1a14a9cbe5f54cb7a 100644 (file)
                goto err;                                               \
 } while (0)
 
+#define DEBUGFS_ADD_U32(name, parent, ptr, mode) do {                  \
+       struct dentry *__tmp;                                           \
+       __tmp = debugfs_create_u32(#name, mode,                         \
+                                  parent, ptr);                        \
+       if (IS_ERR(__tmp) || !__tmp)                                    \
+               goto err;                                               \
+} while (0)
+
 /* file operation */
 #define DEBUGFS_READ_FUNC(name)                                         \
 static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
@@ -707,6 +715,20 @@ static ssize_t iwl_dbgfs_disable_ht40_read(struct file *file,
        return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
 }
 
+static ssize_t iwl_dbgfs_temperature_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       char buf[8];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "%d\n", priv->temperature);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+
 static ssize_t iwl_dbgfs_sleep_level_override_write(struct file *file,
                                                    const char __user *user_buf,
                                                    size_t count, loff_t *ppos)
@@ -801,6 +823,7 @@ DEBUGFS_READ_WRITE_FILE_OPS(rx_handlers);
 DEBUGFS_READ_FILE_OPS(qos);
 DEBUGFS_READ_FILE_OPS(thermal_throttling);
 DEBUGFS_READ_WRITE_FILE_OPS(disable_ht40);
+DEBUGFS_READ_FILE_OPS(temperature);
 DEBUGFS_READ_WRITE_FILE_OPS(sleep_level_override);
 DEBUGFS_READ_FILE_OPS(current_sleep_command);
 
@@ -2229,8 +2252,8 @@ static ssize_t iwl_dbgfs_plcp_delta_write(struct file *file,
 
 static ssize_t iwl_dbgfs_force_reset_read(struct file *file,
                                        char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
+                                       size_t count, loff_t *ppos)
+{
        struct iwl_priv *priv = file->private_data;
        int i, pos = 0;
        char buf[300];
@@ -2309,8 +2332,8 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
 
 static ssize_t iwl_dbgfs_wd_timeout_write(struct file *file,
                                        const char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
+                                       size_t count, loff_t *ppos)
+{
        struct iwl_priv *priv = file->private_data;
        char buf[8];
        int buf_size;
@@ -2445,6 +2468,52 @@ DEBUGFS_READ_FILE_OPS(bt_traffic);
 DEBUGFS_READ_WRITE_FILE_OPS(protection_mode);
 DEBUGFS_READ_FILE_OPS(reply_tx_error);
 
+#ifdef CONFIG_IWLWIFI_DEBUG
+static ssize_t iwl_dbgfs_debug_level_read(struct file *file,
+                                         char __user *user_buf,
+                                         size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct iwl_shared *shrd = priv->shrd;
+       char buf[11];
+       int len;
+
+       len = scnprintf(buf, sizeof(buf), "0x%.8x",
+                       iwl_get_debug_level(shrd));
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_debug_level_write(struct file *file,
+                                          const char __user *user_buf,
+                                          size_t count, loff_t *ppos)
+{
+       struct iwl_priv *priv = file->private_data;
+       struct iwl_shared *shrd = priv->shrd;
+       char buf[11];
+       unsigned long val;
+       int ret;
+
+       if (count > sizeof(buf))
+               return -EINVAL;
+
+       memset(buf, 0, sizeof(buf));
+       if (copy_from_user(buf, user_buf, count))
+               return -EFAULT;
+
+       ret = strict_strtoul(buf, 0, &val);
+       if (ret)
+               return ret;
+
+       shrd->dbg_level_dev = val;
+       if (iwl_alloc_traffic_mem(priv))
+               IWL_ERR(priv, "Not enough memory to generate traffic log\n");
+
+       return count;
+}
+DEBUGFS_READ_WRITE_FILE_OPS(debug_level);
+#endif /* CONFIG_IWLWIFI_DEBUG */
+
 /*
  * Create the debugfs files and directories
  *
@@ -2482,6 +2551,8 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(current_sleep_command, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(thermal_throttling, dir_data, S_IRUSR);
        DEBUGFS_ADD_FILE(disable_ht40, dir_data, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(temperature, dir_data, S_IRUSR);
+
        DEBUGFS_ADD_FILE(rx_statistics, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(tx_statistics, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(traffic_log, dir_debug, S_IWUSR | S_IRUSR);
@@ -2496,7 +2567,6 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(ucode_general_stats, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(txfifo_flush, dir_debug, S_IWUSR);
        DEBUGFS_ADD_FILE(protection_mode, dir_debug, S_IWUSR | S_IRUSR);
-
        DEBUGFS_ADD_FILE(sensitivity, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(chain_noise, dir_debug, S_IRUSR);
        DEBUGFS_ADD_FILE(ucode_tracing, dir_debug, S_IWUSR | S_IRUSR);
@@ -2507,6 +2577,10 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name)
        DEBUGFS_ADD_FILE(wd_timeout, dir_debug, S_IWUSR);
        if (iwl_advanced_bt_coexist(priv))
                DEBUGFS_ADD_FILE(bt_traffic, dir_debug, S_IRUSR);
+#ifdef CONFIG_IWLWIFI_DEBUG
+       DEBUGFS_ADD_FILE(debug_level, dir_debug, S_IRUSR | S_IWUSR);
+#endif
+
        DEBUGFS_ADD_BOOL(disable_sensitivity, dir_rf,
                         &priv->disable_sens_cal);
        DEBUGFS_ADD_BOOL(disable_chain_noise, dir_rf,
@@ -2534,6 +2608,3 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv)
        debugfs_remove_recursive(priv->debugfs_dir);
        priv->debugfs_dir = NULL;
 }
-
-
-
index 8438a33e17ee03a41c4c6aa01ed05755df1c0d19..257aa9a407ca1ec62d170fc1d6113ae7e984c708 100644 (file)
@@ -202,11 +202,6 @@ struct iwl_station_entry {
        struct iwl_link_quality_cmd *lq;
 };
 
-struct iwl_station_priv_common {
-       struct iwl_rxon_context *ctx;
-       u8 sta_id;
-};
-
 /*
  * iwl_station_priv: Driver's private station information
  *
@@ -215,12 +210,13 @@ struct iwl_station_priv_common {
  * space.
  */
 struct iwl_station_priv {
-       struct iwl_station_priv_common common;
+       struct iwl_rxon_context *ctx;
        struct iwl_lq_sta lq_sta;
        atomic_t pending_frames;
        bool client;
        bool asleep;
        u8 max_agg_bufsize;
+       u8 sta_id;
 };
 
 /**
@@ -845,8 +841,9 @@ struct iwl_priv {
 
        void (*pre_rx_handler)(struct iwl_priv *priv,
                               struct iwl_rx_mem_buffer *rxb);
-       void (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb);
+       int (*rx_handlers[REPLY_MAX])(struct iwl_priv *priv,
+                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_device_cmd *cmd);
 
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
@@ -880,7 +877,7 @@ struct iwl_priv {
        u8 channel_count;       /* # of channels */
 
        /* thermal calibration */
-       s32 temperature;        /* degrees Kelvin */
+       s32 temperature;        /* Celsius */
        s32 last_temperature;
 
        /* init calibration results */
@@ -958,6 +955,8 @@ struct iwl_priv {
        struct iwl_station_entry stations[IWLAGN_STATION_COUNT];
        unsigned long ucode_key_table;
 
+       u8 mac80211_registered;
+
        /* Indication if ieee80211_ops->open has been called */
        u8 is_open;
 
@@ -1031,7 +1030,7 @@ struct iwl_priv {
        struct delayed_work hw_roc_disable_work;
        enum nl80211_channel_type hw_roc_chantype;
        int hw_roc_duration;
-       bool hw_roc_setup;
+       bool hw_roc_setup, hw_roc_start_notified;
 
        /* bt coex */
        u8 bt_enable_flag;
index 80ee65be9cd19b1db9f3f395bfea2bdc40a66941..a4e43bd4a54763bfac47354088f027a4023ebc63 100644 (file)
@@ -72,6 +72,7 @@
 #include "iwl-dev.h"
 #include "iwl-core.h"
 #include "iwl-debug.h"
+#include "iwl-agn.h"
 #include "iwl-eeprom.h"
 #include "iwl-io.h"
 
@@ -138,7 +139,7 @@ static const u8 iwl_eeprom_band_7[] = {       /* 5.2 ht40 channel */
 
 /******************************************************************************
  *
- * EEPROM related functions
+ * generic NVM functions
  *
 ******************************************************************************/
 
@@ -214,6 +215,93 @@ static int iwl_eeprom_verify_signature(struct iwl_priv *priv)
        return ret;
 }
 
+u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
+{
+       if (!priv->eeprom)
+               return 0;
+       return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
+}
+
+int iwl_eeprom_check_version(struct iwl_priv *priv)
+{
+       u16 eeprom_ver;
+       u16 calib_ver;
+
+       eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION);
+       calib_ver = iwlagn_eeprom_calib_version(priv);
+
+       if (eeprom_ver < priv->cfg->eeprom_ver ||
+           calib_ver < priv->cfg->eeprom_calib_ver)
+               goto err;
+
+       IWL_INFO(priv, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+                eeprom_ver, calib_ver);
+
+       return 0;
+err:
+       IWL_ERR(priv, "Unsupported (too old) EEPROM VER=0x%x < 0x%x "
+                 "CALIB=0x%x < 0x%x\n",
+                 eeprom_ver, priv->cfg->eeprom_ver,
+                 calib_ver,  priv->cfg->eeprom_calib_ver);
+       return -EINVAL;
+
+}
+
+int iwl_eeprom_check_sku(struct iwl_priv *priv)
+{
+       u16 radio_cfg;
+
+       if (!priv->cfg->sku) {
+               /* not using sku overwrite */
+               priv->cfg->sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
+               if (priv->cfg->sku & EEPROM_SKU_CAP_11N_ENABLE &&
+                   !priv->cfg->ht_params) {
+                       IWL_ERR(priv, "Invalid 11n configuration\n");
+                       return -EINVAL;
+               }
+       }
+       if (!priv->cfg->sku) {
+               IWL_ERR(priv, "Invalid device sku\n");
+               return -EINVAL;
+       }
+
+       IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
+
+       if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
+               /* not using .cfg overwrite */
+               radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+               priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+               priv->cfg->valid_rx_ant = EEPROM_RF_CFG_RX_ANT_MSK(radio_cfg);
+               if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
+                       IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
+                               priv->cfg->valid_tx_ant,
+                               priv->cfg->valid_rx_ant);
+                       return -EINVAL;
+               }
+               IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
+                        priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
+       }
+       /*
+        * for some special cases,
+        * EEPROM did not reflect the correct antenna setting
+        * so overwrite the valid tx/rx antenna from .cfg
+        */
+       return 0;
+}
+
+void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac)
+{
+       const u8 *addr = iwl_eeprom_query_addr(priv,
+                                       EEPROM_MAC_ADDRESS);
+       memcpy(mac, addr, ETH_ALEN);
+}
+
+/******************************************************************************
+ *
+ * OTP related functions
+ *
+******************************************************************************/
+
 static void iwl_set_otp_access(struct iwl_priv *priv, enum iwl_access_mode mode)
 {
        iwl_read32(bus(priv), CSR_OTP_GP_REG);
@@ -407,11 +495,152 @@ static int iwl_find_otp_image(struct iwl_priv *priv,
        return -EINVAL;
 }
 
-u16 iwl_eeprom_query16(const struct iwl_priv *priv, size_t offset)
+/******************************************************************************
+ *
+ * Tx Power related functions
+ *
+******************************************************************************/
+/**
+ * iwl_get_max_txpower_avg - get the highest tx power from all chains.
+ *     find the highest tx power from all chains for the channel
+ */
+static s8 iwl_get_max_txpower_avg(struct iwl_priv *priv,
+               struct iwl_eeprom_enhanced_txpwr *enhanced_txpower,
+               int element, s8 *max_txpower_in_half_dbm)
 {
-       if (!priv->eeprom)
-               return 0;
-       return (u16)priv->eeprom[offset] | ((u16)priv->eeprom[offset + 1] << 8);
+       s8 max_txpower_avg = 0; /* (dBm) */
+
+       /* Take the highest tx power from any valid chains */
+       if ((priv->cfg->valid_tx_ant & ANT_A) &&
+           (enhanced_txpower[element].chain_a_max > max_txpower_avg))
+               max_txpower_avg = enhanced_txpower[element].chain_a_max;
+       if ((priv->cfg->valid_tx_ant & ANT_B) &&
+           (enhanced_txpower[element].chain_b_max > max_txpower_avg))
+               max_txpower_avg = enhanced_txpower[element].chain_b_max;
+       if ((priv->cfg->valid_tx_ant & ANT_C) &&
+           (enhanced_txpower[element].chain_c_max > max_txpower_avg))
+               max_txpower_avg = enhanced_txpower[element].chain_c_max;
+       if (((priv->cfg->valid_tx_ant == ANT_AB) |
+           (priv->cfg->valid_tx_ant == ANT_BC) |
+           (priv->cfg->valid_tx_ant == ANT_AC)) &&
+           (enhanced_txpower[element].mimo2_max > max_txpower_avg))
+               max_txpower_avg =  enhanced_txpower[element].mimo2_max;
+       if ((priv->cfg->valid_tx_ant == ANT_ABC) &&
+           (enhanced_txpower[element].mimo3_max > max_txpower_avg))
+               max_txpower_avg = enhanced_txpower[element].mimo3_max;
+
+       /*
+        * max. tx power in EEPROM is in 1/2 dBm format
+        * convert from 1/2 dBm to dBm (round-up convert)
+        * but we also do not want to loss 1/2 dBm resolution which
+        * will impact performance
+        */
+       *max_txpower_in_half_dbm = max_txpower_avg;
+       return (max_txpower_avg & 0x01) + (max_txpower_avg >> 1);
+}
+
+static void
+iwl_eeprom_enh_txp_read_element(struct iwl_priv *priv,
+                                   struct iwl_eeprom_enhanced_txpwr *txp,
+                                   s8 max_txpower_avg)
+{
+       int ch_idx;
+       bool is_ht40 = txp->flags & IWL_EEPROM_ENH_TXP_FL_40MHZ;
+       enum ieee80211_band band;
+
+       band = txp->flags & IWL_EEPROM_ENH_TXP_FL_BAND_52G ?
+               IEEE80211_BAND_5GHZ : IEEE80211_BAND_2GHZ;
+
+       for (ch_idx = 0; ch_idx < priv->channel_count; ch_idx++) {
+               struct iwl_channel_info *ch_info = &priv->channel_info[ch_idx];
+
+               /* update matching channel or from common data only */
+               if (txp->channel != 0 && ch_info->channel != txp->channel)
+                       continue;
+
+               /* update matching band only */
+               if (band != ch_info->band)
+                       continue;
+
+               if (ch_info->max_power_avg < max_txpower_avg && !is_ht40) {
+                       ch_info->max_power_avg = max_txpower_avg;
+                       ch_info->curr_txpow = max_txpower_avg;
+                       ch_info->scan_power = max_txpower_avg;
+               }
+
+               if (is_ht40 && ch_info->ht40_max_power_avg < max_txpower_avg)
+                       ch_info->ht40_max_power_avg = max_txpower_avg;
+       }
+}
+
+#define EEPROM_TXP_OFFS        (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT)
+#define EEPROM_TXP_ENTRY_LEN sizeof(struct iwl_eeprom_enhanced_txpwr)
+#define EEPROM_TXP_SZ_OFFS (0x00 | INDIRECT_ADDRESS | INDIRECT_TXP_LIMIT_SIZE)
+
+#define TXP_CHECK_AND_PRINT(x) ((txp->flags & IWL_EEPROM_ENH_TXP_FL_##x) \
+                           ? # x " " : "")
+
+void iwl_eeprom_enhanced_txpower(struct iwl_priv *priv)
+{
+       struct iwl_eeprom_enhanced_txpwr *txp_array, *txp;
+       int idx, entries;
+       __le16 *txp_len;
+       s8 max_txp_avg, max_txp_avg_halfdbm;
+
+       BUILD_BUG_ON(sizeof(struct iwl_eeprom_enhanced_txpwr) != 8);
+
+       /* the length is in 16-bit words, but we want entries */
+       txp_len = (__le16 *) iwl_eeprom_query_addr(priv, EEPROM_TXP_SZ_OFFS);
+       entries = le16_to_cpup(txp_len) * 2 / EEPROM_TXP_ENTRY_LEN;
+
+       txp_array = (void *) iwl_eeprom_query_addr(priv, EEPROM_TXP_OFFS);
+
+       for (idx = 0; idx < entries; idx++) {
+               txp = &txp_array[idx];
+               /* skip invalid entries */
+               if (!(txp->flags & IWL_EEPROM_ENH_TXP_FL_VALID))
+                       continue;
+
+               IWL_DEBUG_EEPROM(priv, "%s %d:\t %s%s%s%s%s%s%s%s (0x%02x)\n",
+                                (txp->channel && (txp->flags &
+                                       IWL_EEPROM_ENH_TXP_FL_COMMON_TYPE)) ?
+                                       "Common " : (txp->channel) ?
+                                       "Channel" : "Common",
+                                (txp->channel),
+                                TXP_CHECK_AND_PRINT(VALID),
+                                TXP_CHECK_AND_PRINT(BAND_52G),
+                                TXP_CHECK_AND_PRINT(OFDM),
+                                TXP_CHECK_AND_PRINT(40MHZ),
+                                TXP_CHECK_AND_PRINT(HT_AP),
+                                TXP_CHECK_AND_PRINT(RES1),
+                                TXP_CHECK_AND_PRINT(RES2),
+                                TXP_CHECK_AND_PRINT(COMMON_TYPE),
+                                txp->flags);
+               IWL_DEBUG_EEPROM(priv, "\t\t chain_A: 0x%02x "
+                                "chain_B: 0X%02x chain_C: 0X%02x\n",
+                                txp->chain_a_max, txp->chain_b_max,
+                                txp->chain_c_max);
+               IWL_DEBUG_EEPROM(priv, "\t\t MIMO2: 0x%02x "
+                                "MIMO3: 0x%02x High 20_on_40: 0x%02x "
+                                "Low 20_on_40: 0x%02x\n",
+                                txp->mimo2_max, txp->mimo3_max,
+                                ((txp->delta_20_in_40 & 0xf0) >> 4),
+                                (txp->delta_20_in_40 & 0x0f));
+
+               max_txp_avg = iwl_get_max_txpower_avg(priv, txp_array, idx,
+                                                     &max_txp_avg_halfdbm);
+
+               /*
+                * Update the user limit values values to the highest
+                * power supported by any channel
+                */
+               if (max_txp_avg > priv->tx_power_user_lmt)
+                       priv->tx_power_user_lmt = max_txp_avg;
+               if (max_txp_avg_halfdbm > priv->tx_power_lmt_in_half_dbm)
+                       priv->tx_power_lmt_in_half_dbm = max_txp_avg_halfdbm;
+
+               iwl_eeprom_enh_txp_read_element(priv, txp, max_txp_avg);
+       }
 }
 
 /**
@@ -670,8 +899,9 @@ int iwl_init_channel_map(struct iwl_priv *priv)
        IWL_DEBUG_EEPROM(priv, "Parsing data for %d channels.\n",
                        priv->channel_count);
 
-       priv->channel_info = kzalloc(sizeof(struct iwl_channel_info) *
-                                    priv->channel_count, GFP_KERNEL);
+       priv->channel_info = kcalloc(priv->channel_count,
+                                    sizeof(struct iwl_channel_info),
+                                    GFP_KERNEL);
        if (!priv->channel_info) {
                IWL_ERR(priv, "Could not allocate channel_info\n");
                priv->channel_count = 0;
index e2b5e0ea5d9cf4dd26019a0ad8de87a8c2dcf2e1..c94747e7299e234a77b71b27af47cf73ae235495 100644 (file)
@@ -163,11 +163,19 @@ struct iwl_eeprom_enhanced_txpwr {
 } __packed;
 
 /* calibration */
+struct iwl_eeprom_calib_hdr {
+       u8 version;
+       u8 pa_type;
+       __le16 voltage;
+} __packed;
+
 #define EEPROM_CALIB_ALL       (INDIRECT_ADDRESS | INDIRECT_CALIBRATION)
 #define EEPROM_XTAL            ((2*0x128) | EEPROM_CALIB_ALL)
 
 /* temperature */
-#define EEPROM_TEMPERATURE ((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_KELVIN_TEMPERATURE      ((2*0x12A) | EEPROM_CALIB_ALL)
+#define EEPROM_RAW_TEMPERATURE         ((2*0x12B) | EEPROM_CALIB_ALL)
+
 
 /* agn links */
 #define EEPROM_LINK_HOST             (2*0x64)
index 7dffed186f0a5f5abf21ee4090aa5b09b458e730..f149165e801075aca13d9865bfd9b2a35ec3368f 100644 (file)
@@ -104,7 +104,6 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd)
                .len = { sizeof(struct iwl_led_cmd), },
                .data = { led_cmd, },
                .flags = CMD_ASYNC,
-               .callback = NULL,
        };
        u32 reg;
 
index 78a3f8dfe680f67dc57d8fd2dd5b168186e78ab3..1d7bb7423f94b2ebfec2b854dff8eed3d6879f7e 100644 (file)
@@ -68,7 +68,7 @@
 #include "iwl-shared.h"
 #include "iwl-trans.h"
 #include "iwl-csr.h"
-#include "iwl-pci.h"
+#include "iwl-cfg.h"
 
 /* PCI registers */
 #define PCI_CFG_RETRY_TIMEOUT  0x041
@@ -134,12 +134,6 @@ static void iwl_pci_apm_config(struct iwl_bus *bus)
        }
 }
 
-static void iwl_pci_set_drv_data(struct iwl_bus *bus, struct iwl_shared *shrd)
-{
-       bus->shrd = shrd;
-       pci_set_drvdata(IWL_BUS_GET_PCI_DEV(bus), shrd);
-}
-
 static void iwl_pci_get_hw_id(struct iwl_bus *bus, char buf[],
                              int buf_len)
 {
@@ -168,7 +162,6 @@ static u32 iwl_pci_read32(struct iwl_bus *bus, u32 ofs)
 static const struct iwl_bus_ops bus_ops_pci = {
        .get_pm_support = iwl_pci_is_pm_supported,
        .apm_config = iwl_pci_apm_config,
-       .set_drv_data = iwl_pci_set_drv_data,
        .get_hw_id = iwl_pci_get_hw_id,
        .write8 = iwl_pci_write8,
        .write32 = iwl_pci_write32,
@@ -260,6 +253,7 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
        {IWL_PCI_DEVICE(0x0085, 0x1311, iwl6005_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0085, 0x1316, iwl6005_2abg_cfg)},
        {IWL_PCI_DEVICE(0x0082, 0xC020, iwl6005_2agn_sff_cfg)},
+       {IWL_PCI_DEVICE(0x0085, 0xC220, iwl6005_2agn_sff_cfg)},
 
 /* 6x30 Series */
        {IWL_PCI_DEVICE(0x008A, 0x5305, iwl1030_bgn_cfg)},
@@ -392,6 +386,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        pci_bus = IWL_BUS_GET_PCI_BUS(bus);
        pci_bus->pci_dev = pdev;
 
+       pci_set_drvdata(pdev, bus);
+
        /* W/A - seems to solve weird behavior. We need to remove this if we
         * don't want to stay in L1 all the time. This wastes a lot of power */
        pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S | PCIE_LINK_STATE_L1 |
@@ -485,17 +481,18 @@ out_no_pci:
 
 static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 {
-       struct iwl_shared *shrd = pci_get_drvdata(pdev);
-       struct iwl_bus *bus = shrd->bus;
+       struct iwl_bus *bus = pci_get_drvdata(pdev);
        struct iwl_pci_bus *pci_bus = IWL_BUS_GET_PCI_BUS(bus);
+       struct pci_dev *pci_dev = IWL_BUS_GET_PCI_DEV(bus);
+       struct iwl_shared *shrd = bus->shrd;
 
        iwl_remove(shrd->priv);
 
-       pci_disable_msi(pci_bus->pci_dev);
-       pci_iounmap(pci_bus->pci_dev, pci_bus->hw_base);
-       pci_release_regions(pci_bus->pci_dev);
-       pci_disable_device(pci_bus->pci_dev);
-       pci_set_drvdata(pci_bus->pci_dev, NULL);
+       pci_disable_msi(pci_dev);
+       pci_iounmap(pci_dev, pci_bus->hw_base);
+       pci_release_regions(pci_dev);
+       pci_disable_device(pci_dev);
+       pci_set_drvdata(pci_dev, NULL);
 
        kfree(bus);
 }
@@ -505,7 +502,8 @@ static void __devexit iwl_pci_remove(struct pci_dev *pdev)
 static int iwl_pci_suspend(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_shared *shrd = pci_get_drvdata(pdev);
+       struct iwl_bus *bus = pci_get_drvdata(pdev);
+       struct iwl_shared *shrd = bus->shrd;
 
        /* Before you put code here, think about WoWLAN. You cannot check here
         * whether WoWLAN is enabled or not, and your code will run even if
@@ -518,7 +516,8 @@ static int iwl_pci_suspend(struct device *device)
 static int iwl_pci_resume(struct device *device)
 {
        struct pci_dev *pdev = to_pci_dev(device);
-       struct iwl_shared *shrd = pci_get_drvdata(pdev);
+       struct iwl_bus *bus = pci_get_drvdata(pdev);
+       struct iwl_shared *shrd = bus->shrd;
 
        /* Before you put code here, think about WoWLAN. You cannot check here
         * whether WoWLAN is enabled or not, and your code will run even if
index c7e6a746c3ea49dc10d0206badfa47ad4bb5043b..bcd7f64683aa02c06ebd1af0e8650ef39d8fdd11 100644 (file)
@@ -130,8 +130,9 @@ const char *get_cmd_string(u8 cmd)
  *
  ******************************************************************************/
 
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_error(struct iwl_priv *priv,
+                              struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
@@ -142,9 +143,11 @@ static void iwl_rx_reply_error(struct iwl_priv *priv,
                pkt->u.err_resp.cmd_id,
                le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
                le32_to_cpu(pkt->u.err_resp.error_info));
+       return 0;
 }
 
-static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_csa_notification *csa = &(pkt->u.csa_notif);
@@ -156,7 +159,7 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
        if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->shrd->status))
-               return;
+               return 0;
 
        if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
                rxon->channel = csa->channel;
@@ -169,11 +172,13 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
                        le16_to_cpu(csa->channel));
                iwl_chswitch_done(priv, false);
        }
+       return 0;
 }
 
 
-static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
+                                         struct iwl_rx_mem_buffer *rxb,
+                                         struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
@@ -181,15 +186,17 @@ static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv,
        if (!report->state) {
                IWL_DEBUG_11H(priv,
                        "Spectrum Measure Notification: Start\n");
-               return;
+               return 0;
        }
 
        memcpy(&priv->measure_report, report, sizeof(*report));
        priv->measurement_status |= MEASUREMENT_READY;
+       return 0;
 }
 
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+                                 struct iwl_rx_mem_buffer *rxb,
+                                 struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -197,10 +204,12 @@ static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
        IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
                     sleep->pm_sleep_mode, sleep->pm_wakeup_src);
 #endif
+       return 0;
 }
 
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                            struct iwl_rx_mem_buffer *rxb,
+                                            struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u32 __maybe_unused len =
@@ -209,10 +218,12 @@ static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
                        "notification for %s:\n", len,
                        get_cmd_string(pkt->hdr.cmd));
        iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, len);
+       return 0;
 }
 
-static void iwl_rx_beacon_notif(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_beacon_notif(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwlagn_beacon_notif *beacon = (void *)pkt->u.raw;
@@ -233,6 +244,7 @@ static void iwl_rx_beacon_notif(struct iwl_priv *priv,
 
        if (!test_bit(STATUS_EXIT_PENDING, &priv->shrd->status))
                queue_work(priv->shrd->workqueue, &priv->beacon_update);
+       return 0;
 }
 
 /* the threshold ratio of actual_ack_cnt to expected_ack_cnt in percent */
@@ -475,8 +487,9 @@ iwl_accumulative_statistics(struct iwl_priv *priv,
 }
 #endif
 
-static void iwl_rx_statistics(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_statistics(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb,
+                             struct iwl_device_cmd *cmd)
 {
        unsigned long stamp = jiffies;
        const int reg_recalib_period = 60;
@@ -530,7 +543,7 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
                WARN_ONCE(1, "len %d doesn't match BT (%zu) or normal (%zu)\n",
                          len, sizeof(struct iwl_bt_notif_statistics),
                          sizeof(struct iwl_notif_statistics));
-               return;
+               return 0;
        }
 
        change = common->temperature != priv->statistics.common.temperature ||
@@ -573,10 +586,12 @@ static void iwl_rx_statistics(struct iwl_priv *priv,
        }
        if (priv->cfg->lib->temperature && change)
                priv->cfg->lib->temperature(priv);
+       return 0;
 }
 
-static void iwl_rx_reply_statistics(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_statistics(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
@@ -591,13 +606,15 @@ static void iwl_rx_reply_statistics(struct iwl_priv *priv,
 #endif
                IWL_DEBUG_RX(priv, "Statistics have been cleared\n");
        }
-       iwl_rx_statistics(priv, rxb);
+       iwl_rx_statistics(priv, rxb, cmd);
+       return 0;
 }
 
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
-static void iwl_rx_card_state_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_card_state_notif(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u32 flags = le32_to_cpu(pkt->u.card_state_notif.flags);
@@ -644,11 +661,13 @@ static void iwl_rx_card_state_notif(struct iwl_priv *priv,
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->shrd->status));
        else
-               wake_up_interruptible(&priv->shrd->wait_command_queue);
+               wake_up(&priv->shrd->wait_command_queue);
+       return 0;
 }
 
-static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
+                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_device_cmd *cmd)
 
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -666,18 +685,21 @@ static void iwl_rx_missed_beacon_notif(struct iwl_priv *priv,
                if (!test_bit(STATUS_SCANNING, &priv->shrd->status))
                        iwl_init_sensitivity(priv);
        }
+       return 0;
 }
 
 /* Cache phy data (Rx signal strength, etc) for HT frame (REPLY_RX_PHY_CMD).
  * This will be used later in iwl_rx_reply_rx() for REPLY_RX_MPDU_CMD. */
-static void iwl_rx_reply_rx_phy(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_rx_phy(struct iwl_priv *priv,
+                               struct iwl_rx_mem_buffer *rxb,
+                               struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
 
        priv->last_phy_res_valid = true;
        memcpy(&priv->last_phy_res, pkt->u.raw,
               sizeof(struct iwl_rx_phy_res));
+       return 0;
 }
 
 /*
@@ -892,8 +914,9 @@ static int iwlagn_calc_rssi(struct iwl_priv *priv,
 
 /* Called for REPLY_RX (legacy ABG frames), or
  * REPLY_RX_MPDU_CMD (HT high-throughput N frames). */
-static void iwl_rx_reply_rx(struct iwl_priv *priv,
-                           struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_rx(struct iwl_priv *priv,
+                           struct iwl_rx_mem_buffer *rxb,
+                           struct iwl_device_cmd *cmd)
 {
        struct ieee80211_hdr *header;
        struct ieee80211_rx_status rx_status;
@@ -926,7 +949,7 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
        } else {
                if (!priv->last_phy_res_valid) {
                        IWL_ERR(priv, "MPDU frame without cached PHY data\n");
-                       return;
+                       return 0;
                }
                phy_res = &priv->last_phy_res;
                amsdu = (struct iwl_rx_mpdu_res_start *)pkt->u.raw;
@@ -940,14 +963,14 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
        if ((unlikely(phy_res->cfg_phy_cnt > 20))) {
                IWL_DEBUG_DROP(priv, "dsp size out of range [0,20]: %d/n",
                                phy_res->cfg_phy_cnt);
-               return;
+               return 0;
        }
 
        if (!(rx_pkt_status & RX_RES_STATUS_NO_CRC32_ERROR) ||
            !(rx_pkt_status & RX_RES_STATUS_NO_RXE_OVERFLOW)) {
                IWL_DEBUG_RX(priv, "Bad CRC or FIFO: 0x%08X.\n",
                                le32_to_cpu(rx_pkt_status));
-               return;
+               return 0;
        }
 
        /* This will be used in several places later */
@@ -1008,6 +1031,7 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
 
        iwl_pass_packet_to_mac80211(priv, header, len, ampdu_status,
                                    rxb, &rx_status);
+       return 0;
 }
 
 /**
@@ -1018,7 +1042,8 @@ static void iwl_rx_reply_rx(struct iwl_priv *priv,
  */
 void iwl_setup_rx_handlers(struct iwl_priv *priv)
 {
-       void (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
+       int (**handlers)(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
 
        handlers = priv->rx_handlers;
 
@@ -1028,6 +1053,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
        handlers[PM_SLEEP_NOTIFICATION]         = iwl_rx_pm_sleep_notif;
        handlers[PM_DEBUG_STATISTIC_NOTIFIC]    = iwl_rx_pm_debug_statistics_notif;
        handlers[BEACON_NOTIFICATION]           = iwl_rx_beacon_notif;
+       handlers[REPLY_ADD_STA]                 = iwl_add_sta_callback;
 
        /*
         * The same handler is used for both the REPLY to a discrete
@@ -1065,9 +1091,11 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
 
 }
 
-void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
+int iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                    struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
+       int err = 0;
 
        /*
         * Do the notification wait before RX handlers so
@@ -1102,11 +1130,12 @@ void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
         *   rx_handlers table.  See iwl_setup_rx_handlers() */
        if (priv->rx_handlers[pkt->hdr.cmd]) {
                priv->rx_handlers_stats[pkt->hdr.cmd]++;
-               priv->rx_handlers[pkt->hdr.cmd] (priv, rxb);
+               err = priv->rx_handlers[pkt->hdr.cmd] (priv, rxb, cmd);
        } else {
                /* No handling needed */
                IWL_DEBUG_RX(priv,
                        "No handler needed for %s, 0x%02x\n",
                        get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd);
        }
+       return err;
 }
index fc5af3475392b7bf897844afe54f241b10def001..c5c95d5319b19f172deb0b806e764e10d1181477 100644 (file)
@@ -114,6 +114,65 @@ static void iwl_complete_scan(struct iwl_priv *priv, bool aborted)
        priv->scan_request = NULL;
 }
 
+static void iwl_process_scan_complete(struct iwl_priv *priv)
+{
+       bool aborted;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (!test_and_clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status))
+               return;
+
+       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
+
+       cancel_delayed_work(&priv->scan_check);
+
+       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
+       if (aborted)
+               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
+
+       if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
+               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
+               goto out_settings;
+       }
+
+       if (priv->scan_type == IWL_SCAN_ROC) {
+               ieee80211_remain_on_channel_expired(priv->hw);
+               priv->hw_roc_channel = NULL;
+               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
+       }
+
+       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
+               int err;
+
+               /* Check if mac80211 requested scan during our internal scan */
+               if (priv->scan_request == NULL)
+                       goto out_complete;
+
+               /* If so request a new scan */
+               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
+                                       priv->scan_request->channels[0]->band);
+               if (err) {
+                       IWL_DEBUG_SCAN(priv,
+                               "failed to initiate pending scan: %d\n", err);
+                       aborted = true;
+                       goto out_complete;
+               }
+
+               return;
+       }
+
+out_complete:
+       iwl_complete_scan(priv, aborted);
+
+out_settings:
+       /* Can we still talk to firmware ? */
+       if (!iwl_is_ready_rf(priv->shrd))
+               return;
+
+       iwlagn_post_scan(priv);
+}
+
 void iwl_force_scan_end(struct iwl_priv *priv)
 {
        lockdep_assert_held(&priv->shrd->mutex);
@@ -127,6 +186,7 @@ void iwl_force_scan_end(struct iwl_priv *priv)
        clear_bit(STATUS_SCANNING, &priv->shrd->status);
        clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
        clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
+       clear_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
        iwl_complete_scan(priv, true);
 }
 
@@ -169,7 +229,7 @@ int iwl_scan_cancel(struct iwl_priv *priv)
  * @ms: amount of time to wait (in milliseconds) for scan to abort
  *
  */
-int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
+void iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 {
        unsigned long timeout = jiffies + msecs_to_jiffies(ms);
 
@@ -181,16 +241,30 @@ int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms)
 
        while (time_before_eq(jiffies, timeout)) {
                if (!test_bit(STATUS_SCAN_HW, &priv->shrd->status))
-                       break;
+                       goto finished;
                msleep(20);
        }
 
-       return test_bit(STATUS_SCAN_HW, &priv->shrd->status);
+       return;
+
+ finished:
+       /*
+        * Now STATUS_SCAN_HW is clear. This means that the
+        * device finished, but the background work is going
+        * to execute at best as soon as we release the mutex.
+        * Since we need to be able to issue a new scan right
+        * after this function returns, run the complete here.
+        * The STATUS_SCAN_COMPLETE bit will then be cleared
+        * and prevent the background work from "completing"
+        * a possible new scan.
+        */
+       iwl_process_scan_complete(priv);
 }
 
 /* Service response to REPLY_SCAN_CMD (0x80) */
-static void iwl_rx_reply_scan(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_reply_scan(struct iwl_priv *priv,
+                             struct iwl_rx_mem_buffer *rxb,
+                             struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -199,11 +273,13 @@ static void iwl_rx_reply_scan(struct iwl_priv *priv,
 
        IWL_DEBUG_SCAN(priv, "Scan request status = 0x%x\n", notif->status);
 #endif
+       return 0;
 }
 
 /* Service SCAN_START_NOTIFICATION (0x82) */
-static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_start_notif(struct iwl_priv *priv,
+                                   struct iwl_rx_mem_buffer *rxb,
+                                   struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scanstart_notification *notif =
@@ -218,13 +294,19 @@ static void iwl_rx_scan_start_notif(struct iwl_priv *priv,
                       le32_to_cpu(notif->tsf_low),
                       notif->status, notif->beacon_timer);
 
-       if (priv->scan_type == IWL_SCAN_ROC)
+       if (priv->scan_type == IWL_SCAN_ROC &&
+           !priv->hw_roc_start_notified) {
                ieee80211_ready_on_channel(priv->hw);
+               priv->hw_roc_start_notified = true;
+       }
+
+       return 0;
 }
 
 /* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_results_notif(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb,
+                                     struct iwl_device_cmd *cmd)
 {
 #ifdef CONFIG_IWLWIFI_DEBUG
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
@@ -233,20 +315,24 @@ static void iwl_rx_scan_results_notif(struct iwl_priv *priv,
 
        IWL_DEBUG_SCAN(priv, "Scan ch.res: "
                       "%d [802.11%s] "
+                      "probe status: %u:%u "
                       "(TSF: 0x%08X:%08X) - %d "
                       "elapsed=%lu usec\n",
                       notif->channel,
                       notif->band ? "bg" : "a",
+                      notif->probe_status, notif->num_probe_not_sent,
                       le32_to_cpu(notif->tsf_high),
                       le32_to_cpu(notif->tsf_low),
                       le32_to_cpu(notif->statistics[0]),
                       le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf);
 #endif
+       return 0;
 }
 
 /* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb)
+static int iwl_rx_scan_complete_notif(struct iwl_priv *priv,
+                                      struct iwl_rx_mem_buffer *rxb,
+                                      struct iwl_device_cmd *cmd)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
@@ -256,13 +342,20 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                       scan_notif->tsf_low,
                       scan_notif->tsf_high, scan_notif->status);
 
-       /* The HW is no longer scanning */
-       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
-
        IWL_DEBUG_SCAN(priv, "Scan on %sGHz took %dms\n",
                       (priv->scan_band == IEEE80211_BAND_2GHZ) ? "2.4" : "5.2",
                       jiffies_to_msecs(jiffies - priv->scan_start));
 
+       /*
+        * When aborting, we run the scan completed background work inline
+        * and the background work must then do nothing. The SCAN_COMPLETE
+        * bit helps implement that logic and thus needs to be set before
+        * queueing the work. Also, since the scan abort waits for SCAN_HW
+        * to clear, we need to set SCAN_COMPLETE before clearing SCAN_HW
+        * to avoid a race there.
+        */
+       set_bit(STATUS_SCAN_COMPLETE, &priv->shrd->status);
+       clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
        queue_work(priv->shrd->workqueue, &priv->scan_completed);
 
        if (priv->iw_mode != NL80211_IFTYPE_ADHOC &&
@@ -286,6 +379,7 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv,
                queue_work(priv->shrd->workqueue,
                           &priv->bt_traffic_change_work);
        }
+       return 0;
 }
 
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
@@ -299,9 +393,8 @@ void iwl_setup_rx_scan_handlers(struct iwl_priv *priv)
                                        iwl_rx_scan_complete_notif;
 }
 
-inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
-                                    enum ieee80211_band band,
-                                    u8 n_probes)
+static u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
+                                    enum ieee80211_band band, u8 n_probes)
 {
        if (band == IEEE80211_BAND_5GHZ)
                return IWL_ACTIVE_DWELL_TIME_52 +
@@ -311,35 +404,481 @@ inline u16 iwl_get_active_dwell_time(struct iwl_priv *priv,
                        IWL_ACTIVE_DWELL_FACTOR_24GHZ * (n_probes + 1);
 }
 
-u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
-                              enum ieee80211_band band,
-                              struct ieee80211_vif *vif)
+static u16 iwl_limit_dwell(struct iwl_priv *priv, u16 dwell_time)
 {
        struct iwl_rxon_context *ctx;
+
+       /*
+        * If we're associated, we clamp the dwell time 98%
+        * of the smallest beacon interval (minus 2 * channel
+        * tune time)
+        */
+       for_each_context(priv, ctx) {
+               u16 value;
+
+               if (!iwl_is_associated_ctx(ctx))
+                       continue;
+               value = ctx->beacon_int;
+               if (!value)
+                       value = IWL_PASSIVE_DWELL_BASE;
+               value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
+               dwell_time = min(value, dwell_time);
+       }
+
+       return dwell_time;
+}
+
+static u16 iwl_get_passive_dwell_time(struct iwl_priv *priv,
+                                     enum ieee80211_band band)
+{
        u16 passive = (band == IEEE80211_BAND_2GHZ) ?
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_24 :
            IWL_PASSIVE_DWELL_BASE + IWL_PASSIVE_DWELL_TIME_52;
 
-       if (iwl_is_any_associated(priv)) {
+       return iwl_limit_dwell(priv, passive);
+}
+
+static int iwl_get_single_channel_for_scan(struct iwl_priv *priv,
+                                          struct ieee80211_vif *vif,
+                                          enum ieee80211_band band,
+                                          struct iwl_scan_channel *scan_ch)
+{
+       const struct ieee80211_supported_band *sband;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int added = 0;
+       u16 channel = 0;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband) {
+               IWL_ERR(priv, "invalid band\n");
+               return added;
+       }
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, 0);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       channel = iwl_get_single_channel_number(priv, band);
+       if (channel) {
+               scan_ch->channel = cpu_to_le16(channel);
+               scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+               added++;
+       } else
+               IWL_ERR(priv, "no valid channel found\n");
+       return added;
+}
+
+static int iwl_get_channels_for_scan(struct iwl_priv *priv,
+                                    struct ieee80211_vif *vif,
+                                    enum ieee80211_band band,
+                                    u8 is_active, u8 n_probes,
+                                    struct iwl_scan_channel *scan_ch)
+{
+       struct ieee80211_channel *chan;
+       const struct ieee80211_supported_band *sband;
+       const struct iwl_channel_info *ch_info;
+       u16 passive_dwell = 0;
+       u16 active_dwell = 0;
+       int added, i;
+       u16 channel;
+
+       sband = iwl_get_hw_mode(priv, band);
+       if (!sband)
+               return 0;
+
+       active_dwell = iwl_get_active_dwell_time(priv, band, n_probes);
+       passive_dwell = iwl_get_passive_dwell_time(priv, band);
+
+       if (passive_dwell <= active_dwell)
+               passive_dwell = active_dwell + 1;
+
+       for (i = 0, added = 0; i < priv->scan_request->n_channels; i++) {
+               chan = priv->scan_request->channels[i];
+
+               if (chan->band != band)
+                       continue;
+
+               channel = chan->hw_value;
+               scan_ch->channel = cpu_to_le16(channel);
+
+               ch_info = iwl_get_channel_info(priv, band, channel);
+               if (!is_channel_valid(ch_info)) {
+                       IWL_DEBUG_SCAN(priv,
+                                      "Channel %d is INVALID for this band.\n",
+                                      channel);
+                       continue;
+               }
+
+               if (!is_active || is_channel_passive(ch_info) ||
+                   (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN))
+                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+               else
+                       scan_ch->type = SCAN_CHANNEL_TYPE_ACTIVE;
+
+               if (n_probes)
+                       scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes);
+
+               scan_ch->active_dwell = cpu_to_le16(active_dwell);
+               scan_ch->passive_dwell = cpu_to_le16(passive_dwell);
+
+               /* Set txpower levels to defaults */
+               scan_ch->dsp_atten = 110;
+
+               /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                * power level:
+                * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                */
+               if (band == IEEE80211_BAND_5GHZ)
+                       scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+               else
+                       scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+               IWL_DEBUG_SCAN(priv, "Scanning ch=%d prob=0x%X [%s %d]\n",
+                              channel, le32_to_cpu(scan_ch->type),
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                               "ACTIVE" : "PASSIVE",
+                              (scan_ch->type & SCAN_CHANNEL_TYPE_ACTIVE) ?
+                              active_dwell : passive_dwell);
+
+               scan_ch++;
+               added++;
+       }
+
+       IWL_DEBUG_SCAN(priv, "total channels to scan %d\n", added);
+       return added;
+}
+
+static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
+{
+       struct iwl_host_cmd cmd = {
+               .id = REPLY_SCAN_CMD,
+               .len = { sizeof(struct iwl_scan_cmd), },
+               .flags = CMD_SYNC,
+       };
+       struct iwl_scan_cmd *scan;
+       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
+       u32 rate_flags = 0;
+       u16 cmd_len;
+       u16 rx_chain = 0;
+       enum ieee80211_band band;
+       u8 n_probes = 0;
+       u8 rx_ant = hw_params(priv).valid_rx_ant;
+       u8 rate;
+       bool is_active = false;
+       int  chan_mod;
+       u8 active_chains;
+       u8 scan_tx_antennas = hw_params(priv).valid_tx_ant;
+       int ret;
+
+       lockdep_assert_held(&priv->shrd->mutex);
+
+       if (vif)
+               ctx = iwl_rxon_ctx_from_vif(vif);
+
+       if (!priv->scan_cmd) {
+               priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
+                                        IWL_MAX_SCAN_SIZE, GFP_KERNEL);
+               if (!priv->scan_cmd) {
+                       IWL_DEBUG_SCAN(priv,
+                                      "fail to allocate memory for scan\n");
+                       return -ENOMEM;
+               }
+       }
+       scan = priv->scan_cmd;
+       memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
+
+       scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
+       scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
+
+       if (priv->scan_type != IWL_SCAN_ROC &&
+           iwl_is_any_associated(priv)) {
+               u16 interval = 0;
+               u32 extra;
+               u32 suspend_time = 100;
+               u32 scan_suspend_time = 100;
+
+               IWL_DEBUG_INFO(priv, "Scanning while associated...\n");
+               switch (priv->scan_type) {
+               case IWL_SCAN_ROC:
+                       WARN_ON(1);
+                       break;
+               case IWL_SCAN_RADIO_RESET:
+                       interval = 0;
+                       break;
+               case IWL_SCAN_NORMAL:
+                       interval = vif->bss_conf.beacon_int;
+                       break;
+               }
+
+               scan->suspend_time = 0;
+               scan->max_out_time = cpu_to_le32(200 * 1024);
+               if (!interval)
+                       interval = suspend_time;
+
+               extra = (suspend_time / interval) << 22;
+               scan_suspend_time = (extra |
+                   ((suspend_time % interval) * 1024));
+               scan->suspend_time = cpu_to_le32(scan_suspend_time);
+               IWL_DEBUG_SCAN(priv, "suspend_time 0x%X beacon interval %d\n",
+                              scan_suspend_time, interval);
+       } else if (priv->scan_type == IWL_SCAN_ROC) {
+               scan->suspend_time = 0;
+               scan->max_out_time = 0;
+               scan->quiet_time = 0;
+               scan->quiet_plcp_th = 0;
+       }
+
+       switch (priv->scan_type) {
+       case IWL_SCAN_RADIO_RESET:
+               IWL_DEBUG_SCAN(priv, "Start internal passive scan.\n");
+               break;
+       case IWL_SCAN_NORMAL:
+               if (priv->scan_request->n_ssids) {
+                       int i, p = 0;
+                       IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
+                       for (i = 0; i < priv->scan_request->n_ssids; i++) {
+                               /* always does wildcard anyway */
+                               if (!priv->scan_request->ssids[i].ssid_len)
+                                       continue;
+                               scan->direct_scan[p].id = WLAN_EID_SSID;
+                               scan->direct_scan[p].len =
+                                       priv->scan_request->ssids[i].ssid_len;
+                               memcpy(scan->direct_scan[p].ssid,
+                                      priv->scan_request->ssids[i].ssid,
+                                      priv->scan_request->ssids[i].ssid_len);
+                               n_probes++;
+                               p++;
+                       }
+                       is_active = true;
+               } else
+                       IWL_DEBUG_SCAN(priv, "Start passive scan.\n");
+               break;
+       case IWL_SCAN_ROC:
+               IWL_DEBUG_SCAN(priv, "Start ROC scan.\n");
+               break;
+       }
+
+       scan->tx_cmd.tx_flags = TX_CMD_FLG_SEQ_CTL_MSK;
+       scan->tx_cmd.sta_id = ctx->bcast_sta_id;
+       scan->tx_cmd.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE;
+
+       switch (priv->scan_band) {
+       case IEEE80211_BAND_2GHZ:
+               scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK;
+               chan_mod = le32_to_cpu(
+                       priv->contexts[IWL_RXON_CTX_BSS].active.flags &
+                                               RXON_FLG_CHANNEL_MODE_MSK)
+                                      >> RXON_FLG_CHANNEL_MODE_POS;
+               if (chan_mod == CHANNEL_MODE_PURE_40) {
+                       rate = IWL_RATE_6M_PLCP;
+               } else {
+                       rate = IWL_RATE_1M_PLCP;
+                       rate_flags = RATE_MCS_CCK_MSK;
+               }
                /*
-                * If we're associated, we clamp the maximum passive
-                * dwell time to be 98% of the smallest beacon interval
-                * (minus 2 * channel tune time)
+                * Internal scans are passive, so we can indiscriminately set
+                * the BT ignore flag on 2.4 GHz since it applies to TX only.
                 */
-               for_each_context(priv, ctx) {
-                       u16 value;
-
-                       if (!iwl_is_associated_ctx(ctx))
-                               continue;
-                       value = ctx->vif ? ctx->vif->bss_conf.beacon_int : 0;
-                       if ((value > IWL_PASSIVE_DWELL_BASE) || !value)
-                               value = IWL_PASSIVE_DWELL_BASE;
-                       value = (value * 98) / 100 - IWL_CHANNEL_TUNE_TIME * 2;
-                       passive = min(value, passive);
+               if (priv->cfg->bt_params &&
+                   priv->cfg->bt_params->advanced_bt_coexist)
+                       scan->tx_cmd.tx_flags |= TX_CMD_FLG_IGNORE_BT;
+               break;
+       case IEEE80211_BAND_5GHZ:
+               rate = IWL_RATE_6M_PLCP;
+               break;
+       default:
+               IWL_WARN(priv, "Invalid scan band\n");
+               return -EIO;
+       }
+
+       /*
+        * If active scanning is requested but a certain channel is
+        * marked passive, we can do active scanning if we detect
+        * transmissions.
+        *
+        * There is an issue with some firmware versions that triggers
+        * a sysassert on a "good CRC threshold" of zero (== disabled),
+        * on a radar channel even though this means that we should NOT
+        * send probes.
+        *
+        * The "good CRC threshold" is the number of frames that we
+        * need to receive during our dwell time on a channel before
+        * sending out probes -- setting this to a huge value will
+        * mean we never reach it, but at the same time work around
+        * the aforementioned issue. Thus use IWL_GOOD_CRC_TH_NEVER
+        * here instead of IWL_GOOD_CRC_TH_DISABLED.
+        *
+        * This was fixed in later versions along with some other
+        * scan changes, and the threshold behaves as a flag in those
+        * versions.
+        */
+       if (priv->new_scan_threshold_behaviour)
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_DISABLED;
+       else
+               scan->good_CRC_th = is_active ? IWL_GOOD_CRC_TH_DEFAULT :
+                                               IWL_GOOD_CRC_TH_NEVER;
+
+       band = priv->scan_band;
+
+       if (priv->cfg->scan_rx_antennas[band])
+               rx_ant = priv->cfg->scan_rx_antennas[band];
+
+       if (band == IEEE80211_BAND_2GHZ &&
+           priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist) {
+               /* transmit 2.4 GHz probes only on first antenna */
+               scan_tx_antennas = first_antenna(scan_tx_antennas);
+       }
+
+       priv->scan_tx_ant[band] = iwl_toggle_tx_ant(priv,
+                                                   priv->scan_tx_ant[band],
+                                                   scan_tx_antennas);
+       rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]);
+       scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags);
+
+       /* In power save mode use one chain, otherwise use all chains */
+       if (test_bit(STATUS_POWER_PMI, &priv->shrd->status)) {
+               /* rx_ant has been set to all valid chains previously */
+               active_chains = rx_ant &
+                               ((u8)(priv->chain_noise_data.active_chains));
+               if (!active_chains)
+                       active_chains = rx_ant;
+
+               IWL_DEBUG_SCAN(priv, "chain_noise_data.active_chains: %u\n",
+                               priv->chain_noise_data.active_chains);
+
+               rx_ant = first_antenna(active_chains);
+       }
+       if (priv->cfg->bt_params &&
+           priv->cfg->bt_params->advanced_bt_coexist &&
+           priv->bt_full_concurrent) {
+               /* operated as 1x1 in full concurrency mode */
+               rx_ant = first_antenna(rx_ant);
+       }
+
+       /* MIMO is not used here, but value is required */
+       rx_chain |=
+               hw_params(priv).valid_rx_ant << RXON_RX_CHAIN_VALID_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_MIMO_SEL_POS;
+       rx_chain |= rx_ant << RXON_RX_CHAIN_FORCE_SEL_POS;
+       rx_chain |= 0x1 << RXON_RX_CHAIN_DRIVER_FORCE_POS;
+       scan->rx_chain = cpu_to_le16(rx_chain);
+       switch (priv->scan_type) {
+       case IWL_SCAN_NORMAL:
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       vif->addr,
+                                       priv->scan_request->ie,
+                                       priv->scan_request->ie_len,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
+               break;
+       case IWL_SCAN_RADIO_RESET:
+       case IWL_SCAN_ROC:
+               /* use bcast addr, will not be transmitted but must be valid */
+               cmd_len = iwl_fill_probe_req(priv,
+                                       (struct ieee80211_mgmt *)scan->data,
+                                       iwl_bcast_addr, NULL, 0,
+                                       IWL_MAX_SCAN_SIZE - sizeof(*scan));
+               break;
+       default:
+               BUG();
+       }
+       scan->tx_cmd.len = cpu_to_le16(cmd_len);
+
+       scan->filter_flags |= (RXON_FILTER_ACCEPT_GRP_MSK |
+                              RXON_FILTER_BCON_AWARE_MSK);
+
+       switch (priv->scan_type) {
+       case IWL_SCAN_RADIO_RESET:
+               scan->channel_count =
+                       iwl_get_single_channel_for_scan(priv, vif, band,
+                               (void *)&scan->data[cmd_len]);
+               break;
+       case IWL_SCAN_NORMAL:
+               scan->channel_count =
+                       iwl_get_channels_for_scan(priv, vif, band,
+                               is_active, n_probes,
+                               (void *)&scan->data[cmd_len]);
+               break;
+       case IWL_SCAN_ROC: {
+               struct iwl_scan_channel *scan_ch;
+               int n_chan, i;
+               u16 dwell;
+
+               dwell = iwl_limit_dwell(priv, priv->hw_roc_duration);
+               n_chan = DIV_ROUND_UP(priv->hw_roc_duration, dwell);
+
+               scan->channel_count = n_chan;
+
+               scan_ch = (void *)&scan->data[cmd_len];
+
+               for (i = 0; i < n_chan; i++) {
+                       scan_ch->type = SCAN_CHANNEL_TYPE_PASSIVE;
+                       scan_ch->channel =
+                               cpu_to_le16(priv->hw_roc_channel->hw_value);
+
+                       if (i == n_chan - 1)
+                               dwell = priv->hw_roc_duration - i * dwell;
+
+                       scan_ch->active_dwell =
+                       scan_ch->passive_dwell = cpu_to_le16(dwell);
+
+                       /* Set txpower levels to defaults */
+                       scan_ch->dsp_atten = 110;
+
+                       /* NOTE: if we were doing 6Mb OFDM for scans we'd use
+                        * power level:
+                        * scan_ch->tx_gain = ((1 << 5) | (2 << 3)) | 3;
+                        */
+                       if (priv->hw_roc_channel->band == IEEE80211_BAND_5GHZ)
+                               scan_ch->tx_gain = ((1 << 5) | (3 << 3)) | 3;
+                       else
+                               scan_ch->tx_gain = ((1 << 5) | (5 << 3));
+
+                       scan_ch++;
+               }
                }
+
+               break;
+       }
+
+       if (scan->channel_count == 0) {
+               IWL_DEBUG_SCAN(priv, "channel count %d\n", scan->channel_count);
+               return -EIO;
+       }
+
+       cmd.len[0] += le16_to_cpu(scan->tx_cmd.len) +
+           scan->channel_count * sizeof(struct iwl_scan_channel);
+       cmd.data[0] = scan;
+       cmd.dataflags[0] = IWL_HCMD_DFL_NOCOPY;
+       scan->len = cpu_to_le16(cmd.len[0]);
+
+       /* set scan bit here for PAN params */
+       set_bit(STATUS_SCAN_HW, &priv->shrd->status);
+
+       ret = iwlagn_set_pan_params(priv);
+       if (ret)
+               return ret;
+
+       ret = iwl_trans_send_cmd(trans(priv), &cmd);
+       if (ret) {
+               clear_bit(STATUS_SCAN_HW, &priv->shrd->status);
+               iwlagn_set_pan_params(priv);
        }
 
-       return passive;
+       return ret;
 }
 
 void iwl_init_scan_params(struct iwl_priv *priv)
@@ -415,31 +954,33 @@ int iwl_mac_hw_scan(struct ieee80211_hw *hw,
 
        mutex_lock(&priv->shrd->mutex);
 
-       if (test_bit(STATUS_SCANNING, &priv->shrd->status) &&
-           priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-               ret = -EAGAIN;
-               goto out_unlock;
-       }
-
-       /* mac80211 will only ask for one band at a time */
-       priv->scan_request = req;
-       priv->scan_vif = vif;
-
        /*
         * If an internal scan is in progress, just set
         * up the scan_request as per above.
         */
        if (priv->scan_type != IWL_SCAN_NORMAL) {
-               IWL_DEBUG_SCAN(priv, "SCAN request during internal scan\n");
+               IWL_DEBUG_SCAN(priv,
+                              "SCAN request during internal scan - defer\n");
+               priv->scan_request = req;
+               priv->scan_vif = vif;
                ret = 0;
-       } else
+       } else {
+               priv->scan_request = req;
+               priv->scan_vif = vif;
+               /*
+                * mac80211 will only ask for one band at a time
+                * so using channels[0] here is ok
+                */
                ret = iwl_scan_initiate(priv, vif, IWL_SCAN_NORMAL,
                                        req->channels[0]->band);
+               if (ret) {
+                       priv->scan_request = NULL;
+                       priv->scan_vif = NULL;
+               }
+       }
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
 
-out_unlock:
        mutex_unlock(&priv->shrd->mutex);
 
        return ret;
@@ -557,61 +1098,10 @@ static void iwl_bg_abort_scan(struct work_struct *work)
 static void iwl_bg_scan_completed(struct work_struct *work)
 {
        struct iwl_priv *priv =
-           container_of(work, struct iwl_priv, scan_completed);
-       bool aborted;
-
-       IWL_DEBUG_SCAN(priv, "Completed scan.\n");
-
-       cancel_delayed_work(&priv->scan_check);
+               container_of(work, struct iwl_priv, scan_completed);
 
        mutex_lock(&priv->shrd->mutex);
-
-       aborted = test_and_clear_bit(STATUS_SCAN_ABORTING, &priv->shrd->status);
-       if (aborted)
-               IWL_DEBUG_SCAN(priv, "Aborted scan completed.\n");
-
-       if (!test_and_clear_bit(STATUS_SCANNING, &priv->shrd->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan already completed.\n");
-               goto out_settings;
-       }
-
-       if (priv->scan_type == IWL_SCAN_ROC) {
-               ieee80211_remain_on_channel_expired(priv->hw);
-               priv->hw_roc_channel = NULL;
-               schedule_delayed_work(&priv->hw_roc_disable_work, 10 * HZ);
-       }
-
-       if (priv->scan_type != IWL_SCAN_NORMAL && !aborted) {
-               int err;
-
-               /* Check if mac80211 requested scan during our internal scan */
-               if (priv->scan_request == NULL)
-                       goto out_complete;
-
-               /* If so request a new scan */
-               err = iwl_scan_initiate(priv, priv->scan_vif, IWL_SCAN_NORMAL,
-                                       priv->scan_request->channels[0]->band);
-               if (err) {
-                       IWL_DEBUG_SCAN(priv,
-                               "failed to initiate pending scan: %d\n", err);
-                       aborted = true;
-                       goto out_complete;
-               }
-
-               goto out;
-       }
-
-out_complete:
-       iwl_complete_scan(priv, aborted);
-
-out_settings:
-       /* Can we still talk to firmware ? */
-       if (!iwl_is_ready_rf(priv->shrd))
-               goto out;
-
-       iwlagn_post_scan(priv);
-
-out:
+       iwl_process_scan_complete(priv);
        mutex_unlock(&priv->shrd->mutex);
 }
 
index d987bee5e6ceee8804bbc9ba65dea5b992895f9d..8747bbdf898311cfc2a9f75b3111dfb0329577eb 100644 (file)
 
 #include "iwl-commands.h"
 
-/*This files includes all the types / functions that are exported by the
- * upper layer to the bus and transport layer */
+/**
+ * DOC: shared area - role and goal
+ *
+ * The shared area contains all the data exported by the upper layer to the
+ * other layers. Since the bus and transport layer shouldn't dereference
+ * iwl_priv, all the data needed by the upper layer and the transport / bus
+ * layer must be here.
+ * The shared area also holds pointer to all the other layers. This allows a
+ * layer to call a function from another layer.
+ *
+ * NOTE: All the layers hold a pointer to the shared area which must be shrd.
+ *     A few macros assume that (_m)->shrd points to the shared area no matter
+ *     what _m is.
+ *
+ * gets notifications about enumeration, suspend, resume.
+ * For the moment, the bus layer is not a linux kernel module as itself, and
+ * the module_init function of the driver must call the bus specific
+ * registration functions. These functions are listed at the end of this file.
+ * For the moment, there is only one implementation of this interface: PCI-e.
+ * This implementation is iwl-pci.c
+ */
 
 struct iwl_cfg;
 struct iwl_bus;
@@ -90,6 +109,9 @@ extern struct iwl_mod_params iwlagn_mod_params;
 
 /**
  * struct iwl_mod_params
+ *
+ * Holds the module parameters
+ *
  * @sw_crypto: using hardware encryption, default = 0
  * @num_of_queues: number of tx queue, HW dependent
  * @disable_11n: 11n capabilities enabled, default = 0
@@ -134,20 +156,24 @@ struct iwl_mod_params {
 
 /**
  * struct iwl_hw_params
+ *
+ * Holds the module parameters
+ *
  * @max_txq_num: Max # Tx queues supported
  * @num_ampdu_queues: num of ampdu queues
- * @tx/rx_chains_num: Number of TX/RX chains
- * @valid_tx/rx_ant: usable antennas
- * @max_stations:
- * @ht40_channel: is 40MHz width possible in band 2.4
- * @beacon_time_tsf_bits: number of valid tsf bits for beacon time
- * @sku:
+ * @tx_chains_num: Number of TX chains
+ * @rx_chains_num: Number of RX chains
+ * @valid_tx_ant: usable antennas for TX
+ * @valid_rx_ant: usable antennas for RX
+ * @max_stations: the maximal number of stations
+ * @ht40_channel: is 40MHz width possible: BIT(IEEE80211_BAND_XXX)
+ * @sku: sku read from EEPROM
  * @rx_page_order: Rx buffer page order
- * @rx_wrt_ptr_reg: FH{39}_RSCSR_CHNL0_WPTR
- * BIT(IEEE80211_BAND_5GHZ) BIT(IEEE80211_BAND_5GHZ)
- * @sw_crypto: 0 for hw, 1 for sw
- * @max_xxx_size: for ucode uses
- * @ct_kill_threshold: temperature threshold
+ * @max_inst_size: for ucode use
+ * @max_data_size: for ucode use
+ * @ct_kill_threshold: temperature threshold - in hw dependent unit
+ * @ct_kill_exit_threshold: when to reeable the device - in hw dependent unit
+ *     relevant for 1000, 6000 and up
  * @wd_timeout: TX queues watchdog timeout
  * @calib_init_cfg: setup initial calibrations for the hw
  * @calib_rt_cfg: setup runtime calibrations for the hw
@@ -163,14 +189,12 @@ struct iwl_hw_params {
        u8  max_stations;
        u8  ht40_channel;
        bool shadow_reg_enable;
-       u16 beacon_time_tsf_bits;
        u16 sku;
        u32 rx_page_order;
        u32 max_inst_size;
        u32 max_data_size;
-       u32 ct_kill_threshold; /* value in hw-dependent units */
-       u32 ct_kill_exit_threshold; /* value in hw-dependent units */
-                                   /* for 1000, 6000 series and up */
+       u32 ct_kill_threshold;
+       u32 ct_kill_exit_threshold;
        unsigned int wd_timeout;
 
        u32 calib_init_cfg;
@@ -179,28 +203,59 @@ struct iwl_hw_params {
 };
 
 /**
- * struct iwl_ht_agg - aggregation status while waiting for block-ack
- * @txq_id: Tx queue used for Tx attempt
- * @wait_for_ba: Expect block-ack before next Tx reply
- * @rate_n_flags: Rate at which Tx was attempted
+ * enum iwl_agg_state
  *
- * If REPLY_TX indicates that aggregation was attempted, driver must wait
- * for block ack (REPLY_COMPRESSED_BA).  This struct stores tx reply info
- * until block ack arrives.
+ * The state machine of the BA agreement establishment / tear down.
+ * These states relate to a specific RA / TID.
+ *
+ * @IWL_AGG_OFF: aggregation is not used
+ * @IWL_AGG_ON: aggregation session is up
+ * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the
+ *     HW queue to be empty from packets for this RA /TID.
+ * @IWL_EMPTYING_HW_QUEUE_DELBA: tearing down a BA session - waiting for the
+ *     HW queue to be empty from packets for this RA /TID.
+ */
+enum iwl_agg_state {
+       IWL_AGG_OFF = 0,
+       IWL_AGG_ON,
+       IWL_EMPTYING_HW_QUEUE_ADDBA,
+       IWL_EMPTYING_HW_QUEUE_DELBA,
+};
+
+/**
+ * struct iwl_ht_agg - aggregation state machine
+
+ * This structs holds the states for the BA agreement establishment and tear
+ * down. It also holds the state during the BA session itself. This struct is
+ * duplicated for each RA / TID.
+
+ * @rate_n_flags: Rate at which Tx was attempted. Holds the data between the
+ *     Tx response (REPLY_TX), and the block ack notification
+ *     (REPLY_COMPRESSED_BA).
+ * @state: state of the BA agreement establishment / tear down.
+ * @txq_id: Tx queue used by the BA session - used by the transport layer.
+ *     Needed by the upper layer for debugfs only.
+ * @wait_for_ba: Expect block-ack before next Tx reply
  */
 struct iwl_ht_agg {
-       u16 txq_id;
-       u16 wait_for_ba;
        u32 rate_n_flags;
-#define IWL_AGG_OFF 0
-#define IWL_AGG_ON 1
-#define IWL_EMPTYING_HW_QUEUE_ADDBA 2
-#define IWL_EMPTYING_HW_QUEUE_DELBA 3
-       u8 state;
+       enum iwl_agg_state state;
+       u16 txq_id;
+       bool wait_for_ba;
 };
 
+/**
+ * struct iwl_tid_data - one for each RA / TID
+
+ * This structs holds the states for each RA / TID.
+
+ * @seq_number: the next WiFi sequence number to use
+ * @tfds_in_queue: number of packets sent to the HW queues.
+ *     Exported for debugfs only
+ * @agg: aggregation state machine
+ */
 struct iwl_tid_data {
-       u16 seq_number; /* agn only */
+       u16 seq_number;
        u16 tfds_in_queue;
        struct iwl_ht_agg agg;
 };
@@ -246,12 +301,6 @@ struct iwl_shared {
        spinlock_t sta_lock;
        struct mutex mutex;
 
-       /*these 2 shouldn't really be here, but they are needed for
-        * iwl_queue_stop, which is called from the upper layer too
-        */
-       u8 mac80211_registered;
-       struct ieee80211_hw *hw;
-
        struct iwl_tid_data tid_data[IWLAGN_STATION_COUNT][IWL_MAX_TID_COUNT];
 
        wait_queue_head_t wait_command_queue;
@@ -371,16 +420,14 @@ enum iwl_rxon_context_id {
        NUM_IWL_RXON_CTX
 };
 
-#ifdef CONFIG_PM
-int iwl_suspend(struct iwl_priv *priv);
-int iwl_resume(struct iwl_priv *priv);
-#endif /* !CONFIG_PM */
-
 int iwl_probe(struct iwl_bus *bus, const struct iwl_trans_ops *trans_ops,
                struct iwl_cfg *cfg);
 void __devexit iwl_remove(struct iwl_priv * priv);
+struct iwl_device_cmd;
+int __must_check iwl_rx_dispatch(struct iwl_priv *priv,
+                                struct iwl_rx_mem_buffer *rxb,
+                                struct iwl_device_cmd *cmd);
 
-void iwl_rx_dispatch(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
 int iwlagn_hw_valid_rtc_data_addr(u32 addr);
 void iwl_start_tx_ba_trans_ready(struct iwl_priv *priv,
                                 enum iwl_rxon_context_id ctx,
@@ -390,20 +437,26 @@ void iwl_stop_tx_ba_trans_ready(struct iwl_priv *priv,
                                u8 sta_id, u8 tid);
 void iwl_set_hw_rfkill_state(struct iwl_priv *priv, bool state);
 void iwl_nic_config(struct iwl_priv *priv);
+void iwl_free_skb(struct iwl_priv *priv, struct sk_buff *skb);
 void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand);
 const char *get_cmd_string(u8 cmd);
 bool iwl_check_for_ct_kill(struct iwl_priv *priv);
 
+void iwl_stop_sw_queue(struct iwl_priv *priv, u8 ac);
+void iwl_wake_sw_queue(struct iwl_priv *priv, u8 ac);
+
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 void iwl_reset_traffic_log(struct iwl_priv *priv);
 #endif /* CONFIG_IWLWIFI_DEBUGFS */
 
 #ifdef CONFIG_IWLWIFI_DEBUG
-void iwl_print_rx_config_cmd(struct iwl_priv *priv, u8 ctxid);
+void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                            enum iwl_rxon_context_id ctxid);
 #else
-static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, u8 ctxid)
+static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv,
+                                          enum iwl_rxon_context_id ctxid)
 {
 }
 #endif
@@ -436,6 +489,7 @@ static inline void iwl_print_rx_config_cmd(struct iwl_priv *priv, u8 ctxid)
 #define STATUS_FW_ERROR                17
 #define STATUS_DEVICE_ENABLED  18
 #define STATUS_CHANNEL_SWITCH_PENDING 19
+#define STATUS_SCAN_COMPLETE   20
 
 static inline int iwl_is_ready(struct iwl_shared *shrd)
 {
index e24135e7d37d78d45a2376e137da289ca614295b..580a4d702ff3c019ef7c84880ae080f272eae3eb 100644 (file)
@@ -59,8 +59,7 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id)
 
 static int iwl_process_add_sta_resp(struct iwl_priv *priv,
                                    struct iwl_addsta_cmd *addsta,
-                                   struct iwl_rx_packet *pkt,
-                                   bool sync)
+                                   struct iwl_rx_packet *pkt)
 {
        u8 sta_id = addsta->sta.sta_id;
        unsigned long flags;
@@ -123,15 +122,14 @@ static int iwl_process_add_sta_resp(struct iwl_priv *priv,
        return ret;
 }
 
-static void iwl_add_sta_callback(struct iwl_shared *shrd,
-                                struct iwl_device_cmd *cmd,
-                                struct iwl_rx_packet *pkt)
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd)
 {
+       struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_addsta_cmd *addsta =
-               (struct iwl_addsta_cmd *)cmd->cmd.payload;
-
-       iwl_process_add_sta_resp(shrd->priv, addsta, pkt, false);
+               (struct iwl_addsta_cmd *) cmd->payload;
 
+       return iwl_process_add_sta_resp(priv, addsta, pkt);
 }
 
 static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
@@ -147,7 +145,6 @@ static u16 iwlagn_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data)
 int iwl_send_add_sta(struct iwl_priv *priv,
                     struct iwl_addsta_cmd *sta, u8 flags)
 {
-       struct iwl_rx_packet *pkt = NULL;
        int ret = 0;
        u8 data[sizeof(*sta)];
        struct iwl_host_cmd cmd = {
@@ -160,9 +157,7 @@ int iwl_send_add_sta(struct iwl_priv *priv,
        IWL_DEBUG_INFO(priv, "Adding sta %u (%pM) %ssynchronously\n",
                       sta_id, sta->sta.addr, flags & CMD_ASYNC ?  "a" : "");
 
-       if (flags & CMD_ASYNC)
-               cmd.callback = iwl_add_sta_callback;
-       else {
+       if (!(flags & CMD_ASYNC)) {
                cmd.flags |= CMD_WANT_SKB;
                might_sleep();
        }
@@ -172,14 +167,16 @@ int iwl_send_add_sta(struct iwl_priv *priv,
 
        if (ret || (flags & CMD_ASYNC))
                return ret;
+       /*else the command was successfully sent in SYNC mode, need to free
+        * the reply page */
 
-       if (ret == 0) {
-               pkt = (struct iwl_rx_packet *)cmd.reply_page;
-               ret = iwl_process_add_sta_resp(priv, sta, pkt, true);
-       }
        iwl_free_pages(priv->shrd, cmd.reply_page);
 
-       return ret;
+       if (cmd.handler_status)
+               IWL_ERR(priv, "%s - error in the CMD response %d", __func__,
+                       cmd.handler_status);
+
+       return cmd.handler_status;
 }
 
 static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index,
@@ -305,7 +302,7 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
        station->ctxid = ctx->ctxid;
 
        if (sta) {
-               struct iwl_station_priv_common *sta_priv;
+               struct iwl_station_priv *sta_priv;
 
                sta_priv = (void *)sta->drv_priv;
                sta_priv->ctx = ctx;
@@ -821,7 +818,7 @@ int iwl_mac_sta_remove(struct ieee80211_hw *hw,
                       struct ieee80211_sta *sta)
 {
        struct iwl_priv *priv = hw->priv;
-       struct iwl_station_priv_common *sta_common = (void *)sta->drv_priv;
+       struct iwl_station_priv *sta_priv = (void *)sta->drv_priv;
        int ret;
 
        IWL_DEBUG_INFO(priv, "received request to remove station %pM\n",
@@ -829,7 +826,7 @@ int iwl_mac_sta_remove(struct ieee80211_hw *hw,
        mutex_lock(&priv->shrd->mutex);
        IWL_DEBUG_INFO(priv, "proceeding to remove station %pM\n",
                        sta->addr);
-       ret = iwl_remove_station(priv, sta_common->sta_id, sta->addr);
+       ret = iwl_remove_station(priv, sta_priv->sta_id, sta->addr);
        if (ret)
                IWL_ERR(priv, "Error removing station %pM\n",
                        sta->addr);
index 9641eb6b1d0afa435fed3803c6b95fbc289376cd..1bca0dabde8d1009309a3e662db95aebca3b3b8c 100644 (file)
@@ -61,6 +61,9 @@ u8 iwl_prep_station(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
 int iwl_send_lq_cmd(struct iwl_priv *priv, struct iwl_rxon_context *ctx,
                    struct iwl_link_quality_cmd *lq, u8 flags, bool init);
 void iwl_reprogram_ap_sta(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
+int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
+                              struct iwl_device_cmd *cmd);
+
 
 /**
  * iwl_clear_driver_stations - clear knowledge of all stations from driver
@@ -102,7 +105,7 @@ static inline int iwl_sta_id(struct ieee80211_sta *sta)
        if (WARN_ON(!sta))
                return IWL_INVALID_STATION;
 
-       return ((struct iwl_station_priv_common *)sta->drv_priv)->sta_id;
+       return ((struct iwl_station_priv *)sta->drv_priv)->sta_id;
 }
 
 /**
similarity index 94%
rename from drivers/net/wireless/iwlwifi/iwl-trans-int-pcie.h
rename to drivers/net/wireless/iwlwifi/iwl-trans-pcie-int.h
index 8047e955a27b0bb0661dc762fab0e868e1ed633e..2b6756e8b8f97578394bdfd2a473f8acd0bd95d6 100644 (file)
@@ -118,16 +118,6 @@ struct iwl_dma_ptr {
 struct iwl_cmd_meta {
        /* only for SYNC commands, iff the reply skb is wanted */
        struct iwl_host_cmd *source;
-       /*
-        * only for ASYNC commands
-        * (which is somewhat stupid -- look at iwl-sta.c for instance
-        * which duplicates a bunch of code because the callback isn't
-        * invoked for SYNC commands, if it were and its result passed
-        * through it would be simpler...)
-        */
-       void (*callback)(struct iwl_shared *shrd,
-                        struct iwl_device_cmd *cmd,
-                        struct iwl_rx_packet *pkt);
 
        u32 flags;
 
@@ -285,10 +275,8 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
                                 dma_addr_t addr, u16 len, u8 reset);
 int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
 int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
-int __must_check iwl_trans_pcie_send_cmd_pdu(struct iwl_trans *trans, u8 id,
-                       u32 flags, u16 len, const void *data);
 void iwl_tx_cmd_complete(struct iwl_trans *trans,
-                        struct iwl_rx_mem_buffer *rxb);
+                        struct iwl_rx_mem_buffer *rxb, int handler_status);
 void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
                                           struct iwl_tx_queue *txq,
                                           u16 byte_cnt);
@@ -307,7 +295,7 @@ void iwl_trans_pcie_tx_agg_setup(struct iwl_trans *trans,
                                 enum iwl_rxon_context_id ctx,
                                 int sta_id, int tid, int frame_limit);
 void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-       int index);
+       int index, enum dma_data_direction dma_dir);
 int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
                         struct sk_buff_head *skbs);
 int iwl_queue_space(const struct iwl_queue *q);
@@ -375,12 +363,9 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (unlikely(!trans->shrd->mac80211_registered))
-               return;
-
        if (test_and_clear_bit(hwq, trans_pcie->queue_stopped))
                if (atomic_dec_return(&trans_pcie->queue_stop_count[ac]) <= 0)
-                       ieee80211_wake_queue(trans->shrd->hw, ac);
+                       iwl_wake_sw_queue(priv(trans), ac);
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
@@ -392,12 +377,9 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       if (unlikely(!trans->shrd->mac80211_registered))
-               return;
-
        if (!test_and_set_bit(hwq, trans_pcie->queue_stopped))
                if (atomic_inc_return(&trans_pcie->queue_stop_count[ac]) > 0)
-                       ieee80211_stop_queue(trans->shrd->hw, ac);
+                       iwl_stop_sw_queue(priv(trans), ac);
 }
 
 #ifdef ieee80211_stop_queue
similarity index 97%
rename from drivers/net/wireless/iwlwifi/iwl-trans-rx-pcie.c
rename to drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
index 126e5a4cc401e3602095b69001f66702b351e388..b4eff556cd0a84de0662a8e22b91816a5302e270 100644 (file)
@@ -34,7 +34,7 @@
 #include "iwl-core.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
-#include "iwl-trans-int-pcie.h"
+#include "iwl-trans-pcie-int.h"
 
 /******************************************************************************
  *
@@ -372,12 +372,15 @@ static void iwl_rx_handle(struct iwl_trans *trans)
        struct iwl_trans_pcie *trans_pcie =
                IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct iwl_tx_queue *txq = &trans_pcie->txq[trans->shrd->cmd_queue];
+       struct iwl_device_cmd *cmd;
        u32 r, i;
        int reclaim;
        unsigned long flags;
        u8 fill_rx = 0;
        u32 count = 8;
        int total_empty;
+       int index, cmd_index;
 
        /* uCode's read index (stored in shared DRAM) indicates the last Rx
         * buffer that the driver may process (last buffer filled by ucode). */
@@ -397,7 +400,8 @@ static void iwl_rx_handle(struct iwl_trans *trans)
                fill_rx = 1;
 
        while (i != r) {
-               int len;
+               int len, err;
+               u16 sequence;
 
                rxb = rxq->queue[i];
 
@@ -437,7 +441,27 @@ static void iwl_rx_handle(struct iwl_trans *trans)
                        (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
                        (pkt->hdr.cmd != REPLY_TX);
 
-               iwl_rx_dispatch(priv(trans), rxb);
+               sequence = le16_to_cpu(pkt->hdr.sequence);
+               index = SEQ_TO_INDEX(sequence);
+               cmd_index = get_cmd_index(&txq->q, index);
+
+               if (reclaim)
+                       cmd = txq->cmd[cmd_index];
+               else
+                       cmd = NULL;
+
+               /* warn if this is cmd response / notification and the uCode
+                * didn't set the SEQ_RX_FRAME for a frame that is
+                * uCode-originated
+                * If you saw this code after the second half of 2012, then
+                * please remove it
+                */
+               WARN(pkt->hdr.cmd != REPLY_TX && reclaim == false &&
+                    (!(pkt->hdr.sequence & SEQ_RX_FRAME)),
+                    "reclaim is false, SEQ_RX_FRAME unset: %s\n",
+                    get_cmd_string(pkt->hdr.cmd));
+
+               err = iwl_rx_dispatch(priv(trans), rxb, cmd);
 
                /*
                 * XXX: After here, we should always check rxb->page
@@ -452,7 +476,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
                         * iwl_trans_send_cmd()
                         * as we reclaim the driver command queue */
                        if (rxb->page)
-                               iwl_tx_cmd_complete(trans, rxb);
+                               iwl_tx_cmd_complete(trans, rxb, err);
                        else
                                IWL_WARN(trans, "Claim null rxb?\n");
                }
@@ -645,7 +669,7 @@ static void iwl_irq_handle_error(struct iwl_trans *trans)
                 */
                clear_bit(STATUS_READY, &trans->shrd->status);
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
-               wake_up_interruptible(&priv->shrd->wait_command_queue);
+               wake_up(&priv->shrd->wait_command_queue);
                IWL_ERR(trans, "RF is used by WiMAX\n");
                return;
        }
@@ -1086,7 +1110,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                handled |= CSR_INT_BIT_FH_TX;
                /* Wake up uCode load routine, now that load is complete */
                priv(trans)->ucode_write_complete = 1;
-               wake_up_interruptible(&trans->shrd->wait_command_queue);
+               wake_up(&trans->shrd->wait_command_queue);
        }
 
        if (inta & ~handled) {
similarity index 94%
rename from drivers/net/wireless/iwlwifi/iwl-trans-tx-pcie.c
rename to drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index f6d823f012dba9a5b22f020e18f3b702c5b5f417..ee7059dcbbcb1a5bb142547b7ea70fabfd473d88 100644 (file)
@@ -38,7 +38,7 @@
 #include "iwl-io.h"
 #include "iwl-agn-hw.h"
 #include "iwl-helpers.h"
-#include "iwl-trans-int-pcie.h"
+#include "iwl-trans-pcie-int.h"
 
 #define IWL_TX_CRC_SIZE 4
 #define IWL_TX_DELIMITER_SIZE 4
@@ -59,13 +59,15 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
        u8 sta_id = 0;
        u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE;
        __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (struct iwl_tx_cmd *) txq->cmd[txq->q.write_ptr]->payload;
 
        scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
 
        WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX);
 
-       sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id;
-       sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl;
+       sta_id = tx_cmd->sta_id;
+       sec_ctl = tx_cmd->sec_ctl;
 
        switch (sec_ctl & TX_CMD_SEC_MSK) {
        case TX_CMD_SEC_CCM:
@@ -207,17 +209,17 @@ static void iwlagn_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
  * @trans - transport private data
  * @txq - tx queue
  * @index - the index of the TFD to be freed
+ *@dma_dir - the direction of the DMA mapping
  *
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
 void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-       int index)
+       int index, enum dma_data_direction dma_dir)
 {
        struct iwl_tfd *tfd_tmp = txq->tfds;
 
-       iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index],
-                        DMA_TO_DEVICE);
+       iwlagn_unmap_tfd(trans, &txq->meta[index], &tfd_tmp[index], dma_dir);
 
        /* free SKB */
        if (txq->skbs) {
@@ -225,9 +227,12 @@ void iwlagn_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
 
                skb = txq->skbs[index];
 
-               /* can be called from irqs-disabled context */
+               /* Can be called from irqs-disabled context
+                * If skb is not NULL, it means that the whole queue is being
+                * freed and that the queue is not empty - free the skb
+                */
                if (skb) {
-                       dev_kfree_skb_any(skb);
+                       iwl_free_skb(priv(trans), skb);
                        txq->skbs[index] = NULL;
                }
        }
@@ -350,11 +355,13 @@ static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
        int read_ptr = txq->q.read_ptr;
        u8 sta_id = 0;
        __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (struct iwl_tx_cmd *) txq->cmd[txq->q.read_ptr]->payload;
 
        WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
 
        if (txq_id != trans->shrd->cmd_queue)
-               sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id;
+               sta_id = tx_cmd->sta_id;
 
        bc_ent = cpu_to_le16(1 | (sta_id << 12));
        scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
@@ -759,8 +766,6 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        memset(out_meta, 0, sizeof(*out_meta)); /* re-initialize to NULL */
        if (cmd->flags & CMD_WANT_SKB)
                out_meta->source = cmd;
-       if (cmd->flags & CMD_ASYNC)
-               out_meta->callback = cmd->callback;
 
        /* set up the header */
 
@@ -772,7 +777,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        /* and copy the data that needs to be copied */
 
-       cmd_dest = &out_cmd->cmd.payload[0];
+       cmd_dest = out_cmd->payload;
        for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
                if (!cmd->len[i])
                        continue;
@@ -891,12 +896,15 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
 /**
  * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
+ * @handler_status: return value of the handler of the command
+ *     (put in setup_rx_handlers)
  *
  * If an Rx buffer has an async callback associated with it the callback
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
+void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb,
+                        int handler_status)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -933,9 +941,9 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
                meta->source->reply_page = (unsigned long)rxb_addr(rxb);
+               meta->source->handler_status = handler_status;
                rxb->page = NULL;
-       } else if (meta->callback)
-               meta->callback(trans->shrd, cmd, pkt);
+       }
 
        spin_lock_irqsave(&trans->hcmd_lock, flags);
 
@@ -945,7 +953,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
                clear_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
                               get_cmd_string(cmd->hdr.cmd));
-               wake_up_interruptible(&trans->shrd->wait_command_queue);
+               wake_up(&trans->shrd->wait_command_queue);
        }
 
        meta->flags = 0;
@@ -955,30 +963,6 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_mem_buffer *rxb)
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
 
-static void iwl_generic_cmd_callback(struct iwl_shared *shrd,
-                                    struct iwl_device_cmd *cmd,
-                                    struct iwl_rx_packet *pkt)
-{
-       if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
-               IWL_ERR(shrd->trans, "Bad return from %s (0x%08X)\n",
-                       get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-               return;
-       }
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-       switch (cmd->hdr.cmd) {
-       case REPLY_TX_LINK_QUALITY_CMD:
-       case SENSITIVITY_CMD:
-               IWL_DEBUG_HC_DUMP(shrd->trans, "back from %s (0x%08X)\n",
-                               get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-               break;
-       default:
-               IWL_DEBUG_HC(shrd->trans, "back from %s (0x%08X)\n",
-                               get_cmd_string(cmd->hdr.cmd), pkt->hdr.flags);
-       }
-#endif
-}
-
 static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 {
        int ret;
@@ -987,9 +971,6 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (WARN_ON(cmd->flags & CMD_WANT_SKB))
                return -EINVAL;
 
-       /* Assign a generic callback if one is not provided */
-       if (!cmd->callback)
-               cmd->callback = iwl_generic_cmd_callback;
 
        if (test_bit(STATUS_EXIT_PENDING, &trans->shrd->status))
                return -EBUSY;
@@ -1011,10 +992,6 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        lockdep_assert_held(&trans->shrd->mutex);
 
-        /* A synchronous command can not have a callback set. */
-       if (WARN_ON(cmd->callback))
-               return -EINVAL;
-
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
                        get_cmd_string(cmd->id));
 
@@ -1031,7 +1008,7 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                return ret;
        }
 
-       ret = wait_event_interruptible_timeout(trans->shrd->wait_command_queue,
+       ret = wait_event_timeout(trans->shrd->wait_command_queue,
                        !test_bit(STATUS_HCMD_ACTIVE, &trans->shrd->status),
                        HOST_COMPLETE_TIMEOUT);
        if (!ret) {
@@ -1098,19 +1075,6 @@ int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        return iwl_send_cmd_sync(trans, cmd);
 }
 
-int iwl_trans_pcie_send_cmd_pdu(struct iwl_trans *trans, u8 id, u32 flags,
-               u16 len, const void *data)
-{
-       struct iwl_host_cmd cmd = {
-               .id = id,
-               .len = { len, },
-               .data = { data, },
-               .flags = flags,
-       };
-
-       return iwl_trans_pcie_send_cmd(trans, &cmd);
-}
-
 /* Frees buffers until index _not_ inclusive */
 int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
                         struct sk_buff_head *skbs)
@@ -1121,6 +1085,10 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
        int last_to_free;
        int freed = 0;
 
+       /* This function is not meant to release cmd queue*/
+       if (WARN_ON(txq_id == trans->shrd->cmd_queue))
+               return 0;
+
        /*Since we free until index _not_ inclusive, the one before index is
         * the last we will free. This one must be used */
        last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
@@ -1153,7 +1121,7 @@ int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
 
                iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
 
-               iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr);
+               iwlagn_txq_free_tfd(trans, txq, txq->q.read_ptr, DMA_TO_DEVICE);
                freed++;
        }
        return freed;
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
new file mode 100644 (file)
index 0000000..416e992
--- /dev/null
@@ -0,0 +1,1989 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2007 - 2011 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called LICENSE.GPL.
+ *
+ * Contact Information:
+ *  Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2005 - 2011 Intel Corporation. All rights reserved.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * 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.
+ *  * Neither the name Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT
+ * OWNER 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/interrupt.h>
+#include <linux/debugfs.h>
+#include <linux/bitops.h>
+#include <linux/gfp.h>
+
+#include "iwl-trans.h"
+#include "iwl-trans-pcie-int.h"
+#include "iwl-csr.h"
+#include "iwl-prph.h"
+#include "iwl-shared.h"
+#include "iwl-eeprom.h"
+#include "iwl-agn-hw.h"
+
+static int iwl_trans_rx_alloc(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct device *dev = bus(trans)->dev;
+
+       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+
+       spin_lock_init(&rxq->lock);
+
+       if (WARN_ON(rxq->bd || rxq->rb_stts))
+               return -EINVAL;
+
+       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+       rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                                    &rxq->bd_dma, GFP_KERNEL);
+       if (!rxq->bd)
+               goto err_bd;
+       memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
+
+       /*Allocate the driver's pointer to receive buffer status */
+       rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                         &rxq->rb_stts_dma, GFP_KERNEL);
+       if (!rxq->rb_stts)
+               goto err_rb_stts;
+       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
+
+       return 0;
+
+err_rb_stts:
+       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                       rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+err_bd:
+       return -ENOMEM;
+}
+
+static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       int i;
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].page != NULL) {
+                       dma_unmap_page(bus(trans)->dev, rxq->pool[i].page_dma,
+                               PAGE_SIZE << hw_params(trans).rx_page_order,
+                               DMA_FROM_DEVICE);
+                       __free_pages(rxq->pool[i].page,
+                                    hw_params(trans).rx_page_order);
+                       rxq->pool[i].page = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+}
+
+static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
+                                struct iwl_rx_queue *rxq)
+{
+       u32 rb_size;
+       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+       u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
+
+       if (iwlagn_mod_params.amsdu_size_8K)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          (u32)(rxq->bd_dma >> 8));
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          rxq->rb_stts_dma >> 4);
+
+       /* Enable Rx DMA
+        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+        *      the credit mechanism in 5000 HW RX FIFO
+        * Direct rx interrupts to hosts
+        * Rx buffer size 4 or 8k
+        * RB timeout 0x10
+        * 256 RBDs
+        */
+       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
+                          rb_size|
+                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(bus(trans), CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+}
+
+static int iwl_rx_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+       int i, err;
+       unsigned long flags;
+
+       if (!rxq->bd) {
+               err = iwl_trans_rx_alloc(trans);
+               if (err)
+                       return err;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       iwl_trans_rxq_free_rx_bufs(trans);
+
+       for (i = 0; i < RX_QUEUE_SIZE; i++)
+               rxq->queue[i] = NULL;
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->write_actual = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       iwlagn_rx_replenish(trans);
+
+       iwl_trans_rx_hw_init(trans, rxq);
+
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+       rxq->need_update = 1;
+       iwl_rx_queue_update_write_ptr(trans, rxq);
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+
+       unsigned long flags;
+
+       /*if rxq->bd is NULL, it means that nothing has been allocated,
+        * exit now */
+       if (!rxq->bd) {
+               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
+               return;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       iwl_trans_rxq_free_rx_bufs(trans);
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       dma_free_coherent(bus(trans)->dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                         rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+
+       if (rxq->rb_stts)
+               dma_free_coherent(bus(trans)->dev,
+                                 sizeof(struct iwl_rb_status),
+                                 rxq->rb_stts, rxq->rb_stts_dma);
+       else
+               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
+       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+       rxq->rb_stts = NULL;
+}
+
+static int iwl_trans_rx_stop(struct iwl_trans *trans)
+{
+
+       /* stop Rx DMA */
+       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       return iwl_poll_direct_bit(bus(trans), FH_MEM_RSSR_RX_STATUS_REG,
+                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
+static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
+                                   struct iwl_dma_ptr *ptr, size_t size)
+{
+       if (WARN_ON(ptr->addr))
+               return -EINVAL;
+
+       ptr->addr = dma_alloc_coherent(bus(trans)->dev, size,
+                                      &ptr->dma, GFP_KERNEL);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
+                                   struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(bus(trans)->dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
+static int iwl_trans_txq_alloc(struct iwl_trans *trans,
+                               struct iwl_tx_queue *txq, int slots_num,
+                               u32 txq_id)
+{
+       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
+       int i;
+
+       if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds))
+               return -EINVAL;
+
+       txq->q.n_window = slots_num;
+
+       txq->meta = kcalloc(slots_num, sizeof(txq->meta[0]), GFP_KERNEL);
+       txq->cmd = kcalloc(slots_num, sizeof(txq->cmd[0]), GFP_KERNEL);
+
+       if (!txq->meta || !txq->cmd)
+               goto error;
+
+       if (txq_id == trans->shrd->cmd_queue)
+               for (i = 0; i < slots_num; i++) {
+                       txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
+                                               GFP_KERNEL);
+                       if (!txq->cmd[i])
+                               goto error;
+               }
+
+       /* Alloc driver data array and TFD circular buffer */
+       /* Driver private data, only for Tx (not command) queues,
+        * not shared with device. */
+       if (txq_id != trans->shrd->cmd_queue) {
+               txq->skbs = kcalloc(TFD_QUEUE_SIZE_MAX, sizeof(txq->skbs[0]),
+                                   GFP_KERNEL);
+               if (!txq->skbs) {
+                       IWL_ERR(trans, "kmalloc for auxiliary BD "
+                                 "structures failed\n");
+                       goto error;
+               }
+       } else {
+               txq->skbs = NULL;
+       }
+
+       /* Circular buffer of transmit frame descriptors (TFDs),
+        * shared with device */
+       txq->tfds = dma_alloc_coherent(bus(trans)->dev, tfd_sz,
+                                      &txq->q.dma_addr, GFP_KERNEL);
+       if (!txq->tfds) {
+               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+               goto error;
+       }
+       txq->q.id = txq_id;
+
+       return 0;
+error:
+       kfree(txq->skbs);
+       txq->skbs = NULL;
+       /* since txq->cmd has been zeroed,
+        * all non allocated cmd[i] will be NULL */
+       if (txq->cmd && txq_id == trans->shrd->cmd_queue)
+               for (i = 0; i < slots_num; i++)
+                       kfree(txq->cmd[i]);
+       kfree(txq->meta);
+       kfree(txq->cmd);
+       txq->meta = NULL;
+       txq->cmd = NULL;
+
+       return -ENOMEM;
+
+}
+
+static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
+                     int slots_num, u32 txq_id)
+{
+       int ret;
+
+       txq->need_update = 0;
+       memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
+
+       /*
+        * For the default queues 0-3, set up the swq_id
+        * already -- all others need to get one later
+        * (if they need one at all).
+        */
+       if (txq_id < 4)
+               iwl_set_swq_id(txq, txq_id, txq_id);
+
+       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+       /* Initialize queue's high/low-water marks, and head/tail indexes */
+       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+                       txq_id);
+       if (ret)
+               return ret;
+
+       /*
+        * Tell nic where to find circular buffer of Tx Frame Descriptors for
+        * given Tx queue, and enable the DMA channel used for that queue.
+        * Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(bus(trans), FH_MEM_CBBC_QUEUE(txq_id),
+                            txq->q.dma_addr >> 8);
+
+       return 0;
+}
+
+/**
+ * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       enum dma_data_direction dma_dir;
+
+       if (!q->n_bd)
+               return;
+
+       /* In the command queue, all the TBs are mapped as BIDI
+        * so unmap them as such.
+        */
+       if (txq_id == trans->shrd->cmd_queue)
+               dma_dir = DMA_BIDIRECTIONAL;
+       else
+               dma_dir = DMA_TO_DEVICE;
+
+       while (q->write_ptr != q->read_ptr) {
+               /* The read_ptr needs to bound by q->n_window */
+               iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr),
+                                   dma_dir);
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+       }
+}
+
+/**
+ * iwl_tx_queue_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       struct device *dev = bus(trans)->dev;
+       int i;
+       if (WARN_ON(!txq))
+               return;
+
+       iwl_tx_queue_unmap(trans, txq_id);
+
+       /* De-alloc array of command/tx buffers */
+
+       if (txq_id == trans->shrd->cmd_queue)
+               for (i = 0; i < txq->q.n_window; i++)
+                       kfree(txq->cmd[i]);
+
+       /* De-alloc circular buffer of TFDs */
+       if (txq->q.n_bd) {
+               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
+                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+       }
+
+       /* De-alloc array of per-TFD driver data */
+       kfree(txq->skbs);
+       txq->skbs = NULL;
+
+       /* deallocate arrays */
+       kfree(txq->cmd);
+       kfree(txq->meta);
+       txq->cmd = NULL;
+       txq->meta = NULL;
+
+       /* 0-fill queue descriptor structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/**
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
+{
+       int txq_id;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       /* Tx queues */
+       if (trans_pcie->txq) {
+               for (txq_id = 0;
+                    txq_id < hw_params(trans).max_txq_num; txq_id++)
+                       iwl_tx_queue_free(trans, txq_id);
+       }
+
+       kfree(trans_pcie->txq);
+       trans_pcie->txq = NULL;
+
+       iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
+
+       iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
+}
+
+/**
+ * iwl_trans_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ *
+ * @param priv
+ * @return error code
+ */
+static int iwl_trans_tx_alloc(struct iwl_trans *trans)
+{
+       int ret;
+       int txq_id, slots_num;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       u16 scd_bc_tbls_size = hw_params(trans).max_txq_num *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+
+       /*It is not allowed to alloc twice, so warn when this happens.
+        * We cannot rely on the previous allocation, so free and fail */
+       if (WARN_ON(trans_pcie->txq)) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
+                                  scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
+               goto error;
+       }
+
+       /* Alloc keep-warm buffer */
+       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
+       if (ret) {
+               IWL_ERR(trans, "Keep Warm allocation failed\n");
+               goto error;
+       }
+
+       trans_pcie->txq = kcalloc(hw_params(trans).max_txq_num,
+                                 sizeof(struct iwl_tx_queue), GFP_KERNEL);
+       if (!trans_pcie->txq) {
+               IWL_ERR(trans, "Not enough memory for txq\n");
+               ret = ENOMEM;
+               goto error;
+       }
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
+               slots_num = (txq_id == trans->shrd->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
+                                         slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       iwl_trans_pcie_tx_free(trans);
+
+       return ret;
+}
+static int iwl_tx_init(struct iwl_trans *trans)
+{
+       int ret;
+       int txq_id, slots_num;
+       unsigned long flags;
+       bool alloc = false;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (!trans_pcie->txq) {
+               ret = iwl_trans_tx_alloc(trans);
+               if (ret)
+                       goto error;
+               alloc = true;
+       }
+
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       iwl_write_prph(bus(trans), SCD_TXFACT, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(bus(trans), FH_KW_MEM_ADDR_REG,
+                          trans_pcie->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
+               slots_num = (txq_id == trans->shrd->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
+                                        slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+error:
+       /*Upon error, free only if we allocated something */
+       if (alloc)
+               iwl_trans_pcie_tx_free(trans);
+       return ret;
+}
+
+static void iwl_set_pwr_vmain(struct iwl_trans *trans)
+{
+/*
+ * (for documentation purposes)
+ * to set power to V_AUX, do:
+
+               if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
+                       iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
+                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
+                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+ */
+
+       iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
+                              APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
+                              ~APMG_PS_CTRL_MSK_PWR_SRC);
+}
+
+static int iwl_nic_init(struct iwl_trans *trans)
+{
+       unsigned long flags;
+
+       /* nic_init */
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+       iwl_apm_init(priv(trans));
+
+       /* Set interrupt coalescing calibration timer to default (512 usecs) */
+       iwl_write8(bus(trans), CSR_INT_COALESCING,
+               IWL_HOST_INT_CALIB_TIMEOUT_DEF);
+
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       iwl_set_pwr_vmain(trans);
+
+       iwl_nic_config(priv(trans));
+
+       /* Allocate the RX queue, or reset if it is already allocated */
+       iwl_rx_init(trans);
+
+       /* Allocate or reset and init all Tx and Command queues */
+       if (iwl_tx_init(trans))
+               return -ENOMEM;
+
+       if (hw_params(trans).shadow_reg_enable) {
+               /* enable shadow regs in HW */
+               iwl_set_bit(bus(trans), CSR_MAC_SHADOW_REG_CTRL,
+                       0x800FFFFF);
+       }
+
+       set_bit(STATUS_INIT, &trans->shrd->status);
+
+       return 0;
+}
+
+#define HW_READY_TIMEOUT (50)
+
+/* Note: returns poll_bit return value, which is >= 0 if success */
+static int iwl_set_hw_ready(struct iwl_trans *trans)
+{
+       int ret;
+
+       iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
+
+       /* See if we got it */
+       ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
+                               HW_READY_TIMEOUT);
+
+       IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
+       return ret;
+}
+
+/* Note: returns standard 0/-ERROR code */
+static int iwl_trans_pcie_prepare_card_hw(struct iwl_trans *trans)
+{
+       int ret;
+
+       IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
+
+       ret = iwl_set_hw_ready(trans);
+       if (ret >= 0)
+               return 0;
+
+       /* If HW is not ready, prepare the conditions to check again */
+       iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+                       CSR_HW_IF_CONFIG_REG_PREPARE);
+
+       ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
+                       ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
+                       CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
+
+       if (ret < 0)
+               return ret;
+
+       /* HW should be ready by now, check again. */
+       ret = iwl_set_hw_ready(trans);
+       if (ret >= 0)
+               return 0;
+       return ret;
+}
+
+#define IWL_AC_UNSET -1
+
+struct queue_to_fifo_ac {
+       s8 fifo, ac;
+};
+
+static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
+       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
+};
+
+static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
+       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+       { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
+       { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
+       { IWL_TX_FIFO_BE_IPAN, 2, },
+       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
+       { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
+};
+
+static const u8 iwlagn_bss_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO,
+       IWL_TX_FIFO_VI,
+       IWL_TX_FIFO_BE,
+       IWL_TX_FIFO_BK,
+};
+static const u8 iwlagn_bss_ac_to_queue[] = {
+       0, 1, 2, 3,
+};
+static const u8 iwlagn_pan_ac_to_fifo[] = {
+       IWL_TX_FIFO_VO_IPAN,
+       IWL_TX_FIFO_VI_IPAN,
+       IWL_TX_FIFO_BE_IPAN,
+       IWL_TX_FIFO_BK_IPAN,
+};
+static const u8 iwlagn_pan_ac_to_queue[] = {
+       7, 6, 5, 4,
+};
+
+static int iwl_trans_pcie_start_device(struct iwl_trans *trans)
+{
+       int ret;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       trans->shrd->ucode_owner = IWL_OWNERSHIP_DRIVER;
+       trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
+       trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
+
+       trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
+       trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
+
+       trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
+       trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
+
+       if ((hw_params(trans).sku & EEPROM_SKU_CAP_AMT_ENABLE) &&
+            iwl_trans_pcie_prepare_card_hw(trans)) {
+               IWL_WARN(trans, "Exit HW not ready\n");
+               return -EIO;
+       }
+
+       /* If platform's RF_KILL switch is NOT set to KILL */
+       if (iwl_read32(bus(trans), CSR_GP_CNTRL) &
+                       CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
+               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+       else
+               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+
+       if (iwl_is_rfkill(trans->shrd)) {
+               iwl_set_hw_rfkill_state(priv(trans), true);
+               iwl_enable_interrupts(trans);
+               return -ERFKILL;
+       }
+
+       iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
+
+       ret = iwl_nic_init(trans);
+       if (ret) {
+               IWL_ERR(trans, "Unable to init nic\n");
+               return ret;
+       }
+
+       /* make sure rfkill handshake bits are cleared */
+       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR,
+                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
+
+       /* clear (again), then enable host interrupts */
+       iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
+       iwl_enable_interrupts(trans);
+
+       /* really make sure rfkill handshake bits are cleared */
+       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
+
+       return 0;
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ * must be called under priv->shrd->lock and mac access
+ */
+static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
+{
+       iwl_write_prph(bus(trans), SCD_TXFACT, mask);
+}
+
+static void iwl_trans_pcie_tx_start(struct iwl_trans *trans)
+{
+       const struct queue_to_fifo_ac *queue_to_fifo;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 a;
+       unsigned long flags;
+       int i, chan;
+       u32 reg_val;
+
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+
+       trans_pcie->scd_base_addr =
+               iwl_read_prph(bus(trans), SCD_SRAM_BASE_ADDR);
+       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
+       /* reset conext data memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(bus(trans), a, 0);
+       /* reset tx status memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(bus(trans), a, 0);
+       for (; a < trans_pcie->scd_base_addr +
+              SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num);
+              a += 4)
+               iwl_write_targ_mem(bus(trans), a, 0);
+
+       iwl_write_prph(bus(trans), SCD_DRAM_BASE_ADDR,
+                      trans_pcie->scd_bc_tbls.dma >> 10);
+
+       /* Enable DMA channel */
+       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
+               iwl_write_direct32(bus(trans), FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+       /* Update FH chicken bits */
+       reg_val = iwl_read_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG);
+       iwl_write_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG,
+                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+       iwl_write_prph(bus(trans), SCD_QUEUECHAIN_SEL,
+               SCD_QUEUECHAIN_SEL_ALL(trans));
+       iwl_write_prph(bus(trans), SCD_AGGR_SEL, 0);
+
+       /* initiate the queues */
+       for (i = 0; i < hw_params(trans).max_txq_num; i++) {
+               iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(i), 0);
+               iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, 0 | (i << 8));
+               iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
+                               SCD_CONTEXT_QUEUE_OFFSET(i), 0);
+               iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
+                               SCD_CONTEXT_QUEUE_OFFSET(i) +
+                               sizeof(u32),
+                               ((SCD_WIN_SIZE <<
+                               SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
+                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
+                               ((SCD_FRAME_LIMIT <<
+                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
+                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
+       }
+
+       iwl_write_prph(bus(trans), SCD_INTERRUPT_MASK,
+                       IWL_MASK(0, hw_params(trans).max_txq_num));
+
+       /* Activate all Tx DMA/FIFO channels */
+       iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
+
+       /* map queues to FIFOs */
+       if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
+               queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
+       else
+               queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
+
+       iwl_trans_set_wr_ptrs(trans, trans->shrd->cmd_queue, 0);
+
+       /* make sure all queue are not stopped */
+       memset(&trans_pcie->queue_stopped[0], 0,
+               sizeof(trans_pcie->queue_stopped));
+       for (i = 0; i < 4; i++)
+               atomic_set(&trans_pcie->queue_stop_count[i], 0);
+
+       /* reset to 0 to enable all the queue first */
+       trans_pcie->txq_ctx_active_msk = 0;
+
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
+                                               IWLAGN_FIRST_AMPDU_QUEUE);
+       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
+                                               IWLAGN_FIRST_AMPDU_QUEUE);
+
+       for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
+               int fifo = queue_to_fifo[i].fifo;
+               int ac = queue_to_fifo[i].ac;
+
+               iwl_txq_ctx_activate(trans_pcie, i);
+
+               if (fifo == IWL_TX_FIFO_UNUSED)
+                       continue;
+
+               if (ac != IWL_AC_UNSET)
+                       iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
+               iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
+                                             fifo, 0);
+       }
+
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       /* Enable L1-Active */
+       iwl_clear_bits_prph(bus(trans), APMG_PCIDEV_STT_REG,
+                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+}
+
+/**
+ * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
+ */
+static int iwl_trans_tx_stop(struct iwl_trans *trans)
+{
+       int ch, txq_id;
+       unsigned long flags;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+
+       iwl_trans_txq_set_sched(trans, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+               iwl_write_direct32(bus(trans),
+                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               if (iwl_poll_direct_bit(bus(trans), FH_TSSR_TX_STATUS_REG,
+                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
+                                   1000))
+                       IWL_ERR(trans, "Failing on timeout while stopping"
+                           " DMA channel %d [0x%08x]", ch,
+                           iwl_read_direct32(bus(trans),
+                                             FH_TSSR_TX_STATUS_REG));
+       }
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       if (!trans_pcie->txq) {
+               IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
+               return 0;
+       }
+
+       /* Unmap DMA from host system and free skb's */
+       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++)
+               iwl_tx_queue_unmap(trans, txq_id);
+
+       return 0;
+}
+
+static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
+{
+       unsigned long flags;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       spin_lock_irqsave(&trans->shrd->lock, flags);
+       iwl_disable_interrupts(trans);
+       spin_unlock_irqrestore(&trans->shrd->lock, flags);
+
+       /* wait to make sure we flush pending tasklet*/
+       synchronize_irq(bus(trans)->irq);
+       tasklet_kill(&trans_pcie->irq_tasklet);
+}
+
+static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
+{
+       /* stop and reset the on-board processor */
+       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
+
+       /* tell the device to stop sending interrupts */
+       iwl_trans_pcie_disable_sync_irq(trans);
+
+       /* device going down, Stop using ICT table */
+       iwl_disable_ict(trans);
+
+       /*
+        * If a HW restart happens during firmware loading,
+        * then the firmware loading might call this function
+        * and later it might be called again due to the
+        * restart. So don't process again if the device is
+        * already dead.
+        */
+       if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) {
+               iwl_trans_tx_stop(trans);
+               iwl_trans_rx_stop(trans);
+
+               /* Power-down device's busmaster DMA clocks */
+               iwl_write_prph(bus(trans), APMG_CLK_DIS_REG,
+                              APMG_CLK_VAL_DMA_CLK_RQT);
+               udelay(5);
+       }
+
+       /* Make sure (redundant) we've released our request to stay awake */
+       iwl_clear_bit(bus(trans), CSR_GP_CNTRL,
+                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
+
+       /* Stop the device, and put it in low power state */
+       iwl_apm_stop(priv(trans));
+}
+
+static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
+               struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
+               u8 sta_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
+       struct iwl_cmd_meta *out_meta;
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+
+       dma_addr_t phys_addr = 0;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       u16 len, firstlen, secondlen;
+       u16 seq_number = 0;
+       u8 wait_write_ptr = 0;
+       u8 txq_id;
+       u8 tid = 0;
+       bool is_agg = false;
+       __le16 fc = hdr->frame_control;
+       u8 hdr_len = ieee80211_hdrlen(fc);
+
+       /*
+        * Send this frame after DTIM -- there's a special queue
+        * reserved for this for contexts that support AP mode.
+        */
+       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
+               txq_id = trans_pcie->mcast_queue[ctx];
+
+               /*
+                * The microcode will clear the more data
+                * bit in the last frame it transmits.
+                */
+               hdr->frame_control |=
+                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
+       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
+               txq_id = IWL_AUX_QUEUE;
+       else
+               txq_id =
+                   trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
+
+       if (ieee80211_is_data_qos(fc)) {
+               u8 *qc = NULL;
+               struct iwl_tid_data *tid_data;
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+               tid_data = &trans->shrd->tid_data[sta_id][tid];
+
+               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
+                       return -1;
+
+               seq_number = tid_data->seq_number;
+               seq_number &= IEEE80211_SCTL_SEQ;
+               hdr->seq_ctrl = hdr->seq_ctrl &
+                               cpu_to_le16(IEEE80211_SCTL_FRAG);
+               hdr->seq_ctrl |= cpu_to_le16(seq_number);
+               seq_number += 0x10;
+               /* aggregation is on for this <sta,tid> */
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       WARN_ON(tid_data->agg.state != IWL_AGG_ON);
+                       txq_id = tid_data->agg.txq_id;
+                       is_agg = true;
+               }
+       }
+
+       /* Copy MAC header from skb into command buffer */
+       memcpy(tx_cmd->hdr, hdr, hdr_len);
+
+       txq = &trans_pcie->txq[txq_id];
+       q = &txq->q;
+
+       /* Set up driver data for this TFD */
+       txq->skbs[q->write_ptr] = skb;
+       txq->cmd[q->write_ptr] = dev_cmd;
+
+       dev_cmd->hdr.cmd = REPLY_TX;
+       dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                               INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_meta = &txq->meta[q->write_ptr];
+
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+       firstlen = (len + 3) & ~3;
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (firstlen != len)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = dma_map_single(bus(trans)->dev,
+                                   &dev_cmd->hdr, firstlen,
+                                   DMA_BIDIRECTIONAL);
+       if (unlikely(dma_mapping_error(bus(trans)->dev, txcmd_phys)))
+               return -1;
+       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       dma_unmap_len_set(out_meta, len, firstlen);
+
+       if (!ieee80211_has_morefrags(fc)) {
+               txq->need_update = 1;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
+       }
+
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       secondlen = skb->len - hdr_len;
+       if (secondlen > 0) {
+               phys_addr = dma_map_single(bus(trans)->dev, skb->data + hdr_len,
+                                          secondlen, DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) {
+                       dma_unmap_single(bus(trans)->dev,
+                                        dma_unmap_addr(out_meta, mapping),
+                                        dma_unmap_len(out_meta, len),
+                                        DMA_BIDIRECTIONAL);
+                       return -1;
+               }
+       }
+
+       /* Attach buffers to TFD */
+       iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
+       if (secondlen > 0)
+               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
+                                            secondlen, 0);
+
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+                               offsetof(struct iwl_tx_cmd, scratch);
+
+       /* take back ownership of DMA buffer to enable update */
+       dma_sync_single_for_cpu(bus(trans)->dev, txcmd_phys, firstlen,
+                       DMA_BIDIRECTIONAL);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
+
+       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
+                    le16_to_cpu(dev_cmd->hdr.sequence));
+       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
+       iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
+       iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
+
+       /* Set up entry for this TFD in Tx byte-count array */
+       if (is_agg)
+               iwl_trans_txq_update_byte_cnt_tbl(trans, txq,
+                                              le16_to_cpu(tx_cmd->len));
+
+       dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen,
+                       DMA_BIDIRECTIONAL);
+
+       trace_iwlwifi_dev_tx(priv(trans),
+                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &dev_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_txq_update_write_ptr(trans, txq);
+
+       if (ieee80211_is_data_qos(fc)) {
+               trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
+               if (!ieee80211_has_morefrags(fc))
+                       trans->shrd->tid_data[sta_id][tid].seq_number =
+                               seq_number;
+       }
+
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+       if (iwl_queue_space(q) < q->high_mark) {
+               if (wait_write_ptr) {
+                       txq->need_update = 1;
+                       iwl_txq_update_write_ptr(trans, txq);
+               } else {
+                       iwl_stop_queue(trans, txq);
+               }
+       }
+       return 0;
+}
+
+static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans)
+{
+       /* Remove all resets to allow NIC to operate */
+       iwl_write32(bus(trans), CSR_RESET, 0);
+}
+
+static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       int err;
+
+       trans_pcie->inta_mask = CSR_INI_SET_MASK;
+
+       tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
+               iwl_irq_tasklet, (unsigned long)trans);
+
+       iwl_alloc_isr_ict(trans);
+
+       err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED,
+               DRV_NAME, trans);
+       if (err) {
+               IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq);
+               iwl_free_isr_ict(trans);
+               return err;
+       }
+
+       INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
+       return 0;
+}
+
+static int iwlagn_txq_check_empty(struct iwl_trans *trans,
+                          int sta_id, u8 tid, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_queue *q = &trans_pcie->txq[txq_id].q;
+       struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid];
+
+       lockdep_assert_held(&trans->shrd->sta_lock);
+
+       switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
+       case IWL_EMPTYING_HW_QUEUE_DELBA:
+               /* We are reclaiming the last packet of the */
+               /* aggregated HW queue */
+               if ((txq_id  == tid_data->agg.txq_id) &&
+                   (q->read_ptr == q->write_ptr)) {
+                       IWL_DEBUG_HT(trans,
+                               "HW queue empty: continue DELBA flow\n");
+                       iwl_trans_pcie_txq_agg_disable(trans, txq_id);
+                       tid_data->agg.state = IWL_AGG_OFF;
+                       iwl_stop_tx_ba_trans_ready(priv(trans),
+                                                  NUM_IWL_RXON_CTX,
+                                                  sta_id, tid);
+                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+               }
+               break;
+       case IWL_EMPTYING_HW_QUEUE_ADDBA:
+               /* We are reclaiming the last packet of the queue */
+               if (tid_data->tfds_in_queue == 0) {
+                       IWL_DEBUG_HT(trans,
+                               "HW queue empty: continue ADDBA flow\n");
+                       tid_data->agg.state = IWL_AGG_ON;
+                       iwl_start_tx_ba_trans_ready(priv(trans),
+                                                   NUM_IWL_RXON_CTX,
+                                                   sta_id, tid);
+               }
+               break;
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
+                           int sta_id, int tid, int freed)
+{
+       lockdep_assert_held(&trans->shrd->sta_lock);
+
+       if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
+               trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
+       else {
+               IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
+                       trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
+                       freed);
+               trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
+       }
+}
+
+static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
+                     int txq_id, int ssn, u32 status,
+                     struct sk_buff_head *skbs)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
+       enum iwl_agg_state agg_state;
+       /* n_bd is usually 256 => n_bd - 1 = 0xff */
+       int tfd_num = ssn & (txq->q.n_bd - 1);
+       int freed = 0;
+       bool cond;
+
+       txq->time_stamp = jiffies;
+
+       if (txq->sched_retry) {
+               agg_state =
+                       trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state;
+               cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
+       } else {
+               cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
+       }
+
+       if (txq->q.read_ptr != tfd_num) {
+               IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
+                               "scd_ssn=%d idx=%d txq=%d swq=%d\n",
+                               ssn , tfd_num, txq_id, txq->swq_id);
+               freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
+                       iwl_wake_queue(trans, txq);
+       }
+
+       iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
+       iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
+}
+
+static void iwl_trans_pcie_free(struct iwl_trans *trans)
+{
+       iwl_trans_pcie_tx_free(trans);
+       iwl_trans_pcie_rx_free(trans);
+       free_irq(bus(trans)->irq, trans);
+       iwl_free_isr_ict(trans);
+       trans->shrd->trans = NULL;
+       kfree(trans);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
+{
+       /*
+        * This function is called when system goes into suspend state
+        * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
+        * first but since iwl_mac_stop() has no knowledge of who the caller is,
+        * it will not call apm_ops.stop() to stop the DMA operation.
+        * Calling apm_ops.stop here to make sure we stop the DMA.
+        *
+        * But of course ... if we have configured WoWLAN then we did other
+        * things already :-)
+        */
+       if (!trans->shrd->wowlan)
+               iwl_apm_stop(priv(trans));
+
+       return 0;
+}
+
+static int iwl_trans_pcie_resume(struct iwl_trans *trans)
+{
+       bool hw_rfkill = false;
+
+       iwl_enable_interrupts(trans);
+
+       if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) &
+                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
+               hw_rfkill = true;
+
+       if (hw_rfkill)
+               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+       else
+               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
+
+       iwl_set_hw_rfkill_state(priv(trans), hw_rfkill);
+
+       return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
+                                         enum iwl_rxon_context_id ctx)
+{
+       u8 ac, txq_id;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       for (ac = 0; ac < AC_NUM; ac++) {
+               txq_id = trans_pcie->ac_to_queue[ctx][ac];
+               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
+                       ac,
+                       (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
+                             ? "stopped" : "awake");
+               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
+       }
+}
+
+const struct iwl_trans_ops trans_ops_pcie;
+
+static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
+{
+       struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) +
+                                             sizeof(struct iwl_trans_pcie),
+                                             GFP_KERNEL);
+       if (iwl_trans) {
+               struct iwl_trans_pcie *trans_pcie =
+                       IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
+               iwl_trans->ops = &trans_ops_pcie;
+               iwl_trans->shrd = shrd;
+               trans_pcie->trans = iwl_trans;
+               spin_lock_init(&iwl_trans->hcmd_lock);
+       }
+
+       return iwl_trans;
+}
+
+static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
+}
+
+#define IWL_FLUSH_WAIT_MS      2000
+
+static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       int cnt;
+       unsigned long now = jiffies;
+       int ret = 0;
+
+       /* waiting for all the tx frames complete might take a while */
+       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
+               if (cnt == trans->shrd->cmd_queue)
+                       continue;
+               txq = &trans_pcie->txq[cnt];
+               q = &txq->q;
+               while (q->read_ptr != q->write_ptr && !time_after(jiffies,
+                      now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
+                       msleep(1);
+
+               if (q->read_ptr != q->write_ptr) {
+                       IWL_ERR(trans, "fail to flush all tx fifo queues\n");
+                       ret = -ETIMEDOUT;
+                       break;
+               }
+       }
+       return ret;
+}
+
+/*
+ * On every watchdog tick we check (latest) time stamp. If it does not
+ * change during timeout period and queue is not empty we reset firmware.
+ */
+static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq = &trans_pcie->txq[cnt];
+       struct iwl_queue *q = &txq->q;
+       unsigned long timeout;
+
+       if (q->read_ptr == q->write_ptr) {
+               txq->time_stamp = jiffies;
+               return 0;
+       }
+
+       timeout = txq->time_stamp +
+                 msecs_to_jiffies(hw_params(trans).wd_timeout);
+
+       if (time_after(jiffies, timeout)) {
+               IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
+                       hw_params(trans).wd_timeout);
+               IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n",
+                       q->read_ptr, q->write_ptr);
+               return 1;
+       }
+
+       return 0;
+}
+
+static const char *get_fh_string(int cmd)
+{
+       switch (cmd) {
+       IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
+       IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
+       IWL_CMD(FH_RSCSR_CHNL0_WPTR);
+       IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
+       IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
+       IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
+       IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
+       IWL_CMD(FH_TSSR_TX_STATUS_REG);
+       IWL_CMD(FH_TSSR_TX_ERROR_REG);
+       default:
+               return "UNKNOWN";
+       }
+}
+
+int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
+{
+       int i;
+#ifdef CONFIG_IWLWIFI_DEBUG
+       int pos = 0;
+       size_t bufsz = 0;
+#endif
+       static const u32 fh_tbl[] = {
+               FH_RSCSR_CHNL0_STTS_WPTR_REG,
+               FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+               FH_RSCSR_CHNL0_WPTR,
+               FH_MEM_RCSR_CHNL0_CONFIG_REG,
+               FH_MEM_RSSR_SHARED_CTRL_REG,
+               FH_MEM_RSSR_RX_STATUS_REG,
+               FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
+               FH_TSSR_TX_STATUS_REG,
+               FH_TSSR_TX_ERROR_REG
+       };
+#ifdef CONFIG_IWLWIFI_DEBUG
+       if (display) {
+               bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
+               *buf = kmalloc(bufsz, GFP_KERNEL);
+               if (!*buf)
+                       return -ENOMEM;
+               pos += scnprintf(*buf + pos, bufsz - pos,
+                               "FH register values:\n");
+               for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
+                       pos += scnprintf(*buf + pos, bufsz - pos,
+                               "  %34s: 0X%08x\n",
+                               get_fh_string(fh_tbl[i]),
+                               iwl_read_direct32(bus(trans), fh_tbl[i]));
+               }
+               return pos;
+       }
+#endif
+       IWL_ERR(trans, "FH register values:\n");
+       for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
+               IWL_ERR(trans, "  %34s: 0X%08x\n",
+                       get_fh_string(fh_tbl[i]),
+                       iwl_read_direct32(bus(trans), fh_tbl[i]));
+       }
+       return 0;
+}
+
+static const char *get_csr_string(int cmd)
+{
+       switch (cmd) {
+       IWL_CMD(CSR_HW_IF_CONFIG_REG);
+       IWL_CMD(CSR_INT_COALESCING);
+       IWL_CMD(CSR_INT);
+       IWL_CMD(CSR_INT_MASK);
+       IWL_CMD(CSR_FH_INT_STATUS);
+       IWL_CMD(CSR_GPIO_IN);
+       IWL_CMD(CSR_RESET);
+       IWL_CMD(CSR_GP_CNTRL);
+       IWL_CMD(CSR_HW_REV);
+       IWL_CMD(CSR_EEPROM_REG);
+       IWL_CMD(CSR_EEPROM_GP);
+       IWL_CMD(CSR_OTP_GP_REG);
+       IWL_CMD(CSR_GIO_REG);
+       IWL_CMD(CSR_GP_UCODE_REG);
+       IWL_CMD(CSR_GP_DRIVER_REG);
+       IWL_CMD(CSR_UCODE_DRV_GP1);
+       IWL_CMD(CSR_UCODE_DRV_GP2);
+       IWL_CMD(CSR_LED_REG);
+       IWL_CMD(CSR_DRAM_INT_TBL_REG);
+       IWL_CMD(CSR_GIO_CHICKEN_BITS);
+       IWL_CMD(CSR_ANA_PLL_CFG);
+       IWL_CMD(CSR_HW_REV_WA_REG);
+       IWL_CMD(CSR_DBG_HPET_MEM_REG);
+       default:
+               return "UNKNOWN";
+       }
+}
+
+void iwl_dump_csr(struct iwl_trans *trans)
+{
+       int i;
+       static const u32 csr_tbl[] = {
+               CSR_HW_IF_CONFIG_REG,
+               CSR_INT_COALESCING,
+               CSR_INT,
+               CSR_INT_MASK,
+               CSR_FH_INT_STATUS,
+               CSR_GPIO_IN,
+               CSR_RESET,
+               CSR_GP_CNTRL,
+               CSR_HW_REV,
+               CSR_EEPROM_REG,
+               CSR_EEPROM_GP,
+               CSR_OTP_GP_REG,
+               CSR_GIO_REG,
+               CSR_GP_UCODE_REG,
+               CSR_GP_DRIVER_REG,
+               CSR_UCODE_DRV_GP1,
+               CSR_UCODE_DRV_GP2,
+               CSR_LED_REG,
+               CSR_DRAM_INT_TBL_REG,
+               CSR_GIO_CHICKEN_BITS,
+               CSR_ANA_PLL_CFG,
+               CSR_HW_REV_WA_REG,
+               CSR_DBG_HPET_MEM_REG
+       };
+       IWL_ERR(trans, "CSR values:\n");
+       IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
+               "CSR_INT_PERIODIC_REG)\n");
+       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
+               IWL_ERR(trans, "  %25s: 0X%08x\n",
+                       get_csr_string(csr_tbl[i]),
+                       iwl_read32(bus(trans), csr_tbl[i]));
+       }
+}
+
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+/* create and remove of files */
+#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
+       if (!debugfs_create_file(#name, mode, parent, trans,            \
+                                &iwl_dbgfs_##name##_ops))              \
+               return -ENOMEM;                                         \
+} while (0)
+
+/* file operation */
+#define DEBUGFS_READ_FUNC(name)                                         \
+static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
+                                       char __user *user_buf,          \
+                                       size_t count, loff_t *ppos);
+
+#define DEBUGFS_WRITE_FUNC(name)                                        \
+static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
+                                       const char __user *user_buf,    \
+                                       size_t count, loff_t *ppos);
+
+
+static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
+{
+       file->private_data = inode->i_private;
+       return 0;
+}
+
+#define DEBUGFS_READ_FILE_OPS(name)                                    \
+       DEBUGFS_READ_FUNC(name);                                        \
+static const struct file_operations iwl_dbgfs_##name##_ops = {         \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = iwl_dbgfs_open_file_generic,                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {          \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .open = iwl_dbgfs_open_file_generic,                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+#define DEBUGFS_READ_WRITE_FILE_OPS(name)                              \
+       DEBUGFS_READ_FUNC(name);                                        \
+       DEBUGFS_WRITE_FUNC(name);                                       \
+static const struct file_operations iwl_dbgfs_##name##_ops = {         \
+       .write = iwl_dbgfs_##name##_write,                              \
+       .read = iwl_dbgfs_##name##_read,                                \
+       .open = iwl_dbgfs_open_file_generic,                            \
+       .llseek = generic_file_llseek,                                  \
+};
+
+static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_tx_queue *txq;
+       struct iwl_queue *q;
+       char *buf;
+       int pos = 0;
+       int cnt;
+       int ret;
+       const size_t bufsz = sizeof(char) * 64 * hw_params(trans).max_txq_num;
+
+       if (!trans_pcie->txq) {
+               IWL_ERR(trans, "txq not ready\n");
+               return -EAGAIN;
+       }
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
+               txq = &trans_pcie->txq[cnt];
+               q = &txq->q;
+               pos += scnprintf(buf + pos, bufsz - pos,
+                               "hwq %.2d: read=%u write=%u stop=%d"
+                               " swq_id=%#.2x (ac %d/hwq %d)\n",
+                               cnt, q->read_ptr, q->write_ptr,
+                               !!test_bit(cnt, trans_pcie->queue_stopped),
+                               txq->swq_id, txq->swq_id & 3,
+                               (txq->swq_id >> 2) & 0x1f);
+               if (cnt >= 4)
+                       continue;
+               /* for the ACs, display the stop count too */
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "        stop-count: %d\n",
+                       atomic_read(&trans_pcie->queue_stop_count[cnt]));
+       }
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
+                                               char __user *user_buf,
+                                               size_t count, loff_t *ppos) {
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       char buf[256];
+       int pos = 0;
+       const size_t bufsz = sizeof(buf);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
+                                               rxq->read);
+       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
+                                               rxq->write);
+       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
+                                               rxq->free_count);
+       if (rxq->rb_stts) {
+               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
+                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
+       } else {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                                       "closed_rb_num: Not Allocated\n");
+       }
+       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_log_event_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -ENOMEM;
+
+       ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true);
+       if (buf) {
+               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+               kfree(buf);
+       }
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_log_event_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       u32 event_log_flag;
+       char buf[8];
+       int buf_size;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &event_log_flag) != 1)
+               return -EFAULT;
+       if (event_log_flag == 1)
+               iwl_dump_nic_event_log(trans, true, NULL, false);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
+                                       char __user *user_buf,
+                                       size_t count, loff_t *ppos) {
+
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+       int pos = 0;
+       char *buf;
+       int bufsz = 24 * 64; /* 24 items * 64 char per item */
+       ssize_t ret;
+
+       buf = kzalloc(bufsz, GFP_KERNEL);
+       if (!buf) {
+               IWL_ERR(trans, "Can not allocate Buffer\n");
+               return -ENOMEM;
+       }
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+                       "Interrupt Statistics Report:\n");
+
+       pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
+               isr_stats->hw);
+       pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
+               isr_stats->sw);
+       if (isr_stats->sw || isr_stats->hw) {
+               pos += scnprintf(buf + pos, bufsz - pos,
+                       "\tLast Restarting Code:  0x%X\n",
+                       isr_stats->err_code);
+       }
+#ifdef CONFIG_IWLWIFI_DEBUG
+       pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
+               isr_stats->sch);
+       pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
+               isr_stats->alive);
+#endif
+       pos += scnprintf(buf + pos, bufsz - pos,
+               "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
+               isr_stats->ctkill);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
+               isr_stats->wakeup);
+
+       pos += scnprintf(buf + pos, bufsz - pos,
+               "Rx command responses:\t\t %u\n", isr_stats->rx);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
+               isr_stats->tx);
+
+       pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
+               isr_stats->unhandled);
+
+       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+       kfree(buf);
+       return ret;
+}
+
+static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
+
+       char buf[8];
+       int buf_size;
+       u32 reset_flag;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%x", &reset_flag) != 1)
+               return -EFAULT;
+       if (reset_flag == 0)
+               memset(isr_stats, 0, sizeof(*isr_stats));
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_csr_write(struct file *file,
+                                        const char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       char buf[8];
+       int buf_size;
+       int csr;
+
+       memset(buf, 0, sizeof(buf));
+       buf_size = min(count, sizeof(buf) -  1);
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       if (sscanf(buf, "%d", &csr) != 1)
+               return -EFAULT;
+
+       iwl_dump_csr(trans);
+
+       return count;
+}
+
+static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
+                                        char __user *user_buf,
+                                        size_t count, loff_t *ppos)
+{
+       struct iwl_trans *trans = file->private_data;
+       char *buf;
+       int pos = 0;
+       ssize_t ret = -EFAULT;
+
+       ret = pos = iwl_dump_fh(trans, &buf, true);
+       if (buf) {
+               ret = simple_read_from_buffer(user_buf,
+                                             count, ppos, buf, pos);
+               kfree(buf);
+       }
+
+       return ret;
+}
+
+DEBUGFS_READ_WRITE_FILE_OPS(log_event);
+DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
+DEBUGFS_READ_FILE_OPS(fh_reg);
+DEBUGFS_READ_FILE_OPS(rx_queue);
+DEBUGFS_READ_FILE_OPS(tx_queue);
+DEBUGFS_WRITE_FILE_OPS(csr);
+
+/*
+ * Create the debugfs files and directories
+ *
+ */
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                       struct dentry *dir)
+{
+       DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
+       DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
+       DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
+       DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
+       return 0;
+}
+#else
+static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
+                                       struct dentry *dir)
+{ return 0; }
+
+#endif /*CONFIG_IWLWIFI_DEBUGFS */
+
+const struct iwl_trans_ops trans_ops_pcie = {
+       .alloc = iwl_trans_pcie_alloc,
+       .request_irq = iwl_trans_pcie_request_irq,
+       .start_device = iwl_trans_pcie_start_device,
+       .prepare_card_hw = iwl_trans_pcie_prepare_card_hw,
+       .stop_device = iwl_trans_pcie_stop_device,
+
+       .tx_start = iwl_trans_pcie_tx_start,
+       .wake_any_queue = iwl_trans_pcie_wake_any_queue,
+
+       .send_cmd = iwl_trans_pcie_send_cmd,
+
+       .tx = iwl_trans_pcie_tx,
+       .reclaim = iwl_trans_pcie_reclaim,
+
+       .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
+       .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
+       .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
+
+       .kick_nic = iwl_trans_pcie_kick_nic,
+
+       .free = iwl_trans_pcie_free,
+       .stop_queue = iwl_trans_pcie_stop_queue,
+
+       .dbgfs_register = iwl_trans_pcie_dbgfs_register,
+
+       .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
+       .check_stuck_queue = iwl_trans_pcie_check_stuck_queue,
+
+#ifdef CONFIG_PM_SLEEP
+       .suspend = iwl_trans_pcie_suspend,
+       .resume = iwl_trans_pcie_resume,
+#endif
+};
index b2e89077c684fa44e8e0cf8b7b6a7ab80fb91848..1b20c4fb791b07bac2473978d79f24c37a4b5703 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  *****************************************************************************/
-#include <linux/interrupt.h>
-#include <linux/debugfs.h>
-#include <linux/bitops.h>
-#include <linux/gfp.h>
 
 #include "iwl-trans.h"
-#include "iwl-trans-int-pcie.h"
-#include "iwl-csr.h"
-#include "iwl-prph.h"
-#include "iwl-shared.h"
-#include "iwl-eeprom.h"
-#include "iwl-agn-hw.h"
 
-static int iwl_trans_rx_alloc(struct iwl_trans *trans)
+int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
+                          u32 flags, u16 len, const void *data)
 {
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct device *dev = bus(trans)->dev;
-
-       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
-
-       spin_lock_init(&rxq->lock);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-
-       if (WARN_ON(rxq->bd || rxq->rb_stts))
-               return -EINVAL;
-
-       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_alloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                    &rxq->bd_dma, GFP_KERNEL);
-       if (!rxq->bd)
-               goto err_bd;
-       memset(rxq->bd, 0, sizeof(__le32) * RX_QUEUE_SIZE);
-
-       /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_alloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                         &rxq->rb_stts_dma, GFP_KERNEL);
-       if (!rxq->rb_stts)
-               goto err_rb_stts;
-       memset(rxq->rb_stts, 0, sizeof(*rxq->rb_stts));
-
-       return 0;
-
-err_rb_stts:
-       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                       rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-err_bd:
-       return -ENOMEM;
-}
-
-static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       int i;
-
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-               /* In the reset function, these buffers may have been allocated
-                * to an SKB, so we need to unmap and free potential storage */
-               if (rxq->pool[i].page != NULL) {
-                       dma_unmap_page(bus(trans)->dev, rxq->pool[i].page_dma,
-                               PAGE_SIZE << hw_params(trans).rx_page_order,
-                               DMA_FROM_DEVICE);
-                       __free_pages(rxq->pool[i].page,
-                                    hw_params(trans).rx_page_order);
-                       rxq->pool[i].page = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-}
-
-static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
-                                struct iwl_rx_queue *rxq)
-{
-       u32 rb_size;
-       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-       u32 rb_timeout = 0; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-       rb_timeout = RX_RB_TIMEOUT;
-
-       if (iwlagn_mod_params.amsdu_size_8K)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          (u32)(rxq->bd_dma >> 8));
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(bus(trans), FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          rxq->rb_stts_dma >> 4);
-
-       /* Enable Rx DMA
-        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-        *      the credit mechanism in 5000 HW RX FIFO
-        * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
-        * RB timeout 0x10
-        * 256 RBDs
-        */
-       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK |
-                          rb_size|
-                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-       /* Set interrupt coalescing timer to default (2048 usecs) */
-       iwl_write8(bus(trans), CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-}
-
-static int iwl_rx_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-       int i, err;
-       unsigned long flags;
-
-       if (!rxq->bd) {
-               err = iwl_trans_rx_alloc(trans);
-               if (err)
-                       return err;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-
-       iwl_trans_rxq_free_rx_bufs(trans);
-
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
-               rxq->queue[i] = NULL;
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       iwlagn_rx_replenish(trans);
-
-       iwl_trans_rx_hw_init(trans, rxq);
-
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-       rxq->need_update = 1;
-       iwl_rx_queue_update_write_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       return 0;
-}
-
-static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-       unsigned long flags;
-
-       /*if rxq->bd is NULL, it means that nothing has been allocated,
-        * exit now */
-       if (!rxq->bd) {
-               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
-               return;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       iwl_trans_rxq_free_rx_bufs(trans);
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       dma_free_coherent(bus(trans)->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-
-       if (rxq->rb_stts)
-               dma_free_coherent(bus(trans)->dev,
-                                 sizeof(struct iwl_rb_status),
-                                 rxq->rb_stts, rxq->rb_stts_dma);
-       else
-               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
-       rxq->rb_stts = NULL;
-}
-
-static int iwl_trans_rx_stop(struct iwl_trans *trans)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(bus(trans), FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       return iwl_poll_direct_bit(bus(trans), FH_MEM_RSSR_RX_STATUS_REG,
-                           FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-}
-
-static inline int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
-                                   struct iwl_dma_ptr *ptr, size_t size)
-{
-       if (WARN_ON(ptr->addr))
-               return -EINVAL;
-
-       ptr->addr = dma_alloc_coherent(bus(trans)->dev, size,
-                                      &ptr->dma, GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static inline void iwlagn_free_dma_ptr(struct iwl_trans *trans,
-                                   struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(bus(trans)->dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
-static int iwl_trans_txq_alloc(struct iwl_trans *trans,
-                               struct iwl_tx_queue *txq, int slots_num,
-                               u32 txq_id)
-{
-       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
-       int i;
-
-       if (WARN_ON(txq->meta || txq->cmd || txq->skbs || txq->tfds))
-               return -EINVAL;
-
-       txq->q.n_window = slots_num;
-
-       txq->meta = kzalloc(sizeof(txq->meta[0]) * slots_num,
-                           GFP_KERNEL);
-       txq->cmd = kzalloc(sizeof(txq->cmd[0]) * slots_num,
-                          GFP_KERNEL);
-
-       if (!txq->meta || !txq->cmd)
-               goto error;
-
-       if (txq_id == trans->shrd->cmd_queue)
-               for (i = 0; i < slots_num; i++) {
-                       txq->cmd[i] = kmalloc(sizeof(struct iwl_device_cmd),
-                                               GFP_KERNEL);
-                       if (!txq->cmd[i])
-                               goto error;
-               }
-
-       /* Alloc driver data array and TFD circular buffer */
-       /* Driver private data, only for Tx (not command) queues,
-        * not shared with device. */
-       if (txq_id != trans->shrd->cmd_queue) {
-               txq->skbs = kzalloc(sizeof(txq->skbs[0]) *
-                                  TFD_QUEUE_SIZE_MAX, GFP_KERNEL);
-               if (!txq->skbs) {
-                       IWL_ERR(trans, "kmalloc for auxiliary BD "
-                                 "structures failed\n");
-                       goto error;
-               }
-       } else {
-               txq->skbs = NULL;
-       }
-
-       /* Circular buffer of transmit frame descriptors (TFDs),
-        * shared with device */
-       txq->tfds = dma_alloc_coherent(bus(trans)->dev, tfd_sz,
-                                      &txq->q.dma_addr, GFP_KERNEL);
-       if (!txq->tfds) {
-               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
-               goto error;
-       }
-       txq->q.id = txq_id;
-
-       return 0;
-error:
-       kfree(txq->skbs);
-       txq->skbs = NULL;
-       /* since txq->cmd has been zeroed,
-        * all non allocated cmd[i] will be NULL */
-       if (txq->cmd && txq_id == trans->shrd->cmd_queue)
-               for (i = 0; i < slots_num; i++)
-                       kfree(txq->cmd[i]);
-       kfree(txq->meta);
-       kfree(txq->cmd);
-       txq->meta = NULL;
-       txq->cmd = NULL;
-
-       return -ENOMEM;
-
-}
-
-static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                     int slots_num, u32 txq_id)
-{
-       int ret;
-
-       txq->need_update = 0;
-       memset(txq->meta, 0, sizeof(txq->meta[0]) * slots_num);
-
-       /*
-        * For the default queues 0-3, set up the swq_id
-        * already -- all others need to get one later
-        * (if they need one at all).
-        */
-       if (txq_id < 4)
-               iwl_set_swq_id(txq, txq_id, txq_id);
-
-       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-       /* Initialize queue's high/low-water marks, and head/tail indexes */
-       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
-                       txq_id);
-       if (ret)
-               return ret;
-
-       /*
-        * Tell nic where to find circular buffer of Tx Frame Descriptors for
-        * given Tx queue, and enable the DMA channel used for that queue.
-        * Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(bus(trans), FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       return 0;
-}
-
-/**
- * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
- */
-static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-
-       if (!q->n_bd)
-               return;
-
-       while (q->write_ptr != q->read_ptr) {
-               /* The read_ptr needs to bound by q->n_window */
-               iwlagn_txq_free_tfd(trans, txq, get_cmd_index(q, q->read_ptr));
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct device *dev = bus(trans)->dev;
-       int i;
-       if (WARN_ON(!txq))
-               return;
-
-       iwl_tx_queue_unmap(trans, txq_id);
-
-       /* De-alloc array of command/tx buffers */
-
-       if (txq_id == trans->shrd->cmd_queue)
-               for (i = 0; i < txq->q.n_window; i++)
-                       kfree(txq->cmd[i]);
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd) {
-               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
-                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
-       }
-
-       /* De-alloc array of per-TFD driver data */
-       kfree(txq->skbs);
-       txq->skbs = NULL;
-
-       /* deallocate arrays */
-       kfree(txq->cmd);
-       kfree(txq->meta);
-       txq->cmd = NULL;
-       txq->meta = NULL;
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_trans_tx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
-{
-       int txq_id;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* Tx queues */
-       if (trans_pcie->txq) {
-               for (txq_id = 0;
-                    txq_id < hw_params(trans).max_txq_num; txq_id++)
-                       iwl_tx_queue_free(trans, txq_id);
-       }
-
-       kfree(trans_pcie->txq);
-       trans_pcie->txq = NULL;
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
-}
-
-/**
- * iwl_trans_tx_alloc - allocate TX context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-static int iwl_trans_tx_alloc(struct iwl_trans *trans)
-{
-       int ret;
-       int txq_id, slots_num;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       u16 scd_bc_tbls_size = hw_params(trans).max_txq_num *
-                       sizeof(struct iwlagn_scd_bc_tbl);
-
-       /*It is not allowed to alloc twice, so warn when this happens.
-        * We cannot rely on the previous allocation, so free and fail */
-       if (WARN_ON(trans_pcie->txq)) {
-               ret = -EINVAL;
-               goto error;
-       }
-
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
-                                  scd_bc_tbls_size);
-       if (ret) {
-               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
-               goto error;
-       }
-
-       /* Alloc keep-warm buffer */
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
-       if (ret) {
-               IWL_ERR(trans, "Keep Warm allocation failed\n");
-               goto error;
-       }
-
-       trans_pcie->txq = kzalloc(sizeof(struct iwl_tx_queue) *
-                       hw_params(trans).max_txq_num, GFP_KERNEL);
-       if (!trans_pcie->txq) {
-               IWL_ERR(trans, "Not enough memory for txq\n");
-               ret = ENOMEM;
-               goto error;
-       }
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
-               slots_num = (txq_id == trans->shrd->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
-                                         slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       iwl_trans_pcie_tx_free(trans);
-
-       return ret;
-}
-static int iwl_tx_init(struct iwl_trans *trans)
-{
-       int ret;
-       int txq_id, slots_num;
-       unsigned long flags;
-       bool alloc = false;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       if (!trans_pcie->txq) {
-               ret = iwl_trans_tx_alloc(trans);
-               if (ret)
-                       goto error;
-               alloc = true;
-       }
-
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       iwl_write_prph(bus(trans), SCD_TXFACT, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(bus(trans), FH_KW_MEM_ADDR_REG,
-                          trans_pcie->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++) {
-               slots_num = (txq_id == trans->shrd->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
-                                        slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-error:
-       /*Upon error, free only if we allocated something */
-       if (alloc)
-               iwl_trans_pcie_tx_free(trans);
-       return ret;
-}
-
-static void iwl_set_pwr_vmain(struct iwl_trans *trans)
-{
-/*
- * (for documentation purposes)
- * to set power to V_AUX, do:
-
-               if (pci_pme_capable(priv->pci_dev, PCI_D3cold))
-                       iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
-                                              APMG_PS_CTRL_VAL_PWR_SRC_VAUX,
-                                              ~APMG_PS_CTRL_MSK_PWR_SRC);
- */
-
-       iwl_set_bits_mask_prph(bus(trans), APMG_PS_CTRL_REG,
-                              APMG_PS_CTRL_VAL_PWR_SRC_VMAIN,
-                              ~APMG_PS_CTRL_MSK_PWR_SRC);
-}
-
-static int iwl_nic_init(struct iwl_trans *trans)
-{
-       unsigned long flags;
-
-       /* nic_init */
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-       iwl_apm_init(priv(trans));
-
-       /* Set interrupt coalescing calibration timer to default (512 usecs) */
-       iwl_write8(bus(trans), CSR_INT_COALESCING,
-               IWL_HOST_INT_CALIB_TIMEOUT_DEF);
-
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       iwl_set_pwr_vmain(trans);
-
-       iwl_nic_config(priv(trans));
-
-       /* Allocate the RX queue, or reset if it is already allocated */
-       iwl_rx_init(trans);
-
-       /* Allocate or reset and init all Tx and Command queues */
-       if (iwl_tx_init(trans))
-               return -ENOMEM;
-
-       if (hw_params(trans).shadow_reg_enable) {
-               /* enable shadow regs in HW */
-               iwl_set_bit(bus(trans), CSR_MAC_SHADOW_REG_CTRL,
-                       0x800FFFFF);
-       }
-
-       set_bit(STATUS_INIT, &trans->shrd->status);
-
-       return 0;
-}
-
-#define HW_READY_TIMEOUT (50)
-
-/* Note: returns poll_bit return value, which is >= 0 if success */
-static int iwl_set_hw_ready(struct iwl_trans *trans)
-{
-       int ret;
-
-       iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
-               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY);
-
-       /* See if we got it */
-       ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
-                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-                               CSR_HW_IF_CONFIG_REG_BIT_NIC_READY,
-                               HW_READY_TIMEOUT);
-
-       IWL_DEBUG_INFO(trans, "hardware%s ready\n", ret < 0 ? " not" : "");
-       return ret;
-}
-
-/* Note: returns standard 0/-ERROR code */
-static int iwl_trans_pcie_prepare_card_hw(struct iwl_trans *trans)
-{
-       int ret;
-
-       IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
-
-       ret = iwl_set_hw_ready(trans);
-       if (ret >= 0)
-               return 0;
-
-       /* If HW is not ready, prepare the conditions to check again */
-       iwl_set_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
-                       CSR_HW_IF_CONFIG_REG_PREPARE);
-
-       ret = iwl_poll_bit(bus(trans), CSR_HW_IF_CONFIG_REG,
-                       ~CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE,
-                       CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE, 150000);
-
-       if (ret < 0)
-               return ret;
-
-       /* HW should be ready by now, check again. */
-       ret = iwl_set_hw_ready(trans);
-       if (ret >= 0)
-               return 0;
-       return ret;
-}
-
-#define IWL_AC_UNSET -1
-
-struct queue_to_fifo_ac {
-       s8 fifo, ac;
-};
-
-static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
-       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
-};
-
-static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
-       { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
-       { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
-       { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
-       { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
-       { IWL_TX_FIFO_BE_IPAN, 2, },
-       { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
-       { IWL_TX_FIFO_AUX, IWL_AC_UNSET, },
-};
-
-static const u8 iwlagn_bss_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO,
-       IWL_TX_FIFO_VI,
-       IWL_TX_FIFO_BE,
-       IWL_TX_FIFO_BK,
-};
-static const u8 iwlagn_bss_ac_to_queue[] = {
-       0, 1, 2, 3,
-};
-static const u8 iwlagn_pan_ac_to_fifo[] = {
-       IWL_TX_FIFO_VO_IPAN,
-       IWL_TX_FIFO_VI_IPAN,
-       IWL_TX_FIFO_BE_IPAN,
-       IWL_TX_FIFO_BK_IPAN,
-};
-static const u8 iwlagn_pan_ac_to_queue[] = {
-       7, 6, 5, 4,
-};
-
-static int iwl_trans_pcie_start_device(struct iwl_trans *trans)
-{
-       int ret;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       trans->shrd->ucode_owner = IWL_OWNERSHIP_DRIVER;
-       trans_pcie->ac_to_queue[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_queue;
-       trans_pcie->ac_to_queue[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_queue;
-
-       trans_pcie->ac_to_fifo[IWL_RXON_CTX_BSS] = iwlagn_bss_ac_to_fifo;
-       trans_pcie->ac_to_fifo[IWL_RXON_CTX_PAN] = iwlagn_pan_ac_to_fifo;
-
-       trans_pcie->mcast_queue[IWL_RXON_CTX_BSS] = 0;
-       trans_pcie->mcast_queue[IWL_RXON_CTX_PAN] = IWL_IPAN_MCAST_QUEUE;
-
-       if ((hw_params(trans).sku & EEPROM_SKU_CAP_AMT_ENABLE) &&
-            iwl_trans_pcie_prepare_card_hw(trans)) {
-               IWL_WARN(trans, "Exit HW not ready\n");
-               return -EIO;
-       }
-
-       /* If platform's RF_KILL switch is NOT set to KILL */
-       if (iwl_read32(bus(trans), CSR_GP_CNTRL) &
-                       CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)
-               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-       else
-               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-
-       if (iwl_is_rfkill(trans->shrd)) {
-               iwl_set_hw_rfkill_state(priv(trans), true);
-               iwl_enable_interrupts(trans);
-               return -ERFKILL;
-       }
-
-       iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
-
-       ret = iwl_nic_init(trans);
-       if (ret) {
-               IWL_ERR(trans, "Unable to init nic\n");
-               return ret;
-       }
-
-       /* make sure rfkill handshake bits are cleared */
-       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR,
-                   CSR_UCODE_DRV_GP1_BIT_CMD_BLOCKED);
-
-       /* clear (again), then enable host interrupts */
-       iwl_write32(bus(trans), CSR_INT, 0xFFFFFFFF);
-       iwl_enable_interrupts(trans);
-
-       /* really make sure rfkill handshake bits are cleared */
-       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-       iwl_write32(bus(trans), CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       return 0;
-}
-
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- * must be called under priv->shrd->lock and mac access
- */
-static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
-{
-       iwl_write_prph(bus(trans), SCD_TXFACT, mask);
-}
-
-static void iwl_trans_pcie_tx_start(struct iwl_trans *trans)
-{
-       const struct queue_to_fifo_ac *queue_to_fifo;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 a;
-       unsigned long flags;
-       int i, chan;
-       u32 reg_val;
-
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-
-       trans_pcie->scd_base_addr =
-               iwl_read_prph(bus(trans), SCD_SRAM_BASE_ADDR);
-       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-       /* reset conext data memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(bus(trans), a, 0);
-       /* reset tx status memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(bus(trans), a, 0);
-       for (; a < trans_pcie->scd_base_addr +
-              SCD_TRANS_TBL_OFFSET_QUEUE(hw_params(trans).max_txq_num);
-              a += 4)
-               iwl_write_targ_mem(bus(trans), a, 0);
-
-       iwl_write_prph(bus(trans), SCD_DRAM_BASE_ADDR,
-                      trans_pcie->scd_bc_tbls.dma >> 10);
-
-       /* Enable DMA channel */
-       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
-               iwl_write_direct32(bus(trans), FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                               FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-       /* Update FH chicken bits */
-       reg_val = iwl_read_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG);
-       iwl_write_direct32(bus(trans), FH_TX_CHICKEN_BITS_REG,
-                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-       iwl_write_prph(bus(trans), SCD_QUEUECHAIN_SEL,
-               SCD_QUEUECHAIN_SEL_ALL(trans));
-       iwl_write_prph(bus(trans), SCD_AGGR_SEL, 0);
-
-       /* initiate the queues */
-       for (i = 0; i < hw_params(trans).max_txq_num; i++) {
-               iwl_write_prph(bus(trans), SCD_QUEUE_RDPTR(i), 0);
-               iwl_write_direct32(bus(trans), HBUS_TARG_WRPTR, 0 | (i << 8));
-               iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
-                               SCD_CONTEXT_QUEUE_OFFSET(i), 0);
-               iwl_write_targ_mem(bus(trans), trans_pcie->scd_base_addr +
-                               SCD_CONTEXT_QUEUE_OFFSET(i) +
-                               sizeof(u32),
-                               ((SCD_WIN_SIZE <<
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
-                               SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
-                               ((SCD_FRAME_LIMIT <<
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
-                               SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
-       }
-
-       iwl_write_prph(bus(trans), SCD_INTERRUPT_MASK,
-                       IWL_MASK(0, hw_params(trans).max_txq_num));
-
-       /* Activate all Tx DMA/FIFO channels */
-       iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
-
-       /* map queues to FIFOs */
-       if (trans->shrd->valid_contexts != BIT(IWL_RXON_CTX_BSS))
-               queue_to_fifo = iwlagn_ipan_queue_to_tx_fifo;
-       else
-               queue_to_fifo = iwlagn_default_queue_to_tx_fifo;
-
-       iwl_trans_set_wr_ptrs(trans, trans->shrd->cmd_queue, 0);
-
-       /* make sure all queue are not stopped */
-       memset(&trans_pcie->queue_stopped[0], 0,
-               sizeof(trans_pcie->queue_stopped));
-       for (i = 0; i < 4; i++)
-               atomic_set(&trans_pcie->queue_stop_count[i], 0);
-
-       /* reset to 0 to enable all the queue first */
-       trans_pcie->txq_ctx_active_msk = 0;
-
-       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_default_queue_to_tx_fifo) <
-                                               IWLAGN_FIRST_AMPDU_QUEUE);
-       BUILD_BUG_ON(ARRAY_SIZE(iwlagn_ipan_queue_to_tx_fifo) <
-                                               IWLAGN_FIRST_AMPDU_QUEUE);
-
-       for (i = 0; i < IWLAGN_FIRST_AMPDU_QUEUE; i++) {
-               int fifo = queue_to_fifo[i].fifo;
-               int ac = queue_to_fifo[i].ac;
-
-               iwl_txq_ctx_activate(trans_pcie, i);
-
-               if (fifo == IWL_TX_FIFO_UNUSED)
-                       continue;
-
-               if (ac != IWL_AC_UNSET)
-                       iwl_set_swq_id(&trans_pcie->txq[i], ac, i);
-               iwl_trans_tx_queue_set_status(trans, &trans_pcie->txq[i],
-                                             fifo, 0);
-       }
-
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       /* Enable L1-Active */
-       iwl_clear_bits_prph(bus(trans), APMG_PCIDEV_STT_REG,
-                         APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-static int iwl_trans_tx_stop(struct iwl_trans *trans)
-{
-       int ch, txq_id;
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-
-       iwl_trans_txq_set_sched(trans, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
-               iwl_write_direct32(bus(trans),
-                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               if (iwl_poll_direct_bit(bus(trans), FH_TSSR_TX_STATUS_REG,
-                                   FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch),
-                                   1000))
-                       IWL_ERR(trans, "Failing on timeout while stopping"
-                           " DMA channel %d [0x%08x]", ch,
-                           iwl_read_direct32(bus(trans),
-                                             FH_TSSR_TX_STATUS_REG));
-       }
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans, "Stopping tx queues that aren't allocated...");
-               return 0;
-       }
-
-       /* Unmap DMA from host system and free skb's */
-       for (txq_id = 0; txq_id < hw_params(trans).max_txq_num; txq_id++)
-               iwl_tx_queue_unmap(trans, txq_id);
-
-       return 0;
-}
-
-static void iwl_trans_pcie_disable_sync_irq(struct iwl_trans *trans)
-{
-       unsigned long flags;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       spin_lock_irqsave(&trans->shrd->lock, flags);
-       iwl_disable_interrupts(trans);
-       spin_unlock_irqrestore(&trans->shrd->lock, flags);
-
-       /* wait to make sure we flush pending tasklet*/
-       synchronize_irq(bus(trans)->irq);
-       tasklet_kill(&trans_pcie->irq_tasklet);
-}
-
-static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
-{
-       /* stop and reset the on-board processor */
-       iwl_write32(bus(trans), CSR_RESET, CSR_RESET_REG_FLAG_NEVO_RESET);
-
-       /* tell the device to stop sending interrupts */
-       iwl_trans_pcie_disable_sync_irq(trans);
-
-       /* device going down, Stop using ICT table */
-       iwl_disable_ict(trans);
-
-       /*
-        * If a HW restart happens during firmware loading,
-        * then the firmware loading might call this function
-        * and later it might be called again due to the
-        * restart. So don't process again if the device is
-        * already dead.
-        */
-       if (test_bit(STATUS_DEVICE_ENABLED, &trans->shrd->status)) {
-               iwl_trans_tx_stop(trans);
-               iwl_trans_rx_stop(trans);
-
-               /* Power-down device's busmaster DMA clocks */
-               iwl_write_prph(bus(trans), APMG_CLK_DIS_REG,
-                              APMG_CLK_VAL_DMA_CLK_RQT);
-               udelay(5);
-       }
-
-       /* Make sure (redundant) we've released our request to stay awake */
-       iwl_clear_bit(bus(trans), CSR_GP_CNTRL,
-                       CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
-
-       /* Stop the device, and put it in low power state */
-       iwl_apm_stop(priv(trans));
-}
-
-static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
-               struct iwl_device_cmd *dev_cmd, u8 ctx, u8 sta_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct iwl_tx_cmd *tx_cmd = &dev_cmd->cmd.tx;
-       struct iwl_cmd_meta *out_meta;
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-
-       dma_addr_t phys_addr = 0;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       u16 len, firstlen, secondlen;
-       u16 seq_number = 0;
-       u8 wait_write_ptr = 0;
-       u8 txq_id;
-       u8 tid = 0;
-       bool is_agg = false;
-       __le16 fc = hdr->frame_control;
-       u8 hdr_len = ieee80211_hdrlen(fc);
-
-       /*
-        * Send this frame after DTIM -- there's a special queue
-        * reserved for this for contexts that support AP mode.
-        */
-       if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) {
-               txq_id = trans_pcie->mcast_queue[ctx];
-
-               /*
-                * The microcode will clear the more data
-                * bit in the last frame it transmits.
-                */
-               hdr->frame_control |=
-                       cpu_to_le16(IEEE80211_FCTL_MOREDATA);
-       } else if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
-               txq_id = IWL_AUX_QUEUE;
-       else
-               txq_id =
-                   trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
-
-       if (ieee80211_is_data_qos(fc)) {
-               u8 *qc = NULL;
-               struct iwl_tid_data *tid_data;
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               tid_data = &trans->shrd->tid_data[sta_id][tid];
-
-               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
-                       return -1;
-
-               seq_number = tid_data->seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = hdr->seq_ctrl &
-                               cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               seq_number += 0x10;
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU &&
-                   tid_data->agg.state == IWL_AGG_ON) {
-                       txq_id = tid_data->agg.txq_id;
-                       is_agg = true;
-               }
-       }
-
-       txq = &trans_pcie->txq[txq_id];
-       q = &txq->q;
-
-       /* Set up driver data for this TFD */
-       txq->skbs[q->write_ptr] = skb;
-       txq->cmd[q->write_ptr] = dev_cmd;
-
-       dev_cmd->hdr.cmd = REPLY_TX;
-       dev_cmd->hdr.sequence = cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                               INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_meta = &txq->meta[q->write_ptr];
-
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-       firstlen = (len + 3) & ~3;
-
-       /* Tell NIC about any 2-byte padding after MAC header */
-       if (firstlen != len)
-               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = dma_map_single(bus(trans)->dev,
-                                   &dev_cmd->hdr, firstlen,
-                                   DMA_BIDIRECTIONAL);
-       if (unlikely(dma_mapping_error(bus(trans)->dev, txcmd_phys)))
-               return -1;
-       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       dma_unmap_len_set(out_meta, len, firstlen);
-
-       if (!ieee80211_has_morefrags(fc)) {
-               txq->need_update = 1;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       secondlen = skb->len - hdr_len;
-       if (secondlen > 0) {
-               phys_addr = dma_map_single(bus(trans)->dev, skb->data + hdr_len,
-                                          secondlen, DMA_TO_DEVICE);
-               if (unlikely(dma_mapping_error(bus(trans)->dev, phys_addr))) {
-                       dma_unmap_single(bus(trans)->dev,
-                                        dma_unmap_addr(out_meta, mapping),
-                                        dma_unmap_len(out_meta, len),
-                                        DMA_BIDIRECTIONAL);
-                       return -1;
-               }
-       }
-
-       /* Attach buffers to TFD */
-       iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
-       if (secondlen > 0)
-               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-                                            secondlen, 0);
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-                               offsetof(struct iwl_tx_cmd, scratch);
-
-       /* take back ownership of DMA buffer to enable update */
-       dma_sync_single_for_cpu(bus(trans)->dev, txcmd_phys, firstlen,
-                       DMA_BIDIRECTIONAL);
-       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-                    le16_to_cpu(dev_cmd->hdr.sequence));
-       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-       iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd, sizeof(*tx_cmd));
-       iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       if (is_agg)
-               iwl_trans_txq_update_byte_cnt_tbl(trans, txq,
-                                              le16_to_cpu(tx_cmd->len));
-
-       dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen,
-                       DMA_BIDIRECTIONAL);
-
-       trace_iwlwifi_dev_tx(priv(trans),
-                            &((struct iwl_tfd *)txq->tfds)[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &dev_cmd->hdr, firstlen,
-                            skb->data + hdr_len, secondlen);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(trans, txq);
-
-       if (ieee80211_is_data_qos(fc)) {
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
-               if (!ieee80211_has_morefrags(fc))
-                       trans->shrd->tid_data[sta_id][tid].seq_number =
-                               seq_number;
-       }
-
-       /*
-        * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
-        */
-       if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr) {
-                       txq->need_update = 1;
-                       iwl_txq_update_write_ptr(trans, txq);
-               } else {
-                       iwl_stop_queue(trans, txq);
-               }
-       }
-       return 0;
-}
-
-static void iwl_trans_pcie_kick_nic(struct iwl_trans *trans)
-{
-       /* Remove all resets to allow NIC to operate */
-       iwl_write32(bus(trans), CSR_RESET, 0);
-}
-
-static int iwl_trans_pcie_request_irq(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       int err;
-
-       trans_pcie->inta_mask = CSR_INI_SET_MASK;
-
-       tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-               iwl_irq_tasklet, (unsigned long)trans);
-
-       iwl_alloc_isr_ict(trans);
-
-       err = request_irq(bus(trans)->irq, iwl_isr_ict, IRQF_SHARED,
-               DRV_NAME, trans);
-       if (err) {
-               IWL_ERR(trans, "Error allocating IRQ %d\n", bus(trans)->irq);
-               iwl_free_isr_ict(trans);
-               return err;
-       }
-
-       INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
-       return 0;
-}
-
-static int iwlagn_txq_check_empty(struct iwl_trans *trans,
-                          int sta_id, u8 tid, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_queue *q = &trans_pcie->txq[txq_id].q;
-       struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid];
-
-       lockdep_assert_held(&trans->shrd->sta_lock);
-
-       switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if ((txq_id  == tid_data->agg.txq_id) &&
-                   (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_HT(trans,
-                               "HW queue empty: continue DELBA flow\n");
-                       iwl_trans_pcie_txq_agg_disable(trans, txq_id);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       iwl_stop_tx_ba_trans_ready(priv(trans),
-                                                  NUM_IWL_RXON_CTX,
-                                                  sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_HT(trans,
-                               "HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       iwl_start_tx_ba_trans_ready(priv(trans),
-                                                   NUM_IWL_RXON_CTX,
-                                                   sta_id, tid);
-               }
-               break;
-       }
-
-       return 0;
-}
-
-static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
-                           int sta_id, int tid, int freed)
-{
-       lockdep_assert_held(&trans->shrd->sta_lock);
-
-       if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
-       else {
-               IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
-                       trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
-                       freed);
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
-       }
-}
-
-static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
-                     int txq_id, int ssn, u32 status,
-                     struct sk_buff_head *skbs)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       /* n_bd is usually 256 => n_bd - 1 = 0xff */
-       int tfd_num = ssn & (txq->q.n_bd - 1);
-       int freed = 0;
-       u8 agg_state;
-       bool cond;
-
-       txq->time_stamp = jiffies;
-
-       if (txq->sched_retry) {
-               agg_state =
-                       trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state;
-               cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
-       } else {
-               cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
-       }
-
-       if (txq->q.read_ptr != tfd_num) {
-               IWL_DEBUG_TX_REPLY(trans, "Retry scheduler reclaim "
-                               "scd_ssn=%d idx=%d txq=%d swq=%d\n",
-                               ssn , tfd_num, txq_id, txq->swq_id);
-               freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
-                       iwl_wake_queue(trans, txq);
-       }
-
-       iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
-       iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
-}
-
-static void iwl_trans_pcie_free(struct iwl_trans *trans)
-{
-       iwl_trans_pcie_tx_free(trans);
-       iwl_trans_pcie_rx_free(trans);
-       free_irq(bus(trans)->irq, trans);
-       iwl_free_isr_ict(trans);
-       trans->shrd->trans = NULL;
-       kfree(trans);
-}
-
-#ifdef CONFIG_PM
-
-static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
-{
-       /*
-        * This function is called when system goes into suspend state
-        * mac80211 will call iwl_mac_stop() from the mac80211 suspend function
-        * first but since iwl_mac_stop() has no knowledge of who the caller is,
-        * it will not call apm_ops.stop() to stop the DMA operation.
-        * Calling apm_ops.stop here to make sure we stop the DMA.
-        *
-        * But of course ... if we have configured WoWLAN then we did other
-        * things already :-)
-        */
-       if (!trans->shrd->wowlan)
-               iwl_apm_stop(priv(trans));
-
-       return 0;
-}
-
-static int iwl_trans_pcie_resume(struct iwl_trans *trans)
-{
-       bool hw_rfkill = false;
-
-       iwl_enable_interrupts(trans);
-
-       if (!(iwl_read32(bus(trans), CSR_GP_CNTRL) &
-                               CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW))
-               hw_rfkill = true;
-
-       if (hw_rfkill)
-               set_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-       else
-               clear_bit(STATUS_RF_KILL_HW, &trans->shrd->status);
-
-       iwl_set_hw_rfkill_state(priv(trans), hw_rfkill);
-
-       return 0;
-}
-#else /* CONFIG_PM */
-static int iwl_trans_pcie_suspend(struct iwl_trans *trans)
-{ return 0; }
-
-static int iwl_trans_pcie_resume(struct iwl_trans *trans)
-{ return 0; }
-
-#endif /* CONFIG_PM */
-
-static void iwl_trans_pcie_wake_any_queue(struct iwl_trans *trans,
-                                         u8 ctx)
-{
-       u8 ac, txq_id;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       for (ac = 0; ac < AC_NUM; ac++) {
-               txq_id = trans_pcie->ac_to_queue[ctx][ac];
-               IWL_DEBUG_INFO(trans, "Queue Status: Q[%d] %s\n",
-                       ac,
-                       (atomic_read(&trans_pcie->queue_stop_count[ac]) > 0)
-                             ? "stopped" : "awake");
-               iwl_wake_queue(trans, &trans_pcie->txq[txq_id]);
-       }
-}
-
-const struct iwl_trans_ops trans_ops_pcie;
-
-static struct iwl_trans *iwl_trans_pcie_alloc(struct iwl_shared *shrd)
-{
-       struct iwl_trans *iwl_trans = kzalloc(sizeof(struct iwl_trans) +
-                                             sizeof(struct iwl_trans_pcie),
-                                             GFP_KERNEL);
-       if (iwl_trans) {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(iwl_trans);
-               iwl_trans->ops = &trans_ops_pcie;
-               iwl_trans->shrd = shrd;
-               trans_pcie->trans = iwl_trans;
-               spin_lock_init(&iwl_trans->hcmd_lock);
-       }
-
-       return iwl_trans;
-}
-
-static void iwl_trans_pcie_stop_queue(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_stop_queue(trans, &trans_pcie->txq[txq_id]);
-}
-
-#define IWL_FLUSH_WAIT_MS      2000
-
-static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       int cnt;
-       unsigned long now = jiffies;
-       int ret = 0;
-
-       /* waiting for all the tx frames complete might take a while */
-       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
-               if (cnt == trans->shrd->cmd_queue)
-                       continue;
-               txq = &trans_pcie->txq[cnt];
-               q = &txq->q;
-               while (q->read_ptr != q->write_ptr && !time_after(jiffies,
-                      now + msecs_to_jiffies(IWL_FLUSH_WAIT_MS)))
-                       msleep(1);
-
-               if (q->read_ptr != q->write_ptr) {
-                       IWL_ERR(trans, "fail to flush all tx fifo queues\n");
-                       ret = -ETIMEDOUT;
-                       break;
-               }
-       }
-       return ret;
-}
-
-/*
- * On every watchdog tick we check (latest) time stamp. If it does not
- * change during timeout period and queue is not empty we reset firmware.
- */
-static int iwl_trans_pcie_check_stuck_queue(struct iwl_trans *trans, int cnt)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[cnt];
-       struct iwl_queue *q = &txq->q;
-       unsigned long timeout;
-
-       if (q->read_ptr == q->write_ptr) {
-               txq->time_stamp = jiffies;
-               return 0;
-       }
-
-       timeout = txq->time_stamp +
-                 msecs_to_jiffies(hw_params(trans).wd_timeout);
-
-       if (time_after(jiffies, timeout)) {
-               IWL_ERR(trans, "Queue %d stuck for %u ms.\n", q->id,
-                       hw_params(trans).wd_timeout);
-               IWL_ERR(trans, "Current read_ptr %d write_ptr %d\n",
-                       q->read_ptr, q->write_ptr);
-               return 1;
-       }
-
-       return 0;
-}
-
-static const char *get_fh_string(int cmd)
-{
-       switch (cmd) {
-       IWL_CMD(FH_RSCSR_CHNL0_STTS_WPTR_REG);
-       IWL_CMD(FH_RSCSR_CHNL0_RBDCB_BASE_REG);
-       IWL_CMD(FH_RSCSR_CHNL0_WPTR);
-       IWL_CMD(FH_MEM_RCSR_CHNL0_CONFIG_REG);
-       IWL_CMD(FH_MEM_RSSR_SHARED_CTRL_REG);
-       IWL_CMD(FH_MEM_RSSR_RX_STATUS_REG);
-       IWL_CMD(FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV);
-       IWL_CMD(FH_TSSR_TX_STATUS_REG);
-       IWL_CMD(FH_TSSR_TX_ERROR_REG);
-       default:
-               return "UNKNOWN";
-       }
-}
-
-int iwl_dump_fh(struct iwl_trans *trans, char **buf, bool display)
-{
-       int i;
-#ifdef CONFIG_IWLWIFI_DEBUG
-       int pos = 0;
-       size_t bufsz = 0;
-#endif
-       static const u32 fh_tbl[] = {
-               FH_RSCSR_CHNL0_STTS_WPTR_REG,
-               FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-               FH_RSCSR_CHNL0_WPTR,
-               FH_MEM_RCSR_CHNL0_CONFIG_REG,
-               FH_MEM_RSSR_SHARED_CTRL_REG,
-               FH_MEM_RSSR_RX_STATUS_REG,
-               FH_MEM_RSSR_RX_ENABLE_ERR_IRQ2DRV,
-               FH_TSSR_TX_STATUS_REG,
-               FH_TSSR_TX_ERROR_REG
-       };
-#ifdef CONFIG_IWLWIFI_DEBUG
-       if (display) {
-               bufsz = ARRAY_SIZE(fh_tbl) * 48 + 40;
-               *buf = kmalloc(bufsz, GFP_KERNEL);
-               if (!*buf)
-                       return -ENOMEM;
-               pos += scnprintf(*buf + pos, bufsz - pos,
-                               "FH register values:\n");
-               for (i = 0; i < ARRAY_SIZE(fh_tbl); i++) {
-                       pos += scnprintf(*buf + pos, bufsz - pos,
-                               "  %34s: 0X%08x\n",
-                               get_fh_string(fh_tbl[i]),
-                               iwl_read_direct32(bus(trans), fh_tbl[i]));
-               }
-               return pos;
-       }
-#endif
-       IWL_ERR(trans, "FH register values:\n");
-       for (i = 0; i <  ARRAY_SIZE(fh_tbl); i++) {
-               IWL_ERR(trans, "  %34s: 0X%08x\n",
-                       get_fh_string(fh_tbl[i]),
-                       iwl_read_direct32(bus(trans), fh_tbl[i]));
-       }
-       return 0;
-}
-
-static const char *get_csr_string(int cmd)
-{
-       switch (cmd) {
-       IWL_CMD(CSR_HW_IF_CONFIG_REG);
-       IWL_CMD(CSR_INT_COALESCING);
-       IWL_CMD(CSR_INT);
-       IWL_CMD(CSR_INT_MASK);
-       IWL_CMD(CSR_FH_INT_STATUS);
-       IWL_CMD(CSR_GPIO_IN);
-       IWL_CMD(CSR_RESET);
-       IWL_CMD(CSR_GP_CNTRL);
-       IWL_CMD(CSR_HW_REV);
-       IWL_CMD(CSR_EEPROM_REG);
-       IWL_CMD(CSR_EEPROM_GP);
-       IWL_CMD(CSR_OTP_GP_REG);
-       IWL_CMD(CSR_GIO_REG);
-       IWL_CMD(CSR_GP_UCODE_REG);
-       IWL_CMD(CSR_GP_DRIVER_REG);
-       IWL_CMD(CSR_UCODE_DRV_GP1);
-       IWL_CMD(CSR_UCODE_DRV_GP2);
-       IWL_CMD(CSR_LED_REG);
-       IWL_CMD(CSR_DRAM_INT_TBL_REG);
-       IWL_CMD(CSR_GIO_CHICKEN_BITS);
-       IWL_CMD(CSR_ANA_PLL_CFG);
-       IWL_CMD(CSR_HW_REV_WA_REG);
-       IWL_CMD(CSR_DBG_HPET_MEM_REG);
-       default:
-               return "UNKNOWN";
-       }
-}
-
-void iwl_dump_csr(struct iwl_trans *trans)
-{
-       int i;
-       static const u32 csr_tbl[] = {
-               CSR_HW_IF_CONFIG_REG,
-               CSR_INT_COALESCING,
-               CSR_INT,
-               CSR_INT_MASK,
-               CSR_FH_INT_STATUS,
-               CSR_GPIO_IN,
-               CSR_RESET,
-               CSR_GP_CNTRL,
-               CSR_HW_REV,
-               CSR_EEPROM_REG,
-               CSR_EEPROM_GP,
-               CSR_OTP_GP_REG,
-               CSR_GIO_REG,
-               CSR_GP_UCODE_REG,
-               CSR_GP_DRIVER_REG,
-               CSR_UCODE_DRV_GP1,
-               CSR_UCODE_DRV_GP2,
-               CSR_LED_REG,
-               CSR_DRAM_INT_TBL_REG,
-               CSR_GIO_CHICKEN_BITS,
-               CSR_ANA_PLL_CFG,
-               CSR_HW_REV_WA_REG,
-               CSR_DBG_HPET_MEM_REG
+       struct iwl_host_cmd cmd = {
+               .id = id,
+               .len = { len, },
+               .data = { data, },
+               .flags = flags,
        };
-       IWL_ERR(trans, "CSR values:\n");
-       IWL_ERR(trans, "(2nd byte of CSR_INT_COALESCING is "
-               "CSR_INT_PERIODIC_REG)\n");
-       for (i = 0; i <  ARRAY_SIZE(csr_tbl); i++) {
-               IWL_ERR(trans, "  %25s: 0X%08x\n",
-                       get_csr_string(csr_tbl[i]),
-                       iwl_read32(bus(trans), csr_tbl[i]));
-       }
-}
-
-#ifdef CONFIG_IWLWIFI_DEBUGFS
-/* create and remove of files */
-#define DEBUGFS_ADD_FILE(name, parent, mode) do {                      \
-       if (!debugfs_create_file(#name, mode, parent, trans,            \
-                                &iwl_dbgfs_##name##_ops))              \
-               return -ENOMEM;                                         \
-} while (0)
-
-/* file operation */
-#define DEBUGFS_READ_FUNC(name)                                         \
-static ssize_t iwl_dbgfs_##name##_read(struct file *file,               \
-                                       char __user *user_buf,          \
-                                       size_t count, loff_t *ppos);
-
-#define DEBUGFS_WRITE_FUNC(name)                                        \
-static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
-                                       const char __user *user_buf,    \
-                                       size_t count, loff_t *ppos);
-
-
-static int iwl_dbgfs_open_file_generic(struct inode *inode, struct file *file)
-{
-       file->private_data = inode->i_private;
-       return 0;
-}
-
-#define DEBUGFS_READ_FILE_OPS(name)                                    \
-       DEBUGFS_READ_FUNC(name);                                        \
-static const struct file_operations iwl_dbgfs_##name##_ops = {         \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
-       .llseek = generic_file_llseek,                                  \
-};
 
-#define DEBUGFS_WRITE_FILE_OPS(name)                                    \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {          \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .open = iwl_dbgfs_open_file_generic,                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-#define DEBUGFS_READ_WRITE_FILE_OPS(name)                              \
-       DEBUGFS_READ_FUNC(name);                                        \
-       DEBUGFS_WRITE_FUNC(name);                                       \
-static const struct file_operations iwl_dbgfs_##name##_ops = {         \
-       .write = iwl_dbgfs_##name##_write,                              \
-       .read = iwl_dbgfs_##name##_read,                                \
-       .open = iwl_dbgfs_open_file_generic,                            \
-       .llseek = generic_file_llseek,                                  \
-};
-
-static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       char *buf;
-       int pos = 0;
-       int cnt;
-       int ret;
-       const size_t bufsz = sizeof(char) * 64 * hw_params(trans).max_txq_num;
-
-       if (!trans_pcie->txq) {
-               IWL_ERR(trans, "txq not ready\n");
-               return -EAGAIN;
-       }
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf)
-               return -ENOMEM;
-
-       for (cnt = 0; cnt < hw_params(trans).max_txq_num; cnt++) {
-               txq = &trans_pcie->txq[cnt];
-               q = &txq->q;
-               pos += scnprintf(buf + pos, bufsz - pos,
-                               "hwq %.2d: read=%u write=%u stop=%d"
-                               " swq_id=%#.2x (ac %d/hwq %d)\n",
-                               cnt, q->read_ptr, q->write_ptr,
-                               !!test_bit(cnt, trans_pcie->queue_stopped),
-                               txq->swq_id, txq->swq_id & 3,
-                               (txq->swq_id >> 2) & 0x1f);
-               if (cnt >= 4)
-                       continue;
-               /* for the ACs, display the stop count too */
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "        stop-count: %d\n",
-                       atomic_read(&trans_pcie->queue_stop_count[cnt]));
-       }
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
+       return iwl_trans_send_cmd(trans, &cmd);
 }
-
-static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
-                                               char __user *user_buf,
-                                               size_t count, loff_t *ppos) {
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       char buf[256];
-       int pos = 0;
-       const size_t bufsz = sizeof(buf);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "read: %u\n",
-                                               rxq->read);
-       pos += scnprintf(buf + pos, bufsz - pos, "write: %u\n",
-                                               rxq->write);
-       pos += scnprintf(buf + pos, bufsz - pos, "free_count: %u\n",
-                                               rxq->free_count);
-       if (rxq->rb_stts) {
-               pos += scnprintf(buf + pos, bufsz - pos, "closed_rb_num: %u\n",
-                        le16_to_cpu(rxq->rb_stts->closed_rb_num) &  0x0FFF);
-       } else {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                                       "closed_rb_num: Not Allocated\n");
-       }
-       return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-}
-
-static ssize_t iwl_dbgfs_log_event_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char *buf;
-       int pos = 0;
-       ssize_t ret = -ENOMEM;
-
-       ret = pos = iwl_dump_nic_event_log(trans, true, &buf, true);
-       if (buf) {
-               ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-               kfree(buf);
-       }
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_log_event_write(struct file *file,
-                                       const char __user *user_buf,
-                                       size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       u32 event_log_flag;
-       char buf[8];
-       int buf_size;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &event_log_flag) != 1)
-               return -EFAULT;
-       if (event_log_flag == 1)
-               iwl_dump_nic_event_log(trans, true, NULL, false);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_interrupt_read(struct file *file,
-                                       char __user *user_buf,
-                                       size_t count, loff_t *ppos) {
-
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-       int pos = 0;
-       char *buf;
-       int bufsz = 24 * 64; /* 24 items * 64 char per item */
-       ssize_t ret;
-
-       buf = kzalloc(bufsz, GFP_KERNEL);
-       if (!buf) {
-               IWL_ERR(trans, "Can not allocate Buffer\n");
-               return -ENOMEM;
-       }
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-                       "Interrupt Statistics Report:\n");
-
-       pos += scnprintf(buf + pos, bufsz - pos, "HW Error:\t\t\t %u\n",
-               isr_stats->hw);
-       pos += scnprintf(buf + pos, bufsz - pos, "SW Error:\t\t\t %u\n",
-               isr_stats->sw);
-       if (isr_stats->sw || isr_stats->hw) {
-               pos += scnprintf(buf + pos, bufsz - pos,
-                       "\tLast Restarting Code:  0x%X\n",
-                       isr_stats->err_code);
-       }
-#ifdef CONFIG_IWLWIFI_DEBUG
-       pos += scnprintf(buf + pos, bufsz - pos, "Frame transmitted:\t\t %u\n",
-               isr_stats->sch);
-       pos += scnprintf(buf + pos, bufsz - pos, "Alive interrupt:\t\t %u\n",
-               isr_stats->alive);
-#endif
-       pos += scnprintf(buf + pos, bufsz - pos,
-               "HW RF KILL switch toggled:\t %u\n", isr_stats->rfkill);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "CT KILL:\t\t\t %u\n",
-               isr_stats->ctkill);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Wakeup Interrupt:\t\t %u\n",
-               isr_stats->wakeup);
-
-       pos += scnprintf(buf + pos, bufsz - pos,
-               "Rx command responses:\t\t %u\n", isr_stats->rx);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Tx/FH interrupt:\t\t %u\n",
-               isr_stats->tx);
-
-       pos += scnprintf(buf + pos, bufsz - pos, "Unexpected INTA:\t\t %u\n",
-               isr_stats->unhandled);
-
-       ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos);
-       kfree(buf);
-       return ret;
-}
-
-static ssize_t iwl_dbgfs_interrupt_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
-
-       char buf[8];
-       int buf_size;
-       u32 reset_flag;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%x", &reset_flag) != 1)
-               return -EFAULT;
-       if (reset_flag == 0)
-               memset(isr_stats, 0, sizeof(*isr_stats));
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_csr_write(struct file *file,
-                                        const char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char buf[8];
-       int buf_size;
-       int csr;
-
-       memset(buf, 0, sizeof(buf));
-       buf_size = min(count, sizeof(buf) -  1);
-       if (copy_from_user(buf, user_buf, buf_size))
-               return -EFAULT;
-       if (sscanf(buf, "%d", &csr) != 1)
-               return -EFAULT;
-
-       iwl_dump_csr(trans);
-
-       return count;
-}
-
-static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
-                                        char __user *user_buf,
-                                        size_t count, loff_t *ppos)
-{
-       struct iwl_trans *trans = file->private_data;
-       char *buf;
-       int pos = 0;
-       ssize_t ret = -EFAULT;
-
-       ret = pos = iwl_dump_fh(trans, &buf, true);
-       if (buf) {
-               ret = simple_read_from_buffer(user_buf,
-                                             count, ppos, buf, pos);
-               kfree(buf);
-       }
-
-       return ret;
-}
-
-DEBUGFS_READ_WRITE_FILE_OPS(log_event);
-DEBUGFS_READ_WRITE_FILE_OPS(interrupt);
-DEBUGFS_READ_FILE_OPS(fh_reg);
-DEBUGFS_READ_FILE_OPS(rx_queue);
-DEBUGFS_READ_FILE_OPS(tx_queue);
-DEBUGFS_WRITE_FILE_OPS(csr);
-
-/*
- * Create the debugfs files and directories
- *
- */
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                       struct dentry *dir)
-{
-       DEBUGFS_ADD_FILE(rx_queue, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(tx_queue, dir, S_IRUSR);
-       DEBUGFS_ADD_FILE(log_event, dir, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(interrupt, dir, S_IWUSR | S_IRUSR);
-       DEBUGFS_ADD_FILE(csr, dir, S_IWUSR);
-       DEBUGFS_ADD_FILE(fh_reg, dir, S_IRUSR);
-       return 0;
-}
-#else
-static int iwl_trans_pcie_dbgfs_register(struct iwl_trans *trans,
-                                       struct dentry *dir)
-{ return 0; }
-
-#endif /*CONFIG_IWLWIFI_DEBUGFS */
-
-const struct iwl_trans_ops trans_ops_pcie = {
-       .alloc = iwl_trans_pcie_alloc,
-       .request_irq = iwl_trans_pcie_request_irq,
-       .start_device = iwl_trans_pcie_start_device,
-       .prepare_card_hw = iwl_trans_pcie_prepare_card_hw,
-       .stop_device = iwl_trans_pcie_stop_device,
-
-       .tx_start = iwl_trans_pcie_tx_start,
-       .wake_any_queue = iwl_trans_pcie_wake_any_queue,
-
-       .send_cmd = iwl_trans_pcie_send_cmd,
-       .send_cmd_pdu = iwl_trans_pcie_send_cmd_pdu,
-
-       .tx = iwl_trans_pcie_tx,
-       .reclaim = iwl_trans_pcie_reclaim,
-
-       .tx_agg_disable = iwl_trans_pcie_tx_agg_disable,
-       .tx_agg_alloc = iwl_trans_pcie_tx_agg_alloc,
-       .tx_agg_setup = iwl_trans_pcie_tx_agg_setup,
-
-       .kick_nic = iwl_trans_pcie_kick_nic,
-
-       .free = iwl_trans_pcie_free,
-       .stop_queue = iwl_trans_pcie_stop_queue,
-
-       .dbgfs_register = iwl_trans_pcie_dbgfs_register,
-
-       .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
-       .check_stuck_queue = iwl_trans_pcie_check_stuck_queue,
-
-       .suspend = iwl_trans_pcie_suspend,
-       .resume = iwl_trans_pcie_resume,
-};
-
index 71a6fb05356a1f6d702962658c5a8b00477b4184..c5923125c3f96bb8fe7625e2b59e0ba1cde4b8d7 100644 (file)
@@ -97,15 +97,7 @@ enum {
  */
 struct iwl_device_cmd {
        struct iwl_cmd_header hdr;      /* uCode API */
-       union {
-               u32 flags;
-               u8 val8;
-               u16 val16;
-               u32 val32;
-               struct iwl_tx_cmd tx;
-               struct iwl6000_channel_switch_cmd chswitch;
-               u8 payload[DEF_CMD_PAYLOAD_SIZE];
-       } __packed cmd;
+       u8 payload[DEF_CMD_PAYLOAD_SIZE];
 } __packed;
 
 #define TFD_MAX_PAYLOAD_SIZE (sizeof(struct iwl_device_cmd))
@@ -120,6 +112,8 @@ enum iwl_hcmd_dataflag {
  * struct iwl_host_cmd - Host command to the uCode
  * @data: array of chunks that composes the data of the host command
  * @reply_page: pointer to the page that holds the response to the host command
+ * @handler_status: return value of the handler of the command
+ *     (put in setup_rx_handlers) - valid for SYNC mode only
  * @callback:
  * @flags: can be CMD_* note CMD_WANT_SKB is incompatible withe CMD_ASYNC
  * @len: array of the lenths of the chunks in data
@@ -129,9 +123,8 @@ enum iwl_hcmd_dataflag {
 struct iwl_host_cmd {
        const void *data[IWL_MAX_CMD_TFDS];
        unsigned long reply_page;
-       void (*callback)(struct iwl_shared *shrd,
-                        struct iwl_device_cmd *cmd,
-                        struct iwl_rx_packet *pkt);
+       int handler_status;
+
        u32 flags;
        u16 len[IWL_MAX_CMD_TFDS];
        u8 dataflags[IWL_MAX_CMD_TFDS];
@@ -151,7 +144,6 @@ struct iwl_host_cmd {
  * @wake_any_queue: wake all the queues of a specfic context IWL_RXON_CTX_*
  * @stop_device:stops the whole device (embedded CPU put to reset)
  * @send_cmd:send a host command
- * @send_cmd_pdu:send a host command: flags can be CMD_*
  * @tx: send an skb
  * @reclaim: free packet until ssn. Returns a list of freed packets.
  * @tx_agg_alloc: allocate resources for a TX BA session
@@ -178,14 +170,14 @@ struct iwl_trans_ops {
        void (*stop_device)(struct iwl_trans *trans);
        void (*tx_start)(struct iwl_trans *trans);
 
-       void (*wake_any_queue)(struct iwl_trans *trans, u8 ctx);
+       void (*wake_any_queue)(struct iwl_trans *trans,
+                              enum iwl_rxon_context_id ctx);
 
        int (*send_cmd)(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
 
-       int (*send_cmd_pdu)(struct iwl_trans *trans, u8 id, u32 flags, u16 len,
-                    const void *data);
        int (*tx)(struct iwl_trans *trans, struct sk_buff *skb,
-               struct iwl_device_cmd *dev_cmd, u8 ctx, u8 sta_id);
+               struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
+               u8 sta_id);
        void (*reclaim)(struct iwl_trans *trans, int sta_id, int tid,
                        int txq_id, int ssn, u32 status,
                        struct sk_buff_head *skbs);
@@ -209,9 +201,10 @@ struct iwl_trans_ops {
        int (*dbgfs_register)(struct iwl_trans *trans, struct dentry* dir);
        int (*check_stuck_queue)(struct iwl_trans *trans, int q);
        int (*wait_tx_queue_empty)(struct iwl_trans *trans);
-
+#ifdef CONFIG_PM_SLEEP
        int (*suspend)(struct iwl_trans *trans);
        int (*resume)(struct iwl_trans *trans);
+#endif
 };
 
 /**
@@ -255,7 +248,8 @@ static inline void iwl_trans_tx_start(struct iwl_trans *trans)
        trans->ops->tx_start(trans);
 }
 
-static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans, u8 ctx)
+static inline void iwl_trans_wake_any_queue(struct iwl_trans *trans,
+                                           enum iwl_rxon_context_id ctx)
 {
        trans->ops->wake_any_queue(trans, ctx);
 }
@@ -267,14 +261,12 @@ static inline int iwl_trans_send_cmd(struct iwl_trans *trans,
        return trans->ops->send_cmd(trans, cmd);
 }
 
-static inline int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
-                                       u32 flags, u16 len, const void *data)
-{
-       return trans->ops->send_cmd_pdu(trans, id, flags, len, data);
-}
+int iwl_trans_send_cmd_pdu(struct iwl_trans *trans, u8 id,
+                          u32 flags, u16 len, const void *data);
 
 static inline int iwl_trans_tx(struct iwl_trans *trans, struct sk_buff *skb,
-               struct iwl_device_cmd *dev_cmd, u8 ctx, u8 sta_id)
+               struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
+               u8 sta_id)
 {
        return trans->ops->tx(trans, skb, dev_cmd, ctx, sta_id);
 }
@@ -339,6 +331,7 @@ static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
        return trans->ops->dbgfs_register(trans, dir);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static inline int iwl_trans_suspend(struct iwl_trans *trans)
 {
        return trans->ops->suspend(trans);
@@ -348,6 +341,7 @@ static inline int iwl_trans_resume(struct iwl_trans *trans)
 {
        return trans->ops->resume(trans);
 }
+#endif
 
 /*****************************************************
 * Transport layers implementations
index 85b3169c40d70148593a81e4f98f242d04e01d21..610bfcee3cf6462c37c880866840a76398bcb3e8 100644 (file)
@@ -695,7 +695,7 @@ static void lbs_scan_worker(struct work_struct *work)
        tlv = scan_cmd->tlvbuffer;
 
        /* add SSID TLV */
-       if (priv->scan_req->n_ssids)
+       if (priv->scan_req->n_ssids && priv->scan_req->ssids[0].ssid_len > 0)
                tlv += lbs_add_ssid_tlv(tlv,
                                        priv->scan_req->ssids[0].ssid,
                                        priv->scan_req->ssids[0].ssid_len);
@@ -736,7 +736,6 @@ static void lbs_scan_worker(struct work_struct *work)
                        cfg80211_scan_done(priv->scan_req, false);
 
                priv->scan_req = NULL;
-               priv->last_scan = jiffies;
        }
 
        /* Restart network */
@@ -1302,24 +1301,26 @@ static int lbs_cfg_connect(struct wiphy *wiphy, struct net_device *dev,
        lbs_deb_enter(LBS_DEB_CFG80211);
 
        if (!sme->bssid) {
-               /* Run a scan if one isn't in-progress already and if the last
-                * scan was done more than 2 seconds ago.
-                */
-               if (priv->scan_req == NULL &&
-                   time_after(jiffies, priv->last_scan + (2 * HZ))) {
-                       struct cfg80211_scan_request *creq;
+               struct cfg80211_scan_request *creq;
 
-                       creq = _new_connect_scan_req(wiphy, sme);
-                       if (!creq) {
-                               ret = -EINVAL;
-                               goto done;
-                       }
+               /*
+                * Scan for the requested network after waiting for existing
+                * scans to finish.
+                */
+               lbs_deb_assoc("assoc: waiting for existing scans\n");
+               wait_event_interruptible_timeout(priv->scan_q,
+                                                (priv->scan_req == NULL),
+                                                (15 * HZ));
 
-                       lbs_deb_assoc("assoc: scanning for compatible AP\n");
-                       _internal_start_scan(priv, true, creq);
+               creq = _new_connect_scan_req(wiphy, sme);
+               if (!creq) {
+                       ret = -EINVAL;
+                       goto done;
                }
 
-               /* Wait for any in-progress scan to complete */
+               lbs_deb_assoc("assoc: scanning for compatible AP\n");
+               _internal_start_scan(priv, true, creq);
+
                lbs_deb_assoc("assoc: waiting for scan to complete\n");
                wait_event_interruptible_timeout(priv->scan_q,
                                                 (priv->scan_req == NULL),
index b9ff0dc53e8df047e4d01f2c2704073f32d96891..fb3e40bf59025fa7bd189f1eae4c61b089d15a20 100644 (file)
@@ -179,7 +179,6 @@ struct lbs_private {
        wait_queue_head_t scan_q;
        /* Whether the scan was initiated internally and not by cfg80211 */
        bool internal_scan;
-       unsigned long last_scan;
 };
 
 extern struct cmd_confirm_sleep confirm_sleep;
index 6fd53e4e3fe646248036a082893cd6a8991ac51b..0ddcdca63cf7bded5bb81e956b91734dc0054ac8 100644 (file)
@@ -768,6 +768,7 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
        struct mwifiex_bss_info bss_info;
        int ie_len;
        u8 ie_buf[IEEE80211_MAX_SSID_LEN + sizeof(struct ieee_types_header)];
+       enum ieee80211_band band;
 
        if (mwifiex_get_bss_info(priv, &bss_info))
                return -1;
@@ -780,9 +781,10 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
                        bss_info.ssid.ssid_len);
        ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
 
+       band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
        chan = __ieee80211_get_channel(priv->wdev->wiphy,
                        ieee80211_channel_to_frequency(bss_info.bss_chan,
-                                               priv->curr_bss_params.band));
+                                                      band));
 
        cfg80211_inform_bss(priv->wdev->wiphy, chan,
                bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
@@ -1219,6 +1221,9 @@ int mwifiex_register_cfg80211(struct net_device *dev, u8 *mac,
        /* We are using custom domains */
        wdev->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY;
 
+       /* Reserve space for bss band information */
+       wdev->wiphy->bss_priv_size = sizeof(u8);
+
        wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
 
        /* Set struct mwifiex_private pointer in wiphy_priv */
index b5352afb8714884752474936dc8a031b611ecbf3..d12e25d0c88060c5d8968ee504894b57f64f4f77 100644 (file)
@@ -90,6 +90,9 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
        cmd_node->data_buf = NULL;
        cmd_node->wait_q_enabled = false;
 
+       if (cmd_node->cmd_skb)
+               skb_trim(cmd_node->cmd_skb, 0);
+
        if (cmd_node->resp_skb) {
                dev_kfree_skb_any(cmd_node->resp_skb);
                cmd_node->resp_skb = NULL;
index e6b6c0cfb63e32df41aee6ad2655bdde8e47dc58..1e801328a558266a5c74a7a4521ea4b8e234f8d0 100644 (file)
@@ -958,7 +958,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *,
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
                              u8 *bssid, s32 rssi, u8 *ie_buf,
                              size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap,
+                             u16 cap_info_bitmap, u8 band,
                              struct mwifiex_bssdescriptor *bss_desc);
 int mwifiex_update_bss_desc_with_ie(struct mwifiex_adapter *adapter,
                                struct mwifiex_bssdescriptor *bss_entry,
index 8d8588db1cd960d71fc34c4e564768ecf40bd30b..ca3761965e858a8e0855ae304c547adf00c35b58 100644 (file)
@@ -532,7 +532,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
 
                sband = priv->wdev->wiphy->bands[band];
 
-               for (i = 0; (i < sband->n_channels) ; i++, chan_idx++) {
+               for (i = 0; (i < sband->n_channels) ; i++) {
                        ch = &sband->channels[i];
                        if (ch->flags & IEEE80211_CHAN_DISABLED)
                                continue;
@@ -563,6 +563,7 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        |= MWIFIEX_DISABLE_CHAN_FILT;
                        }
+                       chan_idx++;
                }
 
        }
@@ -1463,9 +1464,9 @@ int mwifiex_check_network_compatibility(struct mwifiex_private *priv,
 }
 
 static int
-mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
-                       u8 *bssid, s32 rssi, const u8 *ie_buf,
-                       size_t ie_len, u16 beacon_period, u16 cap_info_bitmap)
+mwifiex_update_curr_bss_params(struct mwifiex_private *priv, u8 *bssid,
+                              s32 rssi, const u8 *ie_buf, size_t ie_len,
+                              u16 beacon_period, u16 cap_info_bitmap, u8 band)
 {
        struct mwifiex_bssdescriptor *bss_desc = NULL;
        int ret;
@@ -1488,7 +1489,7 @@ mwifiex_update_curr_bss_params(struct mwifiex_private *priv,
 
        ret = mwifiex_fill_new_bss_desc(priv, bssid, rssi, beacon_ie,
                                        ie_len, beacon_period,
-                                       cap_info_bitmap, bss_desc);
+                                       cap_info_bitmap, band, bss_desc);
        if (ret)
                goto done;
 
@@ -1532,6 +1533,11 @@ done:
        return 0;
 }
 
+static void mwifiex_free_bss_priv(struct cfg80211_bss *bss)
+{
+       kfree(bss->priv);
+}
+
 /*
  * This function handles the command response of scan.
  *
@@ -1570,6 +1576,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
        struct chan_band_param_set *chan_band;
        u8 is_bgscan_resp;
        unsigned long flags;
+       struct cfg80211_bss *bss;
 
        is_bgscan_resp = (le16_to_cpu(resp->command)
                == HostCmd_CMD_802_11_BG_SCAN_QUERY);
@@ -1751,10 +1758,12 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                        chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
 
                        if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
-                               cfg80211_inform_bss(priv->wdev->wiphy, chan,
-                                       bssid, network_tsf, cap_info_bitmap,
-                                       beacon_period, ie_buf, ie_len, rssi,
-                                       GFP_KERNEL);
+                               bss = cfg80211_inform_bss(priv->wdev->wiphy,
+                                             chan, bssid, network_tsf,
+                                             cap_info_bitmap, beacon_period,
+                                             ie_buf, ie_len, rssi, GFP_KERNEL);
+                               *(u8 *)bss->priv = band;
+                               bss->free_priv = mwifiex_free_bss_priv;
 
                                if (priv->media_connected && !memcmp(bssid,
                                        priv->curr_bss_params.bss_descriptor
@@ -1762,7 +1771,7 @@ int mwifiex_ret_802_11_scan(struct mwifiex_private *priv,
                                        mwifiex_update_curr_bss_params(priv,
                                                        bssid, rssi, ie_buf,
                                                        ie_len, beacon_period,
-                                                       cap_info_bitmap);
+                                                       cap_info_bitmap, band);
                        }
                } else {
                        dev_dbg(adapter->dev, "missing BSS channel IE\n");
index eb569fa9adbaa5652da67ae297e9e6b8693c0684..a9dfeb1b4ace591c6f13545edc34e2c21f1f409f 100644 (file)
@@ -148,7 +148,7 @@ int mwifiex_request_set_multicast_list(struct mwifiex_private *priv,
 int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
                              u8 *bssid, s32 rssi, u8 *ie_buf,
                              size_t ie_len, u16 beacon_period,
-                             u16 cap_info_bitmap,
+                             u16 cap_info_bitmap, u8 band,
                              struct mwifiex_bssdescriptor *bss_desc)
 {
        int ret;
@@ -159,6 +159,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        bss_desc->beacon_buf_size = ie_len;
        bss_desc->beacon_period = beacon_period;
        bss_desc->cap_info_bitmap = cap_info_bitmap;
+       bss_desc->bss_band = band;
        if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_PRIVACY) {
                dev_dbg(priv->adapter->dev, "info: InterpretIE: AP WEP enabled\n");
                bss_desc->privacy = MWIFIEX_802_11_PRIV_FILTER_8021X_WEP;
@@ -203,6 +204,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                beacon_ie = kmemdup(bss->information_elements,
                                        bss->len_beacon_ies, GFP_KERNEL);
                if (!beacon_ie) {
+                       kfree(bss_desc);
                        dev_err(priv->adapter->dev, " failed to alloc beacon_ie\n");
                        return -ENOMEM;
                }
@@ -210,7 +212,8 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                ret = mwifiex_fill_new_bss_desc(priv, bss->bssid, bss->signal,
                                                beacon_ie, bss->len_beacon_ies,
                                                bss->beacon_interval,
-                                               bss->capability, bss_desc);
+                                               bss->capability,
+                                               *(u8 *)bss->priv, bss_desc);
                if (ret)
                        goto done;
        }
@@ -652,6 +655,7 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
        u16 curr_chan = 0;
        struct cfg80211_bss *bss = NULL;
        struct ieee80211_channel *chan;
+       enum ieee80211_band band;
 
        memset(&bss_info, 0, sizeof(bss_info));
 
@@ -688,9 +692,9 @@ mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, int channel)
                goto done;
        }
 
+       band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
        chan = __ieee80211_get_channel(priv->wdev->wiphy,
-                       ieee80211_channel_to_frequency(channel,
-                                               priv->curr_bss_params.band));
+                       ieee80211_channel_to_frequency(channel, band));
 
        /* Find the BSS we want using available scan results */
        bss = cfg80211_get_bss(priv->wdev->wiphy, chan, bss_info.bssid,
@@ -867,10 +871,10 @@ int mwifiex_drv_get_data_rate(struct mwifiex_private *priv,
        ret = mwifiex_rate_ioctl_cfg(priv, rate);
 
        if (!ret) {
-               if (rate && rate->is_rate_auto)
+               if (rate->is_rate_auto)
                        rate->rate = mwifiex_index_to_data_rate(priv->tx_rate,
                                                        priv->tx_htinfo);
-               else if (rate)
+               else
                        rate->rate = priv->data_rate;
        } else {
                ret = -1;
index daa32fc9398bb7712886b4707fbd6f1096162680..7e9272b8f01d8718bc047128f8f0a440563a74b8 100644 (file)
@@ -1239,7 +1239,7 @@ static void rt2400pci_fill_rxdone(struct queue_entry *entry,
         * call, we must decrease the higher 32bits with 1 to get
         * to correct value.
         */
-       tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw);
+       tsf = rt2x00dev->ops->hw->get_tsf(rt2x00dev->hw, NULL);
        rx_low = rt2x00_get_field32(word4, RXD_W4_RX_END_TIME);
        rx_high = upper_32_bits(tsf);
 
@@ -1673,7 +1673,8 @@ static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return 0;
 }
 
-static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2400pci_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index b46c3b8866fa99b29f582ba016a0cf6377065c51..dcc0e1fcca77726e002ed490dc41aa640655830b 100644 (file)
@@ -1966,7 +1966,8 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev)
 /*
  * IEEE80211 stack callback functions.
  */
-static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 31c98509f7e6c639565fb7d2c72492fb47d7ba7c..9688dd0a7ebd1b8d7415b47ca65e85ecd2c88410 100644 (file)
@@ -4466,7 +4466,7 @@ int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
 }
 EXPORT_SYMBOL_GPL(rt2800_conf_tx);
 
-u64 rt2800_get_tsf(struct ieee80211_hw *hw)
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 7a2511f6785c53d7423abd495c3c10b19c84fe97..6de128e9c612fe6bfc4497b30e4df4286c772d31 100644 (file)
@@ -199,7 +199,7 @@ void rt2800_get_tkip_seq(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32,
 int rt2800_set_rts_threshold(struct ieee80211_hw *hw, u32 value);
 int rt2800_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
                   const struct ieee80211_tx_queue_params *params);
-u64 rt2800_get_tsf(struct ieee80211_hw *hw);
+u64 rt2800_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int rt2800_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum ieee80211_ampdu_mlme_action action,
                        struct ieee80211_sta *sta, u16 tid, u16 *ssn,
index 058ef4b19d1db54896567da65901c2a4ad91ab27..6b6a8e2dcddc952aeb61843d60b73e8335369437 100644 (file)
@@ -2940,7 +2940,7 @@ static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 
-static u64 rt61pci_get_tsf(struct ieee80211_hw *hw)
+static u64 rt61pci_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 0baeb894f093e11e81f13f3d55c4c1624f546536..6f51e39f5595ae12a8ff2d3f56760a63e181cae2 100644 (file)
@@ -2279,7 +2279,7 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 
-static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
+static u64 rt73usb_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
        u64 tsf;
index 66b29dc07cc39ac3cfc2e614db78f0a79878b121..0082015ff664e9e5af45298dd804f46cf028d4a4 100644 (file)
@@ -669,7 +669,8 @@ static void rtl8180_stop(struct ieee80211_hw *dev)
                rtl8180_free_tx_ring(dev, i);
 }
 
-static u64 rtl8180_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8180_get_tsf(struct ieee80211_hw *dev,
+                          struct ieee80211_vif *vif)
 {
        struct rtl8180_priv *priv = dev->priv;
 
@@ -701,7 +702,7 @@ static void rtl8180_beacon_work(struct work_struct *work)
         * TODO: make hardware update beacon timestamp
         */
        mgmt = (struct ieee80211_mgmt *)skb->data;
-       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev));
+       mgmt->u.beacon.timestamp = cpu_to_le64(rtl8180_get_tsf(dev, vif));
 
        /* TODO: use actual beacon queue */
        skb_set_queue_mapping(skb, 0);
index 1e0be14d10d4687c6f1ad81b60c31d69c4f931a2..f5afa155ce9134984db0d521aa8c5e407e18eb4f 100644 (file)
@@ -1277,7 +1277,7 @@ static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue,
        return 0;
 }
 
-static u64 rtl8187_get_tsf(struct ieee80211_hw *dev)
+static u64 rtl8187_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
 {
        struct rtl8187_priv *priv = dev->priv;
 
index 04c4e9eb6ee6ed726357fb6bb3ac8da26c4aa7be..21e40f62a8d744a2bead4f190cb72c266028066e 100644 (file)
@@ -775,7 +775,7 @@ out:
        mutex_unlock(&rtlpriv->locks.conf_mutex);
 }
 
-static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
+static u64 rtl_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u64 tsf;
@@ -784,7 +784,8 @@ static u64 rtl_op_get_tsf(struct ieee80211_hw *hw)
        return tsf;
 }
 
-static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void rtl_op_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          u64 tsf)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
@@ -794,7 +795,8 @@ static void rtl_op_set_tsf(struct ieee80211_hw *hw, u64 tsf)
        rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_CORRECT_TSF, (u8 *) (&bibss));
 }
 
-static void rtl_op_reset_tsf(struct ieee80211_hw *hw)
+static void rtl_op_reset_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u8 tmp = 0;
index 4c34c4c1ae56b96f0a1c248cafe20e13027f0030..b7ecb9e44aa93de421dc4ba6e839c3c909a6908b 100644 (file)
@@ -133,6 +133,10 @@ int rtl92c_init_sw_vars(struct ieee80211_hw *hw)
        rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
        rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
        rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+       if (!rtlpriv->psc.inactiveps)
+               pr_info("rtl8192ce: Power Save off (module option)\n");
+       if (!rtlpriv->psc.fwctrl_lps)
+               pr_info("rtl8192ce: FW Power Save off (module option)\n");
        rtlpriv->psc.reg_fwctrl_lps = 3;
        rtlpriv->psc.reg_max_lps_awakeintvl = 5;
        /* for ASPM, you can close aspm through
@@ -356,10 +360,10 @@ module_param_named(swenc, rtl92ce_mod_params.sw_crypto, bool, 0444);
 module_param_named(ips, rtl92ce_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl92ce_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl92ce_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(fwlps, "using linked fw control power save "
-                "(default 1 is open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
 
 static struct pci_driver rtl92ce_driver = {
        .name = KBUILD_MODNAME,
index 81ae64234f80a102a317b78cb3e3a79a263d49a7..c8977a50ca36de7b2d52f3abe8f55d4abd004e07 100644 (file)
@@ -537,12 +537,6 @@ do {                                                       \
                memset(__pdesc, 0, _size);      \
 } while (0);
 
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
-       (_pdesc->rxmcs == DESC92_RATE1M ||              \
-        _pdesc->rxmcs == DESC92_RATE2M ||              \
-        _pdesc->rxmcs == DESC92_RATE5_5M ||            \
-        _pdesc->rxmcs == DESC92_RATE11M)
-
 struct rx_fwinfo_92c {
        u8 gain_trsw[4];
        u8 pwdb_all;
index 35529f701fc04b1f469cd911ccfd1aa4f5b8cb61..626d88e88e26b70c598d902c01747d8341a18965 100644 (file)
@@ -87,12 +87,6 @@ void rtl92c_set_data_filter(struct ieee80211_hw *hw, u16 filter);
 
 u32 rtl92c_get_txdma_status(struct ieee80211_hw *hw);
 
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
-       (GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE1M ||\
-        GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE2M ||\
-        GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
-        GET_RX_DESC_RX_MCS(_pdesc) == DESC92_RATE11M)
-
 struct rx_fwinfo_92c {
        u8 gain_trsw[4];
        u8 pwdb_all;
index f6419b7ed2f47908cd4dadaca7d35eeb236f2a5d..c681597c7f205084e52f1f2e307d935033542087 100644 (file)
@@ -150,6 +150,10 @@ static int rtl92d_init_sw_vars(struct ieee80211_hw *hw)
        rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
        rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
        rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+       if (!rtlpriv->psc.inactiveps)
+               pr_info("rtl8192ce: Power Save off (module option)\n");
+       if (!rtlpriv->psc.fwctrl_lps)
+               pr_info("rtl8192ce: FW Power Save off (module option)\n");
        rtlpriv->psc.reg_fwctrl_lps = 3;
        rtlpriv->psc.reg_max_lps_awakeintvl = 5;
        /* for ASPM, you can close aspm through
@@ -376,10 +380,10 @@ module_param_named(swenc, rtl92de_mod_params.sw_crypto, bool, 0444);
 module_param_named(ips, rtl92de_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl92de_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl92de_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1"
-                " is open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
 
 static struct pci_driver rtl92de_driver = {
        .name = KBUILD_MODNAME,
index 6c2236868c9aea260fd4099d007eeec48edf1731..4d55d0b6816dca21b1b4322b46be14f1e87cf7b7 100644 (file)
@@ -537,12 +537,6 @@ do {                                                       \
                memset((void *)__pdesc, 0, _size);      \
 } while (0);
 
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
-       (_pdesc->rxmcs == DESC92_RATE1M ||              \
-        _pdesc->rxmcs == DESC92_RATE2M ||              \
-        _pdesc->rxmcs == DESC92_RATE5_5M ||            \
-        _pdesc->rxmcs == DESC92_RATE11M)
-
 /* For 92D early mode */
 #define SET_EARLYMODE_PKTNUM(__paddr, __value)         \
        SET_BITS_OFFSET_LE(__paddr, 0, 3, __value)
index 68204ea175ddf594898cf1a8f60cd327025caa40..c6c044816d39e585a4cf9e0625675aaf1a1d7574 100644 (file)
@@ -459,7 +459,7 @@ do {                                                                \
 #define SET_RX_STATUS__DESC_BUFF_ADDR(__pdesc, __val)  \
        SET_BITS_OFFSET_LE(__pdesc + 24, 0, 32, __val)
 
-#define RX_HAL_IS_CCK_RATE(_pdesc)\
+#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\
        (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M ||  \
         GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M ||  \
         GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
index 0055a1c845a2f8c213e8c8c4f945836e737cf5ad..24bd331a54842bfbcaacdd501ccf8bd14547e044 100644 (file)
@@ -164,6 +164,10 @@ static int rtl92s_init_sw_vars(struct ieee80211_hw *hw)
        rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
        rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
        rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+       if (!rtlpriv->psc.inactiveps)
+               pr_info("rtl8192ce: Power Save off (module option)\n");
+       if (!rtlpriv->psc.fwctrl_lps)
+               pr_info("rtl8192ce: FW Power Save off (module option)\n");
        rtlpriv->psc.reg_fwctrl_lps = 3;
        rtlpriv->psc.reg_max_lps_awakeintvl = 5;
        /* for ASPM, you can close aspm through
@@ -378,6 +382,7 @@ MODULE_DEVICE_TABLE(pci, rtl92se_pci_ids);
 
 MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
 MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.Finger@lwfinger.net>");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Realtek 8192S/8191S 802.11n PCI wireless");
 MODULE_FIRMWARE("rtlwifi/rtl8192sefw.bin");
@@ -386,11 +391,10 @@ module_param_named(swenc, rtl92se_mod_params.sw_crypto, bool, 0444);
 module_param_named(ips, rtl92se_mod_params.inactiveps, bool, 0444);
 module_param_named(swlps, rtl92se_mod_params.swctrl_lps, bool, 0444);
 module_param_named(fwlps, rtl92se_mod_params.fwctrl_lps, bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(swlps, "using linked sw control power save (default 1 is "
-                "open)\n");
-
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
 
 static struct pci_driver rtl92se_driver = {
        .name = KBUILD_MODNAME,
index d9aeae7f8bdbed1e4ec68f7ab8138a2969c22802..ba137da082b5a223e86e073f93e8cc1cff319243 100644 (file)
@@ -126,7 +126,7 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
        bool in_powersavemode = false;
        bool is_cck_rate;
 
-       is_cck_rate = RX_HAL_IS_CCK_RATE(pdesc);
+       is_cck_rate = SE_RX_HAL_IS_CCK_RATE(pdesc);
        pstats->packet_matchbssid = packet_match_bssid;
        pstats->packet_toself = packet_toself;
        pstats->is_cck = is_cck_rate;
index 8b1cef0ffde6627e9d882bf84ee78dba62ddbc89..4bf3cf457ef0dedd02d897be03b47990f9619853 100644 (file)
@@ -863,6 +863,7 @@ static void _rtl_usb_tx_preprocess(struct ieee80211_hw *hw, struct sk_buff *skb,
        u8 tid = 0;
        u16 seq_number = 0;
 
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        if (ieee80211_is_auth(fc)) {
                RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
                rtl_ips_nic_on(hw);
index 8a9091968f316f449a5c7380e9ea7a738db3c76f..615f6b4463e6977b50e345f43778b4737c8a0bfe 100644 (file)
@@ -165,6 +165,12 @@ enum hardware_type {
 #define IS_HARDWARE_TYPE_8723U(rtlhal)                 \
        (rtlhal->hw_type == HARDWARE_TYPE_RTL8723U)
 
+#define RX_HAL_IS_CCK_RATE(_pdesc)\
+       (_pdesc->rxmcs == DESC92_RATE1M ||              \
+        _pdesc->rxmcs == DESC92_RATE2M ||              \
+        _pdesc->rxmcs == DESC92_RATE5_5M ||            \
+        _pdesc->rxmcs == DESC92_RATE11M)
+
 enum scan_operation_backup_opt {
        SCAN_OPT_BACKUP = 0,
        SCAN_OPT_RESTORE,
index 07bcb1548d8b2e51ec758372d7ec0a5b52fcbc2d..3fe388b87c2e339204833eff359eb22b6a0ccba7 100644 (file)
@@ -19,16 +19,6 @@ config WL12XX
          If you choose to build a module, it will be called wl12xx. Say N if
          unsure.
 
-config WL12XX_HT
-        bool "TI wl12xx 802.11 HT support (EXPERIMENTAL)"
-        depends on WL12XX && EXPERIMENTAL
-        default n
-        ---help---
-          This will enable 802.11 HT support in the wl12xx module.
-
-         That configuration is temporary due to the code incomplete and
-         still in testing process.
-
 config WL12XX_SPI
        tristate "TI wl12xx SPI support"
        depends on WL12XX && SPI_MASTER
index 521c0414e52e00f2e5bac3e068d47c526f7a82e7..621b3483ca2c578037c8620a3b0dc6cc562be8d6 100644 (file)
@@ -1,16 +1,16 @@
 wl12xx-objs            = main.o cmd.o io.o event.o tx.o rx.o ps.o acx.o \
                          boot.o init.o debugfs.o scan.o
 
-wl12xx_spi-objs        = spi.o
+wl12xx_spi-objs        = spi.o
 wl12xx_sdio-objs       = sdio.o
-wl12xx_sdio_test-objs = sdio_test.o
+wl12xx_sdio_test-objs  = sdio_test.o
 
 wl12xx-$(CONFIG_NL80211_TESTMODE)      += testmode.o
 obj-$(CONFIG_WL12XX)                   += wl12xx.o
 obj-$(CONFIG_WL12XX_SPI)               += wl12xx_spi.o
 obj-$(CONFIG_WL12XX_SDIO)              += wl12xx_sdio.o
 
-obj-$(CONFIG_WL12XX_SDIO_TEST) += wl12xx_sdio_test.o
+obj-$(CONFIG_WL12XX_SDIO_TEST)         += wl12xx_sdio_test.o
 
 # small builtin driver bit
 obj-$(CONFIG_WL12XX_PLATFORM_DATA)     += wl12xx_platform_data.o
index f2838ae07da54d8b74b9154e4f491483816b91e1..399849eeb247cd3014d3827654b14e28dbeaa184 100644 (file)
@@ -1687,3 +1687,43 @@ out:
        kfree(acx);
        return ret;
 }
+
+int wl12xx_acx_config_hangover(struct wl1271 *wl)
+{
+       struct wl12xx_acx_config_hangover *acx;
+       struct conf_hangover_settings *conf = &wl->conf.hangover;
+       int ret;
+
+       wl1271_debug(DEBUG_ACX, "acx config hangover");
+
+       acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+       if (!acx) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       acx->recover_time = cpu_to_le32(conf->recover_time);
+       acx->hangover_period = conf->hangover_period;
+       acx->dynamic_mode = conf->dynamic_mode;
+       acx->early_termination_mode = conf->early_termination_mode;
+       acx->max_period = conf->max_period;
+       acx->min_period = conf->min_period;
+       acx->increase_delta = conf->increase_delta;
+       acx->decrease_delta = conf->decrease_delta;
+       acx->quiet_time = conf->quiet_time;
+       acx->increase_time = conf->increase_time;
+       acx->window_size = acx->window_size;
+
+       ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx,
+                                  sizeof(*acx));
+
+       if (ret < 0) {
+               wl1271_warning("acx config hangover failed: %d", ret);
+               goto out;
+       }
+
+out:
+       kfree(acx);
+       return ret;
+
+}
index 758c596f62f6042477397b18468151983e3b2a83..556ee4e282d566317a1d9c9244469844d4bd11fe 100644 (file)
@@ -1144,6 +1144,23 @@ struct wl12xx_acx_set_rate_mgmt_params {
        u8 padding2[2];
 } __packed;
 
+struct wl12xx_acx_config_hangover {
+       struct acx_header header;
+
+       __le32 recover_time;
+       u8 hangover_period;
+       u8 dynamic_mode;
+       u8 early_termination_mode;
+       u8 max_period;
+       u8 min_period;
+       u8 increase_delta;
+       u8 decrease_delta;
+       u8 quiet_time;
+       u8 increase_time;
+       u8 window_size;
+       u8 padding[2];
+} __packed;
+
 enum {
        ACX_WAKE_UP_CONDITIONS      = 0x0002,
        ACX_MEM_CFG                 = 0x0003,
@@ -1281,5 +1298,6 @@ int wl1271_acx_config_ps(struct wl1271 *wl);
 int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
 int wl1271_acx_fm_coex(struct wl1271 *wl);
 int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
+int wl12xx_acx_config_hangover(struct wl1271 *wl);
 
 #endif /* __WL1271_ACX_H__ */
index 817bc183bc8372f0a7fb22a286e977229862f2d6..287fe95ecb40092e826b821056ee05e093d3f3a0 100644 (file)
@@ -661,12 +661,9 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
 
        wl1271_debug(DEBUG_CMD, "cmd role start ap %d", wl->role_id);
 
-       /*
-        * We currently do not support hidden SSID. The real SSID
-        * should be fetched from mac80211 first.
-        */
-       if (wl->ssid_len == 0) {
-               wl1271_warning("Hidden SSID currently not supported for AP");
+       /* trying to use hidden SSID with an old hostapd version */
+       if (wl->ssid_len == 0 && !bss_conf->hidden_ssid) {
+               wl1271_error("got a null SSID from beacon/bss");
                ret = -EINVAL;
                goto out;
        }
@@ -695,9 +692,18 @@ int wl12xx_cmd_role_start_ap(struct wl1271 *wl)
        cmd->ap.dtim_interval = bss_conf->dtim_period;
        cmd->ap.beacon_expiry = WL1271_AP_DEF_BEACON_EXP;
        cmd->channel = wl->channel;
-       cmd->ap.ssid_len = wl->ssid_len;
-       cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
-       memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+
+       if (!bss_conf->hidden_ssid) {
+               /* take the SSID from the beacon for backward compatibility */
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_PUBLIC;
+               cmd->ap.ssid_len = wl->ssid_len;
+               memcpy(cmd->ap.ssid, wl->ssid, wl->ssid_len);
+       } else {
+               cmd->ap.ssid_type = WL12XX_SSID_TYPE_HIDDEN;
+               cmd->ap.ssid_len = bss_conf->ssid_len;
+               memcpy(cmd->ap.ssid, bss_conf->ssid, bss_conf->ssid_len);
+       }
+
        cmd->ap.local_rates = cpu_to_le32(0xffffffff);
 
        switch (wl->band) {
@@ -895,7 +901,7 @@ int wl1271_cmd_configure(struct wl1271 *wl, u16 id, void *buf, size_t len)
        struct acx_header *acx = buf;
        int ret;
 
-       wl1271_debug(DEBUG_CMD, "cmd configure");
+       wl1271_debug(DEBUG_CMD, "cmd configure (%d)", id);
 
        acx->id = cpu_to_le16(id);
 
@@ -1106,6 +1112,7 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
 {
        struct sk_buff *skb;
        int ret;
+       u32 rate;
 
        skb = ieee80211_probereq_get(wl->hw, wl->vif, ssid, ssid_len,
                                     ie, ie_len);
@@ -1116,14 +1123,13 @@ int wl1271_cmd_build_probe_req(struct wl1271 *wl,
 
        wl1271_dump(DEBUG_SCAN, "PROBE REQ: ", skb->data, skb->len);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
        if (band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate);
+                                             skb->data, skb->len, 0, rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate_5);
+                                             skb->data, skb->len, 0, rate);
 
 out:
        dev_kfree_skb(skb);
@@ -1134,6 +1140,7 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
                                              struct sk_buff *skb)
 {
        int ret;
+       u32 rate;
 
        if (!skb)
                skb = ieee80211_ap_probereq_get(wl->hw, wl->vif);
@@ -1142,14 +1149,13 @@ struct sk_buff *wl1271_cmd_build_ap_probe_req(struct wl1271 *wl,
 
        wl1271_dump(DEBUG_SCAN, "AP PROBE REQ: ", skb->data, skb->len);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[wl->band]);
        if (wl->band == IEEE80211_BAND_2GHZ)
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_2_4,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate);
+                                             skb->data, skb->len, 0, rate);
        else
                ret = wl1271_cmd_template_set(wl, CMD_TEMPL_CFG_PROBE_REQ_5,
-                                             skb->data, skb->len, 0,
-                                             wl->conf.tx.basic_rate_5);
+                                             skb->data, skb->len, 0, rate);
 
        if (ret < 0)
                wl1271_error("Unable to set ap probe request template.");
@@ -1413,7 +1419,7 @@ out:
 int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
 {
        struct wl12xx_cmd_add_peer *cmd;
-       int ret;
+       int i, ret;
        u32 sta_rates;
 
        wl1271_debug(DEBUG_CMD, "cmd add peer %d", (int)hlid);
@@ -1424,23 +1430,29 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct ieee80211_sta *sta, u8 hlid)
                goto out;
        }
 
-       /* currently we don't support UAPSD */
-       cmd->sp_len = 0;
-
        memcpy(cmd->addr, sta->addr, ETH_ALEN);
        cmd->bss_index = WL1271_AP_BSS_INDEX;
        cmd->aid = sta->aid;
        cmd->hlid = hlid;
+       cmd->sp_len = sta->max_sp;
        cmd->wmm = sta->wme ? 1 : 0;
 
+       for (i = 0; i < NUM_ACCESS_CATEGORIES_COPY; i++)
+               if (sta->wme && (sta->uapsd_queues & BIT(i)))
+                       cmd->psd_type[i] = WL1271_PSD_UPSD_TRIGGER;
+               else
+                       cmd->psd_type[i] = WL1271_PSD_LEGACY;
+
        sta_rates = sta->supp_rates[wl->band];
        if (sta->ht_cap.ht_supported)
                sta_rates |= sta->ht_cap.mcs.rx_mask[0] << HW_HT_RATES_OFFSET;
 
        cmd->supported_rates =
-               cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates));
+               cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates,
+                                                       wl->band));
 
-       wl1271_debug(DEBUG_CMD, "new peer rates: 0x%x", cmd->supported_rates);
+       wl1271_debug(DEBUG_CMD, "new peer rates=0x%x queues=0x%x",
+                    cmd->supported_rates, sta->uapsd_queues);
 
        ret = wl1271_cmd_send(wl, CMD_ADD_PEER, cmd, sizeof(*cmd), 0);
        if (ret < 0) {
index 22c2f373dd04b51d9593df45f0769767c05a4277..8e4d11ec0c55fd7cda5b90a1751a48031d7abb41 100644 (file)
@@ -591,6 +591,13 @@ enum wl12xx_ssid_type {
        WL12XX_SSID_TYPE_ANY = 2,
 };
 
+enum wl1271_psd_type {
+       WL1271_PSD_LEGACY = 0,
+       WL1271_PSD_UPSD_TRIGGER = 1,
+       WL1271_PSD_LEGACY_PSPOLL = 2,
+       WL1271_PSD_SAPSD = 3
+};
+
 struct wl12xx_cmd_add_peer {
        struct wl1271_cmd_header header;
 
index 82f205c4334266e1eb83743c80570f18381796e9..6a6805c3cc747e732bccec4cab0c69a659d49cc8 100644 (file)
@@ -454,12 +454,10 @@ struct conf_rx_settings {
 #define CONF_TX_AP_DEFAULT_MGMT_RATES  (CONF_HW_BIT_RATE_1MBPS | \
        CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS)
 
-/*
- * Default rates for working as IBSS. use 11b rates
- */
+/* default rates for working as IBSS (11b and OFDM) */
 #define CONF_TX_IBSS_DEFAULT_RATES  (CONF_HW_BIT_RATE_1MBPS |       \
                CONF_HW_BIT_RATE_2MBPS | CONF_HW_BIT_RATE_5_5MBPS | \
-               CONF_HW_BIT_RATE_11MBPS);
+               CONF_HW_BIT_RATE_11MBPS | CONF_TX_OFDM_RATES);
 
 struct conf_tx_rate_class {
 
@@ -915,14 +913,6 @@ struct conf_conn_settings {
         */
        u8 psm_entry_nullfunc_retries;
 
-       /*
-        * Specifies the time to linger in active mode after successfully
-        * transmitting the PSM entry null-func frame.
-        *
-        * Range 0 - 255 TU's
-        */
-       u8 psm_entry_hangover_period;
-
        /*
         *
         * Specifies the interval of the connection keep-alive null-func
@@ -1236,6 +1226,20 @@ struct conf_rate_policy_settings {
        u8 rate_retry_policy[ACX_RATE_MGMT_NUM_OF_RATES];
 };
 
+struct conf_hangover_settings {
+       u32 recover_time;
+       u8 hangover_period;
+       u8 dynamic_mode;
+       u8 early_termination_mode;
+       u8 max_period;
+       u8 min_period;
+       u8 increase_delta;
+       u8 decrease_delta;
+       u8 quiet_time;
+       u8 increase_time;
+       u8 window_size;
+};
+
 struct conf_drv_settings {
        struct conf_sg_settings sg;
        struct conf_rx_settings rx;
@@ -1254,6 +1258,7 @@ struct conf_drv_settings {
        struct conf_rx_streaming_settings rx_streaming;
        struct conf_fwlog fwlog;
        struct conf_rate_policy_settings rate;
+       struct conf_hangover_settings hangover;
        u8 hci_io_ds;
 };
 
index d59354f537021f7b6ebbfeb5c4a77bf25c762a5e..3999fd528302cfbadd26a7f9fe8862caaf175656 100644 (file)
@@ -265,18 +265,10 @@ static ssize_t gpio_power_write(struct file *file,
                           size_t count, loff_t *ppos)
 {
        struct wl1271 *wl = file->private_data;
-       char buf[10];
-       size_t len;
        unsigned long value;
        int ret;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len)) {
-               return -EFAULT;
-       }
-       buf[len] = '\0';
-
-       ret = kstrtoul(buf, 0, &value);
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
        if (ret < 0) {
                wl1271_warning("illegal value in gpio_power");
                return -EINVAL;
@@ -427,17 +419,10 @@ static ssize_t dtim_interval_write(struct file *file,
                                   size_t count, loff_t *ppos)
 {
        struct wl1271 *wl = file->private_data;
-       char buf[10];
-       size_t len;
        unsigned long value;
        int ret;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       ret = kstrtoul(buf, 0, &value);
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
        if (ret < 0) {
                wl1271_warning("illegal value for dtim_interval");
                return -EINVAL;
@@ -492,17 +477,10 @@ static ssize_t beacon_interval_write(struct file *file,
                                     size_t count, loff_t *ppos)
 {
        struct wl1271 *wl = file->private_data;
-       char buf[10];
-       size_t len;
        unsigned long value;
        int ret;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       ret = kstrtoul(buf, 0, &value);
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
        if (ret < 0) {
                wl1271_warning("illegal value for beacon_interval");
                return -EINVAL;
@@ -542,17 +520,10 @@ static ssize_t rx_streaming_interval_write(struct file *file,
                           size_t count, loff_t *ppos)
 {
        struct wl1271 *wl = file->private_data;
-       char buf[10];
-       size_t len;
        unsigned long value;
        int ret;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       ret = kstrtoul(buf, 0, &value);
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
        if (ret < 0) {
                wl1271_warning("illegal value in rx_streaming_interval!");
                return -EINVAL;
@@ -601,17 +572,10 @@ static ssize_t rx_streaming_always_write(struct file *file,
                           size_t count, loff_t *ppos)
 {
        struct wl1271 *wl = file->private_data;
-       char buf[10];
-       size_t len;
        unsigned long value;
        int ret;
 
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       ret = kstrtoul(buf, 0, &value);
+       ret = kstrtoul_from_user(user_buf, count, 10, &value);
        if (ret < 0) {
                wl1271_warning("illegal value in rx_streaming_write!");
                return -EINVAL;
@@ -655,6 +619,47 @@ static const struct file_operations rx_streaming_always_ops = {
        .llseek = default_llseek,
 };
 
+static ssize_t beacon_filtering_write(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct wl1271 *wl = file->private_data;
+       char buf[10];
+       size_t len;
+       unsigned long value;
+       int ret;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+       buf[len] = '\0';
+
+       ret = kstrtoul(buf, 0, &value);
+       if (ret < 0) {
+               wl1271_warning("illegal value for beacon_filtering!");
+               return -EINVAL;
+       }
+
+       mutex_lock(&wl->mutex);
+
+       ret = wl1271_ps_elp_wakeup(wl);
+       if (ret < 0)
+               goto out;
+
+       ret = wl1271_acx_beacon_filter_opt(wl, !!value);
+
+       wl1271_ps_elp_sleep(wl);
+out:
+       mutex_unlock(&wl->mutex);
+       return count;
+}
+
+static const struct file_operations beacon_filtering_ops = {
+       .write = beacon_filtering_write,
+       .open = wl1271_open_file_generic,
+       .llseek = default_llseek,
+};
+
 static int wl1271_debugfs_add_files(struct wl1271 *wl,
                                     struct dentry *rootdir)
 {
@@ -767,6 +772,7 @@ static int wl1271_debugfs_add_files(struct wl1271 *wl,
        DEBUGFS_ADD(driver_state, rootdir);
        DEBUGFS_ADD(dtim_interval, rootdir);
        DEBUGFS_ADD(beacon_interval, rootdir);
+       DEBUGFS_ADD(beacon_filtering, rootdir);
 
        streaming = debugfs_create_dir("rx_streaming", rootdir);
        if (!streaming || IS_ERR(streaming))
index 0bd7b020a42025f44e306d39de7819153a21fb41..e66db69f8d17e38dd8abd76668fa4aaa06109225 100644 (file)
@@ -171,19 +171,26 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
        wl->last_rssi_event = event;
 }
 
-static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
+static void wl1271_stop_ba_event(struct wl1271 *wl)
 {
-       /* Convert the value to bool */
-       wl->ba_allowed = !!ba_allowed;
-
-       /*
-        * Return in case:
-        * there are not BA open or the event indication is to allowed BA
-        */
-       if ((!wl->ba_rx_bitmap) || (wl->ba_allowed))
-               return;
+       if (wl->bss_type != BSS_TYPE_AP_BSS) {
+               if (!wl->ba_rx_bitmap)
+                       return;
+               ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap,
+                                            wl->bssid);
+       } else {
+               int i;
+               struct wl1271_link *lnk;
+               for (i = WL1271_AP_STA_HLID_START; i < AP_MAX_LINKS; i++) {
+                       lnk = &wl->links[i];
+                       if (!wl1271_is_active_sta(wl, i) || !lnk->ba_bitmap)
+                               continue;
 
-       ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
+                       ieee80211_stop_rx_ba_session(wl->vif,
+                                                    lnk->ba_bitmap,
+                                                    lnk->addr);
+               }
+       }
 }
 
 static void wl12xx_event_soft_gemini_sense(struct wl1271 *wl,
@@ -283,12 +290,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        wl1271_event_rssi_trigger(wl, mbox);
        }
 
-       if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
+       if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID)) {
                wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
                             "ba_allowed = 0x%x", mbox->rx_ba_allowed);
 
-               if (wl->vif)
-                       wl1271_stop_ba_event(wl, mbox->rx_ba_allowed);
+               wl->ba_allowed = !!mbox->rx_ba_allowed;
+
+               if (wl->vif && !wl->ba_allowed)
+                       wl1271_stop_ba_event(wl);
        }
 
        if ((vector & DUMMY_PACKET_EVENT_ID)) {
index b13bebea95e00c0cbe9070ad19847b92ca94a995..04db64c94e9a642fa21885ccdf276d8c3fcc9545 100644 (file)
@@ -103,6 +103,7 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
 {
        struct wl12xx_disconn_template *tmpl;
        int ret;
+       u32 rate;
 
        tmpl = kzalloc(sizeof(*tmpl), GFP_KERNEL);
        if (!tmpl) {
@@ -113,9 +114,9 @@ static int wl1271_ap_init_deauth_template(struct wl1271 *wl)
        tmpl->header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                             IEEE80211_STYPE_DEAUTH);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_DEAUTH_AP,
-                                     tmpl, sizeof(*tmpl), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     tmpl, sizeof(*tmpl), 0, rate);
 
 out:
        kfree(tmpl);
@@ -126,6 +127,7 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
 {
        struct ieee80211_hdr_3addr *nullfunc;
        int ret;
+       u32 rate;
 
        nullfunc = kzalloc(sizeof(*nullfunc), GFP_KERNEL);
        if (!nullfunc) {
@@ -142,9 +144,9 @@ static int wl1271_ap_init_null_template(struct wl1271 *wl)
        memcpy(nullfunc->addr2, wl->mac_addr, ETH_ALEN);
        memcpy(nullfunc->addr3, wl->mac_addr, ETH_ALEN);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_NULL_DATA, nullfunc,
-                                     sizeof(*nullfunc), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     sizeof(*nullfunc), 0, rate);
 
 out:
        kfree(nullfunc);
@@ -155,6 +157,7 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
 {
        struct ieee80211_qos_hdr *qosnull;
        int ret;
+       u32 rate;
 
        qosnull = kzalloc(sizeof(*qosnull), GFP_KERNEL);
        if (!qosnull) {
@@ -171,9 +174,9 @@ static int wl1271_ap_init_qos_null_template(struct wl1271 *wl)
        memcpy(qosnull->addr2, wl->mac_addr, ETH_ALEN);
        memcpy(qosnull->addr3, wl->mac_addr, ETH_ALEN);
 
+       rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        ret = wl1271_cmd_template_set(wl, CMD_TEMPL_QOS_NULL_DATA, qosnull,
-                                     sizeof(*qosnull), 0,
-                                     wl1271_tx_min_rate_get(wl));
+                                     sizeof(*qosnull), 0, rate);
 
 out:
        kfree(qosnull);
@@ -498,7 +501,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl)
                return ret;
 
        /* use the min basic rate for AP broadcast/multicast */
-       rc.enabled_rates = wl1271_tx_min_rate_get(wl);
+       rc.enabled_rates = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
        rc.short_retry_limit = 10;
        rc.long_retry_limit = 10;
        rc.aflags = 0;
@@ -707,6 +710,11 @@ int wl1271_hw_init(struct wl1271 *wl)
        if (ret < 0)
                goto out_free_memmap;
 
+       /* configure hangover */
+       ret = wl12xx_acx_config_hangover(wl);
+       if (ret < 0)
+               goto out_free_memmap;
+
        return 0;
 
  out_free_memmap:
index bde84027ab7f8d3183712194d105af59f5f26e36..7d409b0f335753406526e7d1e89a0e234b9fcc55 100644 (file)
@@ -239,7 +239,6 @@ static struct conf_drv_settings default_conf = {
                .psm_entry_retries           = 8,
                .psm_exit_retries            = 16,
                .psm_entry_nullfunc_retries  = 3,
-               .psm_entry_hangover_period   = 1,
                .keep_alive_interval         = 55000,
                .max_listen_interval         = 20,
        },
@@ -267,8 +266,8 @@ static struct conf_drv_settings default_conf = {
        },
        .sched_scan = {
                /* sched_scan requires dwell times in TU instead of TU/1000 */
-               .min_dwell_time_active = 8,
-               .max_dwell_time_active = 30,
+               .min_dwell_time_active = 30,
+               .max_dwell_time_active = 60,
                .dwell_time_passive    = 100,
                .dwell_time_dfs        = 150,
                .num_probe_reqs        = 2,
@@ -359,9 +358,23 @@ static struct conf_drv_settings default_conf = {
                        0x00, 0x00, 0x00,
                },
        },
+       .hangover = {
+               .recover_time               = 0,
+               .hangover_period            = 20,
+               .dynamic_mode               = 1,
+               .early_termination_mode     = 1,
+               .max_period                 = 20,
+               .min_period                 = 1,
+               .increase_delta             = 1,
+               .decrease_delta             = 2,
+               .quiet_time                 = 4,
+               .increase_time              = 1,
+               .window_size                = 16,
+       },
 };
 
 static char *fwlog_param;
+static bool bug_on_recovery;
 
 static void __wl1271_op_remove_interface(struct wl1271 *wl,
                                         bool reset_tx_queues);
@@ -757,13 +770,14 @@ static int wl1271_plt_init(struct wl1271 *wl)
 
 static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
 {
-       bool fw_ps;
+       bool fw_ps, single_sta;
 
        /* only regulate station links */
        if (hlid < WL1271_AP_STA_HLID_START)
                return;
 
        fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+       single_sta = (wl->active_sta_count == 1);
 
        /*
         * Wake up from high level PS if the STA is asleep with too little
@@ -772,8 +786,12 @@ static void wl12xx_irq_ps_regulate_link(struct wl1271 *wl, u8 hlid, u8 tx_pkts)
        if (!fw_ps || tx_pkts < WL1271_PS_STA_MAX_PACKETS)
                wl1271_ps_link_end(wl, hlid);
 
-       /* Start high-level PS if the STA is asleep with enough blocks in FW */
-       else if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+       /*
+        * Start high-level PS if the STA is asleep with enough blocks in FW.
+        * Make an exception if this is the only connected station. In this
+        * case FW-memory congestion is not a problem.
+        */
+       else if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
                wl1271_ps_link_start(wl, hlid, true);
 }
 
@@ -1213,6 +1231,8 @@ static void wl1271_recovery_work(struct work_struct *work)
        wl1271_info("Hardware recovery in progress. FW ver: %s pc: 0x%x",
                    wl->chip.fw_ver_str, wl1271_read32(wl, SCR_PAD4));
 
+       BUG_ON(bug_on_recovery);
+
        /*
         * Advance security sequence number to overcome potential progress
         * in the firmware during recovery. This doens't hurt if the network is
@@ -1222,9 +1242,6 @@ static void wl1271_recovery_work(struct work_struct *work)
            test_bit(WL1271_FLAG_AP_STARTED, &wl->flags))
                wl->tx_security_seq += WL1271_TX_SQN_POST_RECOVERY_PADDING;
 
-       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
-               ieee80211_connection_loss(wl->vif);
-
        /* Prevent spurious TX during FW restart */
        ieee80211_stop_queues(wl->hw);
 
@@ -1528,7 +1545,13 @@ out:
 int wl1271_tx_dummy_packet(struct wl1271 *wl)
 {
        unsigned long flags;
-       int q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
+       int q;
+
+       /* no need to queue a new dummy packet if one is already pending */
+       if (test_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags))
+               return 0;
+
+       q = wl1271_tx_get_queue(skb_get_queue_mapping(wl->dummy_packet));
 
        spin_lock_irqsave(&wl->wl_lock, flags);
        set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
@@ -1802,10 +1825,16 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl)
 {
        switch (wl->bss_type) {
        case BSS_TYPE_AP_BSS:
-               return WL1271_ROLE_AP;
+               if (wl->p2p)
+                       return WL1271_ROLE_P2P_GO;
+               else
+                       return WL1271_ROLE_AP;
 
        case BSS_TYPE_STA_BSS:
-               return WL1271_ROLE_STA;
+               if (wl->p2p)
+                       return WL1271_ROLE_P2P_CL;
+               else
+                       return WL1271_ROLE_STA;
 
        case BSS_TYPE_IBSS:
                return WL1271_ROLE_IBSS;
@@ -1827,7 +1856,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
        bool booted = false;
 
        wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
-                    vif->type, vif->addr);
+                    ieee80211_vif_type_p2p(vif), vif->addr);
 
        mutex_lock(&wl->mutex);
        if (wl->vif) {
@@ -1847,7 +1876,10 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                goto out;
        }
 
-       switch (vif->type) {
+       switch (ieee80211_vif_type_p2p(vif)) {
+       case NL80211_IFTYPE_P2P_CLIENT:
+               wl->p2p = 1;
+               /* fall-through */
        case NL80211_IFTYPE_STATION:
                wl->bss_type = BSS_TYPE_STA_BSS;
                wl->set_bss_type = BSS_TYPE_STA_BSS;
@@ -1856,6 +1888,9 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
                wl->bss_type = BSS_TYPE_IBSS;
                wl->set_bss_type = BSS_TYPE_STA_BSS;
                break;
+       case NL80211_IFTYPE_P2P_GO:
+               wl->p2p = 1;
+               /* fall-through */
        case NL80211_IFTYPE_AP:
                wl->bss_type = BSS_TYPE_AP_BSS;
                break;
@@ -2051,6 +2086,7 @@ deinit:
        wl->ssid_len = 0;
        wl->bss_type = MAX_BSS_TYPE;
        wl->set_bss_type = MAX_BSS_TYPE;
+       wl->p2p = 0;
        wl->band = IEEE80211_BAND_2GHZ;
 
        wl->rx_counter = 0;
@@ -2063,6 +2099,8 @@ deinit:
        wl->time_offset = 0;
        wl->session_counter = 0;
        wl->rate_set = CONF_TX_RATE_MASK_BASIC;
+       wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+       wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
        wl->vif = NULL;
        wl->tx_spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT;
        wl1271_free_ap_keys(wl);
@@ -2075,6 +2113,7 @@ deinit:
        memset(wl->roles_map, 0, sizeof(wl->roles_map));
        memset(wl->links_map, 0, sizeof(wl->links_map));
        memset(wl->roc_map, 0, sizeof(wl->roc_map));
+       wl->active_sta_count = 0;
 
        /* The system link is always allocated */
        __set_bit(WL12XX_SYSTEM_HLID, wl->links_map);
@@ -2200,14 +2239,8 @@ out:
 
 static void wl1271_set_band_rate(struct wl1271 *wl)
 {
-       if (wl->band == IEEE80211_BAND_2GHZ) {
-               wl->basic_rate_set = wl->conf.tx.basic_rate;
-               wl->rate_set = wl->conf.tx.basic_rate;
-       } else {
-               wl->basic_rate_set = wl->conf.tx.basic_rate_5;
-               wl->rate_set = wl->conf.tx.basic_rate_5;
-       }
-
+       wl->basic_rate_set = wl->bitrate_masks[wl->band];
+       wl->rate_set = wl->basic_rate_set;
 }
 
 static bool wl12xx_is_roc(struct wl1271 *wl)
@@ -2236,7 +2269,7 @@ static int wl1271_sta_handle_idle(struct wl1271 *wl, bool idle)
                        if (ret < 0)
                                goto out;
                }
-               wl->rate_set = wl1271_tx_min_rate_get(wl);
+               wl->rate_set = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                ret = wl1271_acx_sta_rate_policies(wl);
                if (ret < 0)
                        goto out;
@@ -2318,6 +2351,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL &&
            ((wl->band != conf->channel->band) ||
             (wl->channel != channel))) {
+               /* send all pending packets */
+               wl1271_tx_work_locked(wl);
                wl->band = conf->channel->band;
                wl->channel = channel;
 
@@ -2331,7 +2366,8 @@ static int wl1271_op_config(struct ieee80211_hw *hw, u32 changed)
                        if (!test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags))
                                wl1271_set_band_rate(wl);
 
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                wl1271_warning("rate policy for channel "
@@ -3032,6 +3068,93 @@ static int wl1271_ssid_set(struct wl1271 *wl, struct sk_buff *skb,
        return 0;
 }
 
+static void wl12xx_remove_ie(struct sk_buff *skb, u8 eid, int ieoffset)
+{
+       int len;
+       const u8 *next, *end = skb->data + skb->len;
+       u8 *ie = (u8 *)cfg80211_find_ie(eid, skb->data + ieoffset,
+                                       skb->len - ieoffset);
+       if (!ie)
+               return;
+       len = ie[1] + 2;
+       next = ie + len;
+       memmove(ie, next, end - next);
+       skb_trim(skb, skb->len - len);
+}
+
+static void wl12xx_remove_vendor_ie(struct sk_buff *skb,
+                                           unsigned int oui, u8 oui_type,
+                                           int ieoffset)
+{
+       int len;
+       const u8 *next, *end = skb->data + skb->len;
+       u8 *ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
+                                              skb->data + ieoffset,
+                                              skb->len - ieoffset);
+       if (!ie)
+               return;
+       len = ie[1] + 2;
+       next = ie + len;
+       memmove(ie, next, end - next);
+       skb_trim(skb, skb->len - len);
+}
+
+static int wl1271_ap_set_probe_resp_tmpl(struct wl1271 *wl,
+                                        u8 *probe_rsp_data,
+                                        size_t probe_rsp_len,
+                                        u32 rates)
+{
+       struct ieee80211_bss_conf *bss_conf = &wl->vif->bss_conf;
+       u8 probe_rsp_templ[WL1271_CMD_TEMPL_MAX_SIZE];
+       int ssid_ie_offset, ie_offset, templ_len;
+       const u8 *ptr;
+
+       /* no need to change probe response if the SSID is set correctly */
+       if (wl->ssid_len > 0)
+               return wl1271_cmd_template_set(wl,
+                                              CMD_TEMPL_AP_PROBE_RESPONSE,
+                                              probe_rsp_data,
+                                              probe_rsp_len, 0,
+                                              rates);
+
+       if (probe_rsp_len + bss_conf->ssid_len > WL1271_CMD_TEMPL_MAX_SIZE) {
+               wl1271_error("probe_rsp template too big");
+               return -EINVAL;
+       }
+
+       /* start searching from IE offset */
+       ie_offset = offsetof(struct ieee80211_mgmt, u.probe_resp.variable);
+
+       ptr = cfg80211_find_ie(WLAN_EID_SSID, probe_rsp_data + ie_offset,
+                              probe_rsp_len - ie_offset);
+       if (!ptr) {
+               wl1271_error("No SSID in beacon!");
+               return -EINVAL;
+       }
+
+       ssid_ie_offset = ptr - probe_rsp_data;
+       ptr += (ptr[1] + 2);
+
+       memcpy(probe_rsp_templ, probe_rsp_data, ssid_ie_offset);
+
+       /* insert SSID from bss_conf */
+       probe_rsp_templ[ssid_ie_offset] = WLAN_EID_SSID;
+       probe_rsp_templ[ssid_ie_offset + 1] = bss_conf->ssid_len;
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2,
+              bss_conf->ssid, bss_conf->ssid_len);
+       templ_len = ssid_ie_offset + 2 + bss_conf->ssid_len;
+
+       memcpy(probe_rsp_templ + ssid_ie_offset + 2 + bss_conf->ssid_len,
+              ptr, probe_rsp_len - (ptr - probe_rsp_data));
+       templ_len += probe_rsp_len - (ptr - probe_rsp_data);
+
+       return wl1271_cmd_template_set(wl,
+                                      CMD_TEMPL_AP_PROBE_RESPONSE,
+                                      probe_rsp_templ,
+                                      templ_len, 0,
+                                      rates);
+}
+
 static int wl1271_bss_erp_info_changed(struct wl1271 *wl,
                                       struct ieee80211_bss_conf *bss_conf,
                                       u32 changed)
@@ -3088,6 +3211,7 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
 
        if ((changed & BSS_CHANGED_BEACON)) {
                struct ieee80211_hdr *hdr;
+               u32 min_rate;
                int ieoffset = offsetof(struct ieee80211_mgmt,
                                        u.beacon.variable);
                struct sk_buff *beacon = ieee80211_beacon_get(wl->hw, vif);
@@ -3103,28 +3227,46 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
                        dev_kfree_skb(beacon);
                        goto out;
                }
+               min_rate = wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                tmpl_id = is_ap ? CMD_TEMPL_AP_BEACON :
                                  CMD_TEMPL_BEACON;
                ret = wl1271_cmd_template_set(wl, tmpl_id,
                                              beacon->data,
                                              beacon->len, 0,
-                                             wl1271_tx_min_rate_get(wl));
+                                             min_rate);
                if (ret < 0) {
                        dev_kfree_skb(beacon);
                        goto out;
                }
 
+               /* remove TIM ie from probe response */
+               wl12xx_remove_ie(beacon, WLAN_EID_TIM, ieoffset);
+
+               /*
+                * remove p2p ie from probe response.
+                * the fw reponds to probe requests that don't include
+                * the p2p ie. probe requests with p2p ie will be passed,
+                * and will be responded by the supplicant (the spec
+                * forbids including the p2p ie when responding to probe
+                * requests that didn't include it).
+                */
+               wl12xx_remove_vendor_ie(beacon, WLAN_OUI_WFA,
+                                       WLAN_OUI_TYPE_WFA_P2P, ieoffset);
+
                hdr = (struct ieee80211_hdr *) beacon->data;
                hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                 IEEE80211_STYPE_PROBE_RESP);
-
-               tmpl_id = is_ap ? CMD_TEMPL_AP_PROBE_RESPONSE :
-                                 CMD_TEMPL_PROBE_RESPONSE;
-               ret = wl1271_cmd_template_set(wl,
-                                             tmpl_id,
-                                             beacon->data,
-                                             beacon->len, 0,
-                                             wl1271_tx_min_rate_get(wl));
+               if (is_ap)
+                       ret = wl1271_ap_set_probe_resp_tmpl(wl,
+                                               beacon->data,
+                                               beacon->len,
+                                               min_rate);
+               else
+                       ret = wl1271_cmd_template_set(wl,
+                                               CMD_TEMPL_PROBE_RESPONSE,
+                                               beacon->data,
+                                               beacon->len, 0,
+                                               min_rate);
                dev_kfree_skb(beacon);
                if (ret < 0)
                        goto out;
@@ -3145,8 +3287,10 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
        if ((changed & BSS_CHANGED_BASIC_RATES)) {
                u32 rates = bss_conf->basic_rates;
 
-               wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates);
-               wl->basic_rate = wl1271_tx_min_rate_get(wl);
+               wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl, rates,
+                                                                wl->band);
+               wl->basic_rate = wl1271_tx_min_rate_get(wl,
+                                                       wl->basic_rate_set);
 
                ret = wl1271_init_ap_rates(wl);
                if (ret < 0) {
@@ -3328,12 +3472,15 @@ sta_not_found:
                         * to use with control frames.
                         */
                        rates = bss_conf->basic_rates;
-                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                                        rates);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate_set =
+                               wl1271_tx_enabled_rates_get(wl, rates,
+                                                           wl->band);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        if (sta_rate_set)
                                wl->rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                               sta_rate_set);
+                                                               sta_rate_set,
+                                                               wl->band);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                goto out;
@@ -3380,7 +3527,8 @@ sta_not_found:
 
                        /* revert back to minimum rates for the current band */
                        wl1271_set_band_rate(wl);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
                                goto out;
@@ -3431,11 +3579,13 @@ sta_not_found:
 
                if (bss_conf->ibss_joined) {
                        u32 rates = bss_conf->basic_rates;
-                       wl->basic_rate_set = wl1271_tx_enabled_rates_get(wl,
-                                                                        rates);
-                       wl->basic_rate = wl1271_tx_min_rate_get(wl);
+                       wl->basic_rate_set =
+                               wl1271_tx_enabled_rates_get(wl, rates,
+                                                           wl->band);
+                       wl->basic_rate =
+                               wl1271_tx_min_rate_get(wl, wl->basic_rate_set);
 
-                       /* by default, use 11b rates */
+                       /* by default, use 11b + OFDM rates */
                        wl->rate_set = CONF_TX_IBSS_DEFAULT_RATES;
                        ret = wl1271_acx_sta_rate_policies(wl);
                        if (ret < 0)
@@ -3665,7 +3815,8 @@ out:
        return ret;
 }
 
-static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw)
+static u64 wl1271_op_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
 
        struct wl1271 *wl = hw->priv;
@@ -3729,14 +3880,18 @@ static int wl1271_allocate_sta(struct wl1271 *wl,
        wl_sta->hlid = WL1271_AP_STA_HLID_START + id;
        *hlid = wl_sta->hlid;
        memcpy(wl->links[wl_sta->hlid].addr, sta->addr, ETH_ALEN);
+       wl->active_sta_count++;
        return 0;
 }
 
-static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
 {
        int id = hlid - WL1271_AP_STA_HLID_START;
 
-       if (WARN_ON(!test_bit(id, wl->ap_hlid_map)))
+       if (hlid < WL1271_AP_STA_HLID_START)
+               return;
+
+       if (!test_bit(id, wl->ap_hlid_map))
                return;
 
        clear_bit(id, wl->ap_hlid_map);
@@ -3745,6 +3900,7 @@ static void wl1271_free_sta(struct wl1271 *wl, u8 hlid)
        wl1271_tx_reset_link_queues(wl, hlid);
        __clear_bit(hlid, &wl->ap_ps_map);
        __clear_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
+       wl->active_sta_count--;
 }
 
 static int wl1271_op_sta_add(struct ieee80211_hw *hw,
@@ -3950,6 +4106,29 @@ out:
        return ret;
 }
 
+static int wl12xx_set_bitrate_mask(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  const struct cfg80211_bitrate_mask *mask)
+{
+       struct wl1271 *wl = hw->priv;
+       int i;
+
+       wl1271_debug(DEBUG_MAC80211, "mac80211 set_bitrate_mask 0x%x 0x%x",
+               mask->control[NL80211_BAND_2GHZ].legacy,
+               mask->control[NL80211_BAND_5GHZ].legacy);
+
+       mutex_lock(&wl->mutex);
+
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               wl->bitrate_masks[i] =
+                       wl1271_tx_enabled_rates_get(wl,
+                                                   mask->control[i].legacy,
+                                                   i);
+       mutex_unlock(&wl->mutex);
+
+       return 0;
+}
+
 static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
 {
        struct wl1271 *wl = hw->priv;
@@ -4066,7 +4245,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
 /* 11n STA capabilities */
 #define HW_RX_HIGHEST_RATE     72
 
-#ifdef CONFIG_WL12XX_HT
 #define WL12XX_HT_CAP { \
        .cap = IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_20 | \
               (1 << IEEE80211_HT_CAP_RX_STBC_SHIFT), \
@@ -4079,11 +4257,6 @@ static const u8 wl1271_rate_to_idx_2ghz[] = {
                .tx_params = IEEE80211_HT_MCS_TX_DEFINED, \
                }, \
 }
-#else
-#define WL12XX_HT_CAP { \
-       .ht_supported = false, \
-}
-#endif
 
 /* can't be const, mac80211 writes to this */
 static struct ieee80211_supported_band wl1271_band_2ghz = {
@@ -4231,6 +4404,7 @@ static const struct ieee80211_ops wl1271_ops = {
        .sta_remove = wl1271_op_sta_remove,
        .ampdu_action = wl1271_op_ampdu_action,
        .tx_frames_pending = wl1271_tx_frames_pending,
+       .set_bitrate_mask = wl12xx_set_bitrate_mask,
        CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
 };
 
@@ -4483,15 +4657,19 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
                IEEE80211_HW_SUPPORTS_CQM_RSSI |
                IEEE80211_HW_REPORTS_TX_ACK_STATUS |
                IEEE80211_HW_SPECTRUM_MGMT |
-               IEEE80211_HW_AP_LINK_PS;
+               IEEE80211_HW_AP_LINK_PS |
+               IEEE80211_HW_AMPDU_AGGREGATION |
+               IEEE80211_HW_TX_AMPDU_SETUP_IN_HW;
 
        wl->hw->wiphy->cipher_suites = cipher_suites;
        wl->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
 
        wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP);
+               BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO);
        wl->hw->wiphy->max_scan_ssids = 1;
-       wl->hw->wiphy->max_sched_scan_ssids = 8;
+       wl->hw->wiphy->max_sched_scan_ssids = 16;
+       wl->hw->wiphy->max_match_sets = 16;
        /*
         * Maximum length of elements in scanning probe request templates
         * should be the maximum length possible for a template, without
@@ -4500,6 +4678,8 @@ int wl1271_init_ieee80211(struct wl1271 *wl)
        wl->hw->wiphy->max_scan_ie_len = WL1271_CMD_TEMPL_DFLT_SIZE -
                        sizeof(struct ieee80211_header);
 
+       wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD;
+
        /* make sure all our channels fit in the scanned_ch bitmask */
        BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
                     ARRAY_SIZE(wl1271_channels_5ghz) >
@@ -4543,6 +4723,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        int i, j, ret;
        unsigned int order;
 
+       BUILD_BUG_ON(AP_MAX_LINKS > WL12XX_MAX_LINKS);
+
        hw = ieee80211_alloc_hw(sizeof(*wl), &wl1271_ops);
        if (!hw) {
                wl1271_error("could not alloc ieee80211_hw");
@@ -4625,6 +4807,7 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
        wl->session_counter = 0;
        wl->ap_bcast_hlid = WL12XX_INVALID_LINK_ID;
        wl->ap_global_hlid = WL12XX_INVALID_LINK_ID;
+       wl->active_sta_count = 0;
        setup_timer(&wl->rx_streaming_timer, wl1271_rx_streaming_timer,
                    (unsigned long) wl);
        wl->fwlog_size = 0;
@@ -4644,6 +4827,8 @@ struct ieee80211_hw *wl1271_alloc_hw(void)
 
        /* Apply default driver configuration. */
        wl1271_conf_init(wl);
+       wl->bitrate_masks[IEEE80211_BAND_2GHZ] = wl->conf.tx.basic_rate;
+       wl->bitrate_masks[IEEE80211_BAND_5GHZ] = wl->conf.tx.basic_rate_5;
 
        order = get_order(WL1271_AGGR_BUFFER_SIZE);
        wl->aggr_buf = (u8 *)__get_free_pages(GFP_KERNEL, order);
@@ -4776,6 +4961,9 @@ module_param_named(fwlog, fwlog_param, charp, 0);
 MODULE_PARM_DESC(keymap,
                 "FW logger options: continuous, ondemand, dbgpins or disable");
 
+module_param(bug_on_recovery, bool, S_IRUSR | S_IWUSR);
+MODULE_PARM_DESC(bug_on_recovery, "BUG() on fw recovery");
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Luciano Coelho <coelho@ti.com>");
 MODULE_AUTHOR("Juuso Oikarinen <juuso.oikarinen@nokia.com>");
index 4b720b1b9f65666de26aa9a91f56df1e101116e3..c15ebf2efd40a6e71fc710da1de8206c98c5294d 100644 (file)
@@ -199,15 +199,19 @@ static void wl1271_ps_filter_frames(struct wl1271 *wl, u8 hlid)
        unsigned long flags;
        int filtered[NUM_TX_QUEUES];
 
-       /* filter all frames currently the low level queus for this hlid */
+       /* filter all frames currently in the low level queues for this hlid */
        for (i = 0; i < NUM_TX_QUEUES; i++) {
                filtered[i] = 0;
                while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) {
+                       filtered[i]++;
+
+                       if (WARN_ON(wl12xx_is_dummy_packet(wl, skb)))
+                               continue;
+
                        info = IEEE80211_SKB_CB(skb);
                        info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
                        info->status.rates[0].idx = -1;
                        ieee80211_tx_status_ni(wl->hw, skb);
-                       filtered[i]++;
                }
        }
 
index 78d8410da1f4586c947912c8ec9086b7a0fd81dc..dee4cfe9ccc1ed87a9979418e12bfc1f46ace708 100644 (file)
@@ -66,11 +66,9 @@ static void wl1271_rx_status(struct wl1271 *wl,
 
        status->rate_idx = wl1271_rate_to_idx(desc->rate, status->band);
 
-#ifdef CONFIG_WL12XX_HT
        /* 11n support */
        if (desc->rate <= CONF_HW_RXTX_RATE_MCS0)
                status->flag |= RX_FLAG_HT;
-#endif
 
        status->signal = desc->rssi;
 
@@ -107,6 +105,7 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
        u8 beacon = 0;
        u8 is_data = 0;
        u8 reserved = unaligned ? NET_IP_ALIGN : 0;
+       u16 seq_num;
 
        /*
         * In PLT mode we seem to get frames and mac80211 warns about them,
@@ -169,9 +168,11 @@ static int wl1271_rx_handle_data(struct wl1271 *wl, u8 *data, u32 length,
 
        wl1271_rx_status(wl, desc, IEEE80211_SKB_RXCB(skb), beacon);
 
-       wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s", skb,
+       seq_num = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+       wl1271_debug(DEBUG_RX, "rx skb 0x%p: %d B %s seq %d", skb,
                     skb->len - desc->pad_len,
-                    beacon ? "beacon" : "");
+                    beacon ? "beacon" : "",
+                    seq_num);
 
        skb_trim(skb, skb->len - desc->pad_len);
 
index af4ad2353f59ef45ddc897a299529ee7748f3a24..128ccb79318c86c7e0a8bc4a65c61389b58e959f 100644 (file)
@@ -28,6 +28,7 @@
 #include "scan.h"
 #include "acx.h"
 #include "ps.h"
+#include "tx.h"
 
 void wl1271_scan_complete_work(struct work_struct *work)
 {
@@ -65,8 +66,9 @@ void wl1271_scan_complete_work(struct work_struct *work)
        /* return to ROC if needed */
        is_sta = (wl->bss_type == BSS_TYPE_STA_BSS);
        is_ibss = (wl->bss_type == BSS_TYPE_IBSS);
-       if ((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
-           (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) {
+       if (((is_sta && !test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags)) ||
+            (is_ibss && !test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))) &&
+           !test_bit(wl->dev_role_id, wl->roc_map)) {
                /* restore remain on channel */
                wl12xx_cmd_role_start_dev(wl);
                wl12xx_roc(wl, wl->dev_role_id);
@@ -98,14 +100,18 @@ static int wl1271_get_scan_channels(struct wl1271 *wl,
        for (i = 0, j = 0;
             i < req->n_channels && j < WL1271_SCAN_MAX_CHANNELS;
             i++) {
-
                flags = req->channels[i]->flags;
 
                if (!test_bit(i, wl->scan.scanned_ch) &&
                    !(flags & IEEE80211_CHAN_DISABLED) &&
-                   ((!!(flags & IEEE80211_CHAN_PASSIVE_SCAN)) == passive) &&
-                   (req->channels[i]->band == band)) {
-
+                   (req->channels[i]->band == band) &&
+                   /*
+                    * In passive scans, we scan all remaining
+                    * channels, even if not marked as such.
+                    * In active scans, we only scan channels not
+                    * marked as passive.
+                    */
+                   (passive || !(flags & IEEE80211_CHAN_PASSIVE_SCAN))) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
@@ -157,6 +163,10 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
        int ret;
        u16 scan_options = 0;
 
+       /* skip active scans if we don't have SSIDs */
+       if (!passive && wl->scan.req->n_ssids == 0)
+               return WL1271_NOTHING_TO_SCAN;
+
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
        trigger = kzalloc(sizeof(*trigger), GFP_KERNEL);
        if (!cmd || !trigger) {
@@ -164,11 +174,7 @@ static int wl1271_scan_send(struct wl1271 *wl, enum ieee80211_band band,
                goto out;
        }
 
-       /* We always use high priority scans */
-       scan_options = WL1271_SCAN_OPT_PRIORITY_HIGH;
-
-       /* No SSIDs means that we have a forced passive scan */
-       if (passive || wl->scan.req->n_ssids == 0)
+       if (passive)
                scan_options |= WL1271_SCAN_OPT_PASSIVE;
 
        if (WARN_ON(wl->role_id == WL12XX_INVALID_ROLE_ID)) {
@@ -238,14 +244,17 @@ out:
 void wl1271_scan_stm(struct wl1271 *wl)
 {
        int ret = 0;
+       enum ieee80211_band band;
+       u32 rate;
 
        switch (wl->scan.state) {
        case WL1271_SCAN_STATE_IDLE:
                break;
 
        case WL1271_SCAN_STATE_2GHZ_ACTIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, false,
-                                      wl->conf.tx.basic_rate);
+               band = IEEE80211_BAND_2GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, false, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_2GHZ_PASSIVE;
                        wl1271_scan_stm(wl);
@@ -254,8 +263,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_2GHZ_PASSIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_2GHZ, true,
-                                      wl->conf.tx.basic_rate);
+               band = IEEE80211_BAND_2GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, true, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        if (wl->enable_11a)
                                wl->scan.state = WL1271_SCAN_STATE_5GHZ_ACTIVE;
@@ -267,8 +277,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_5GHZ_ACTIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, false,
-                                      wl->conf.tx.basic_rate_5);
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, false, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_5GHZ_PASSIVE;
                        wl1271_scan_stm(wl);
@@ -277,8 +288,9 @@ void wl1271_scan_stm(struct wl1271 *wl)
                break;
 
        case WL1271_SCAN_STATE_5GHZ_PASSIVE:
-               ret = wl1271_scan_send(wl, IEEE80211_BAND_5GHZ, true,
-                                      wl->conf.tx.basic_rate_5);
+               band = IEEE80211_BAND_5GHZ;
+               rate = wl1271_tx_min_rate_get(wl, wl->bitrate_masks[band]);
+               ret = wl1271_scan_send(wl, band, true, rate);
                if (ret == WL1271_NOTHING_TO_SCAN) {
                        wl->scan.state = WL1271_SCAN_STATE_DONE;
                        wl1271_scan_stm(wl);
@@ -473,34 +485,86 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                cfg->passive[2] || cfg->active[2];
 }
 
-/* Returns 0 if no wildcard is used, 1 if wildcard is used or a
- * negative value on error */
+/* Returns the scan type to be used or a negative value on error */
 static int
 wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                                 struct cfg80211_sched_scan_request *req)
 {
        struct wl1271_cmd_sched_scan_ssid_list *cmd = NULL;
-       struct cfg80211_ssid *ssid = req->ssids;
-       int ret, wildcard = 0;
+       struct cfg80211_match_set *sets = req->match_sets;
+       struct cfg80211_ssid *ssids = req->ssids;
+       int ret = 0, type, i, j, n_match_ssids = 0;
 
        wl1271_debug(DEBUG_CMD, "cmd sched scan ssid list");
 
+       /* count the match sets that contain SSIDs */
+       for (i = 0; i < req->n_match_sets; i++)
+               if (sets[i].ssid.ssid_len > 0)
+                       n_match_ssids++;
+
+       /* No filter, no ssids or only bcast ssid */
+       if (!n_match_ssids &&
+           (!req->n_ssids ||
+            (req->n_ssids == 1 && req->ssids[0].ssid_len == 0))) {
+               type = SCAN_SSID_FILTER_ANY;
+               goto out;
+       }
+
        cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
-       if (!cmd)
-               return -ENOMEM;
+       if (!cmd) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (!n_match_ssids) {
+               /* No filter, with ssids */
+               type = SCAN_SSID_FILTER_DISABLED;
+
+               for (i = 0; i < req->n_ssids; i++) {
+                       cmd->ssids[cmd->n_ssids].type = (ssids[i].ssid_len) ?
+                               SCAN_SSID_TYPE_HIDDEN : SCAN_SSID_TYPE_PUBLIC;
+                       cmd->ssids[cmd->n_ssids].len = ssids[i].ssid_len;
+                       memcpy(cmd->ssids[cmd->n_ssids].ssid, ssids[i].ssid,
+                              ssids[i].ssid_len);
+                       cmd->n_ssids++;
+               }
+       } else {
+               type = SCAN_SSID_FILTER_LIST;
+
+               /* Add all SSIDs from the filters */
+               for (i = 0; i < req->n_match_sets; i++) {
+                       /* ignore sets without SSIDs */
+                       if (!sets[i].ssid.ssid_len)
+                               continue;
 
-       while ((cmd->n_ssids < req->n_ssids) && ssid) {
-               if (ssid->ssid_len == 0) {
-                       wildcard = 1;
                        cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_PUBLIC;
-               } else {
-                       cmd->ssids[cmd->n_ssids].type = SCAN_SSID_TYPE_HIDDEN;
+                       cmd->ssids[cmd->n_ssids].len = sets[i].ssid.ssid_len;
+                       memcpy(cmd->ssids[cmd->n_ssids].ssid,
+                              sets[i].ssid.ssid, sets[i].ssid.ssid_len);
+                       cmd->n_ssids++;
+               }
+               if ((req->n_ssids > 1) ||
+                   (req->n_ssids == 1 && req->ssids[0].ssid_len > 0)) {
+                       /*
+                        * Mark all the SSIDs passed in the SSID list as HIDDEN,
+                        * so they're used in probe requests.
+                        */
+                       for (i = 0; i < req->n_ssids; i++) {
+                               for (j = 0; j < cmd->n_ssids; j++)
+                                       if (!memcmp(req->ssids[i].ssid,
+                                                  cmd->ssids[j].ssid,
+                                                  req->ssids[i].ssid_len)) {
+                                               cmd->ssids[j].type =
+                                                       SCAN_SSID_TYPE_HIDDEN;
+                                               break;
+                                       }
+                               /* Fail if SSID isn't present in the filters */
+                               if (j == req->n_ssids) {
+                                       ret = -EINVAL;
+                                       goto out_free;
+                               }
+                       }
                }
-               cmd->ssids[cmd->n_ssids].len = ssid->ssid_len;
-               memcpy(cmd->ssids[cmd->n_ssids].ssid, ssid->ssid,
-                      ssid->ssid_len);
-               ssid++;
-               cmd->n_ssids++;
        }
 
        wl1271_dump(DEBUG_SCAN, "SSID_LIST: ", cmd, sizeof(*cmd));
@@ -509,13 +573,15 @@ wl12xx_scan_sched_scan_ssid_list(struct wl1271 *wl,
                              sizeof(*cmd), 0);
        if (ret < 0) {
                wl1271_error("cmd sched scan ssid list failed");
-               goto out;
+               goto out_free;
        }
 
-       ret = wildcard;
-out:
+out_free:
        kfree(cmd);
-       return ret;
+out:
+       if (ret < 0)
+               return ret;
+       return type;
 }
 
 int wl1271_scan_sched_scan_config(struct wl1271 *wl,
@@ -550,21 +616,13 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                cfg->intervals[i] = cpu_to_le32(req->interval);
 
        cfg->ssid_len = 0;
-       if (req->n_ssids == 0) {
-               wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_ANY");
-               cfg->filter_type = SCAN_SSID_FILTER_ANY;
-       } else {
-               ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
-               if (ret < 0)
-                       goto out;
-               if (ret) {
-                       wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_DISABLED");
-                       cfg->filter_type = SCAN_SSID_FILTER_DISABLED;
-               } else {
-                       wl1271_debug(DEBUG_SCAN, "using SCAN_SSID_FILTER_LIST");
-                       cfg->filter_type = SCAN_SSID_FILTER_LIST;
-               }
-       }
+       ret = wl12xx_scan_sched_scan_ssid_list(wl, req);
+       if (ret < 0)
+               goto out;
+
+       cfg->filter_type = ret;
+
+       wl1271_debug(DEBUG_SCAN, "filter_type = %d", cfg->filter_type);
 
        if (!wl1271_scan_sched_scan_channels(wl, req, cfg)) {
                wl1271_error("scan channel list is empty");
index c3610492852eb3d49e7b8f81e1fa9b19c64d7093..f25d5d9212e79c9a1eb4aa501bfd592bc08865ed 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
 #include <linux/gpio.h>
 #include <linux/wl12xx.h>
 #include <linux/kthread.h>
@@ -142,14 +143,23 @@ static int wl1271_sdio_set_power(struct wl1271 *wl, bool enable)
                ret = pm_runtime_get_sync(&func->dev);
                if (ret < 0)
                        goto out;
+
+               /* Runtime PM might be disabled, power up the card manually */
+               ret = mmc_power_restore_host(func->card->host);
+               if (ret < 0)
+                       goto out;
+
                sdio_claim_host(func);
                sdio_enable_func(func);
-               sdio_release_host(func);
        } else {
-               sdio_claim_host(func);
                sdio_disable_func(func);
                sdio_release_host(func);
 
+               /* Runtime PM might be disabled, power off the card manually */
+               ret = mmc_power_save_host(func->card->host);
+               if (ret < 0)
+                       goto out;
+
                /* Power down the card */
                ret = pm_runtime_put_sync(&func->dev);
        }
@@ -433,7 +443,6 @@ static int __devinit wl1271_probe(struct sdio_func *func,
 
        sdio_set_drvdata(func, wl_test);
 
-
        /* power up the device */
        ret = wl1271_chip_wakeup(wl);
        if (ret) {
index 08227e69616b0d93ca56135d20529a5d4465a4ff..bad9e29d49b0145bd3ec5220be6372cc16840c36 100644 (file)
@@ -30,6 +30,7 @@
 #include "reg.h"
 #include "ps.h"
 #include "tx.h"
+#include "event.h"
 
 static int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id)
 {
@@ -80,8 +81,7 @@ static int wl1271_tx_update_filters(struct wl1271 *wl,
        struct ieee80211_hdr *hdr;
        int ret;
 
-       hdr = (struct ieee80211_hdr *)(skb->data +
-                                      sizeof(struct wl1271_tx_hw_descr));
+       hdr = (struct ieee80211_hdr *)skb->data;
 
        /*
         * stop bssid-based filtering before transmitting authentication
@@ -125,25 +125,31 @@ static void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
 
 static void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid)
 {
-       bool fw_ps;
+       bool fw_ps, single_sta;
        u8 tx_pkts;
 
        /* only regulate station links */
        if (hlid < WL1271_AP_STA_HLID_START)
                return;
 
+       if (WARN_ON(!wl1271_is_active_sta(wl, hlid)))
+           return;
+
        fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map);
        tx_pkts = wl->links[hlid].allocated_pkts;
+       single_sta = (wl->active_sta_count == 1);
 
        /*
         * if in FW PS and there is enough data in FW we can put the link
         * into high-level PS and clean out its TX queues.
+        * Make an exception if this is the only connected station. In this
+        * case FW-memory congestion is not a problem.
         */
-       if (fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
+       if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
                wl1271_ps_link_start(wl, hlid, true);
 }
 
-static bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
 {
        return wl->dummy_packet == skb;
 }
@@ -174,14 +180,20 @@ u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb)
 
 static u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb)
 {
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
        if (wl12xx_is_dummy_packet(wl, skb))
                return wl->system_hlid;
 
        if (wl->bss_type == BSS_TYPE_AP_BSS)
                return wl12xx_tx_get_hlid_ap(wl, skb);
 
-       if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
-           test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags))
+       wl1271_tx_update_filters(wl, skb);
+
+       if ((test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) ||
+            test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) &&
+           !ieee80211_is_auth(hdr->frame_control) &&
+           !ieee80211_is_assoc_req(hdr->frame_control))
                return wl->sta_hlid;
        else
                return wl->dev_hlid;
@@ -416,8 +428,6 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
                wl1271_tx_ap_update_inconnection_sta(wl, skb);
                wl1271_tx_regulate_link(wl, hlid);
-       } else {
-               wl1271_tx_update_filters(wl, skb);
        }
 
        /*
@@ -440,20 +450,20 @@ static int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb,
        return total_len;
 }
 
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+                               enum ieee80211_band rate_band)
 {
        struct ieee80211_supported_band *band;
        u32 enabled_rates = 0;
        int bit;
 
-       band = wl->hw->wiphy->bands[wl->band];
+       band = wl->hw->wiphy->bands[rate_band];
        for (bit = 0; bit < band->n_bitrates; bit++) {
                if (rate_set & 0x1)
                        enabled_rates |= band->bitrates[bit].hw_value;
                rate_set >>= 1;
        }
 
-#ifdef CONFIG_WL12XX_HT
        /* MCS rates indication are on bits 16 - 23 */
        rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
 
@@ -462,7 +472,6 @@ u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set)
                        enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
                rate_set >>= 1;
        }
-#endif
 
        return enabled_rates;
 }
@@ -886,6 +895,7 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
        /* TX failure */
        if (wl->bss_type == BSS_TYPE_AP_BSS) {
                for (i = 0; i < AP_MAX_LINKS; i++) {
+                       wl1271_free_sta(wl, i);
                        wl1271_tx_reset_link_queues(wl, i);
                        wl->links[i].allocated_pkts = 0;
                        wl->links[i].prev_freed_pkts = 0;
@@ -905,10 +915,14 @@ void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues)
                                        ieee80211_tx_status_ni(wl->hw, skb);
                                }
                        }
-                       wl->tx_queue_count[i] = 0;
                }
+
+               wl->ba_rx_bitmap = 0;
        }
 
+       for (i = 0; i < NUM_TX_QUEUES; i++)
+               wl->tx_queue_count[i] = 0;
+
        wl->stopped_queues_map = 0;
 
        /*
@@ -976,20 +990,10 @@ void wl1271_tx_flush(struct wl1271 *wl)
        wl1271_warning("Unable to flush all TX buffers, timed out.");
 }
 
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl)
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
 {
-       int i;
-       u32 rate = 0;
-
-       if (!wl->basic_rate_set) {
-               WARN_ON(1);
-               wl->basic_rate_set = wl->conf.tx.basic_rate;
-       }
-
-       for (i = 0; !rate; i++) {
-               if ((wl->basic_rate_set >> i) & 0x1)
-                       rate = 1 << i;
-       }
+       if (WARN_ON(!rate_set))
+               return 0;
 
-       return rate;
+       return BIT(__ffs(rate_set));
 }
index 6519be4b2c38c0be86382db51c9291c2abeb5b3f..dc4f09adf088541b5ae642f84a7cfac960e9b3b7 100644 (file)
@@ -209,10 +209,15 @@ void wl1271_tx_complete(struct wl1271 *wl);
 void wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues);
 void wl1271_tx_flush(struct wl1271 *wl);
 u8 wl1271_rate_to_idx(int rate, enum ieee80211_band band);
-u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set);
-u32 wl1271_tx_min_rate_get(struct wl1271 *wl);
+u32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
+                               enum ieee80211_band rate_band);
+u32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set);
 u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb);
 void wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid);
 void wl1271_handle_tx_low_watermark(struct wl1271 *wl);
+bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb);
+
+/* from main.c */
+void wl1271_free_sta(struct wl1271 *wl, u8 hlid);
 
 #endif
index fb2753c46300d6c265bc483ad556c086a340b86c..997f532450111577905c055eaacf122b6035b3fb 100644 (file)
@@ -138,7 +138,7 @@ extern u32 wl12xx_debug_level;
 #define WL1271_DEFAULT_DTIM_PERIOD 1
 
 #define WL12XX_MAX_ROLES           4
-#define WL12XX_MAX_LINKS           8
+#define WL12XX_MAX_LINKS           12
 #define WL12XX_INVALID_ROLE_ID     0xff
 #define WL12XX_INVALID_LINK_ID     0xff
 
@@ -234,14 +234,14 @@ struct wl1271_stats {
 #define NUM_TX_QUEUES              4
 #define NUM_RX_PKT_DESC            8
 
-#define AP_MAX_STATIONS            5
+#define AP_MAX_STATIONS            8
 
 /* Broadcast and Global links + system link + links to stations */
 /*
  * TODO: when WL1271_AP_STA_HLID_START is no longer constant, change all
  * the places that use this.
  */
-#define AP_MAX_LINKS               (AP_MAX_STATIONS + 3)
+#define AP_MAX_LINKS               (AP_MAX_STATIONS + WL1271_AP_STA_HLID_START)
 
 /* FW status registers */
 struct wl12xx_fw_status {
@@ -279,7 +279,7 @@ struct wl12xx_fw_status {
 
        /* Cumulative counter of released Voice memory blocks */
        u8 tx_voice_released_blks;
-       u8 padding_1[7];
+       u8 padding_1[3];
        __le32 log_start_addr;
 } __packed;
 
@@ -402,6 +402,7 @@ struct wl1271 {
        u8 mac_addr[ETH_ALEN];
        u8 bss_type;
        u8 set_bss_type;
+       u8 p2p; /* we are using p2p role */
        u8 ssid[IEEE80211_MAX_SSID_LEN + 1];
        u8 ssid_len;
        int channel;
@@ -525,6 +526,7 @@ struct wl1271 {
        u32 basic_rate_set;
        u32 basic_rate;
        u32 rate_set;
+       u32 bitrate_masks[IEEE80211_NUM_BANDS];
 
        /* The current band */
        enum ieee80211_band band;
@@ -626,6 +628,9 @@ struct wl1271 {
 
        /* number of currently active RX BA sessions */
        int ba_rx_session_count;
+
+       /* AP-mode - number of currently connected stations */
+       int active_sta_count;
 };
 
 struct wl1271_station {
index 6bc7c92fbff73b580c5f0fc334f21407322aebad..98fbf54f6004144e832f713034728a8b302c45ee 100644 (file)
@@ -1781,7 +1781,7 @@ static int wl3501_get_encode(struct net_device *dev,
                                  keys, len_keys);
        if (rc)
                goto out;
-       tocopy = min_t(u8, len_keys, wrqu->encoding.length);
+       tocopy = min_t(u16, len_keys, wrqu->encoding.length);
        tocopy = min_t(u8, tocopy, 100);
        wrqu->encoding.length = tocopy;
        memcpy(extra, keys, tocopy);
index cabfae1e70b14027e5e5d381783590869c23f0d8..0a70149df3fcb8aa39c9bbf7556edc5af7cf2da4 100644 (file)
@@ -1332,7 +1332,7 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 }
 
-static u64 zd_op_get_tsf(struct ieee80211_hw *hw)
+static u64 zd_op_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 {
        struct zd_mac *mac = zd_hw_mac(hw);
        return zd_chip_get_tsf(&mac->chip);
index 2acff4307ca401c70b40909826e9d5e1cccb6c3f..5af959274d4ef0c6ba4b355a49575604101db0d1 100644 (file)
@@ -27,4 +27,15 @@ config NFC_PN533
          Say Y here to compile support for PN533 devices into the
          kernel or say M to compile it as module (pn533).
 
+config NFC_WILINK
+       tristate "Texas Instruments NFC WiLink driver"
+       depends on TI_ST && NFC_NCI
+       help
+         This enables the NFC driver for Texas Instrument's BT/FM/GPS/NFC
+         combo devices. This makes use of shared transport line discipline
+         core driver to communicate with the NFC core of the combo chip.
+
+         Say Y here to compile support for Texas Instrument's NFC WiLink driver
+         into the kernel or say M to compile it as module.
+
 endmenu
index 8ef446d2c1bd9f57206c8c48cba7a0487eb6d98a..ab99e8572f02a8f1cdb5ef389559e1a1ccb5dd37 100644 (file)
@@ -4,5 +4,6 @@
 
 obj-$(CONFIG_PN544_NFC)                += pn544.o
 obj-$(CONFIG_NFC_PN533)                += pn533.o
+obj-$(CONFIG_NFC_WILINK)       += nfcwilink.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
new file mode 100644 (file)
index 0000000..5b0f1ff
--- /dev/null
@@ -0,0 +1,342 @@
+/*
+ *  Texas Instrument's NFC Driver For Shared Transport.
+ *
+ *  NFC Driver acts as interface between NCI core and
+ *  TI Shared Transport Layer.
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on btwilink.c, which was written
+ *  by Raja Mani and Pavan Savoy.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/platform_device.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/ti_wilink_st.h>
+
+#define NFCWILINK_CHNL                 12
+#define NFCWILINK_OPCODE               7
+#define NFCWILINK_MAX_FRAME_SIZE       300
+#define NFCWILINK_HDR_LEN              4
+#define NFCWILINK_OFFSET_LEN_IN_HDR    1
+#define NFCWILINK_LEN_SIZE             2
+#define NFCWILINK_REGISTER_TIMEOUT     8000    /* 8 sec */
+
+struct nfcwilink_hdr {
+       u8 chnl;
+       u8 opcode;
+       u16 len;
+} __packed;
+
+struct nfcwilink {
+       struct platform_device          *pdev;
+       struct nci_dev                  *ndev;
+       unsigned long                   flags;
+
+       char                            st_register_cb_status;
+       long                            (*st_write) (struct sk_buff *);
+       struct completion               st_register_completed;
+};
+
+/* NFCWILINK driver flags */
+enum {
+       NFCWILINK_RUNNING,
+};
+
+/* Called by ST when registration is complete */
+static void nfcwilink_register_complete(void *priv_data, char data)
+{
+       struct nfcwilink *drv = priv_data;
+
+       nfc_dev_dbg(&drv->pdev->dev, "register_complete entry");
+
+       /* store ST registration status */
+       drv->st_register_cb_status = data;
+
+       /* complete the wait in nfc_st_open() */
+       complete(&drv->st_register_completed);
+}
+
+/* Called by ST when receive data is available */
+static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
+{
+       struct nfcwilink *drv = priv_data;
+       int rc;
+
+       nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len);
+
+       if (!skb)
+               return -EFAULT;
+
+       if (!drv) {
+               kfree_skb(skb);
+               return -EFAULT;
+       }
+
+       /* strip the ST header
+       (apart for the chnl byte, which is not received in the hdr) */
+       skb_pull(skb, (NFCWILINK_HDR_LEN-1));
+
+       skb->dev = (void *) drv->ndev;
+
+       /* Forward skb to NCI core layer */
+       rc = nci_recv_frame(skb);
+       if (rc < 0) {
+               nfc_dev_err(&drv->pdev->dev, "nci_recv_frame failed %d", rc);
+               return rc;
+       }
+
+       return 0;
+}
+
+/* protocol structure registered with ST */
+static struct st_proto_s nfcwilink_proto = {
+       .chnl_id = NFCWILINK_CHNL,
+       .max_frame_size = NFCWILINK_MAX_FRAME_SIZE,
+       .hdr_len = (NFCWILINK_HDR_LEN-1),       /* not including chnl byte */
+       .offset_len_in_hdr = NFCWILINK_OFFSET_LEN_IN_HDR,
+       .len_size = NFCWILINK_LEN_SIZE,
+       .reserve = 0,
+       .recv = nfcwilink_receive,
+       .reg_complete_cb = nfcwilink_register_complete,
+       .write = NULL,
+};
+
+static int nfcwilink_open(struct nci_dev *ndev)
+{
+       struct nfcwilink *drv = nci_get_drvdata(ndev);
+       unsigned long comp_ret;
+       int rc;
+
+       nfc_dev_dbg(&drv->pdev->dev, "open entry");
+
+       if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
+               rc = -EBUSY;
+               goto exit;
+       }
+
+       nfcwilink_proto.priv_data = drv;
+
+       init_completion(&drv->st_register_completed);
+       drv->st_register_cb_status = -EINPROGRESS;
+
+       rc = st_register(&nfcwilink_proto);
+       if (rc < 0) {
+               if (rc == -EINPROGRESS) {
+                       comp_ret = wait_for_completion_timeout(
+                       &drv->st_register_completed,
+                       msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
+
+                       nfc_dev_dbg(&drv->pdev->dev,
+                       "wait_for_completion_timeout returned %ld",
+                       comp_ret);
+
+                       if (comp_ret == 0) {
+                               /* timeout */
+                               rc = -ETIMEDOUT;
+                               goto clear_exit;
+                       } else if (drv->st_register_cb_status != 0) {
+                               rc = drv->st_register_cb_status;
+                               nfc_dev_err(&drv->pdev->dev,
+                               "st_register_cb failed %d", rc);
+                               goto clear_exit;
+                       }
+               } else {
+                       nfc_dev_err(&drv->pdev->dev,
+                               "st_register failed %d", rc);
+                       goto clear_exit;
+               }
+       }
+
+       /* st_register MUST fill the write callback */
+       BUG_ON(nfcwilink_proto.write == NULL);
+       drv->st_write = nfcwilink_proto.write;
+
+       goto exit;
+
+clear_exit:
+       clear_bit(NFCWILINK_RUNNING, &drv->flags);
+
+exit:
+       return rc;
+}
+
+static int nfcwilink_close(struct nci_dev *ndev)
+{
+       struct nfcwilink *drv = nci_get_drvdata(ndev);
+       int rc;
+
+       nfc_dev_dbg(&drv->pdev->dev, "close entry");
+
+       if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
+               return 0;
+
+       rc = st_unregister(&nfcwilink_proto);
+       if (rc)
+               nfc_dev_err(&drv->pdev->dev, "st_unregister failed %d", rc);
+
+       drv->st_write = NULL;
+
+       return rc;
+}
+
+static int nfcwilink_send(struct sk_buff *skb)
+{
+       struct nci_dev *ndev = (struct nci_dev *)skb->dev;
+       struct nfcwilink *drv = nci_get_drvdata(ndev);
+       struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
+       long len;
+
+       nfc_dev_dbg(&drv->pdev->dev, "send entry, len %d", skb->len);
+
+       if (!test_bit(NFCWILINK_RUNNING, &drv->flags))
+               return -EBUSY;
+
+       /* add the ST hdr to the start of the buffer */
+       hdr.len = skb->len;
+       memcpy(skb_push(skb, NFCWILINK_HDR_LEN), &hdr, NFCWILINK_HDR_LEN);
+
+       /* Insert skb to shared transport layer's transmit queue.
+        * Freeing skb memory is taken care in shared transport layer,
+        * so don't free skb memory here.
+        */
+       len = drv->st_write(skb);
+       if (len < 0) {
+               kfree_skb(skb);
+               nfc_dev_err(&drv->pdev->dev, "st_write failed %ld", len);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+static struct nci_ops nfcwilink_ops = {
+       .open = nfcwilink_open,
+       .close = nfcwilink_close,
+       .send = nfcwilink_send,
+};
+
+static int nfcwilink_probe(struct platform_device *pdev)
+{
+       static struct nfcwilink *drv;
+       int rc;
+       u32 protocols;
+
+       nfc_dev_dbg(&pdev->dev, "probe entry");
+
+       drv = kzalloc(sizeof(struct nfcwilink), GFP_KERNEL);
+       if (!drv) {
+               rc = -ENOMEM;
+               goto exit;
+       }
+
+       drv->pdev = pdev;
+
+       protocols = NFC_PROTO_JEWEL_MASK
+                       | NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+                       | NFC_PROTO_ISO14443_MASK
+                       | NFC_PROTO_NFC_DEP_MASK;
+
+       drv->ndev = nci_allocate_device(&nfcwilink_ops,
+                                       protocols,
+                                       NFCWILINK_HDR_LEN,
+                                       0);
+       if (!drv->ndev) {
+               nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
+               rc = -ENOMEM;
+               goto free_exit;
+       }
+
+       nci_set_parent_dev(drv->ndev, &pdev->dev);
+       nci_set_drvdata(drv->ndev, drv);
+
+       rc = nci_register_device(drv->ndev);
+       if (rc < 0) {
+               nfc_dev_err(&pdev->dev, "nci_register_device failed %d", rc);
+               goto free_dev_exit;
+       }
+
+       dev_set_drvdata(&pdev->dev, drv);
+
+       goto exit;
+
+free_dev_exit:
+       nci_free_device(drv->ndev);
+
+free_exit:
+       kfree(drv);
+
+exit:
+       return rc;
+}
+
+static int nfcwilink_remove(struct platform_device *pdev)
+{
+       struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
+       struct nci_dev *ndev;
+
+       nfc_dev_dbg(&pdev->dev, "remove entry");
+
+       if (!drv)
+               return -EFAULT;
+
+       ndev = drv->ndev;
+
+       nci_unregister_device(ndev);
+       nci_free_device(ndev);
+
+       kfree(drv);
+
+       dev_set_drvdata(&pdev->dev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver nfcwilink_driver = {
+       .probe = nfcwilink_probe,
+       .remove = nfcwilink_remove,
+       .driver = {
+               .name = "nfcwilink",
+               .owner = THIS_MODULE,
+       },
+};
+
+/* ------- Module Init/Exit interfaces ------ */
+static int __init nfcwilink_init(void)
+{
+       printk(KERN_INFO "NFC Driver for TI WiLink");
+
+       return platform_driver_register(&nfcwilink_driver);
+}
+
+static void __exit nfcwilink_exit(void)
+{
+       platform_driver_unregister(&nfcwilink_driver);
+}
+
+module_init(nfcwilink_init);
+module_exit(nfcwilink_exit);
+
+/* ------ Module Info ------ */
+
+MODULE_AUTHOR("Ilan Elias <ilane@ti.com>");
+MODULE_DESCRIPTION("NFC Driver for TI Shared Transport");
+MODULE_LICENSE("GPL");
index f81a93e5b59dfa865e413454a82ab01539c6457f..7bcb1febef0dd06246642f58878cace232706500 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/usb.h>
 #include <linux/nfc.h>
 #include <linux/netdevice.h>
-#include <net/nfc.h>
+#include <net/nfc/nfc.h>
 
 #define VERSION "0.1"
 
@@ -1432,6 +1432,8 @@ static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
 }
 
 struct nfc_ops pn533_nfc_ops = {
+       .dev_up = NULL,
+       .dev_down = NULL,
        .start_poll = pn533_start_poll,
        .stop_poll = pn533_stop_poll,
        .activate_target = pn533_activate_target,
index d6de44e430d32d5f86539692225856252b4691b3..315dd91800b6a7ed09068d8a4f5b03792a8d78bb 100644 (file)
@@ -133,7 +133,8 @@ static int brcms_ops_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
                          bool set);
 static void brcms_ops_sw_scan_start(struct ieee80211_hw *hw);
 static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw);
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf);
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf);
 static int brcms_ops_get_stats(struct ieee80211_hw *hw,
                            struct ieee80211_low_level_stats *stats);
 static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
@@ -142,7 +143,8 @@ static void brcms_ops_sta_notify(struct ieee80211_hw *hw,
                              struct ieee80211_sta *sta);
 static int brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
                          const struct ieee80211_tx_queue_params *params);
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw);
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif);
 static int brcms_ops_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                      struct ieee80211_sta *sta);
 static int brcms_ops_sta_remove(struct ieee80211_hw *hw,
@@ -516,7 +518,8 @@ static void brcms_ops_sw_scan_complete(struct ieee80211_hw *hw)
        return;
 }
 
-static void brcms_ops_set_tsf(struct ieee80211_hw *hw, u64 tsf)
+static void brcms_ops_set_tsf(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif, u64 tsf)
 {
        wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
        return;
@@ -565,7 +568,8 @@ brcms_ops_conf_tx(struct ieee80211_hw *hw, u16 queue,
        return 0;
 }
 
-static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw)
+static u64 brcms_ops_get_tsf(struct ieee80211_hw *hw,
+                            struct ieee80211_vif *vif)
 {
        wiphy_err(hw->wiphy, "%s: Enter\n", __func__);
        return 0;
index 3724e1e67ec23adfd56d52b0e1cf6a5e0fe9e523..a2e8bd452ed9dfed2ae3f324b19cab9e0672075f 100644 (file)
@@ -277,7 +277,7 @@ static int wbsoft_config(struct ieee80211_hw *dev, u32 changed)
        return 0;
 }
 
-static u64 wbsoft_get_tsf(struct ieee80211_hw *dev)
+static u64 wbsoft_get_tsf(struct ieee80211_hw *dev, struct ieee80211_vif *vif)
 {
        printk("wbsoft_get_tsf called\n");
        return 0;
index a7ae33d06f246006f56a39b2a84adc40a0114c59..1526d965ed064d864fb9c38db5d4067b8dd7bbe0 100644 (file)
@@ -378,4 +378,13 @@ u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value);
 /* PMU support */
 extern void bcma_pmu_init(struct bcma_drv_cc *cc);
 
+extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
+                                 u32 value);
+extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
+                                   u32 mask, u32 set);
+extern void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
+                                       u32 offset, u32 mask, u32 set);
+extern void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc,
+                                      u32 offset, u32 mask, u32 set);
+
 #endif /* LINUX_BCMA_DRIVER_CC_H_ */
index 72f3933938c0e850982c90c69b48a851ccd4086f..b5e0a5c344fd69677507f8e24ed4890d143e6136 100644 (file)
@@ -777,6 +777,13 @@ struct ieee80211_mmie {
        u8 mic[8];
 } __attribute__ ((packed));
 
+struct ieee80211_vendor_ie {
+       u8 element_id;
+       u8 len;
+       u8 oui[3];
+       u8 oui_type;
+} __packed;
+
 /* Control frames */
 struct ieee80211_rts {
        __le16 frame_control;
@@ -1470,6 +1477,9 @@ enum ieee80211_sa_query_action {
 
 #define WLAN_PMKID_LEN                 16
 
+#define WLAN_OUI_WFA                   0x506f9a
+#define WLAN_OUI_TYPE_WFA_P2P          9
+
 /*
  * WMM/802.11e Tspec Element
  */
index c525e0b5876b9286d110a5f4dc14de7e4b93f010..36cb955b05cc517fc09ffcb0126571f7ccb5bcc0 100644 (file)
  *
  * @NFC_CMD_GET_DEVICE: request information about a device (requires
  *     %NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
+ * @NFC_CMD_DEV_UP: turn on the nfc device
+ *     (requires %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_CMD_DEV_DOWN: turn off the nfc device
+ *     (requires %NFC_ATTR_DEVICE_INDEX)
  * @NFC_CMD_START_POLL: start polling for targets using the given protocols
  *     (requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
  * @NFC_CMD_STOP_POLL: stop polling for targets (requires
@@ -56,6 +60,8 @@
 enum nfc_commands {
        NFC_CMD_UNSPEC,
        NFC_CMD_GET_DEVICE,
+       NFC_CMD_DEV_UP,
+       NFC_CMD_DEV_DOWN,
        NFC_CMD_START_POLL,
        NFC_CMD_STOP_POLL,
        NFC_CMD_GET_TARGET,
index f17307590e61fe269a104d232f4eaa8513227840..c73582fb9d205b7f71b90e27dbf40cb7825beb40 100644 (file)
  *
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     probe requests at CCK rate or not.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *     NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *     specified using %NL80211_ATTR_DURATION. When called, this operation
  *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
  *     TX status event pertaining to the TX request.
+ *     %NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *     management frames at CCK rate or not in 2GHz band.
  * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
  *     command may be used with the corresponding cookie to cancel the wait
  *     time if it is known that it is no longer necessary.
  *     this command may also be sent by the driver as an MLME event to
  *     inform userspace of the new replay counter.
  *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ *     of PMKSA caching dandidates.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -623,6 +630,8 @@ enum nl80211_commands {
 
        NL80211_CMD_SET_REKEY_OFFLOAD,
 
+       NL80211_CMD_PMKSA_CANDIDATE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -1070,6 +1079,16 @@ enum nl80211_commands {
  * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
  *     roaming to another AP in the same ESS if the signal lever is low.
  *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *     candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *     for management frames transmission. In order to avoid p2p probe/action
+ *     frames are being transmitted at CCK rate in 2GHz band, the user space
+ *     applications use this attribute.
+ *     This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *     %NL80211_CMD_FRAME commands.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1288,6 +1307,10 @@ enum nl80211_attrs {
        NL80211_ATTR_SCHED_SCAN_MATCH,
        NL80211_ATTR_MAX_MATCH_SETS,
 
+       NL80211_ATTR_PMKSA_CANDIDATE,
+
+       NL80211_ATTR_TX_NO_CCK_RATE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -2558,4 +2581,27 @@ enum nl80211_sta_wme_attr {
        NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ *     priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ *     (internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ *     (internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+       __NL80211_PMKSA_CANDIDATE_INVALID,
+       NL80211_PMKSA_CANDIDATE_INDEX,
+       NL80211_PMKSA_CANDIDATE_BSSID,
+       NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+       /* keep last */
+       NUM_NL80211_PMKSA_CANDIDATE,
+       MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
 #endif /* __LINUX_NL80211_H */
index be30aabe7b88b95825eab3e65dc606ae91d3ea83..aaf79af7243262592607924aa1e4dd609da7d2aa 100644 (file)
@@ -716,6 +716,16 @@ struct hci_rp_read_bd_addr {
        bdaddr_t bdaddr;
 } __packed;
 
+#define HCI_OP_WRITE_PAGE_SCAN_ACTIVITY        0x0c1c
+struct hci_cp_write_page_scan_activity {
+       __le16   interval;
+       __le16   window;
+} __packed;
+
+#define HCI_OP_WRITE_PAGE_SCAN_TYPE    0x0c47
+       #define PAGE_SCAN_TYPE_STANDARD         0x00
+       #define PAGE_SCAN_TYPE_INTERLACED       0x01
+
 #define HCI_OP_LE_SET_EVENT_MASK       0x2001
 struct hci_cp_le_set_event_mask {
        __u8     mask[8];
index 8f441b8b2963d685330d8981263b5d8454a0acb5..5b924423cf205ad9e927c7de4045e86160f1a082 100644 (file)
@@ -195,8 +195,6 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
-       struct crypto_blkcipher *tfm;
-
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -348,6 +346,7 @@ enum {
        HCI_CONN_RSWITCH_PEND,
        HCI_CONN_MODE_CHANGE_PEND,
        HCI_CONN_SCO_SETUP_PEND,
+       HCI_CONN_LE_SMP_PEND,
 };
 
 static inline void hci_conn_hash_init(struct hci_dev *hdev)
@@ -395,6 +394,22 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
        }
 }
 
+static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       switch (type) {
+       case ACL_LINK:
+               return h->acl_num;
+       case LE_LINK:
+               return h->le_num;
+       case SCO_LINK:
+       case ESCO_LINK:
+               return h->sco_num;
+       default:
+               return 0;
+       }
+}
+
 static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
                                                                __u16 handle)
 {
@@ -475,7 +490,7 @@ static inline void hci_conn_put(struct hci_conn *conn)
 {
        if (atomic_dec_and_test(&conn->refcnt)) {
                unsigned long timeo;
-               if (conn->type == ACL_LINK) {
+               if (conn->type == ACL_LINK || conn->type == LE_LINK) {
                        del_timer(&conn->idle_timer);
                        if (conn->state == BT_CONNECTED) {
                                timeo = msecs_to_jiffies(conn->disc_timeout);
@@ -838,7 +853,7 @@ int mgmt_powered(u16 index, u8 powered);
 int mgmt_discoverable(u16 index, u8 discoverable);
 int mgmt_connectable(u16 index, u8 connectable);
 int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr);
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
 int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
 int mgmt_disconnect_failed(u16 index);
 int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
@@ -858,6 +873,8 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
                                                                u8 *eir);
 int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
 int mgmt_discovering(u16 index, u8 discovering);
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
index 4f34ad25e75c62b3ce2f5c642c79d7c26ecdcf58..7f878b9d5642b4a3cf5a40ae86ee6bd14c58fd94 100644 (file)
@@ -409,14 +409,8 @@ struct l2cap_conn {
 
        __u8            disc_reason;
 
-       __u8            preq[7]; /* SMP Pairing Request */
-       __u8            prsp[7]; /* SMP Pairing Response */
-       __u8            prnd[16]; /* SMP Pairing Random */
-       __u8            pcnf[16]; /* SMP Pairing Confirm */
-       __u8            tk[16]; /* SMP Temporary Key */
-       __u8            smp_key_size;
-
        struct timer_list security_timer;
+       struct smp_chan *smp_chan;
 
        struct list_head chan_l;
        rwlock_t        chan_lock;
index 5428fd32ccec228a4df03c6be87539bcb2985919..d66da0f94f95ae60e4ceb1d2fe713bc90c376e08 100644 (file)
@@ -211,6 +211,11 @@ struct mgmt_cp_unblock_device {
        bdaddr_t bdaddr;
 } __packed;
 
+#define MGMT_OP_SET_FAST_CONNECTABLE   0x001F
+struct mgmt_cp_set_fast_connectable {
+       __u8 enable;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        __le16 opcode;
@@ -249,6 +254,7 @@ struct mgmt_ev_new_key {
 #define MGMT_EV_CONNECTED              0x000B
 struct mgmt_ev_connected {
        bdaddr_t bdaddr;
+       __u8 link_type;
 } __packed;
 
 #define MGMT_EV_DISCONNECTED           0x000C
@@ -301,3 +307,13 @@ struct mgmt_ev_remote_name {
 } __packed;
 
 #define MGMT_EV_DISCOVERING            0x0014
+
+#define MGMT_EV_DEVICE_BLOCKED         0x0015
+struct mgmt_ev_device_blocked {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_EV_DEVICE_UNBLOCKED       0x0016
+struct mgmt_ev_device_unblocked {
+       bdaddr_t bdaddr;
+} __packed;
index 46c457612300c8fcbca5ebdaa3be1f387dd95512..15b97d54944195b19f52d57434a01f5443407d92 100644 (file)
@@ -115,9 +115,26 @@ struct smp_cmd_security_req {
 #define SMP_MIN_ENC_KEY_SIZE           7
 #define SMP_MAX_ENC_KEY_SIZE           16
 
+struct smp_chan {
+       struct l2cap_conn *conn;
+       u8              preq[7]; /* SMP Pairing Request */
+       u8              prsp[7]; /* SMP Pairing Response */
+       u8              prnd[16]; /* SMP Pairing Random (local) */
+       u8              rrnd[16]; /* SMP Pairing Random (remote) */
+       u8              pcnf[16]; /* SMP Pairing Confirm */
+       u8              tk[16]; /* SMP Temporary Key */
+       u8              smp_key_size;
+       struct crypto_blkcipher *tfm;
+       struct work_struct confirm;
+       struct work_struct random;
+
+};
+
 /* SMP Commands */
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
 int smp_distribute_keys(struct l2cap_conn *conn, __u8 force);
 
+void smp_chan_destroy(struct l2cap_conn *conn);
+
 #endif /* __SMP_H */
index f4b19b223941e1105dc4c87994680757a5a57e89..31d823a3092b43f6a4e9c9904ce2512e034aa71c 100644 (file)
@@ -860,6 +860,7 @@ struct cfg80211_ssid {
  * @wiphy: the wiphy this was for
  * @dev: the interface
  * @aborted: (internal) scan request was notified as aborted
+ * @no_cck: used to send probe requests at non CCK rate in 2GHz band
  */
 struct cfg80211_scan_request {
        struct cfg80211_ssid *ssids;
@@ -874,6 +875,7 @@ struct cfg80211_scan_request {
        struct wiphy *wiphy;
        struct net_device *dev;
        bool aborted;
+       bool no_cck;
 
        /* keep last */
        struct ieee80211_channel *channels[0];
@@ -1484,7 +1486,7 @@ struct cfg80211_ops {
        int     (*change_bss)(struct wiphy *wiphy, struct net_device *dev,
                              struct bss_parameters *params);
 
-       int     (*set_txq_params)(struct wiphy *wiphy,
+       int     (*set_txq_params)(struct wiphy *wiphy, struct net_device *dev,
                                  struct ieee80211_txq_params *params);
 
        int     (*set_channel)(struct wiphy *wiphy, struct net_device *dev,
@@ -1560,7 +1562,8 @@ struct cfg80211_ops {
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie);
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct net_device *dev,
                                       u64 cookie);
@@ -2461,6 +2464,24 @@ unsigned int cfg80211_classify8021d(struct sk_buff *skb);
  */
 const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len);
 
+/**
+ * cfg80211_find_vendor_ie - find vendor specific information element in data
+ *
+ * @oui: vendor OUI
+ * @oui_type: vendor-specific OUI type
+ * @ies: data consisting of IEs
+ * @len: length of data
+ *
+ * This function will return %NULL if the vendor specific element ID
+ * could not be found or if the element is invalid (claims to be
+ * longer than the given data), or a pointer to the first byte
+ * of the requested element, that is the byte containing the
+ * element ID. There are no checks on the element length
+ * other than having to fit into the given data.
+ */
+const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
+                                 const u8 *ies, int len);
+
 /**
  * DOC: Regulatory enforcement infrastructure
  *
@@ -3121,6 +3142,17 @@ void cfg80211_cqm_pktloss_notify(struct net_device *dev,
 void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
                               const u8 *replay_ctr, gfp_t gfp);
 
+/**
+ * cfg80211_pmksa_candidate_notify - notify about PMKSA caching candidate
+ * @dev: network device
+ * @index: candidate index (the smaller the index, the higher the priority)
+ * @bssid: BSSID of AP
+ * @preauth: Whether AP advertises support for RSN pre-authentication
+ * @gfp: allocation flags
+ */
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+                                    const u8 *bssid, bool preauth, gfp_t gfp);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 9edba09547e4c048ed37b430161c90595d6c25dc..1e83afae3c64719c02f33dddc102343f34d73d4e 100644 (file)
@@ -171,7 +171,7 @@ enum ieee80211_bss_change {
        BSS_CHANGED_ERP_CTS_PROT        = 1<<1,
        BSS_CHANGED_ERP_PREAMBLE        = 1<<2,
        BSS_CHANGED_ERP_SLOT            = 1<<3,
-       BSS_CHANGED_HT                  = 1<<4,
+       BSS_CHANGED_HT                  = 1<<4,
        BSS_CHANGED_BASIC_RATES         = 1<<5,
        BSS_CHANGED_BEACON_INT          = 1<<6,
        BSS_CHANGED_BSSID               = 1<<7,
@@ -363,6 +363,9 @@ struct ieee80211_bss_conf {
  * @IEEE80211_TX_INTFL_TKIP_MIC_FAILURE: Marks this packet to be used for TKIP
  *     testing. It will be sent out with incorrect Michael MIC key to allow
  *     TKIP countermeasures to be tested.
+ * @IEEE80211_TX_CTL_NO_CCK_RATE: This frame will be sent at non CCK rate.
+ *     This flag is actually used for management frame especially for P2P
+ *     frames not being sent at CCK rate in 2GHz band.
  *
  * Note: If you have to add new flags to the enumeration, then don't
  *      forget to update %IEEE80211_TX_TEMPORARY_FLAGS when necessary.
@@ -393,6 +396,7 @@ enum mac80211_tx_control_flags {
        IEEE80211_TX_CTL_STBC                   = BIT(23) | BIT(24),
        IEEE80211_TX_CTL_TX_OFFCHAN             = BIT(25),
        IEEE80211_TX_INTFL_TKIP_MIC_FAILURE     = BIT(26),
+       IEEE80211_TX_CTL_NO_CCK_RATE            = BIT(27),
 };
 
 #define IEEE80211_TX_CTL_STBC_SHIFT            23
@@ -2000,9 +2004,10 @@ struct ieee80211_ops {
                        enum sta_notify_cmd, struct ieee80211_sta *sta);
        int (*conf_tx)(struct ieee80211_hw *hw, u16 queue,
                       const struct ieee80211_tx_queue_params *params);
-       u64 (*get_tsf)(struct ieee80211_hw *hw);
-       void (*set_tsf)(struct ieee80211_hw *hw, u64 tsf);
-       void (*reset_tsf)(struct ieee80211_hw *hw);
+       u64 (*get_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+       void (*set_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                       u64 tsf);
+       void (*reset_tsf)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
        int (*tx_last_beacon)(struct ieee80211_hw *hw);
        int (*ampdu_action)(struct ieee80211_hw *hw,
                            struct ieee80211_vif *vif,
diff --git a/include/net/nfc/nci.h b/include/net/nfc/nci.h
new file mode 100644 (file)
index 0000000..39b85bc
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci.h, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __NCI_H
+#define __NCI_H
+
+/* NCI constants */
+#define NCI_MAX_NUM_MAPPING_CONFIGS                            10
+#define NCI_MAX_NUM_RF_CONFIGS                                 10
+#define NCI_MAX_NUM_CONN                                       10
+
+/* NCI Status Codes */
+#define        NCI_STATUS_OK                                           0x00
+#define        NCI_STATUS_REJECTED                                     0x01
+#define        NCI_STATUS_MESSAGE_CORRUPTED                            0x02
+#define        NCI_STATUS_BUFFER_FULL                                  0x03
+#define        NCI_STATUS_FAILED                                       0x04
+#define        NCI_STATUS_NOT_INITIALIZED                              0x05
+#define        NCI_STATUS_SYNTAX_ERROR                                 0x06
+#define        NCI_STATUS_SEMANTIC_ERROR                               0x07
+#define        NCI_STATUS_UNKNOWN_GID                                  0x08
+#define        NCI_STATUS_UNKNOWN_OID                                  0x09
+#define        NCI_STATUS_INVALID_PARAM                                0x0a
+#define        NCI_STATUS_MESSAGE_SIZE_EXCEEDED                        0x0b
+/* Discovery Specific Status Codes */
+#define        NCI_STATUS_DISCOVERY_ALREADY_STARTED                    0xa0
+#define        NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED           0xa1
+/* RF Interface Specific Status Codes */
+#define        NCI_STATUS_RF_TRANSMISSION_ERROR                        0xb0
+#define        NCI_STATUS_RF_PROTOCOL_ERROR                            0xb1
+#define        NCI_STATUS_RF_TIMEOUT_ERROR                             0xb2
+#define        NCI_STATUS_RF_LINK_LOSS_ERROR                           0xb3
+/* NFCEE Interface Specific Status Codes */
+#define        NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED          0xc0
+#define        NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED            0xc1
+#define        NCI_STATUS_NFCEE_TRANSMISSION_ERROR                     0xc2
+#define        NCI_STATUS_NFCEE_PROTOCOL_ERROR                         0xc3
+#define NCI_STATUS_NFCEE_TIMEOUT_ERROR                         0xc4
+
+/* NCI RF Technology and Mode */
+#define NCI_NFC_A_PASSIVE_POLL_MODE                            0x00
+#define NCI_NFC_B_PASSIVE_POLL_MODE                            0x01
+#define NCI_NFC_F_PASSIVE_POLL_MODE                            0x02
+#define NCI_NFC_A_ACTIVE_POLL_MODE                             0x03
+#define NCI_NFC_F_ACTIVE_POLL_MODE                             0x05
+#define NCI_NFC_A_PASSIVE_LISTEN_MODE                          0x80
+#define NCI_NFC_B_PASSIVE_LISTEN_MODE                          0x81
+#define NCI_NFC_F_PASSIVE_LISTEN_MODE                          0x82
+#define NCI_NFC_A_ACTIVE_LISTEN_MODE                           0x83
+#define NCI_NFC_F_ACTIVE_LISTEN_MODE                           0x85
+
+/* NCI RF Protocols */
+#define NCI_RF_PROTOCOL_UNKNOWN                                        0x00
+#define NCI_RF_PROTOCOL_T1T                                    0x01
+#define NCI_RF_PROTOCOL_T2T                                    0x02
+#define NCI_RF_PROTOCOL_T3T                                    0x03
+#define NCI_RF_PROTOCOL_ISO_DEP                                        0x04
+#define NCI_RF_PROTOCOL_NFC_DEP                                        0x05
+
+/* NCI RF Interfaces */
+#define NCI_RF_INTERFACE_RFU                                   0x00
+#define        NCI_RF_INTERFACE_FRAME                                  0x01
+#define        NCI_RF_INTERFACE_ISO_DEP                                0x02
+#define        NCI_RF_INTERFACE_NFC_DEP                                0x03
+
+/* NCI RF_DISCOVER_MAP_CMD modes */
+#define NCI_DISC_MAP_MODE_POLL                                 0x01
+#define NCI_DISC_MAP_MODE_LISTEN                               0x02
+#define NCI_DISC_MAP_MODE_BOTH                                 0x03
+
+/* NCI Discovery Types */
+#define NCI_DISCOVERY_TYPE_POLL_A_PASSIVE                      0x00
+#define        NCI_DISCOVERY_TYPE_POLL_B_PASSIVE                       0x01
+#define        NCI_DISCOVERY_TYPE_POLL_F_PASSIVE                       0x02
+#define        NCI_DISCOVERY_TYPE_POLL_A_ACTIVE                        0x03
+#define        NCI_DISCOVERY_TYPE_POLL_F_ACTIVE                        0x05
+#define        NCI_DISCOVERY_TYPE_WAKEUP_A_PASSIVE                     0x06
+#define        NCI_DISCOVERY_TYPE_WAKEUP_B_PASSIVE                     0x07
+#define        NCI_DISCOVERY_TYPE_WAKEUP_A_ACTIVE                      0x09
+#define        NCI_DISCOVERY_TYPE_LISTEN_A_PASSIVE                     0x80
+#define        NCI_DISCOVERY_TYPE_LISTEN_B_PASSIVE                     0x81
+#define        NCI_DISCOVERY_TYPE_LISTEN_F_PASSIVE                     0x82
+#define        NCI_DISCOVERY_TYPE_LISTEN_A_ACTIVE                      0x83
+#define        NCI_DISCOVERY_TYPE_LISTEN_F_ACTIVE                      0x85
+
+/* NCI Deactivation Type */
+#define        NCI_DEACTIVATE_TYPE_IDLE_MODE                           0x00
+#define        NCI_DEACTIVATE_TYPE_SLEEP_MODE                          0x01
+#define        NCI_DEACTIVATE_TYPE_SLEEP_AF_MODE                       0x02
+#define        NCI_DEACTIVATE_TYPE_RF_LINK_LOSS                        0x03
+#define        NCI_DEACTIVATE_TYPE_DISCOVERY_ERROR                     0x04
+
+/* Message Type (MT) */
+#define NCI_MT_DATA_PKT                                                0x00
+#define NCI_MT_CMD_PKT                                         0x01
+#define NCI_MT_RSP_PKT                                         0x02
+#define NCI_MT_NTF_PKT                                         0x03
+
+#define nci_mt(hdr)                    (((hdr)[0]>>5)&0x07)
+#define nci_mt_set(hdr, mt)            ((hdr)[0] |= (__u8)(((mt)&0x07)<<5))
+
+/* Packet Boundary Flag (PBF) */
+#define NCI_PBF_LAST                                           0x00
+#define NCI_PBF_CONT                                           0x01
+
+#define nci_pbf(hdr)                   (__u8)(((hdr)[0]>>4)&0x01)
+#define nci_pbf_set(hdr, pbf)          ((hdr)[0] |= (__u8)(((pbf)&0x01)<<4))
+
+/* Control Opcode manipulation */
+#define nci_opcode_pack(gid, oid)      (__u16)((((__u16)((gid)&0x0f))<<8)|\
+                                       ((__u16)((oid)&0x3f)))
+#define nci_opcode(hdr)                        nci_opcode_pack(hdr[0], hdr[1])
+#define nci_opcode_gid(op)             (__u8)(((op)&0x0f00)>>8)
+#define nci_opcode_oid(op)             (__u8)((op)&0x003f)
+
+/* Payload Length */
+#define nci_plen(hdr)                  (__u8)((hdr)[2])
+
+/* Connection ID */
+#define nci_conn_id(hdr)               (__u8)(((hdr)[0])&0x0f)
+
+/* GID values */
+#define        NCI_GID_CORE                                            0x0
+#define        NCI_GID_RF_MGMT                                         0x1
+#define        NCI_GID_NFCEE_MGMT                                      0x2
+#define        NCI_GID_PROPRIETARY                                     0xf
+
+/* ---- NCI Packet structures ---- */
+#define NCI_CTRL_HDR_SIZE                                      3
+#define NCI_DATA_HDR_SIZE                                      3
+
+struct nci_ctrl_hdr {
+       __u8    gid;            /* MT & PBF & GID */
+       __u8    oid;
+       __u8    plen;
+} __packed;
+
+struct nci_data_hdr {
+       __u8    conn_id;        /* MT & PBF & ConnID */
+       __u8    rfu;
+       __u8    plen;
+} __packed;
+
+/* ------------------------ */
+/* -----  NCI Commands ---- */
+/* ------------------------ */
+#define NCI_OP_CORE_RESET_CMD          nci_opcode_pack(NCI_GID_CORE, 0x00)
+
+#define NCI_OP_CORE_INIT_CMD           nci_opcode_pack(NCI_GID_CORE, 0x01)
+
+#define NCI_OP_CORE_SET_CONFIG_CMD     nci_opcode_pack(NCI_GID_CORE, 0x02)
+
+#define NCI_OP_CORE_CONN_CREATE_CMD    nci_opcode_pack(NCI_GID_CORE, 0x04)
+struct nci_core_conn_create_cmd {
+       __u8    target_handle;
+       __u8    num_target_specific_params;
+} __packed;
+
+#define NCI_OP_CORE_CONN_CLOSE_CMD     nci_opcode_pack(NCI_GID_CORE, 0x06)
+
+#define NCI_OP_RF_DISCOVER_MAP_CMD     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
+struct disc_map_config {
+       __u8    rf_protocol;
+       __u8    mode;
+       __u8    rf_interface_type;
+} __packed;
+
+struct nci_rf_disc_map_cmd {
+       __u8                            num_mapping_configs;
+       struct disc_map_config          mapping_configs
+                                       [NCI_MAX_NUM_MAPPING_CONFIGS];
+} __packed;
+
+#define NCI_OP_RF_DISCOVER_CMD         nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
+struct disc_config {
+       __u8    type;
+       __u8    frequency;
+} __packed;
+
+struct nci_rf_disc_cmd {
+       __u8                            num_disc_configs;
+       struct disc_config              disc_configs[NCI_MAX_NUM_RF_CONFIGS];
+} __packed;
+
+#define NCI_OP_RF_DEACTIVATE_CMD       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+struct nci_rf_deactivate_cmd {
+       __u8    type;
+} __packed;
+
+/* ----------------------- */
+/* ---- NCI Responses ---- */
+/* ----------------------- */
+#define NCI_OP_CORE_RESET_RSP          nci_opcode_pack(NCI_GID_CORE, 0x00)
+struct nci_core_reset_rsp {
+       __u8    status;
+       __u8    nci_ver;
+} __packed;
+
+#define NCI_OP_CORE_INIT_RSP           nci_opcode_pack(NCI_GID_CORE, 0x01)
+struct nci_core_init_rsp_1 {
+       __u8    status;
+       __le32  nfcc_features;
+       __u8    num_supported_rf_interfaces;
+       __u8    supported_rf_interfaces[0];     /* variable size array */
+       /* continuted in nci_core_init_rsp_2 */
+} __packed;
+
+struct nci_core_init_rsp_2 {
+       __u8    max_logical_connections;
+       __le16  max_routing_table_size;
+       __u8    max_control_packet_payload_length;
+       __le16  rf_sending_buffer_size;
+       __le16  rf_receiving_buffer_size;
+       __le16  manufacturer_id;
+} __packed;
+
+#define NCI_OP_CORE_SET_CONFIG_RSP     nci_opcode_pack(NCI_GID_CORE, 0x02)
+
+#define NCI_OP_CORE_CONN_CREATE_RSP    nci_opcode_pack(NCI_GID_CORE, 0x04)
+struct nci_core_conn_create_rsp {
+       __u8    status;
+       __u8    max_pkt_payload_size;
+       __u8    initial_num_credits;
+       __u8    conn_id;
+} __packed;
+
+#define NCI_OP_CORE_CONN_CLOSE_RSP     nci_opcode_pack(NCI_GID_CORE, 0x06)
+
+#define NCI_OP_RF_DISCOVER_MAP_RSP     nci_opcode_pack(NCI_GID_RF_MGMT, 0x00)
+
+#define NCI_OP_RF_DISCOVER_RSP         nci_opcode_pack(NCI_GID_RF_MGMT, 0x03)
+
+#define NCI_OP_RF_DEACTIVATE_RSP       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+
+/* --------------------------- */
+/* ---- NCI Notifications ---- */
+/* --------------------------- */
+#define NCI_OP_CORE_CONN_CREDITS_NTF   nci_opcode_pack(NCI_GID_CORE, 0x07)
+struct conn_credit_entry {
+       __u8    conn_id;
+       __u8    credits;
+} __packed;
+
+struct nci_core_conn_credit_ntf {
+       __u8                            num_entries;
+       struct conn_credit_entry        conn_entries[NCI_MAX_NUM_CONN];
+} __packed;
+
+#define NCI_OP_RF_FIELD_INFO_NTF       nci_opcode_pack(NCI_GID_CORE, 0x08)
+struct nci_rf_field_info_ntf {
+       __u8    rf_field_status;
+} __packed;
+
+#define NCI_OP_RF_ACTIVATE_NTF         nci_opcode_pack(NCI_GID_RF_MGMT, 0x05)
+struct rf_tech_specific_params_nfca_poll {
+       __u16   sens_res;
+       __u8    nfcid1_len;     /* 0, 4, 7, or 10 Bytes */
+       __u8    nfcid1[10];
+       __u8    sel_res_len;    /* 0 or 1 Bytes */
+       __u8    sel_res;
+} __packed;
+
+struct activation_params_nfca_poll_iso_dep {
+       __u8    rats_res_len;
+       __u8    rats_res[20];
+};
+
+struct nci_rf_activate_ntf {
+       __u8    target_handle;
+       __u8    rf_protocol;
+       __u8    rf_tech_and_mode;
+       __u8    rf_tech_specific_params_len;
+
+       union {
+               struct rf_tech_specific_params_nfca_poll nfca_poll;
+       } rf_tech_specific_params;
+
+       __u8    rf_interface_type;
+       __u8    activation_params_len;
+
+       union {
+               struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep;
+       } activation_params;
+
+} __packed;
+
+#define NCI_OP_RF_DEACTIVATE_NTF       nci_opcode_pack(NCI_GID_RF_MGMT, 0x06)
+
+#endif /* __NCI_H */
diff --git a/include/net/nfc/nci_core.h b/include/net/nfc/nci_core.h
new file mode 100644 (file)
index 0000000..b8b4bbd
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_core.h, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef __NCI_CORE_H
+#define __NCI_CORE_H
+
+#include <linux/interrupt.h>
+#include <linux/skbuff.h>
+
+#include <net/nfc/nfc.h>
+#include <net/nfc/nci.h>
+
+/* NCI device state */
+enum {
+       NCI_INIT,
+       NCI_UP,
+       NCI_DISCOVERY,
+       NCI_POLL_ACTIVE,
+       NCI_DATA_EXCHANGE,
+};
+
+/* NCI timeouts */
+#define NCI_RESET_TIMEOUT                      5000
+#define NCI_INIT_TIMEOUT                       5000
+#define NCI_RF_DISC_TIMEOUT                    5000
+#define NCI_RF_DEACTIVATE_TIMEOUT              5000
+#define NCI_CMD_TIMEOUT                                5000
+
+struct nci_dev;
+
+struct nci_ops {
+       int (*open)(struct nci_dev *ndev);
+       int (*close)(struct nci_dev *ndev);
+       int (*send)(struct sk_buff *skb);
+};
+
+#define NCI_MAX_SUPPORTED_RF_INTERFACES                4
+
+/* NCI Core structures */
+struct nci_dev {
+       struct nfc_dev          *nfc_dev;
+       struct nci_ops          *ops;
+
+       int                     tx_headroom;
+       int                     tx_tailroom;
+
+       unsigned long           flags;
+
+       atomic_t                cmd_cnt;
+       atomic_t                credits_cnt;
+
+       struct timer_list       cmd_timer;
+
+       struct workqueue_struct *cmd_wq;
+       struct work_struct      cmd_work;
+
+       struct workqueue_struct *rx_wq;
+       struct work_struct      rx_work;
+
+       struct workqueue_struct *tx_wq;
+       struct work_struct      tx_work;
+
+       struct sk_buff_head     cmd_q;
+       struct sk_buff_head     rx_q;
+       struct sk_buff_head     tx_q;
+
+       struct mutex            req_lock;
+       struct completion       req_completion;
+       __u32                   req_status;
+       __u32                   req_result;
+
+       void                    *driver_data;
+
+       __u32                   poll_prots;
+       __u32                   target_available_prots;
+       __u32                   target_active_prot;
+
+       /* received during NCI_OP_CORE_RESET_RSP */
+       __u8                    nci_ver;
+
+       /* received during NCI_OP_CORE_INIT_RSP */
+       __u32                   nfcc_features;
+       __u8                    num_supported_rf_interfaces;
+       __u8                    supported_rf_interfaces
+                               [NCI_MAX_SUPPORTED_RF_INTERFACES];
+       __u8                    max_logical_connections;
+       __u16                   max_routing_table_size;
+       __u8                    max_control_packet_payload_length;
+       __u16                   rf_sending_buffer_size;
+       __u16                   rf_receiving_buffer_size;
+       __u16                   manufacturer_id;
+
+       /* received during NCI_OP_CORE_CONN_CREATE_RSP for static conn 0 */
+       __u8                    max_pkt_payload_size;
+       __u8                    initial_num_credits;
+       __u8                    conn_id;
+
+       /* stored during nci_data_exchange */
+       data_exchange_cb_t      data_exchange_cb;
+       void                    *data_exchange_cb_context;
+       struct sk_buff          *rx_data_reassembly;
+};
+
+/* ----- NCI Devices ----- */
+struct nci_dev *nci_allocate_device(struct nci_ops *ops,
+                               __u32 supported_protocols,
+                               int tx_headroom,
+                               int tx_tailroom);
+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 sk_buff *skb);
+
+static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev,
+                                               unsigned int len,
+                                               gfp_t how)
+{
+       struct sk_buff *skb;
+
+       skb = alloc_skb(len + ndev->tx_headroom + ndev->tx_tailroom, how);
+       if (skb)
+               skb_reserve(skb, ndev->tx_headroom);
+
+       return skb;
+}
+
+static inline void nci_set_parent_dev(struct nci_dev *ndev, struct device *dev)
+{
+       nfc_set_parent_dev(ndev->nfc_dev, dev);
+}
+
+static inline void nci_set_drvdata(struct nci_dev *ndev, void *data)
+{
+       ndev->driver_data = data;
+}
+
+static inline void *nci_get_drvdata(struct nci_dev *ndev)
+{
+       return ndev->driver_data;
+}
+
+void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb);
+void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb);
+void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb);
+int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload);
+int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb);
+void nci_data_exchange_complete(struct nci_dev *ndev, struct sk_buff *skb,
+                               int err);
+
+/* ----- NCI requests ----- */
+#define NCI_REQ_DONE           0
+#define NCI_REQ_PEND           1
+#define NCI_REQ_CANCELED       2
+
+void nci_req_complete(struct nci_dev *ndev, int result);
+
+/* ----- NCI status code ----- */
+int nci_to_errno(__u8 code);
+
+#endif /* __NCI_CORE_H */
similarity index 97%
rename from include/net/nfc.h
rename to include/net/nfc/nfc.h
index 87b51fe15b707c14ad1c662af04726b07fff45e1..6a7f602aa841d87794fa175c7e3ca7d2d934d4c0 100644 (file)
@@ -48,6 +48,8 @@ typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb,
                                                                int err);
 
 struct nfc_ops {
+       int (*dev_up)(struct nfc_dev *dev);
+       int (*dev_down)(struct nfc_dev *dev);
        int (*start_poll)(struct nfc_dev *dev, u32 protocols);
        void (*stop_poll)(struct nfc_dev *dev);
        int (*activate_target)(struct nfc_dev *dev, u32 target_idx,
@@ -78,7 +80,9 @@ struct nfc_dev {
        int targets_generation;
        spinlock_t targets_lock;
        struct device dev;
+       bool dev_up;
        bool polling;
+       bool remote_activated;
        struct nfc_genl_data genl_data;
        u32 supported_protocols;
 
index ea7f031f3b04607efc65e79ab061dd0c5cb9337c..c2df7bf1d37430f63a24fff7c9e24813c4648ad5 100644 (file)
@@ -218,7 +218,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
        cp.handle = cpu_to_le16(conn->handle);
        memcpy(cp.ltk, ltk, sizeof(cp.ltk));
        cp.ediv = ediv;
-       memcpy(cp.rand, rand, sizeof(rand));
+       memcpy(cp.rand, rand, sizeof(cp.rand));
 
        hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
 }
index 56943add45cc44707167f4877e27fe5630b00c95..b84458dcc2261259d83e1bad2aecef95ed622113 100644 (file)
@@ -1312,59 +1312,41 @@ int hci_blacklist_clear(struct hci_dev *hdev)
 int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct bdaddr_list *entry;
-       int err;
 
        if (bacmp(bdaddr, BDADDR_ANY) == 0)
                return -EBADF;
 
-       hci_dev_lock_bh(hdev);
-
-       if (hci_blacklist_lookup(hdev, bdaddr)) {
-               err = -EEXIST;
-               goto err;
-       }
+       if (hci_blacklist_lookup(hdev, bdaddr))
+               return -EEXIST;
 
        entry = kzalloc(sizeof(struct bdaddr_list), GFP_KERNEL);
-       if (!entry) {
-               err = -ENOMEM;
-               goto err;
-       }
+       if (!entry)
+               return -ENOMEM;
 
        bacpy(&entry->bdaddr, bdaddr);
 
        list_add(&entry->list, &hdev->blacklist);
 
-       err = 0;
-
-err:
-       hci_dev_unlock_bh(hdev);
-       return err;
+       return mgmt_device_blocked(hdev->id, bdaddr);
 }
 
 int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct bdaddr_list *entry;
-       int err = 0;
-
-       hci_dev_lock_bh(hdev);
 
        if (bacmp(bdaddr, BDADDR_ANY) == 0) {
-               hci_blacklist_clear(hdev);
-               goto done;
+               return hci_blacklist_clear(hdev);
        }
 
        entry = hci_blacklist_lookup(hdev, bdaddr);
        if (!entry) {
-               err = -ENOENT;
-               goto done;
+               return -ENOENT;
        }
 
        list_del(&entry->list);
        kfree(entry);
 
-done:
-       hci_dev_unlock_bh(hdev);
-       return err;
+       return mgmt_device_unblocked(hdev->id, bdaddr);
 }
 
 static void hci_clear_adv_cache(unsigned long arg)
@@ -1523,11 +1505,6 @@ int hci_register_dev(struct hci_dev *hdev)
        if (!hdev->workqueue)
                goto nomem;
 
-       hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
-       if (IS_ERR(hdev->tfm))
-               BT_INFO("Failed to load transform for ecb(aes): %ld",
-                                                       PTR_ERR(hdev->tfm));
-
        hci_register_sysfs(hdev);
 
        hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
@@ -1576,9 +1553,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
                                        !test_bit(HCI_SETUP, &hdev->flags))
                mgmt_index_removed(hdev->id);
 
-       if (!IS_ERR(hdev->tfm))
-               crypto_free_blkcipher(hdev->tfm);
-
        hci_notify(hdev, HCI_DEV_UNREG);
 
        if (hdev->rfkill) {
@@ -2074,6 +2048,9 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
                        min  = c->sent;
                        conn = c;
                }
+
+               if (hci_conn_num(hdev, type) == num)
+                       break;
        }
 
        if (conn) {
@@ -2131,6 +2108,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, ACL_LINK))
+               return;
+
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* ACL tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
@@ -2162,6 +2142,9 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, SCO_LINK))
+               return;
+
        while (hdev->sco_cnt && (conn = hci_low_sent(hdev, SCO_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
@@ -2182,6 +2165,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, ESCO_LINK))
+               return;
+
        while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
@@ -2202,6 +2188,9 @@ static inline void hci_sched_le(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
+       if (!hci_conn_num(hdev, LE_LINK))
+               return;
+
        if (!test_bit(HCI_RAW, &hdev->flags)) {
                /* LE tx timeout must be longer than maximum
                 * link supervision timeout (40.9 seconds) */
index 7ef4eb4435fb4444585e9e8c6b54ef1effd486a9..35083f2aa2ea0c0ae23608b4fa421f0646b9b08d 100644 (file)
@@ -898,16 +898,15 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
        if (!cp)
                return;
 
-       hci_dev_lock(hdev);
-
        if (cp->enable == 0x01) {
                del_timer(&hdev->adv_timer);
+
+               hci_dev_lock(hdev);
                hci_adv_entries_clear(hdev);
+               hci_dev_unlock(hdev);
        } else if (cp->enable == 0x00) {
                mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
        }
-
-       hci_dev_unlock(hdev);
 }
 
 static void hci_cc_le_ltk_reply(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1103,9 +1102,10 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
                return 0;
 
        /* Only request authentication for SSP connections or non-SSP
-        * devices with sec_level HIGH */
+        * devices with sec_level HIGH or if MITM protection is requested */
        if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
-                               conn->pending_sec_level != BT_SECURITY_HIGH)
+                               conn->pending_sec_level != BT_SECURITY_HIGH &&
+                               !(conn->auth_type & 0x01))
                return 0;
 
        return 1;
@@ -1412,7 +1412,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->state = BT_CONFIG;
                        hci_conn_hold(conn);
                        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
-                       mgmt_connected(hdev->id, &ev->bdaddr);
+                       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
                } else
                        conn->state = BT_CONNECTED;
 
@@ -2816,7 +2816,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
                goto unlock;
        }
 
-       mgmt_connected(hdev->id, &ev->bdaddr);
+       mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
 
        conn->sec_level = BT_SECURITY_LOW;
        conn->handle = __le16_to_cpu(ev->handle);
index ff02cf5e77ccdd576d2f42f78f2c4715e3a47d5e..f6afe3d76a668154a3131fe55f78bf3de34ed636 100644 (file)
@@ -183,21 +183,35 @@ static int hci_sock_release(struct socket *sock)
 static int hci_sock_blacklist_add(struct hci_dev *hdev, void __user *arg)
 {
        bdaddr_t bdaddr;
+       int err;
 
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
 
-       return hci_blacklist_add(hdev, &bdaddr);
+       hci_dev_lock_bh(hdev);
+
+       err = hci_blacklist_add(hdev, &bdaddr);
+
+       hci_dev_unlock_bh(hdev);
+
+       return err;
 }
 
 static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
 {
        bdaddr_t bdaddr;
+       int err;
 
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
 
-       return hci_blacklist_del(hdev, &bdaddr);
+       hci_dev_lock_bh(hdev);
+
+       err = hci_blacklist_del(hdev, &bdaddr);
+
+       hci_dev_unlock_bh(hdev);
+
+       return err;
 }
 
 /* Ioctls that require bound socket */
index a6c3aa8be1f79796dbfa051af03b3503f23fbe4e..22f1a6c87035b551c352acf70d53ed369d6e9dcd 100644 (file)
@@ -23,6 +23,8 @@ static inline char *link_typetostr(int type)
                return "SCO";
        case ESCO_LINK:
                return "eSCO";
+       case LE_LINK:
+               return "LE";
        default:
                return "UNKNOWN";
        }
index fb68f344c34a68e5a4334b751196680ac33ffdfe..b83979c548b2ee706908a053430ad94a2df5a82c 100644 (file)
@@ -872,6 +872,9 @@ static int hidp_start(struct hid_device *hid)
        struct hidp_session *session = hid->driver_data;
        struct hid_report *report;
 
+       if (hid->quirks & HID_QUIRK_NO_INIT_REPORTS)
+               return 0;
+
        list_for_each_entry(report, &hid->report_enum[HID_INPUT_REPORT].
                        report_list, list)
                hidp_send_report(session, report);
index b3bdb482bbe6f5fdf2d197fc1035082f495c448b..1611b3544bb1fc7770db9d9333b495a719e17e1c 100644 (file)
@@ -907,6 +907,9 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
        if (!conn->hcon->out && conn->hcon->type == LE_LINK)
                l2cap_le_conn_ready(conn);
 
+       if (conn->hcon->out && conn->hcon->type == LE_LINK)
+               smp_conn_security(conn, conn->hcon->pending_sec_level);
+
        read_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
@@ -986,8 +989,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
                del_timer_sync(&conn->info_timer);
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+       if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
                del_timer(&conn->security_timer);
+               smp_chan_destroy(conn);
+       }
 
        hcon->l2cap_data = NULL;
        kfree(conn);
@@ -1519,7 +1524,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m
        return skb;
 }
 
-struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen)
+static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
+                                               struct msghdr *msg, size_t len,
+                                               u16 control, u16 sdulen)
 {
        struct sock *sk = chan->sk;
        struct l2cap_conn *conn = chan->conn;
@@ -4093,6 +4100,11 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
        BT_DBG("conn %p", conn);
 
+       if (hcon->type == LE_LINK) {
+               smp_distribute_keys(conn, 0);
+               del_timer(&conn->security_timer);
+       }
+
        read_lock(&conn->chan_lock);
 
        list_for_each_entry(chan, &conn->chan_l, list) {
@@ -4105,9 +4117,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                if (chan->scid == L2CAP_CID_LE_DATA) {
                        if (!status && encrypt) {
                                chan->sec_level = hcon->sec_level;
-                               del_timer(&conn->security_timer);
                                l2cap_chan_ready(sk);
-                               smp_distribute_keys(conn, 0);
                        }
 
                        bh_unlock_sock(sk);
index 53e109eb043e073a22479b479082bdee0a321d6d..5a94eec06caa900f9bb422b5cd7376076d67c63d 100644 (file)
@@ -908,7 +908,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        struct hci_dev *hdev;
        struct mgmt_cp_load_keys *cp;
        u16 key_count, expected_len;
-       int i, err;
+       int i;
 
        cp = (void *) data;
 
@@ -918,9 +918,9 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        key_count = get_unaligned_le16(&cp->key_count);
 
        expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
-       if (expected_len > len) {
-               BT_ERR("load_keys: expected at least %u bytes, got %u bytes",
-                                                       expected_len, len);
+       if (expected_len != len) {
+               BT_ERR("load_keys: expected %u bytes, got %u bytes",
+                                                       len, expected_len);
                return -EINVAL;
        }
 
@@ -942,36 +942,17 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
        else
                clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
 
-       len -= sizeof(*cp);
-       i = 0;
-
-       while (i < len) {
-               struct mgmt_key_info *key = (void *) cp->keys + i;
-
-               i += sizeof(*key) + key->dlen;
-
-               if (key->type == HCI_LK_SMP_LTK) {
-                       struct key_master_id *id = (void *) key->data;
-
-                       if (key->dlen != sizeof(struct key_master_id))
-                               continue;
-
-                       hci_add_ltk(hdev, 0, &key->bdaddr, key->pin_len,
-                                               id->ediv, id->rand, key->val);
-
-                       continue;
-               }
+       for (i = 0; i < key_count; i++) {
+               struct mgmt_key_info *key = &cp->keys[i];
 
                hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
                                                                key->pin_len);
        }
 
-       err = cmd_complete(sk, index, MGMT_OP_LOAD_KEYS, NULL, 0);
-
        hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
-       return err;
+       return 0;
 }
 
 static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
@@ -1347,6 +1328,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
        struct hci_dev *hdev;
        struct mgmt_cp_pair_device *cp;
        struct pending_cmd *cmd;
+       struct adv_entry *entry;
        u8 sec_level, auth_type;
        struct hci_conn *conn;
        int err;
@@ -1364,15 +1346,20 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
 
        hci_dev_lock_bh(hdev);
 
-       if (cp->io_cap == 0x03) {
-               sec_level = BT_SECURITY_MEDIUM;
+       sec_level = BT_SECURITY_MEDIUM;
+       if (cp->io_cap == 0x03)
                auth_type = HCI_AT_DEDICATED_BONDING;
-       } else {
-               sec_level = BT_SECURITY_HIGH;
+       else
                auth_type = HCI_AT_DEDICATED_BONDING_MITM;
-       }
 
-       conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level, auth_type);
+       entry = hci_find_adv_entry(hdev, &cp->bdaddr);
+       if (entry)
+               conn = hci_connect(hdev, LE_LINK, &cp->bdaddr, sec_level,
+                                                               auth_type);
+       else
+               conn = hci_connect(hdev, ACL_LINK, &cp->bdaddr, sec_level,
+                                                               auth_type);
+
        if (IS_ERR(conn)) {
                err = PTR_ERR(conn);
                goto unlock;
@@ -1391,7 +1378,10 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
                goto unlock;
        }
 
-       conn->connect_cfm_cb = pairing_complete_cb;
+       /* For LE, just connecting isn't a proof that the pairing finished */
+       if (!entry)
+               conn->connect_cfm_cb = pairing_complete_cb;
+
        conn->security_cfm_cb = pairing_complete_cb;
        conn->disconn_cfm_cb = pairing_complete_cb;
        conn->io_capability = cp->io_cap;
@@ -1689,13 +1679,12 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_block_device *cp;
+       struct pending_cmd *cmd;
+       struct mgmt_cp_block_device *cp = (void *) data;
        int err;
 
        BT_DBG("hci%u", index);
 
-       cp = (void *) data;
-
        if (len != sizeof(*cp))
                return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        EINVAL);
@@ -1705,6 +1694,14 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        ENODEV);
 
+       hci_dev_lock_bh(hdev);
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
        err = hci_blacklist_add(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1712,6 +1709,11 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
        else
                err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
                                                        NULL, 0);
+
+       mgmt_pending_remove(cmd);
+
+failed:
+       hci_dev_unlock_bh(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1721,13 +1723,12 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                                                                u16 len)
 {
        struct hci_dev *hdev;
-       struct mgmt_cp_unblock_device *cp;
+       struct pending_cmd *cmd;
+       struct mgmt_cp_unblock_device *cp = (void *) data;
        int err;
 
        BT_DBG("hci%u", index);
 
-       cp = (void *) data;
-
        if (len != sizeof(*cp))
                return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                EINVAL);
@@ -1737,6 +1738,14 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
                return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                ENODEV);
 
+       hci_dev_lock_bh(hdev);
+
+       cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
+       if (!cmd) {
+               err = -ENOMEM;
+               goto failed;
+       }
+
        err = hci_blacklist_del(hdev, &cp->bdaddr);
 
        if (err < 0)
@@ -1744,6 +1753,67 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
        else
                err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
                                                                NULL, 0);
+
+       mgmt_pending_remove(cmd);
+
+failed:
+       hci_dev_unlock_bh(hdev);
+       hci_dev_put(hdev);
+
+       return err;
+}
+
+static int set_fast_connectable(struct sock *sk, u16 index,
+                                       unsigned char *data, u16 len)
+{
+       struct hci_dev *hdev;
+       struct mgmt_cp_set_fast_connectable *cp = (void *) data;
+       struct hci_cp_write_page_scan_activity acp;
+       u8 type;
+       int err;
+
+       BT_DBG("hci%u", index);
+
+       if (len != sizeof(*cp))
+               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               EINVAL);
+
+       hdev = hci_dev_get(index);
+       if (!hdev)
+               return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               ENODEV);
+
+       hci_dev_lock(hdev);
+
+       if (cp->enable) {
+               type = PAGE_SCAN_TYPE_INTERLACED;
+               acp.interval = 0x0024;  /* 22.5 msec page scan interval */
+       } else {
+               type = PAGE_SCAN_TYPE_STANDARD; /* default */
+               acp.interval = 0x0800;  /* default 1.28 sec page scan */
+       }
+
+       acp.window = 0x0012;    /* default 11.25 msec page scan window */
+
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
+                                               sizeof(acp), &acp);
+       if (err < 0) {
+               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               -err);
+               goto done;
+       }
+
+       err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
+       if (err < 0) {
+               err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                               -err);
+               goto done;
+       }
+
+       err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
+                                                       NULL, 0);
+done:
+       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
 
        return err;
@@ -1869,6 +1939,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
        case MGMT_OP_UNBLOCK_DEVICE:
                err = unblock_device(sk, index, buf + sizeof(*hdr), len);
                break;
+       case MGMT_OP_SET_FAST_CONNECTABLE:
+               err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
+                                                               len);
+               break;
        default:
                BT_DBG("Unknown op %u", opcode);
                err = cmd_status(sk, index, opcode, 0x01);
@@ -1977,35 +2051,25 @@ int mgmt_connectable(u16 index, u8 connectable)
 
 int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
 {
-       struct mgmt_ev_new_key *ev;
-       int err, total;
-
-       total = sizeof(struct mgmt_ev_new_key) + key->dlen;
-       ev = kzalloc(total, GFP_ATOMIC);
-       if (!ev)
-               return -ENOMEM;
-
-       bacpy(&ev->key.bdaddr, &key->bdaddr);
-       ev->key.type = key->type;
-       memcpy(ev->key.val, key->val, 16);
-       ev->key.pin_len = key->pin_len;
-       ev->key.dlen = key->dlen;
-       ev->store_hint = persistent;
+       struct mgmt_ev_new_key ev;
 
-       memcpy(ev->key.data, key->data, key->dlen);
-
-       err = mgmt_event(MGMT_EV_NEW_KEY, index, ev, total, NULL);
+       memset(&ev, 0, sizeof(ev));
 
-       kfree(ev);
+       ev.store_hint = persistent;
+       bacpy(&ev.key.bdaddr, &key->bdaddr);
+       ev.key.type = key->type;
+       memcpy(ev.key.val, key->val, 16);
+       ev.key.pin_len = key->pin_len;
 
-       return err;
+       return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
 }
 
-int mgmt_connected(u16 index, bdaddr_t *bdaddr)
+int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
 {
        struct mgmt_ev_connected ev;
 
        bacpy(&ev.bdaddr, bdaddr);
+       ev.link_type = link_type;
 
        return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
 }
@@ -2260,12 +2324,14 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
        memset(&ev, 0, sizeof(ev));
 
        bacpy(&ev.bdaddr, bdaddr);
-       memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
        ev.rssi = rssi;
 
        if (eir)
                memcpy(ev.eir, eir, sizeof(ev.eir));
 
+       if (dev_class)
+               memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
+
        return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
 }
 
@@ -2286,3 +2352,29 @@ int mgmt_discovering(u16 index, u8 discovering)
        return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
                                                sizeof(discovering), NULL);
 }
+
+int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_ev_device_blocked ev;
+
+       cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
+
+       bacpy(&ev.bdaddr, bdaddr);
+
+       return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
+                                               cmd ? cmd->sk : NULL);
+}
+
+int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
+{
+       struct pending_cmd *cmd;
+       struct mgmt_ev_device_unblocked ev;
+
+       cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
+
+       bacpy(&ev.bdaddr, bdaddr);
+
+       return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
+                                               cmd ? cmd->sk : NULL);
+}
index 391888b88a929bdcb93166b0d3ed2c1ae1e3d7f3..759b63572641012b4c89fa5f48fcf6c68eee6918 100644 (file)
@@ -182,18 +182,9 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
                return;
 
        hci_send_acl(conn->hcon, skb, 0);
-}
-
-static __u8 seclevel_to_authreq(__u8 level)
-{
-       switch (level) {
-       case BT_SECURITY_HIGH:
-               /* Right now we don't support bonding */
-               return SMP_AUTH_MITM;
 
-       default:
-               return SMP_AUTH_NONE;
-       }
+       mod_timer(&conn->security_timer, jiffies +
+                                       msecs_to_jiffies(SMP_TIMEOUT));
 }
 
 static void build_pairing_cmd(struct l2cap_conn *conn,
@@ -205,7 +196,7 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
        dist_keys = 0;
        if (test_bit(HCI_PAIRABLE, &conn->hcon->hdev->flags)) {
-               dist_keys = SMP_DIST_ENC_KEY | SMP_DIST_ID_KEY | SMP_DIST_SIGN;
+               dist_keys = SMP_DIST_ENC_KEY;
                authreq |= SMP_AUTH_BONDING;
        }
 
@@ -229,24 +220,184 @@ static void build_pairing_cmd(struct l2cap_conn *conn,
 
 static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
 {
+       struct smp_chan *smp = conn->smp_chan;
+
        if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
                        (max_key_size < SMP_MIN_ENC_KEY_SIZE))
                return SMP_ENC_KEY_SIZE;
 
-       conn->smp_key_size = max_key_size;
+       smp->smp_key_size = max_key_size;
 
        return 0;
 }
 
+static void confirm_work(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan, confirm);
+       struct l2cap_conn *conn = smp->conn;
+       struct crypto_blkcipher *tfm;
+       struct smp_cmd_pairing_confirm cp;
+       int ret;
+       u8 res[16], reason;
+
+       BT_DBG("conn %p", conn);
+
+       tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC);
+       if (IS_ERR(tfm)) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       smp->tfm = tfm;
+
+       if (conn->hcon->out)
+               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp, 0,
+                               conn->src, conn->hcon->dst_type, conn->dst,
+                               res);
+       else
+               ret = smp_c1(tfm, smp->tk, smp->prnd, smp->preq, smp->prsp,
+                               conn->hcon->dst_type, conn->dst, 0, conn->src,
+                               res);
+       if (ret) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       swap128(res, cp.confirm_val);
+       smp_send_cmd(smp->conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+
+       return;
+
+error:
+       smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+       smp_chan_destroy(conn);
+}
+
+static void random_work(struct work_struct *work)
+{
+       struct smp_chan *smp = container_of(work, struct smp_chan, random);
+       struct l2cap_conn *conn = smp->conn;
+       struct hci_conn *hcon = conn->hcon;
+       struct crypto_blkcipher *tfm = smp->tfm;
+       u8 reason, confirm[16], res[16], key[16];
+       int ret;
+
+       if (IS_ERR_OR_NULL(tfm)) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
+
+       if (hcon->out)
+               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp, 0,
+                               conn->src, hcon->dst_type, conn->dst,
+                               res);
+       else
+               ret = smp_c1(tfm, smp->tk, smp->rrnd, smp->preq, smp->prsp,
+                               hcon->dst_type, conn->dst, 0, conn->src,
+                               res);
+       if (ret) {
+               reason = SMP_UNSPECIFIED;
+               goto error;
+       }
+
+       swap128(res, confirm);
+
+       if (memcmp(smp->pcnf, confirm, sizeof(smp->pcnf)) != 0) {
+               BT_ERR("Pairing failed (confirmation values mismatch)");
+               reason = SMP_CONFIRM_FAILED;
+               goto error;
+       }
+
+       if (hcon->out) {
+               u8 stk[16], rand[8];
+               __le16 ediv;
+
+               memset(rand, 0, sizeof(rand));
+               ediv = 0;
+
+               smp_s1(tfm, smp->tk, smp->rrnd, smp->prnd, key);
+               swap128(key, stk);
+
+               memset(stk + smp->smp_key_size, 0,
+                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+
+               if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend)) {
+                       reason = SMP_UNSPECIFIED;
+                       goto error;
+               }
+
+               hci_le_start_enc(hcon, ediv, rand, stk);
+               hcon->enc_key_size = smp->smp_key_size;
+       } else {
+               u8 stk[16], r[16], rand[8];
+               __le16 ediv;
+
+               memset(rand, 0, sizeof(rand));
+               ediv = 0;
+
+               swap128(smp->prnd, r);
+               smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+
+               smp_s1(tfm, smp->tk, smp->prnd, smp->rrnd, key);
+               swap128(key, stk);
+
+               memset(stk + smp->smp_key_size, 0,
+                               SMP_MAX_ENC_KEY_SIZE - smp->smp_key_size);
+
+               hci_add_ltk(hcon->hdev, 0, conn->dst, smp->smp_key_size,
+                                                       ediv, rand, stk);
+       }
+
+       return;
+
+error:
+       smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(reason), &reason);
+       smp_chan_destroy(conn);
+}
+
+static struct smp_chan *smp_chan_create(struct l2cap_conn *conn)
+{
+       struct smp_chan *smp;
+
+       smp = kzalloc(sizeof(struct smp_chan), GFP_ATOMIC);
+       if (!smp)
+               return NULL;
+
+       INIT_WORK(&smp->confirm, confirm_work);
+       INIT_WORK(&smp->random, random_work);
+
+       smp->conn = conn;
+       conn->smp_chan = smp;
+
+       hci_conn_hold(conn->hcon);
+
+       return smp;
+}
+
+void smp_chan_destroy(struct l2cap_conn *conn)
+{
+       kfree(conn->smp_chan);
+       hci_conn_put(conn->hcon);
+}
+
 static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+       struct smp_chan *smp;
        u8 key_size;
+       int ret;
 
        BT_DBG("conn %p", conn);
 
-       conn->preq[0] = SMP_CMD_PAIRING_REQ;
-       memcpy(&conn->preq[1], req, sizeof(*req));
+       if (!test_and_set_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+               smp = smp_chan_create(conn);
+
+       smp = conn->smp_chan;
+
+       smp->preq[0] = SMP_CMD_PAIRING_REQ;
+       memcpy(&smp->preq[1], req, sizeof(*req));
        skb_pull(skb, sizeof(*req));
 
        if (req->oob_flag)
@@ -260,32 +411,33 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
                return SMP_ENC_KEY_SIZE;
 
        /* Just works */
-       memset(conn->tk, 0, sizeof(conn->tk));
+       memset(smp->tk, 0, sizeof(smp->tk));
+
+       ret = smp_rand(smp->prnd);
+       if (ret)
+               return SMP_UNSPECIFIED;
 
-       conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-       memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
+       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+       memcpy(&smp->prsp[1], &rsp, sizeof(rsp));
 
        smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
        return 0;
 }
 
 static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
-       struct smp_cmd_pairing_confirm cp;
-       struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
+       u8 key_size;
        int ret;
-       u8 res[16], key_size;
 
        BT_DBG("conn %p", conn);
 
        skb_pull(skb, sizeof(*rsp));
 
-       req = (void *) &conn->preq[1];
+       req = (void *) &smp->preq[1];
 
        key_size = min(req->max_key_size, rsp->max_key_size);
        if (check_enc_key_size(conn, key_size))
@@ -295,222 +447,154 @@ static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
                return SMP_OOB_NOT_AVAIL;
 
        /* Just works */
-       memset(conn->tk, 0, sizeof(conn->tk));
-
-       conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-       memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
-
-       ret = smp_rand(conn->prnd);
-       if (ret)
-               return SMP_UNSPECIFIED;
+       memset(smp->tk, 0, sizeof(smp->tk));
 
-       ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
-                       conn->src, conn->hcon->dst_type, conn->dst, res);
+       ret = smp_rand(smp->prnd);
        if (ret)
                return SMP_UNSPECIFIED;
 
-       swap128(res, cp.confirm_val);
+       smp->prsp[0] = SMP_CMD_PAIRING_RSP;
+       memcpy(&smp->prsp[1], rsp, sizeof(*rsp));
 
-       smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+       queue_work(hdev->workqueue, &smp->confirm);
 
        return 0;
 }
 
 static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
 
        BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
-       memcpy(conn->pcnf, skb->data, sizeof(conn->pcnf));
-       skb_pull(skb, sizeof(conn->pcnf));
+       memcpy(smp->pcnf, skb->data, sizeof(smp->pcnf));
+       skb_pull(skb, sizeof(smp->pcnf));
 
        if (conn->hcon->out) {
                u8 random[16];
 
-               swap128(conn->prnd, random);
+               swap128(smp->prnd, random);
                smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(random),
                                                                random);
        } else {
-               struct smp_cmd_pairing_confirm cp;
-               int ret;
-               u8 res[16];
-
-               ret = smp_rand(conn->prnd);
-               if (ret)
-                       return SMP_UNSPECIFIED;
-
-               ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
-                                               conn->hcon->dst_type, conn->dst,
-                                               0, conn->src, res);
-               if (ret)
-                       return SMP_CONFIRM_FAILED;
-
-               swap128(res, cp.confirm_val);
-
-               smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+               queue_work(hdev->workqueue, &smp->confirm);
        }
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
        return 0;
 }
 
 static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-       struct hci_conn *hcon = conn->hcon;
-       struct crypto_blkcipher *tfm = hcon->hdev->tfm;
-       int ret;
-       u8 key[16], res[16], random[16], confirm[16];
+       struct smp_chan *smp = conn->smp_chan;
+       struct hci_dev *hdev = conn->hcon->hdev;
 
-       swap128(skb->data, random);
-       skb_pull(skb, sizeof(random));
-
-       if (conn->hcon->out)
-               ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
-                               conn->src, conn->hcon->dst_type, conn->dst,
-                               res);
-       else
-               ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp,
-                               conn->hcon->dst_type, conn->dst, 0, conn->src,
-                               res);
-       if (ret)
-               return SMP_UNSPECIFIED;
-
-       BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
-
-       swap128(res, confirm);
-
-       if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
-               BT_ERR("Pairing failed (confirmation values mismatch)");
-               return SMP_CONFIRM_FAILED;
-       }
-
-       if (conn->hcon->out) {
-               u8 stk[16], rand[8];
-               __le16 ediv;
-
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+       BT_DBG("conn %p", conn);
 
-               smp_s1(tfm, conn->tk, random, conn->prnd, key);
-               swap128(key, stk);
+       swap128(skb->data, smp->rrnd);
+       skb_pull(skb, sizeof(smp->rrnd));
 
-               memset(stk + conn->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+       queue_work(hdev->workqueue, &smp->random);
 
-               hci_le_start_enc(hcon, ediv, rand, stk);
-               hcon->enc_key_size = conn->smp_key_size;
-       } else {
-               u8 stk[16], r[16], rand[8];
-               __le16 ediv;
+       return 0;
+}
 
-               memset(rand, 0, sizeof(rand));
-               ediv = 0;
+static u8 smp_ltk_encrypt(struct l2cap_conn *conn)
+{
+       struct link_key *key;
+       struct key_master_id *master;
+       struct hci_conn *hcon = conn->hcon;
 
-               swap128(conn->prnd, r);
-               smp_send_cmd(conn, SMP_CMD_PAIRING_RANDOM, sizeof(r), r);
+       key = hci_find_link_key_type(hcon->hdev, conn->dst,
+                                               HCI_LK_SMP_LTK);
+       if (!key)
+               return 0;
 
-               smp_s1(tfm, conn->tk, conn->prnd, random, key);
-               swap128(key, stk);
+       if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND,
+                                       &hcon->pend))
+               return 1;
 
-               memset(stk + conn->smp_key_size, 0,
-                               SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+       master = (void *) key->data;
+       hci_le_start_enc(hcon, master->ediv, master->rand,
+                                               key->val);
+       hcon->enc_key_size = key->pin_len;
 
-               hci_add_ltk(conn->hcon->hdev, 0, conn->dst, conn->smp_key_size,
-                                                       ediv, rand, stk);
-       }
+       return 1;
 
-       return 0;
 }
-
 static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_security_req *rp = (void *) skb->data;
        struct smp_cmd_pairing cp;
        struct hci_conn *hcon = conn->hcon;
+       struct smp_chan *smp;
 
        BT_DBG("conn %p", conn);
 
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+       hcon->pending_sec_level = BT_SECURITY_MEDIUM;
+
+       if (smp_ltk_encrypt(conn))
                return 0;
 
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+               return 0;
+
+       smp = smp_chan_create(conn);
+
        skb_pull(skb, sizeof(*rp));
 
        memset(&cp, 0, sizeof(cp));
        build_pairing_cmd(conn, &cp, NULL, rp->auth_req);
 
-       conn->preq[0] = SMP_CMD_PAIRING_REQ;
-       memcpy(&conn->preq[1], &cp, sizeof(cp));
+       smp->preq[0] = SMP_CMD_PAIRING_REQ;
+       memcpy(&smp->preq[1], &cp, sizeof(cp));
 
        smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 
-       mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
-
-       set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
-
        return 0;
 }
 
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 {
        struct hci_conn *hcon = conn->hcon;
-       __u8 authreq;
+       struct smp_chan *smp = conn->smp_chan;
 
        BT_DBG("conn %p hcon %p level 0x%2.2x", conn, hcon, sec_level);
 
        if (!lmp_host_le_capable(hcon->hdev))
                return 1;
 
-       if (IS_ERR(hcon->hdev->tfm))
-               return 1;
-
-       if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
-               return 0;
-
        if (sec_level == BT_SECURITY_LOW)
                return 1;
 
        if (hcon->sec_level >= sec_level)
                return 1;
 
-       authreq = seclevel_to_authreq(sec_level);
-
-       if (hcon->link_mode & HCI_LM_MASTER) {
-               struct smp_cmd_pairing cp;
-               struct link_key *key;
+       if (hcon->link_mode & HCI_LM_MASTER)
+               if (smp_ltk_encrypt(conn))
+                       goto done;
 
-               key = hci_find_link_key_type(hcon->hdev, conn->dst,
-                                                       HCI_LK_SMP_LTK);
-               if (key) {
-                       struct key_master_id *master = (void *) key->data;
+       if (test_and_set_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend))
+               return 0;
 
-                       hci_le_start_enc(hcon, master->ediv, master->rand,
-                                                               key->val);
-                       hcon->enc_key_size = key->pin_len;
+       smp = smp_chan_create(conn);
 
-                       goto done;
-               }
-
-               build_pairing_cmd(conn, &cp, NULL, authreq);
-               conn->preq[0] = SMP_CMD_PAIRING_REQ;
-               memcpy(&conn->preq[1], &cp, sizeof(cp));
+       if (hcon->link_mode & HCI_LM_MASTER) {
+               struct smp_cmd_pairing cp;
 
-               mod_timer(&conn->security_timer, jiffies +
-                                       msecs_to_jiffies(SMP_TIMEOUT));
+               build_pairing_cmd(conn, &cp, NULL, SMP_AUTH_NONE);
+               smp->preq[0] = SMP_CMD_PAIRING_REQ;
+               memcpy(&smp->preq[1], &cp, sizeof(cp));
 
                smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
        } else {
                struct smp_cmd_security_req cp;
-               cp.auth_req = authreq;
+               cp.auth_req = SMP_AUTH_NONE;
                smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
        }
 
 done:
        hcon->pending_sec_level = sec_level;
-       set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
        return 0;
 }
@@ -518,10 +602,11 @@ done:
 static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_encrypt_info *rp = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
 
        skb_pull(skb, sizeof(*rp));
 
-       memcpy(conn->tk, rp->ltk, sizeof(conn->tk));
+       memcpy(smp->tk, rp->ltk, sizeof(smp->tk));
 
        return 0;
 }
@@ -529,11 +614,12 @@ static int smp_cmd_encrypt_info(struct l2cap_conn *conn, struct sk_buff *skb)
 static int smp_cmd_master_ident(struct l2cap_conn *conn, struct sk_buff *skb)
 {
        struct smp_cmd_master_ident *rp = (void *) skb->data;
+       struct smp_chan *smp = conn->smp_chan;
 
        skb_pull(skb, sizeof(*rp));
 
-       hci_add_ltk(conn->hcon->hdev, 1, conn->src, conn->smp_key_size,
-                                               rp->ediv, rp->rand, conn->tk);
+       hci_add_ltk(conn->hcon->hdev, 1, conn->src, smp->smp_key_size,
+                                               rp->ediv, rp->rand, smp->tk);
 
        smp_distribute_keys(conn, 1);
 
@@ -552,12 +638,6 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
                goto done;
        }
 
-       if (IS_ERR(conn->hcon->hdev->tfm)) {
-               err = PTR_ERR(conn->hcon->hdev->tfm);
-               reason = SMP_PAIRING_NOTSUPP;
-               goto done;
-       }
-
        skb_pull(skb, sizeof(code));
 
        switch (code) {
@@ -621,20 +701,21 @@ done:
 int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 {
        struct smp_cmd_pairing *req, *rsp;
+       struct smp_chan *smp = conn->smp_chan;
        __u8 *keydist;
 
        BT_DBG("conn %p force %d", conn, force);
 
-       if (IS_ERR(conn->hcon->hdev->tfm))
-               return PTR_ERR(conn->hcon->hdev->tfm);
+       if (!test_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend))
+               return 0;
 
-       rsp = (void *) &conn->prsp[1];
+       rsp = (void *) &smp->prsp[1];
 
        /* The responder sends its keys first */
        if (!force && conn->hcon->out && (rsp->resp_key_dist & 0x07))
                return 0;
 
-       req = (void *) &conn->preq[1];
+       req = (void *) &smp->preq[1];
 
        if (conn->hcon->out) {
                keydist = &rsp->init_key_dist;
@@ -658,7 +739,7 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
 
                smp_send_cmd(conn, SMP_CMD_ENCRYPT_INFO, sizeof(enc), &enc);
 
-               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, conn->smp_key_size,
+               hci_add_ltk(conn->hcon->hdev, 1, conn->dst, smp->smp_key_size,
                                                ediv, ident.rand, enc.ltk);
 
                ident.ediv = cpu_to_le16(ediv);
@@ -698,5 +779,11 @@ int smp_distribute_keys(struct l2cap_conn *conn, __u8 force)
                *keydist &= ~SMP_DIST_SIGN;
        }
 
+       if (conn->hcon->out || force) {
+               clear_bit(HCI_CONN_LE_SMP_PEND, &conn->hcon->pend);
+               del_timer(&conn->security_timer);
+               smp_chan_destroy(conn);
+       }
+
        return 0;
 }
index 567e3e54685a6719c224422a9effdef6c82c347e..9b1a95e1f56ac4db210a9e9bf33fab2dd44f746a 100644 (file)
@@ -1271,9 +1271,11 @@ static int ieee80211_change_bss(struct wiphy *wiphy,
 }
 
 static int ieee80211_set_txq_params(struct wiphy *wiphy,
+                                   struct net_device *dev,
                                    struct ieee80211_txq_params *params)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_tx_queue_params p;
 
        if (!local->ops->conf_tx)
@@ -1294,8 +1296,8 @@ static int ieee80211_set_txq_params(struct wiphy *wiphy,
        if (params->queue >= local->hw.queues)
                return -EINVAL;
 
-       local->tx_conf[params->queue] = p;
-       if (drv_conf_tx(local, params->queue, &p)) {
+       sdata->tx_conf[params->queue] = p;
+       if (drv_conf_tx(local, sdata, params->queue, &p)) {
                wiphy_debug(local->hw.wiphy,
                            "failed to set TX queue parameters for queue %d\n",
                            params->queue);
@@ -1869,7 +1871,8 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                             struct ieee80211_channel *chan, bool offchan,
                             enum nl80211_channel_type channel_type,
                             bool channel_type_valid, unsigned int wait,
-                            const u8 *buf, size_t len, u64 *cookie)
+                            const u8 *buf, size_t len, bool no_cck,
+                            u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
@@ -1896,6 +1899,9 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
                flags |= IEEE80211_TX_CTL_TX_OFFCHAN;
        }
 
+       if (no_cck)
+               flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
+
        if (is_offchan && !offchan)
                return -EBUSY;
 
index c9141168fd4343bc562168be5457ba80069fc549..883996b2f99fae26bd21e53d1ce12d7b322a8608 100644 (file)
@@ -78,57 +78,6 @@ DEBUGFS_READONLY_FILE(wep_iv, "%#08x",
 DEBUGFS_READONLY_FILE(rate_ctrl_alg, "%s",
        local->rate_ctrl ? local->rate_ctrl->ops->name : "hw/driver");
 
-static ssize_t tsf_read(struct file *file, char __user *user_buf,
-                            size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       u64 tsf;
-
-       tsf = drv_get_tsf(local);
-
-       return mac80211_format_buffer(user_buf, count, ppos, "0x%016llx\n",
-                                     (unsigned long long) tsf);
-}
-
-static ssize_t tsf_write(struct file *file,
-                         const char __user *user_buf,
-                         size_t count, loff_t *ppos)
-{
-       struct ieee80211_local *local = file->private_data;
-       unsigned long long tsf;
-       char buf[100];
-       size_t len;
-
-       len = min(count, sizeof(buf) - 1);
-       if (copy_from_user(buf, user_buf, len))
-               return -EFAULT;
-       buf[len] = '\0';
-
-       if (strncmp(buf, "reset", 5) == 0) {
-               if (local->ops->reset_tsf) {
-                       drv_reset_tsf(local);
-                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
-               }
-       } else {
-               tsf = simple_strtoul(buf, NULL, 0);
-               if (local->ops->set_tsf) {
-                       drv_set_tsf(local, tsf);
-                       wiphy_info(local->hw.wiphy,
-                                  "debugfs set TSF to %#018llx\n", tsf);
-
-               }
-       }
-
-       return count;
-}
-
-static const struct file_operations tsf_ops = {
-       .read = tsf_read,
-       .write = tsf_write,
-       .open = mac80211_open_file_generic,
-       .llseek = default_llseek,
-};
-
 static ssize_t reset_write(struct file *file, const char __user *user_buf,
                           size_t count, loff_t *ppos)
 {
@@ -447,7 +396,6 @@ void debugfs_hw_add(struct ieee80211_local *local)
        DEBUGFS_ADD(frequency);
        DEBUGFS_ADD(total_ps_buffered);
        DEBUGFS_ADD(wep_iv);
-       DEBUGFS_ADD(tsf);
        DEBUGFS_ADD(queues);
        DEBUGFS_ADD_MODE(reset, 0200);
        DEBUGFS_ADD(noack);
index dd046291751852118783b087f81b6dee6a8da253..9352819a986bb48847ae4ef9349ac2f2100ef3d1 100644 (file)
@@ -21,6 +21,7 @@
 #include "rate.h"
 #include "debugfs.h"
 #include "debugfs_netdev.h"
+#include "driver-ops.h"
 
 static ssize_t ieee80211_if_read(
        struct ieee80211_sub_if_data *sdata,
@@ -331,6 +332,46 @@ static ssize_t ieee80211_if_fmt_num_buffered_multicast(
 }
 __IEEE80211_IF_FILE(num_buffered_multicast, NULL);
 
+/* IBSS attributes */
+static ssize_t ieee80211_if_fmt_tsf(
+       const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
+{
+       struct ieee80211_local *local = sdata->local;
+       u64 tsf;
+
+       tsf = drv_get_tsf(local, (struct ieee80211_sub_if_data *)sdata);
+
+       return scnprintf(buf, buflen, "0x%016llx\n", (unsigned long long) tsf);
+}
+
+static ssize_t ieee80211_if_parse_tsf(
+       struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
+{
+       struct ieee80211_local *local = sdata->local;
+       unsigned long long tsf;
+       int ret;
+
+       if (strncmp(buf, "reset", 5) == 0) {
+               if (local->ops->reset_tsf) {
+                       drv_reset_tsf(local, sdata);
+                       wiphy_info(local->hw.wiphy, "debugfs reset TSF\n");
+               }
+       } else {
+               ret = kstrtoull(buf, 10, &tsf);
+               if (ret < 0)
+                       return -EINVAL;
+               if (local->ops->set_tsf) {
+                       drv_set_tsf(local, sdata, tsf);
+                       wiphy_info(local->hw.wiphy,
+                                  "debugfs set TSF to %#018llx\n", tsf);
+               }
+       }
+
+       return buflen;
+}
+__IEEE80211_IF_FILE_W(tsf);
+
+
 /* WDS attributes */
 IEEE80211_IF_FILE(peer, u.wds.remote_addr, MAC);
 
@@ -421,6 +462,11 @@ static void add_ap_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD_MODE(tkip_mic_test, 0200);
 }
 
+static void add_ibss_files(struct ieee80211_sub_if_data *sdata)
+{
+       DEBUGFS_ADD_MODE(tsf, 0600);
+}
+
 static void add_wds_files(struct ieee80211_sub_if_data *sdata)
 {
        DEBUGFS_ADD(drop_unencrypted);
@@ -515,7 +561,7 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
                add_sta_files(sdata);
                break;
        case NL80211_IFTYPE_ADHOC:
-               /* XXX */
+               add_ibss_files(sdata);
                break;
        case NL80211_IFTYPE_AP:
                add_ap_files(sdata);
index 9001ff331f0a6efa6c6e1234a7975e4f255d775e..4f845c0845ee54172dd7cd722d9f679a5f7ade61 100644 (file)
@@ -413,50 +413,55 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
-static inline int drv_conf_tx(struct ieee80211_local *local, u16 queue,
+static inline int drv_conf_tx(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata, u16 queue,
                              const struct ieee80211_tx_queue_params *params)
 {
        int ret = -EOPNOTSUPP;
 
        might_sleep();
 
-       trace_drv_conf_tx(local, queue, params);
+       trace_drv_conf_tx(local, sdata, queue, params);
        if (local->ops->conf_tx)
                ret = local->ops->conf_tx(&local->hw, queue, params);
        trace_drv_return_int(local, ret);
        return ret;
 }
 
-static inline u64 drv_get_tsf(struct ieee80211_local *local)
+static inline u64 drv_get_tsf(struct ieee80211_local *local,
+                             struct ieee80211_sub_if_data *sdata)
 {
        u64 ret = -1ULL;
 
        might_sleep();
 
-       trace_drv_get_tsf(local);
+       trace_drv_get_tsf(local, sdata);
        if (local->ops->get_tsf)
-               ret = local->ops->get_tsf(&local->hw);
+               ret = local->ops->get_tsf(&local->hw, &sdata->vif);
        trace_drv_return_u64(local, ret);
        return ret;
 }
 
-static inline void drv_set_tsf(struct ieee80211_local *local, u64 tsf)
+static inline void drv_set_tsf(struct ieee80211_local *local,
+                              struct ieee80211_sub_if_data *sdata,
+                              u64 tsf)
 {
        might_sleep();
 
-       trace_drv_set_tsf(local, tsf);
+       trace_drv_set_tsf(local, sdata, tsf);
        if (local->ops->set_tsf)
-               local->ops->set_tsf(&local->hw, tsf);
+               local->ops->set_tsf(&local->hw, &sdata->vif, tsf);
        trace_drv_return_void(local);
 }
 
-static inline void drv_reset_tsf(struct ieee80211_local *local)
+static inline void drv_reset_tsf(struct ieee80211_local *local,
+                                struct ieee80211_sub_if_data *sdata)
 {
        might_sleep();
 
-       trace_drv_reset_tsf(local);
+       trace_drv_reset_tsf(local, sdata);
        if (local->ops->reset_tsf)
-               local->ops->reset_tsf(&local->hw);
+               local->ops->reset_tsf(&local->hw, &sdata->vif);
        trace_drv_return_void(local);
 }
 
index f47b00dc7afd839017a4a485b3ced5149dd9e6b9..a46b279bbbe422d5a0f097879534232ac53f122a 100644 (file)
@@ -697,64 +697,76 @@ TRACE_EVENT(drv_sta_remove,
 );
 
 TRACE_EVENT(drv_conf_tx,
-       TP_PROTO(struct ieee80211_local *local, u16 queue,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u16 queue,
                 const struct ieee80211_tx_queue_params *params),
 
-       TP_ARGS(local, queue, params),
+       TP_ARGS(local, sdata, queue, params),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(u16, queue)
                __field(u16, txop)
                __field(u16, cw_min)
                __field(u16, cw_max)
                __field(u8, aifs)
+               __field(bool, uapsd)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->queue = queue;
                __entry->txop = params->txop;
                __entry->cw_max = params->cw_max;
                __entry->cw_min = params->cw_min;
                __entry->aifs = params->aifs;
+               __entry->uapsd = params->uapsd;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " queue:%d",
-               LOCAL_PR_ARG, __entry->queue
+               LOCAL_PR_FMT  VIF_PR_FMT  " queue:%d",
+               LOCAL_PR_ARG, VIF_PR_ARG, __entry->queue
        )
 );
 
-DEFINE_EVENT(local_only_evt, drv_get_tsf,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_get_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
 );
 
 TRACE_EVENT(drv_set_tsf,
-       TP_PROTO(struct ieee80211_local *local, u64 tsf),
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                u64 tsf),
 
-       TP_ARGS(local, tsf),
+       TP_ARGS(local, sdata, tsf),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(u64, tsf)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->tsf = tsf;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " tsf:%llu",
-               LOCAL_PR_ARG, (unsigned long long)__entry->tsf
+               LOCAL_PR_FMT  VIF_PR_FMT  " tsf:%llu",
+               LOCAL_PR_ARG, VIF_PR_ARG, (unsigned long long)__entry->tsf
        )
 );
 
-DEFINE_EVENT(local_only_evt, drv_reset_tsf,
-       TP_PROTO(struct ieee80211_local *local),
-       TP_ARGS(local)
+DEFINE_EVENT(local_sdata_evt, drv_reset_tsf,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
 );
 
 DEFINE_EVENT(local_only_evt, drv_tx_last_beacon,
index 4f9235b18a03231b643e9b4425b98f0f51fe8186..41f16dd1a2b030ce4c70a24a099201e48df6a48b 100644 (file)
@@ -81,7 +81,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        lockdep_assert_held(&ifibss->mtx);
 
        /* Reset own TSF to allow time synchronization work. */
-       drv_reset_tsf(local);
+       drv_reset_tsf(local, sdata);
 
        skb = ifibss->skb;
        RCU_INIT_POINTER(ifibss->presp, NULL);
@@ -382,7 +382,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                 * second best option: get current TSF
                 * (will return -1 if not supported)
                 */
-               rx_timestamp = drv_get_tsf(local);
+               rx_timestamp = drv_get_tsf(local, sdata);
        }
 
 #ifdef CONFIG_MAC80211_IBSS_DEBUG
@@ -417,7 +417,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
  * must be callable in atomic context.
  */
 struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-                                       u8 *bssid,u8 *addr, u32 supp_rates,
+                                       u8 *bssid, u8 *addr, u32 supp_rates,
                                        gfp_t gfp)
 {
        struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
index 21186e280ceb11e50f47446f83e203e387ba4dd5..5cadcbbc9a5786e45653a92588487692dbb407c1 100644 (file)
@@ -609,6 +609,8 @@ struct ieee80211_sub_if_data {
        __be16 control_port_protocol;
        bool control_port_no_encrypt;
 
+       struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
+
        struct work_struct work;
        struct sk_buff_head skb_queue;
 
@@ -751,7 +753,6 @@ struct ieee80211_local {
        struct workqueue_struct *workqueue;
 
        unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
-       struct ieee80211_tx_queue_params tx_conf[IEEE80211_MAX_QUEUES];
        /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
        spinlock_t queue_stop_reason_lock;
 
@@ -1324,7 +1325,7 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
-                             u32 ratemask, bool directed);
+                             u32 ratemask, bool directed, bool no_cck);
 
 void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
                                  const size_t supp_rates_len,
index a33c58f5137c0c8832dcc20a84e5cf8fbb8c4d04..f4350262663f84d2c931ffd589893a91925c0ed0 100644 (file)
@@ -460,17 +460,15 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
                synchronize_rcu();
                kfree(old_beacon);
 
-               /* free all potentially still buffered bcast frames */
-               while ((skb = skb_dequeue(&sdata->u.ap.ps_bc_buf))) {
-                       local->total_ps_buffered--;
-                       dev_kfree_skb(skb);
-               }
-
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
                                         u.vlan.list)
                        dev_close(vlan->dev);
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
+
+               /* free all potentially still buffered bcast frames */
+               local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps_bc_buf);
+               skb_queue_purge(&sdata->u.ap.ps_bc_buf);
        }
 
        if (going_down)
index 4396906175ae22c00d55978171b4040632d72011..1213a23ff0fa7e28cfb547bbbcb29855891974f2 100644 (file)
@@ -43,6 +43,10 @@ enum plink_event {
        CLS_IGNR
 };
 
+static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata,
+               enum ieee80211_self_protected_actioncode action,
+               u8 *da, __le16 llid, __le16 plid, __le16 reason);
+
 static inline
 void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata)
 {
@@ -133,6 +137,10 @@ void mesh_plink_deactivate(struct sta_info *sta)
 
        spin_lock_bh(&sta->lock);
        deactivated = __mesh_plink_deactivate(sta);
+       sta->reason = cpu_to_le16(WLAN_REASON_MESH_PEER_CANCELED);
+       mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
+                           sta->sta.addr, sta->llid, sta->plid,
+                           sta->reason);
        spin_unlock_bh(&sta->lock);
 
        if (deactivated)
index 2f92ae2f9706c30ad0ddb3fa53cdd3193a9b1b51..cd37a4e3c0d7765f350b4792ed46acf2908c99cf 100644 (file)
@@ -160,7 +160,8 @@ static int ecw2cw(int ecw)
  */
 static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                               struct ieee80211_ht_info *hti,
-                              const u8 *bssid, u16 ap_ht_cap_flags)
+                              const u8 *bssid, u16 ap_ht_cap_flags,
+                              bool beacon_htcap_ie)
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
@@ -232,6 +233,21 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
        }
 
+       if (beacon_htcap_ie && (prev_chantype != channel_type)) {
+               /*
+                * Whenever the AP announces the HT mode change that can be
+                * 40MHz intolerant or etc., it would be safer to stop tx
+                * queues before doing hw config to avoid buffer overflow.
+                */
+               ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+
+               /* flush out all packets */
+               synchronize_net();
+
+               drv_flush(local, false);
+       }
+
        /* channel_type change automatically detected */
        ieee80211_hw_config(local, 0);
 
@@ -243,6 +259,10 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                                                 IEEE80211_RC_HT_CHANGED,
                                                 channel_type);
                rcu_read_unlock();
+
+               if (beacon_htcap_ie)
+                       ieee80211_wake_queues_by_reason(&sdata->local->hw,
+                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
        }
 
        ht_opmode = le16_to_cpu(hti->operation_mode);
@@ -916,8 +936,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                            params.aifs, params.cw_min, params.cw_max,
                            params.txop, params.uapsd);
 #endif
-               local->tx_conf[queue] = params;
-               if (drv_conf_tx(local, queue, &params))
+               sdata->tx_conf[queue] = params;
+               if (drv_conf_tx(local, sdata, queue, &params))
                        wiphy_debug(local->hw.wiphy,
                                    "failed to set TX queue parameters for queue %d\n",
                                    queue);
@@ -1219,7 +1239,7 @@ static void ieee80211_mgd_probe_ap_send(struct ieee80211_sub_if_data *sdata)
        } else {
                ssid = ieee80211_bss_get_ie(ifmgd->associated, WLAN_EID_SSID);
                ieee80211_send_probe_req(sdata, dst, ssid + 2, ssid[1], NULL, 0,
-                                        (u32) -1, true);
+                                        (u32) -1, true, false);
        }
 
        ifmgd->probe_send_count++;
@@ -1588,7 +1608,8 @@ static bool ieee80211_assoc_success(struct ieee80211_work *wk,
            (sdata->local->hw.queues >= 4) &&
            !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-                                              cbss->bssid, ap_ht_cap_flags);
+                                              cbss->bssid, ap_ht_cap_flags,
+                                              false);
 
        /* set AID and assoc capability,
         * ieee80211_set_associated() will tell the driver */
@@ -1921,24 +1942,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
                rcu_read_unlock();
 
-               /*
-                * Whenever the AP announces the HT mode change that can be
-                * 40MHz intolerant or etc., it would be safer to stop tx
-                * queues before doing hw config to avoid buffer overflow.
-                */
-               ieee80211_stop_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
-
-               /* flush out all packets */
-               synchronize_net();
-
-               drv_flush(local, false);
-
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
-                                              bssid, ap_ht_cap_flags);
-
-               ieee80211_wake_queues_by_reason(&sdata->local->hw,
-                               IEEE80211_QUEUE_STOP_REASON_CHTYPE_CHANGE);
+                                              bssid, ap_ht_cap_flags, true);
        }
 
        /* Note: country IE parsing is done for us by cfg80211 */
index 3d5a2cb835c4203bb8cc4e768df7f7705594ee21..f61244c0e0a267422109227e3aab63e4be1eba63 100644 (file)
@@ -233,6 +233,27 @@ static void rc_send_low_broadcast(s8 *idx, u32 basic_rates,
        /* could not find a basic rate; use original selection */
 }
 
+static inline s8
+rate_lowest_non_cck_index(struct ieee80211_supported_band *sband,
+                         struct ieee80211_sta *sta)
+{
+       int i;
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               struct ieee80211_rate *srate = &sband->bitrates[i];
+               if ((srate->bitrate == 10) || (srate->bitrate == 20) ||
+                   (srate->bitrate == 55) || (srate->bitrate == 110))
+                       continue;
+
+               if (rate_supported(sta, sband->band, i))
+                       return i;
+       }
+
+       /* No matching rate found */
+       return 0;
+}
+
+
 bool rate_control_send_low(struct ieee80211_sta *sta,
                           void *priv_sta,
                           struct ieee80211_tx_rate_control *txrc)
@@ -242,7 +263,13 @@ bool rate_control_send_low(struct ieee80211_sta *sta,
        int mcast_rate;
 
        if (!sta || !priv_sta || rc_no_data_or_no_ack(txrc)) {
-               info->control.rates[0].idx = rate_lowest_index(txrc->sband, sta);
+               if ((sband->band != IEEE80211_BAND_2GHZ) ||
+                   !(info->flags & IEEE80211_TX_CTL_NO_CCK_RATE))
+                       info->control.rates[0].idx =
+                               rate_lowest_index(txrc->sband, sta);
+               else
+                       info->control.rates[0].idx =
+                               rate_lowest_non_cck_index(txrc->sband, sta);
                info->control.rates[0].count =
                        (info->flags & IEEE80211_TX_CTL_NO_ACK) ?
                        1 : txrc->hw->max_rate_tries;
index 6f09eca011123de5dac20d3fed5f6712200fd112..830e60f65779670ab8539256d3db3f1814c25a4e 100644 (file)
@@ -660,7 +660,8 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
                        local->scan_req->ssids[i].ssid,
                        local->scan_req->ssids[i].ssid_len,
                        local->scan_req->ie, local->scan_req->ie_len,
-                       local->scan_req->rates[band], false);
+                       local->scan_req->rates[band], false,
+                       local->scan_req->no_cck);
 
        /*
         * After sending probe requests, wait for probe responses
index 4b1466d5b6a1da6bbbe286765c805d445c6465b8..2c9dc360dc6dc08c166104ba79e950c9b5a4fbe4 100644 (file)
@@ -632,8 +632,8 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
 
                qparam.uapsd = false;
 
-               local->tx_conf[queue] = qparam;
-               drv_conf_tx(local, queue, &qparam);
+               sdata->tx_conf[queue] = qparam;
+               drv_conf_tx(local, sdata, queue, &qparam);
        }
 
        /* after reinitialize QoS TX queues setting to default,
@@ -899,14 +899,18 @@ struct sk_buff *ieee80211_build_probe_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
                              const u8 *ssid, size_t ssid_len,
                              const u8 *ie, size_t ie_len,
-                             u32 ratemask, bool directed)
+                             u32 ratemask, bool directed, bool no_cck)
 {
        struct sk_buff *skb;
 
        skb = ieee80211_build_probe_req(sdata, dst, ratemask, ssid, ssid_len,
                                        ie, ie_len, directed);
-       if (skb)
+       if (skb) {
+               if (no_cck)
+                       IEEE80211_SKB_CB(skb)->flags |=
+                               IEEE80211_TX_CTL_NO_CCK_RATE;
                ieee80211_tx_skb(sdata, skb);
+       }
 }
 
 u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
@@ -1040,8 +1044,15 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        mutex_unlock(&local->sta_mtx);
 
        /* reconfigure tx conf */
-       for (i = 0; i < hw->queues; i++)
-               drv_conf_tx(local, i, &local->tx_conf[i]);
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN ||
+                   sdata->vif.type == NL80211_IFTYPE_MONITOR ||
+                   !ieee80211_sdata_running(sdata))
+                       continue;
+
+               for (i = 0; i < hw->queues; i++)
+                       drv_conf_tx(local, sdata, i, &sdata->tx_conf[i]);
+       }
 
        /* reconfigure hardware */
        ieee80211_hw_config(local, ~0);
index bac34394c05ef9262e41df4bc1ce2bda6dcb188f..af374fab1a12b247ccd40dea0c2a8994dd2dc732 100644 (file)
@@ -458,7 +458,7 @@ ieee80211_direct_probe(struct ieee80211_work *wk)
         */
        ieee80211_send_probe_req(sdata, NULL, wk->probe_auth.ssid,
                                 wk->probe_auth.ssid_len, NULL, 0,
-                                (u32) -1, true);
+                                (u32) -1, true, false);
 
        wk->timeout = jiffies + IEEE80211_AUTH_TIMEOUT;
        run_again(local, wk->timeout);
index 33e095b124b323f93a94b873121f7a89e579bf24..58cddadf8e8e2dfb5a915d621bebdc42b032609e 100644 (file)
@@ -13,4 +13,6 @@ menuconfig NFC
          To compile this support as a module, choose M here: the module will
          be called nfc.
 
+source "net/nfc/nci/Kconfig"
+
 source "drivers/nfc/Kconfig"
index 16250c3538519bbc724d9ebdf9ea629fc576daa5..fbb550f2377b9298f755ee5a63428d9f93a06b69 100644 (file)
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_NFC) += nfc.o
+obj-$(CONFIG_NFC_NCI) += nci/
 
 nfc-objs := core.o netlink.o af_nfc.o rawsock.o
index 284e2f6a14ff490f287354bdd60058b87123d475..47e02c1b8c02eea81a67f4432e6d45311ba6bd73 100644 (file)
@@ -52,6 +52,80 @@ int nfc_printk(const char *level, const char *format, ...)
 }
 EXPORT_SYMBOL(nfc_printk);
 
+/**
+ * nfc_dev_up - turn on the NFC device
+ *
+ * @dev: The nfc device to be turned on
+ *
+ * The device remains up until the nfc_dev_down function is called.
+ */
+int nfc_dev_up(struct nfc_dev *dev)
+{
+       int rc = 0;
+
+       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+
+       device_lock(&dev->dev);
+
+       if (!device_is_registered(&dev->dev)) {
+               rc = -ENODEV;
+               goto error;
+       }
+
+       if (dev->dev_up) {
+               rc = -EALREADY;
+               goto error;
+       }
+
+       if (dev->ops->dev_up)
+               rc = dev->ops->dev_up(dev);
+
+       if (!rc)
+               dev->dev_up = true;
+
+error:
+       device_unlock(&dev->dev);
+       return rc;
+}
+
+/**
+ * nfc_dev_down - turn off the NFC device
+ *
+ * @dev: The nfc device to be turned off
+ */
+int nfc_dev_down(struct nfc_dev *dev)
+{
+       int rc = 0;
+
+       nfc_dbg("dev_name=%s", dev_name(&dev->dev));
+
+       device_lock(&dev->dev);
+
+       if (!device_is_registered(&dev->dev)) {
+               rc = -ENODEV;
+               goto error;
+       }
+
+       if (!dev->dev_up) {
+               rc = -EALREADY;
+               goto error;
+       }
+
+       if (dev->polling || dev->remote_activated) {
+               rc = -EBUSY;
+               goto error;
+       }
+
+       if (dev->ops->dev_down)
+               dev->ops->dev_down(dev);
+
+       dev->dev_up = false;
+
+error:
+       device_unlock(&dev->dev);
+       return rc;
+}
+
 /**
  * nfc_start_poll - start polling for nfc targets
  *
@@ -144,6 +218,8 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
        }
 
        rc = dev->ops->activate_target(dev, target_idx, protocol);
+       if (!rc)
+               dev->remote_activated = true;
 
 error:
        device_unlock(&dev->dev);
@@ -170,6 +246,7 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
        }
 
        dev->ops->deactivate_target(dev, target_idx);
+       dev->remote_activated = false;
 
 error:
        device_unlock(&dev->dev);
diff --git a/net/nfc/nci/Kconfig b/net/nfc/nci/Kconfig
new file mode 100644 (file)
index 0000000..decdc49
--- /dev/null
@@ -0,0 +1,10 @@
+config NFC_NCI
+       depends on NFC && EXPERIMENTAL
+       tristate "NCI protocol support (EXPERIMENTAL)"
+       default n
+       help
+         NCI (NFC Controller Interface) is a communication protocol between
+         an NFC Controller (NFCC) and a Device Host (DH).
+
+         Say Y here to compile NCI support into the kernel or say M to
+         compile it as module (nci).
diff --git a/net/nfc/nci/Makefile b/net/nfc/nci/Makefile
new file mode 100644 (file)
index 0000000..cdb3a2e
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux NFC NCI layer.
+#
+
+obj-$(CONFIG_NFC_NCI) += nci.o
+
+nci-objs := core.o data.o lib.o ntf.o rsp.o
\ No newline at end of file
diff --git a/net/nfc/nci/core.c b/net/nfc/nci/core.c
new file mode 100644 (file)
index 0000000..4047e29
--- /dev/null
@@ -0,0 +1,797 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_core.c, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/nfc.h>
+
+static void nci_cmd_work(struct work_struct *work);
+static void nci_rx_work(struct work_struct *work);
+static void nci_tx_work(struct work_struct *work);
+
+/* ---- NCI requests ---- */
+
+void nci_req_complete(struct nci_dev *ndev, int result)
+{
+       if (ndev->req_status == NCI_REQ_PEND) {
+               ndev->req_result = result;
+               ndev->req_status = NCI_REQ_DONE;
+               complete(&ndev->req_completion);
+       }
+}
+
+static void nci_req_cancel(struct nci_dev *ndev, int err)
+{
+       if (ndev->req_status == NCI_REQ_PEND) {
+               ndev->req_result = err;
+               ndev->req_status = NCI_REQ_CANCELED;
+               complete(&ndev->req_completion);
+       }
+}
+
+/* Execute request and wait for completion. */
+static int __nci_request(struct nci_dev *ndev,
+       void (*req)(struct nci_dev *ndev, unsigned long opt),
+       unsigned long opt,
+       __u32 timeout)
+{
+       int rc = 0;
+       unsigned long completion_rc;
+
+       ndev->req_status = NCI_REQ_PEND;
+
+       init_completion(&ndev->req_completion);
+       req(ndev, opt);
+       completion_rc = wait_for_completion_interruptible_timeout(
+                                                       &ndev->req_completion,
+                                                       timeout);
+
+       nfc_dbg("wait_for_completion return %ld", completion_rc);
+
+       if (completion_rc > 0) {
+               switch (ndev->req_status) {
+               case NCI_REQ_DONE:
+                       rc = nci_to_errno(ndev->req_result);
+                       break;
+
+               case NCI_REQ_CANCELED:
+                       rc = -ndev->req_result;
+                       break;
+
+               default:
+                       rc = -ETIMEDOUT;
+                       break;
+               }
+       } else {
+               nfc_err("wait_for_completion_interruptible_timeout failed %ld",
+                       completion_rc);
+
+               rc = ((completion_rc == 0) ? (-ETIMEDOUT) : (completion_rc));
+       }
+
+       ndev->req_status = ndev->req_result = 0;
+
+       return rc;
+}
+
+static inline int nci_request(struct nci_dev *ndev,
+               void (*req)(struct nci_dev *ndev, unsigned long opt),
+               unsigned long opt, __u32 timeout)
+{
+       int rc;
+
+       if (!test_bit(NCI_UP, &ndev->flags))
+               return -ENETDOWN;
+
+       /* Serialize all requests */
+       mutex_lock(&ndev->req_lock);
+       rc = __nci_request(ndev, req, opt, timeout);
+       mutex_unlock(&ndev->req_lock);
+
+       return rc;
+}
+
+static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
+{
+       nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 0, NULL);
+}
+
+static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
+{
+       nci_send_cmd(ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
+}
+
+static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
+{
+       struct nci_core_conn_create_cmd conn_cmd;
+       struct nci_rf_disc_map_cmd cmd;
+       struct disc_map_config *cfg = cmd.mapping_configs;
+       __u8 *num = &cmd.num_mapping_configs;
+       int i;
+
+       /* create static rf connection */
+       conn_cmd.target_handle = 0;
+       conn_cmd.num_target_specific_params = 0;
+       nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, 2, &conn_cmd);
+
+       /* set rf mapping configurations */
+       *num = 0;
+
+       /* by default mapping is set to NCI_RF_INTERFACE_FRAME */
+       for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
+               if (ndev->supported_rf_interfaces[i] ==
+                       NCI_RF_INTERFACE_ISO_DEP) {
+                       cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
+                       cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+                       cfg[*num].rf_interface_type = NCI_RF_INTERFACE_ISO_DEP;
+                       (*num)++;
+               } else if (ndev->supported_rf_interfaces[i] ==
+                       NCI_RF_INTERFACE_NFC_DEP) {
+                       cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
+                       cfg[*num].mode = NCI_DISC_MAP_MODE_BOTH;
+                       cfg[*num].rf_interface_type = NCI_RF_INTERFACE_NFC_DEP;
+                       (*num)++;
+               }
+
+               if (*num == NCI_MAX_NUM_MAPPING_CONFIGS)
+                       break;
+       }
+
+       nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
+               (1 + ((*num)*sizeof(struct disc_map_config))),
+               &cmd);
+}
+
+static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
+{
+       struct nci_rf_disc_cmd cmd;
+       __u32 protocols = opt;
+
+       cmd.num_disc_configs = 0;
+
+       if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
+               (protocols & NFC_PROTO_JEWEL_MASK
+               || protocols & NFC_PROTO_MIFARE_MASK
+               || protocols & NFC_PROTO_ISO14443_MASK
+               || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+               cmd.disc_configs[cmd.num_disc_configs].type =
+               NCI_DISCOVERY_TYPE_POLL_A_PASSIVE;
+               cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
+               cmd.num_disc_configs++;
+       }
+
+       if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
+               (protocols & NFC_PROTO_ISO14443_MASK)) {
+               cmd.disc_configs[cmd.num_disc_configs].type =
+               NCI_DISCOVERY_TYPE_POLL_B_PASSIVE;
+               cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
+               cmd.num_disc_configs++;
+       }
+
+       if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
+               (protocols & NFC_PROTO_FELICA_MASK
+               || protocols & NFC_PROTO_NFC_DEP_MASK)) {
+               cmd.disc_configs[cmd.num_disc_configs].type =
+               NCI_DISCOVERY_TYPE_POLL_F_PASSIVE;
+               cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
+               cmd.num_disc_configs++;
+       }
+
+       nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
+               (1 + (cmd.num_disc_configs*sizeof(struct disc_config))),
+               &cmd);
+}
+
+static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
+{
+       struct nci_rf_deactivate_cmd cmd;
+
+       cmd.type = NCI_DEACTIVATE_TYPE_IDLE_MODE;
+
+       nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
+                       sizeof(struct nci_rf_deactivate_cmd),
+                       &cmd);
+}
+
+static int nci_open_device(struct nci_dev *ndev)
+{
+       int rc = 0;
+
+       mutex_lock(&ndev->req_lock);
+
+       if (test_bit(NCI_UP, &ndev->flags)) {
+               rc = -EALREADY;
+               goto done;
+       }
+
+       if (ndev->ops->open(ndev)) {
+               rc = -EIO;
+               goto done;
+       }
+
+       atomic_set(&ndev->cmd_cnt, 1);
+
+       set_bit(NCI_INIT, &ndev->flags);
+
+       rc = __nci_request(ndev, nci_reset_req, 0,
+                               msecs_to_jiffies(NCI_RESET_TIMEOUT));
+
+       if (!rc) {
+               rc = __nci_request(ndev, nci_init_req, 0,
+                               msecs_to_jiffies(NCI_INIT_TIMEOUT));
+       }
+
+       if (!rc) {
+               rc = __nci_request(ndev, nci_init_complete_req, 0,
+                               msecs_to_jiffies(NCI_INIT_TIMEOUT));
+       }
+
+       clear_bit(NCI_INIT, &ndev->flags);
+
+       if (!rc) {
+               set_bit(NCI_UP, &ndev->flags);
+       } else {
+               /* Init failed, cleanup */
+               skb_queue_purge(&ndev->cmd_q);
+               skb_queue_purge(&ndev->rx_q);
+               skb_queue_purge(&ndev->tx_q);
+
+               ndev->ops->close(ndev);
+               ndev->flags = 0;
+       }
+
+done:
+       mutex_unlock(&ndev->req_lock);
+       return rc;
+}
+
+static int nci_close_device(struct nci_dev *ndev)
+{
+       nci_req_cancel(ndev, ENODEV);
+       mutex_lock(&ndev->req_lock);
+
+       if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
+               del_timer_sync(&ndev->cmd_timer);
+               mutex_unlock(&ndev->req_lock);
+               return 0;
+       }
+
+       /* Drop RX and TX queues */
+       skb_queue_purge(&ndev->rx_q);
+       skb_queue_purge(&ndev->tx_q);
+
+       /* Flush RX and TX wq */
+       flush_workqueue(ndev->rx_wq);
+       flush_workqueue(ndev->tx_wq);
+
+       /* Reset device */
+       skb_queue_purge(&ndev->cmd_q);
+       atomic_set(&ndev->cmd_cnt, 1);
+
+       set_bit(NCI_INIT, &ndev->flags);
+       __nci_request(ndev, nci_reset_req, 0,
+                               msecs_to_jiffies(NCI_RESET_TIMEOUT));
+       clear_bit(NCI_INIT, &ndev->flags);
+
+       /* Flush cmd wq */
+       flush_workqueue(ndev->cmd_wq);
+
+       /* After this point our queues are empty
+        * and no works are scheduled. */
+       ndev->ops->close(ndev);
+
+       /* Clear flags */
+       ndev->flags = 0;
+
+       mutex_unlock(&ndev->req_lock);
+
+       return 0;
+}
+
+/* NCI command timer function */
+static void nci_cmd_timer(unsigned long arg)
+{
+       struct nci_dev *ndev = (void *) arg;
+
+       nfc_dbg("entry");
+
+       atomic_set(&ndev->cmd_cnt, 1);
+       queue_work(ndev->cmd_wq, &ndev->cmd_work);
+}
+
+static int nci_dev_up(struct nfc_dev *nfc_dev)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dbg("entry");
+
+       return nci_open_device(ndev);
+}
+
+static int nci_dev_down(struct nfc_dev *nfc_dev)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dbg("entry");
+
+       return nci_close_device(ndev);
+}
+
+static int nci_start_poll(struct nfc_dev *nfc_dev, __u32 protocols)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+       int rc;
+
+       nfc_dbg("entry");
+
+       if (test_bit(NCI_DISCOVERY, &ndev->flags)) {
+               nfc_err("unable to start poll, since poll is already active");
+               return -EBUSY;
+       }
+
+       if (ndev->target_active_prot) {
+               nfc_err("there is an active target");
+               return -EBUSY;
+       }
+
+       if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+               nfc_dbg("target is active, implicitly deactivate...");
+
+               rc = nci_request(ndev, nci_rf_deactivate_req, 0,
+                       msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+               if (rc)
+                       return -EBUSY;
+       }
+
+       rc = nci_request(ndev, nci_rf_discover_req, protocols,
+               msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
+
+       if (!rc)
+               ndev->poll_prots = protocols;
+
+       return rc;
+}
+
+static void nci_stop_poll(struct nfc_dev *nfc_dev)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dbg("entry");
+
+       if (!test_bit(NCI_DISCOVERY, &ndev->flags)) {
+               nfc_err("unable to stop poll, since poll is not active");
+               return;
+       }
+
+       nci_request(ndev, nci_rf_deactivate_req, 0,
+               msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+}
+
+static int nci_activate_target(struct nfc_dev *nfc_dev, __u32 target_idx,
+                               __u32 protocol)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dbg("entry, target_idx %d, protocol 0x%x", target_idx, protocol);
+
+       if (!test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+               nfc_err("there is no available target to activate");
+               return -EINVAL;
+       }
+
+       if (ndev->target_active_prot) {
+               nfc_err("there is already an active target");
+               return -EBUSY;
+       }
+
+       if (!(ndev->target_available_prots & (1 << protocol))) {
+               nfc_err("target does not support the requested protocol 0x%x",
+                       protocol);
+               return -EINVAL;
+       }
+
+       ndev->target_active_prot = protocol;
+       ndev->target_available_prots = 0;
+
+       return 0;
+}
+
+static void nci_deactivate_target(struct nfc_dev *nfc_dev, __u32 target_idx)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+
+       nfc_dbg("entry, target_idx %d", target_idx);
+
+       if (!ndev->target_active_prot) {
+               nfc_err("unable to deactivate target, no active target");
+               return;
+       }
+
+       ndev->target_active_prot = 0;
+
+       if (test_bit(NCI_POLL_ACTIVE, &ndev->flags)) {
+               nci_request(ndev, nci_rf_deactivate_req, 0,
+                       msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
+       }
+}
+
+static int nci_data_exchange(struct nfc_dev *nfc_dev, __u32 target_idx,
+                                               struct sk_buff *skb,
+                                               data_exchange_cb_t cb,
+                                               void *cb_context)
+{
+       struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
+       int rc;
+
+       nfc_dbg("entry, target_idx %d, len %d", target_idx, skb->len);
+
+       if (!ndev->target_active_prot) {
+               nfc_err("unable to exchange data, no active target");
+               return -EINVAL;
+       }
+
+       if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+               return -EBUSY;
+
+       /* store cb and context to be used on receiving data */
+       ndev->data_exchange_cb = cb;
+       ndev->data_exchange_cb_context = cb_context;
+
+       rc = nci_send_data(ndev, ndev->conn_id, skb);
+       if (rc)
+               clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+
+       return rc;
+}
+
+static struct nfc_ops nci_nfc_ops = {
+       .dev_up = nci_dev_up,
+       .dev_down = nci_dev_down,
+       .start_poll = nci_start_poll,
+       .stop_poll = nci_stop_poll,
+       .activate_target = nci_activate_target,
+       .deactivate_target = nci_deactivate_target,
+       .data_exchange = nci_data_exchange,
+};
+
+/* ---- Interface to NCI drivers ---- */
+
+/**
+ * nci_allocate_device - allocate a new nci device
+ *
+ * @ops: device operations
+ * @supported_protocols: NFC protocols supported by the device
+ */
+struct nci_dev *nci_allocate_device(struct nci_ops *ops,
+                                       __u32 supported_protocols,
+                                       int tx_headroom,
+                                       int tx_tailroom)
+{
+       struct nci_dev *ndev;
+
+       nfc_dbg("entry, supported_protocols 0x%x", supported_protocols);
+
+       if (!ops->open || !ops->close || !ops->send)
+               return NULL;
+
+       if (!supported_protocols)
+               return NULL;
+
+       ndev = kzalloc(sizeof(struct nci_dev), GFP_KERNEL);
+       if (!ndev)
+               return NULL;
+
+       ndev->ops = ops;
+       ndev->tx_headroom = tx_headroom;
+       ndev->tx_tailroom = tx_tailroom;
+
+       ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
+                                               supported_protocols,
+                                               tx_headroom + NCI_DATA_HDR_SIZE,
+                                               tx_tailroom);
+       if (!ndev->nfc_dev)
+               goto free_exit;
+
+       nfc_set_drvdata(ndev->nfc_dev, ndev);
+
+       return ndev;
+
+free_exit:
+       kfree(ndev);
+       return NULL;
+}
+EXPORT_SYMBOL(nci_allocate_device);
+
+/**
+ * nci_free_device - deallocate nci device
+ *
+ * @ndev: The nci device to deallocate
+ */
+void nci_free_device(struct nci_dev *ndev)
+{
+       nfc_dbg("entry");
+
+       nfc_free_device(ndev->nfc_dev);
+       kfree(ndev);
+}
+EXPORT_SYMBOL(nci_free_device);
+
+/**
+ * nci_register_device - register a nci device in the nfc subsystem
+ *
+ * @dev: The nci device to register
+ */
+int nci_register_device(struct nci_dev *ndev)
+{
+       int rc;
+       struct device *dev = &ndev->nfc_dev->dev;
+       char name[32];
+
+       nfc_dbg("entry");
+
+       rc = nfc_register_device(ndev->nfc_dev);
+       if (rc)
+               goto exit;
+
+       ndev->flags = 0;
+
+       INIT_WORK(&ndev->cmd_work, nci_cmd_work);
+       snprintf(name, sizeof(name), "%s_nci_cmd_wq", dev_name(dev));
+       ndev->cmd_wq = create_singlethread_workqueue(name);
+       if (!ndev->cmd_wq) {
+               rc = -ENOMEM;
+               goto unreg_exit;
+       }
+
+       INIT_WORK(&ndev->rx_work, nci_rx_work);
+       snprintf(name, sizeof(name), "%s_nci_rx_wq", dev_name(dev));
+       ndev->rx_wq = create_singlethread_workqueue(name);
+       if (!ndev->rx_wq) {
+               rc = -ENOMEM;
+               goto destroy_cmd_wq_exit;
+       }
+
+       INIT_WORK(&ndev->tx_work, nci_tx_work);
+       snprintf(name, sizeof(name), "%s_nci_tx_wq", dev_name(dev));
+       ndev->tx_wq = create_singlethread_workqueue(name);
+       if (!ndev->tx_wq) {
+               rc = -ENOMEM;
+               goto destroy_rx_wq_exit;
+       }
+
+       skb_queue_head_init(&ndev->cmd_q);
+       skb_queue_head_init(&ndev->rx_q);
+       skb_queue_head_init(&ndev->tx_q);
+
+       setup_timer(&ndev->cmd_timer, nci_cmd_timer,
+                       (unsigned long) ndev);
+
+       mutex_init(&ndev->req_lock);
+
+       goto exit;
+
+destroy_rx_wq_exit:
+       destroy_workqueue(ndev->rx_wq);
+
+destroy_cmd_wq_exit:
+       destroy_workqueue(ndev->cmd_wq);
+
+unreg_exit:
+       nfc_unregister_device(ndev->nfc_dev);
+
+exit:
+       return rc;
+}
+EXPORT_SYMBOL(nci_register_device);
+
+/**
+ * nci_unregister_device - unregister a nci device in the nfc subsystem
+ *
+ * @dev: The nci device to unregister
+ */
+void nci_unregister_device(struct nci_dev *ndev)
+{
+       nfc_dbg("entry");
+
+       nci_close_device(ndev);
+
+       destroy_workqueue(ndev->cmd_wq);
+       destroy_workqueue(ndev->rx_wq);
+       destroy_workqueue(ndev->tx_wq);
+
+       nfc_unregister_device(ndev->nfc_dev);
+}
+EXPORT_SYMBOL(nci_unregister_device);
+
+/**
+ * nci_recv_frame - receive frame from NCI drivers
+ *
+ * @skb: The sk_buff to receive
+ */
+int nci_recv_frame(struct sk_buff *skb)
+{
+       struct nci_dev *ndev = (struct nci_dev *) skb->dev;
+
+       nfc_dbg("entry, len %d", skb->len);
+
+       if (!ndev || (!test_bit(NCI_UP, &ndev->flags)
+               && !test_bit(NCI_INIT, &ndev->flags))) {
+               kfree_skb(skb);
+               return -ENXIO;
+       }
+
+       /* Queue frame for rx worker thread */
+       skb_queue_tail(&ndev->rx_q, skb);
+       queue_work(ndev->rx_wq, &ndev->rx_work);
+
+       return 0;
+}
+EXPORT_SYMBOL(nci_recv_frame);
+
+static int nci_send_frame(struct sk_buff *skb)
+{
+       struct nci_dev *ndev = (struct nci_dev *) skb->dev;
+
+       nfc_dbg("entry, len %d", skb->len);
+
+       if (!ndev) {
+               kfree_skb(skb);
+               return -ENODEV;
+       }
+
+       /* Get rid of skb owner, prior to sending to the driver. */
+       skb_orphan(skb);
+
+       return ndev->ops->send(skb);
+}
+
+/* Send NCI command */
+int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
+{
+       struct nci_ctrl_hdr *hdr;
+       struct sk_buff *skb;
+
+       nfc_dbg("entry, opcode 0x%x, plen %d", opcode, plen);
+
+       skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + plen), GFP_KERNEL);
+       if (!skb) {
+               nfc_err("no memory for command");
+               return -ENOMEM;
+       }
+
+       hdr = (struct nci_ctrl_hdr *) skb_put(skb, NCI_CTRL_HDR_SIZE);
+       hdr->gid = nci_opcode_gid(opcode);
+       hdr->oid = nci_opcode_oid(opcode);
+       hdr->plen = plen;
+
+       nci_mt_set((__u8 *)hdr, NCI_MT_CMD_PKT);
+       nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
+
+       if (plen)
+               memcpy(skb_put(skb, plen), payload, plen);
+
+       skb->dev = (void *) ndev;
+
+       skb_queue_tail(&ndev->cmd_q, skb);
+       queue_work(ndev->cmd_wq, &ndev->cmd_work);
+
+       return 0;
+}
+
+/* ---- NCI TX Data worker thread ---- */
+
+static void nci_tx_work(struct work_struct *work)
+{
+       struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
+       struct sk_buff *skb;
+
+       nfc_dbg("entry, credits_cnt %d", atomic_read(&ndev->credits_cnt));
+
+       /* Send queued tx data */
+       while (atomic_read(&ndev->credits_cnt)) {
+               skb = skb_dequeue(&ndev->tx_q);
+               if (!skb)
+                       return;
+
+               atomic_dec(&ndev->credits_cnt);
+
+               nfc_dbg("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d",
+                               nci_pbf(skb->data),
+                               nci_conn_id(skb->data),
+                               nci_plen(skb->data));
+
+               nci_send_frame(skb);
+       }
+}
+
+/* ----- NCI RX worker thread (data & control) ----- */
+
+static void nci_rx_work(struct work_struct *work)
+{
+       struct nci_dev *ndev = container_of(work, struct nci_dev, rx_work);
+       struct sk_buff *skb;
+
+       while ((skb = skb_dequeue(&ndev->rx_q))) {
+               /* Process frame */
+               switch (nci_mt(skb->data)) {
+               case NCI_MT_RSP_PKT:
+                       nci_rsp_packet(ndev, skb);
+                       break;
+
+               case NCI_MT_NTF_PKT:
+                       nci_ntf_packet(ndev, skb);
+                       break;
+
+               case NCI_MT_DATA_PKT:
+                       nci_rx_data_packet(ndev, skb);
+                       break;
+
+               default:
+                       nfc_err("unknown MT 0x%x", nci_mt(skb->data));
+                       kfree_skb(skb);
+                       break;
+               }
+       }
+}
+
+/* ----- NCI TX CMD worker thread ----- */
+
+static void nci_cmd_work(struct work_struct *work)
+{
+       struct nci_dev *ndev = container_of(work, struct nci_dev, cmd_work);
+       struct sk_buff *skb;
+
+       nfc_dbg("entry, cmd_cnt %d", atomic_read(&ndev->cmd_cnt));
+
+       /* Send queued command */
+       if (atomic_read(&ndev->cmd_cnt)) {
+               skb = skb_dequeue(&ndev->cmd_q);
+               if (!skb)
+                       return;
+
+               atomic_dec(&ndev->cmd_cnt);
+
+               nfc_dbg("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+                               nci_pbf(skb->data),
+                               nci_opcode_gid(nci_opcode(skb->data)),
+                               nci_opcode_oid(nci_opcode(skb->data)),
+                               nci_plen(skb->data));
+
+               nci_send_frame(skb);
+
+               mod_timer(&ndev->cmd_timer,
+                       jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
+       }
+}
diff --git a/net/nfc/nci/data.c b/net/nfc/nci/data.c
new file mode 100644 (file)
index 0000000..e5ed90f
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/wait.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/nfc.h>
+
+/* Complete data exchange transaction and forward skb to nfc core */
+void nci_data_exchange_complete(struct nci_dev *ndev,
+                               struct sk_buff *skb,
+                               int err)
+{
+       data_exchange_cb_t cb = ndev->data_exchange_cb;
+       void *cb_context = ndev->data_exchange_cb_context;
+
+       nfc_dbg("entry, len %d, err %d", ((skb) ? (skb->len) : (0)), err);
+
+       if (cb) {
+               ndev->data_exchange_cb = NULL;
+               ndev->data_exchange_cb_context = 0;
+
+               /* forward skb to nfc core */
+               cb(cb_context, skb, err);
+       } else if (skb) {
+               nfc_err("no rx callback, dropping rx data...");
+
+               /* no waiting callback, free skb */
+               kfree_skb(skb);
+       }
+
+       clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
+}
+
+/* ----------------- NCI TX Data ----------------- */
+
+static inline void nci_push_data_hdr(struct nci_dev *ndev,
+                                       __u8 conn_id,
+                                       struct sk_buff *skb,
+                                       __u8 pbf)
+{
+       struct nci_data_hdr *hdr;
+       int plen = skb->len;
+
+       hdr = (struct nci_data_hdr *) skb_push(skb, NCI_DATA_HDR_SIZE);
+       hdr->conn_id = conn_id;
+       hdr->rfu = 0;
+       hdr->plen = plen;
+
+       nci_mt_set((__u8 *)hdr, NCI_MT_DATA_PKT);
+       nci_pbf_set((__u8 *)hdr, pbf);
+
+       skb->dev = (void *) ndev;
+}
+
+static int nci_queue_tx_data_frags(struct nci_dev *ndev,
+                                       __u8 conn_id,
+                                       struct sk_buff *skb) {
+       int total_len = skb->len;
+       unsigned char *data = skb->data;
+       unsigned long flags;
+       struct sk_buff_head frags_q;
+       struct sk_buff *skb_frag;
+       int frag_len;
+       int rc = 0;
+
+       nfc_dbg("entry, conn_id 0x%x, total_len %d", conn_id, total_len);
+
+       __skb_queue_head_init(&frags_q);
+
+       while (total_len) {
+               frag_len = min_t(int, total_len, ndev->max_pkt_payload_size);
+
+               skb_frag = nci_skb_alloc(ndev,
+                                       (NCI_DATA_HDR_SIZE + frag_len),
+                                       GFP_KERNEL);
+               if (skb_frag == NULL) {
+                       rc = -ENOMEM;
+                       goto free_exit;
+               }
+               skb_reserve(skb_frag, NCI_DATA_HDR_SIZE);
+
+               /* first, copy the data */
+               memcpy(skb_put(skb_frag, frag_len), data, frag_len);
+
+               /* second, set the header */
+               nci_push_data_hdr(ndev, conn_id, skb_frag,
+               ((total_len == frag_len) ? (NCI_PBF_LAST) : (NCI_PBF_CONT)));
+
+               __skb_queue_tail(&frags_q, skb_frag);
+
+               data += frag_len;
+               total_len -= frag_len;
+
+               nfc_dbg("frag_len %d, remaining total_len %d",
+                       frag_len, total_len);
+       }
+
+       /* queue all fragments atomically */
+       spin_lock_irqsave(&ndev->tx_q.lock, flags);
+
+       while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
+               __skb_queue_tail(&ndev->tx_q, skb_frag);
+
+       spin_unlock_irqrestore(&ndev->tx_q.lock, flags);
+
+       /* free the original skb */
+       kfree_skb(skb);
+
+       goto exit;
+
+free_exit:
+       while ((skb_frag = __skb_dequeue(&frags_q)) != NULL)
+               kfree_skb(skb_frag);
+
+exit:
+       return rc;
+}
+
+/* Send NCI data */
+int nci_send_data(struct nci_dev *ndev, __u8 conn_id, struct sk_buff *skb)
+{
+       int rc = 0;
+
+       nfc_dbg("entry, conn_id 0x%x, plen %d", conn_id, skb->len);
+
+       /* check if the packet need to be fragmented */
+       if (skb->len <= ndev->max_pkt_payload_size) {
+               /* no need to fragment packet */
+               nci_push_data_hdr(ndev, conn_id, skb, NCI_PBF_LAST);
+
+               skb_queue_tail(&ndev->tx_q, skb);
+       } else {
+               /* fragment packet and queue the fragments */
+               rc = nci_queue_tx_data_frags(ndev, conn_id, skb);
+               if (rc) {
+                       nfc_err("failed to fragment tx data packet");
+                       goto free_exit;
+               }
+       }
+
+       queue_work(ndev->tx_wq, &ndev->tx_work);
+
+       goto exit;
+
+free_exit:
+       kfree_skb(skb);
+
+exit:
+       return rc;
+}
+
+/* ----------------- NCI RX Data ----------------- */
+
+static void nci_add_rx_data_frag(struct nci_dev *ndev,
+                               struct sk_buff *skb,
+                               __u8 pbf)
+{
+       int reassembly_len;
+       int err = 0;
+
+       if (ndev->rx_data_reassembly) {
+               reassembly_len = ndev->rx_data_reassembly->len;
+
+               /* first, make enough room for the already accumulated data */
+               if (skb_cow_head(skb, reassembly_len)) {
+                       nfc_err("error adding room for accumulated rx data");
+
+                       kfree_skb(skb);
+                       skb = 0;
+
+                       kfree_skb(ndev->rx_data_reassembly);
+                       ndev->rx_data_reassembly = 0;
+
+                       err = -ENOMEM;
+                       goto exit;
+               }
+
+               /* second, combine the two fragments */
+               memcpy(skb_push(skb, reassembly_len),
+                               ndev->rx_data_reassembly->data,
+                               reassembly_len);
+
+               /* third, free old reassembly */
+               kfree_skb(ndev->rx_data_reassembly);
+               ndev->rx_data_reassembly = 0;
+       }
+
+       if (pbf == NCI_PBF_CONT) {
+               /* need to wait for next fragment, store skb and exit */
+               ndev->rx_data_reassembly = skb;
+               return;
+       }
+
+exit:
+       nci_data_exchange_complete(ndev, skb, err);
+}
+
+/* Rx Data packet */
+void nci_rx_data_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       __u8 pbf = nci_pbf(skb->data);
+
+       nfc_dbg("entry, len %d", skb->len);
+
+       nfc_dbg("NCI RX: MT=data, PBF=%d, conn_id=%d, plen=%d",
+                       nci_pbf(skb->data),
+                       nci_conn_id(skb->data),
+                       nci_plen(skb->data));
+
+       /* strip the nci data header */
+       skb_pull(skb, NCI_DATA_HDR_SIZE);
+
+       if (ndev->target_active_prot == NFC_PROTO_MIFARE) {
+               /* frame I/F => remove the status byte */
+               nfc_dbg("NFC_PROTO_MIFARE => remove the status byte");
+               skb_trim(skb, (skb->len - 1));
+       }
+
+       nci_add_rx_data_frag(ndev, skb, pbf);
+}
diff --git a/net/nfc/nci/lib.c b/net/nfc/nci/lib.c
new file mode 100644 (file)
index 0000000..b19dc2f
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on lib.c, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+
+#include <net/nfc/nci.h>
+
+/* NCI status codes to Unix errno mapping */
+int nci_to_errno(__u8 code)
+{
+       switch (code) {
+       case NCI_STATUS_OK:
+               return 0;
+
+       case NCI_STATUS_REJECTED:
+               return -EBUSY;
+
+       case NCI_STATUS_MESSAGE_CORRUPTED:
+               return -EBADMSG;
+
+       case NCI_STATUS_BUFFER_FULL:
+               return -ENOBUFS;
+
+       case NCI_STATUS_NOT_INITIALIZED:
+               return -EHOSTDOWN;
+
+       case NCI_STATUS_SYNTAX_ERROR:
+       case NCI_STATUS_SEMANTIC_ERROR:
+       case NCI_STATUS_INVALID_PARAM:
+       case NCI_STATUS_RF_PROTOCOL_ERROR:
+       case NCI_STATUS_NFCEE_PROTOCOL_ERROR:
+               return -EPROTO;
+
+       case NCI_STATUS_UNKNOWN_GID:
+       case NCI_STATUS_UNKNOWN_OID:
+               return -EBADRQC;
+
+       case NCI_STATUS_MESSAGE_SIZE_EXCEEDED:
+               return -EMSGSIZE;
+
+       case NCI_STATUS_DISCOVERY_ALREADY_STARTED:
+               return -EALREADY;
+
+       case NCI_STATUS_DISCOVERY_TARGET_ACTIVATION_FAILED:
+       case NCI_STATUS_NFCEE_INTERFACE_ACTIVATION_FAILED:
+               return -ECONNREFUSED;
+
+       case NCI_STATUS_RF_TRANSMISSION_ERROR:
+       case NCI_STATUS_NFCEE_TRANSMISSION_ERROR:
+               return -ECOMM;
+
+       case NCI_STATUS_RF_TIMEOUT_ERROR:
+       case NCI_STATUS_NFCEE_TIMEOUT_ERROR:
+               return -ETIMEDOUT;
+
+       case NCI_STATUS_RF_LINK_LOSS_ERROR:
+               return -ENOLINK;
+
+       case NCI_STATUS_MAX_ACTIVE_NFCEE_INTERFACES_REACHED:
+               return -EDQUOT;
+
+       case NCI_STATUS_FAILED:
+       default:
+               return -ENOSYS;
+       }
+}
+EXPORT_SYMBOL(nci_to_errno);
diff --git a/net/nfc/nci/ntf.c b/net/nfc/nci/ntf.c
new file mode 100644 (file)
index 0000000..96633f5
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_event.c, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include <linux/nfc.h>
+
+/* Handle NCI Notification packets */
+
+static void nci_core_conn_credits_ntf_packet(struct nci_dev *ndev,
+                                               struct sk_buff *skb)
+{
+       struct nci_core_conn_credit_ntf *ntf = (void *) skb->data;
+       int i;
+
+       nfc_dbg("entry, num_entries %d", ntf->num_entries);
+
+       if (ntf->num_entries > NCI_MAX_NUM_CONN)
+               ntf->num_entries = NCI_MAX_NUM_CONN;
+
+       /* update the credits */
+       for (i = 0; i < ntf->num_entries; i++) {
+               nfc_dbg("entry[%d]: conn_id %d, credits %d", i,
+                       ntf->conn_entries[i].conn_id,
+                       ntf->conn_entries[i].credits);
+
+               if (ntf->conn_entries[i].conn_id == ndev->conn_id) {
+                       /* found static rf connection */
+                       atomic_add(ntf->conn_entries[i].credits,
+                               &ndev->credits_cnt);
+               }
+       }
+
+       /* trigger the next tx */
+       if (!skb_queue_empty(&ndev->tx_q))
+               queue_work(ndev->tx_wq, &ndev->tx_work);
+}
+
+static void nci_rf_field_info_ntf_packet(struct nci_dev *ndev,
+                                       struct sk_buff *skb)
+{
+       struct nci_rf_field_info_ntf *ntf = (void *) skb->data;
+
+       nfc_dbg("entry, rf_field_status %d", ntf->rf_field_status);
+}
+
+static int nci_rf_activate_nfca_passive_poll(struct nci_dev *ndev,
+                       struct nci_rf_activate_ntf *ntf, __u8 *data)
+{
+       struct rf_tech_specific_params_nfca_poll *nfca_poll;
+       struct activation_params_nfca_poll_iso_dep *nfca_poll_iso_dep;
+
+       nfca_poll = &ntf->rf_tech_specific_params.nfca_poll;
+       nfca_poll_iso_dep = &ntf->activation_params.nfca_poll_iso_dep;
+
+       nfca_poll->sens_res = __le16_to_cpu(*((__u16 *)data));
+       data += 2;
+
+       nfca_poll->nfcid1_len = *data++;
+
+       nfc_dbg("sens_res 0x%x, nfcid1_len %d",
+               nfca_poll->sens_res,
+               nfca_poll->nfcid1_len);
+
+       memcpy(nfca_poll->nfcid1, data, nfca_poll->nfcid1_len);
+       data += nfca_poll->nfcid1_len;
+
+       nfca_poll->sel_res_len = *data++;
+
+       if (nfca_poll->sel_res_len != 0)
+               nfca_poll->sel_res = *data++;
+
+       ntf->rf_interface_type = *data++;
+       ntf->activation_params_len = *data++;
+
+       nfc_dbg("sel_res_len %d, sel_res 0x%x, rf_interface_type %d, activation_params_len %d",
+               nfca_poll->sel_res_len,
+               nfca_poll->sel_res,
+               ntf->rf_interface_type,
+               ntf->activation_params_len);
+
+       switch (ntf->rf_interface_type) {
+       case NCI_RF_INTERFACE_ISO_DEP:
+               nfca_poll_iso_dep->rats_res_len = *data++;
+               if (nfca_poll_iso_dep->rats_res_len > 0) {
+                       memcpy(nfca_poll_iso_dep->rats_res,
+                               data,
+                               nfca_poll_iso_dep->rats_res_len);
+               }
+               break;
+
+       case NCI_RF_INTERFACE_FRAME:
+               /* no activation params */
+               break;
+
+       default:
+               nfc_err("unsupported rf_interface_type 0x%x",
+                       ntf->rf_interface_type);
+               return -EPROTO;
+       }
+
+       return 0;
+}
+
+static void nci_target_found(struct nci_dev *ndev,
+                               struct nci_rf_activate_ntf *ntf)
+{
+       struct nfc_target nfc_tgt;
+
+       if (ntf->rf_protocol == NCI_RF_PROTOCOL_T2T)    /* T2T MifareUL */
+               nfc_tgt.supported_protocols = NFC_PROTO_MIFARE_MASK;
+       else if (ntf->rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)   /* 4A */
+               nfc_tgt.supported_protocols = NFC_PROTO_ISO14443_MASK;
+
+       nfc_tgt.sens_res = ntf->rf_tech_specific_params.nfca_poll.sens_res;
+       nfc_tgt.sel_res = ntf->rf_tech_specific_params.nfca_poll.sel_res;
+
+       if (!(nfc_tgt.supported_protocols & ndev->poll_prots)) {
+               nfc_dbg("the target found does not have the desired protocol");
+               return;
+       }
+
+       nfc_dbg("new target found,  supported_protocols 0x%x",
+               nfc_tgt.supported_protocols);
+
+       ndev->target_available_prots = nfc_tgt.supported_protocols;
+
+       nfc_targets_found(ndev->nfc_dev, &nfc_tgt, 1);
+}
+
+static void nci_rf_activate_ntf_packet(struct nci_dev *ndev,
+                                       struct sk_buff *skb)
+{
+       struct nci_rf_activate_ntf ntf;
+       __u8 *data = skb->data;
+       int rc = -1;
+
+       clear_bit(NCI_DISCOVERY, &ndev->flags);
+       set_bit(NCI_POLL_ACTIVE, &ndev->flags);
+
+       ntf.target_handle = *data++;
+       ntf.rf_protocol = *data++;
+       ntf.rf_tech_and_mode = *data++;
+       ntf.rf_tech_specific_params_len = *data++;
+
+       nfc_dbg("target_handle %d, rf_protocol 0x%x, rf_tech_and_mode 0x%x, rf_tech_specific_params_len %d",
+               ntf.target_handle,
+               ntf.rf_protocol,
+               ntf.rf_tech_and_mode,
+               ntf.rf_tech_specific_params_len);
+
+       switch (ntf.rf_tech_and_mode) {
+       case NCI_NFC_A_PASSIVE_POLL_MODE:
+               rc = nci_rf_activate_nfca_passive_poll(ndev, &ntf,
+                       data);
+               break;
+
+       default:
+               nfc_err("unsupported rf_tech_and_mode 0x%x",
+                       ntf.rf_tech_and_mode);
+               return;
+       }
+
+       if (!rc)
+               nci_target_found(ndev, &ntf);
+}
+
+static void nci_rf_deactivate_ntf_packet(struct nci_dev *ndev,
+                                       struct sk_buff *skb)
+{
+       __u8 type = skb->data[0];
+
+       nfc_dbg("entry, type 0x%x", type);
+
+       clear_bit(NCI_POLL_ACTIVE, &ndev->flags);
+       ndev->target_active_prot = 0;
+
+       /* drop tx data queue */
+       skb_queue_purge(&ndev->tx_q);
+
+       /* drop partial rx data packet */
+       if (ndev->rx_data_reassembly) {
+               kfree_skb(ndev->rx_data_reassembly);
+               ndev->rx_data_reassembly = 0;
+       }
+
+       /* complete the data exchange transaction, if exists */
+       if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
+               nci_data_exchange_complete(ndev, NULL, -EIO);
+}
+
+void nci_ntf_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       __u16 ntf_opcode = nci_opcode(skb->data);
+
+       nfc_dbg("NCI RX: MT=ntf, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+                       nci_pbf(skb->data),
+                       nci_opcode_gid(ntf_opcode),
+                       nci_opcode_oid(ntf_opcode),
+                       nci_plen(skb->data));
+
+       /* strip the nci control header */
+       skb_pull(skb, NCI_CTRL_HDR_SIZE);
+
+       switch (ntf_opcode) {
+       case NCI_OP_CORE_CONN_CREDITS_NTF:
+               nci_core_conn_credits_ntf_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_FIELD_INFO_NTF:
+               nci_rf_field_info_ntf_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_ACTIVATE_NTF:
+               nci_rf_activate_ntf_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_DEACTIVATE_NTF:
+               nci_rf_deactivate_ntf_packet(ndev, skb);
+               break;
+
+       default:
+               nfc_err("unknown ntf opcode 0x%x", ntf_opcode);
+               break;
+       }
+
+       kfree_skb(skb);
+}
diff --git a/net/nfc/nci/rsp.c b/net/nfc/nci/rsp.c
new file mode 100644 (file)
index 0000000..0403d4c
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ *  The NFC Controller Interface is the communication protocol between an
+ *  NFC Controller (NFCC) and a Device Host (DH).
+ *
+ *  Copyright (C) 2011 Texas Instruments, Inc.
+ *
+ *  Written by Ilan Elias <ilane@ti.com>
+ *
+ *  Acknowledgements:
+ *  This file is based on hci_event.c, which was written
+ *  by Maxim Krasnyansky.
+ *
+ *  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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/skbuff.h>
+
+#include "../nfc.h"
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+
+/* Handle NCI Response packets */
+
+static void nci_core_reset_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       struct nci_core_reset_rsp *rsp = (void *) skb->data;
+
+       nfc_dbg("entry, status 0x%x", rsp->status);
+
+       if (rsp->status == NCI_STATUS_OK)
+               ndev->nci_ver = rsp->nci_ver;
+
+       nfc_dbg("nci_ver 0x%x", ndev->nci_ver);
+
+       nci_req_complete(ndev, rsp->status);
+}
+
+static void nci_core_init_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       struct nci_core_init_rsp_1 *rsp_1 = (void *) skb->data;
+       struct nci_core_init_rsp_2 *rsp_2;
+
+       nfc_dbg("entry, status 0x%x", rsp_1->status);
+
+       if (rsp_1->status != NCI_STATUS_OK)
+               return;
+
+       ndev->nfcc_features = __le32_to_cpu(rsp_1->nfcc_features);
+       ndev->num_supported_rf_interfaces = rsp_1->num_supported_rf_interfaces;
+
+       if (ndev->num_supported_rf_interfaces >
+               NCI_MAX_SUPPORTED_RF_INTERFACES) {
+               ndev->num_supported_rf_interfaces =
+                       NCI_MAX_SUPPORTED_RF_INTERFACES;
+       }
+
+       memcpy(ndev->supported_rf_interfaces,
+               rsp_1->supported_rf_interfaces,
+               ndev->num_supported_rf_interfaces);
+
+       rsp_2 = (void *) (skb->data + 6 + ndev->num_supported_rf_interfaces);
+
+       ndev->max_logical_connections =
+               rsp_2->max_logical_connections;
+       ndev->max_routing_table_size =
+               __le16_to_cpu(rsp_2->max_routing_table_size);
+       ndev->max_control_packet_payload_length =
+               rsp_2->max_control_packet_payload_length;
+       ndev->rf_sending_buffer_size =
+               __le16_to_cpu(rsp_2->rf_sending_buffer_size);
+       ndev->rf_receiving_buffer_size =
+               __le16_to_cpu(rsp_2->rf_receiving_buffer_size);
+       ndev->manufacturer_id =
+               __le16_to_cpu(rsp_2->manufacturer_id);
+
+       nfc_dbg("nfcc_features 0x%x",
+               ndev->nfcc_features);
+       nfc_dbg("num_supported_rf_interfaces %d",
+               ndev->num_supported_rf_interfaces);
+       nfc_dbg("supported_rf_interfaces[0] 0x%x",
+               ndev->supported_rf_interfaces[0]);
+       nfc_dbg("supported_rf_interfaces[1] 0x%x",
+               ndev->supported_rf_interfaces[1]);
+       nfc_dbg("supported_rf_interfaces[2] 0x%x",
+               ndev->supported_rf_interfaces[2]);
+       nfc_dbg("supported_rf_interfaces[3] 0x%x",
+               ndev->supported_rf_interfaces[3]);
+       nfc_dbg("max_logical_connections %d",
+               ndev->max_logical_connections);
+       nfc_dbg("max_routing_table_size %d",
+               ndev->max_routing_table_size);
+       nfc_dbg("max_control_packet_payload_length %d",
+               ndev->max_control_packet_payload_length);
+       nfc_dbg("rf_sending_buffer_size %d",
+               ndev->rf_sending_buffer_size);
+       nfc_dbg("rf_receiving_buffer_size %d",
+               ndev->rf_receiving_buffer_size);
+       nfc_dbg("manufacturer_id 0x%x",
+               ndev->manufacturer_id);
+
+       nci_req_complete(ndev, rsp_1->status);
+}
+
+static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
+                                               struct sk_buff *skb)
+{
+       struct nci_core_conn_create_rsp *rsp = (void *) skb->data;
+
+       nfc_dbg("entry, status 0x%x", rsp->status);
+
+       if (rsp->status != NCI_STATUS_OK)
+               return;
+
+       ndev->max_pkt_payload_size = rsp->max_pkt_payload_size;
+       ndev->initial_num_credits = rsp->initial_num_credits;
+       ndev->conn_id = rsp->conn_id;
+
+       atomic_set(&ndev->credits_cnt, ndev->initial_num_credits);
+
+       nfc_dbg("max_pkt_payload_size %d", ndev->max_pkt_payload_size);
+       nfc_dbg("initial_num_credits %d", ndev->initial_num_credits);
+       nfc_dbg("conn_id %d", ndev->conn_id);
+}
+
+static void nci_rf_disc_map_rsp_packet(struct nci_dev *ndev,
+                                       struct sk_buff *skb)
+{
+       __u8 status = skb->data[0];
+
+       nfc_dbg("entry, status 0x%x", status);
+
+       nci_req_complete(ndev, status);
+}
+
+static void nci_rf_disc_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       __u8 status = skb->data[0];
+
+       nfc_dbg("entry, status 0x%x", status);
+
+       if (status == NCI_STATUS_OK)
+               set_bit(NCI_DISCOVERY, &ndev->flags);
+
+       nci_req_complete(ndev, status);
+}
+
+static void nci_rf_deactivate_rsp_packet(struct nci_dev *ndev,
+                                       struct sk_buff *skb)
+{
+       __u8 status = skb->data[0];
+
+       nfc_dbg("entry, status 0x%x", status);
+
+       clear_bit(NCI_DISCOVERY, &ndev->flags);
+
+       nci_req_complete(ndev, status);
+}
+
+void nci_rsp_packet(struct nci_dev *ndev, struct sk_buff *skb)
+{
+       __u16 rsp_opcode = nci_opcode(skb->data);
+
+       /* we got a rsp, stop the cmd timer */
+       del_timer(&ndev->cmd_timer);
+
+       nfc_dbg("NCI RX: MT=rsp, PBF=%d, GID=0x%x, OID=0x%x, plen=%d",
+                       nci_pbf(skb->data),
+                       nci_opcode_gid(rsp_opcode),
+                       nci_opcode_oid(rsp_opcode),
+                       nci_plen(skb->data));
+
+       /* strip the nci control header */
+       skb_pull(skb, NCI_CTRL_HDR_SIZE);
+
+       switch (rsp_opcode) {
+       case NCI_OP_CORE_RESET_RSP:
+               nci_core_reset_rsp_packet(ndev, skb);
+               break;
+
+       case NCI_OP_CORE_INIT_RSP:
+               nci_core_init_rsp_packet(ndev, skb);
+               break;
+
+       case NCI_OP_CORE_CONN_CREATE_RSP:
+               nci_core_conn_create_rsp_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_DISCOVER_MAP_RSP:
+               nci_rf_disc_map_rsp_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_DISCOVER_RSP:
+               nci_rf_disc_rsp_packet(ndev, skb);
+               break;
+
+       case NCI_OP_RF_DEACTIVATE_RSP:
+               nci_rf_deactivate_rsp_packet(ndev, skb);
+               break;
+
+       default:
+               nfc_err("unknown rsp opcode 0x%x", rsp_opcode);
+               break;
+       }
+
+       kfree_skb(skb);
+
+       /* trigger the next cmd */
+       atomic_set(&ndev->cmd_cnt, 1);
+       if (!skb_queue_empty(&ndev->cmd_q))
+               queue_work(ndev->cmd_wq, &ndev->cmd_work);
+}
index ccdff7953f7d888973d2fcb99c7554170e67f01b..03f8818e1f166a2b0eefe11862523df7e582ee33 100644 (file)
@@ -367,6 +367,52 @@ out_putdev:
        return rc;
 }
 
+static int nfc_genl_dev_up(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nfc_dev *dev;
+       int rc;
+       u32 idx;
+
+       nfc_dbg("entry");
+
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+               return -EINVAL;
+
+       idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+       dev = nfc_get_device(idx);
+       if (!dev)
+               return -ENODEV;
+
+       rc = nfc_dev_up(dev);
+
+       nfc_put_device(dev);
+       return rc;
+}
+
+static int nfc_genl_dev_down(struct sk_buff *skb, struct genl_info *info)
+{
+       struct nfc_dev *dev;
+       int rc;
+       u32 idx;
+
+       nfc_dbg("entry");
+
+       if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+               return -EINVAL;
+
+       idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+       dev = nfc_get_device(idx);
+       if (!dev)
+               return -ENODEV;
+
+       rc = nfc_dev_down(dev);
+
+       nfc_put_device(dev);
+       return rc;
+}
+
 static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
 {
        struct nfc_dev *dev;
@@ -440,6 +486,16 @@ static struct genl_ops nfc_genl_ops[] = {
                .done = nfc_genl_dump_devices_done,
                .policy = nfc_genl_policy,
        },
+       {
+               .cmd = NFC_CMD_DEV_UP,
+               .doit = nfc_genl_dev_up,
+               .policy = nfc_genl_policy,
+       },
+       {
+               .cmd = NFC_CMD_DEV_DOWN,
+               .doit = nfc_genl_dev_down,
+               .policy = nfc_genl_policy,
+       },
        {
                .cmd = NFC_CMD_START_POLL,
                .doit = nfc_genl_start_poll,
index aaf9832298f34d9c932c39060a4ca94fe1f5e208..b6753f45624e3e3fdd17c4338173778ee21b136b 100644 (file)
@@ -24,7 +24,7 @@
 #ifndef __LOCAL_NFC_H
 #define __LOCAL_NFC_H
 
-#include <net/nfc.h>
+#include <net/nfc/nfc.h>
 #include <net/sock.h>
 
 __attribute__((format (printf, 2, 3)))
@@ -101,6 +101,10 @@ static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
        class_dev_iter_exit(iter);
 }
 
+int nfc_dev_up(struct nfc_dev *dev);
+
+int nfc_dev_down(struct nfc_dev *dev);
+
 int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
 
 int nfc_stop_poll(struct nfc_dev *dev);
index be90640a2774bfedb73a89ea340186428d2afdfd..5be19575c340886ff869e94dc7ae65c0e959e00c 100644 (file)
@@ -235,7 +235,7 @@ static bool __rfkill_set_hw_state(struct rfkill *rfkill,
        else
                rfkill->state &= ~RFKILL_BLOCK_HW;
        *change = prev != blocked;
-       any = rfkill->state & RFKILL_BLOCK_ANY;
+       any = !!(rfkill->state & RFKILL_BLOCK_ANY);
        spin_unlock_irqrestore(&rfkill->lock, flags);
 
        rfkill_led_trigger_event(rfkill);
index 796a4bdf8b0d8901f571cc81436ab0719abbab17..b9ec3061ed722c4dc58b526d0c545ce64ad5f163 100644 (file)
@@ -375,7 +375,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie);
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie);
 
 /* SME */
 int __cfg80211_connect(struct cfg80211_registered_device *rdev,
@@ -406,6 +407,7 @@ void cfg80211_sme_failed_assoc(struct wireless_dev *wdev);
 bool cfg80211_sme_failed_reassoc(struct wireless_dev *wdev);
 
 /* internal helpers */
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher);
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr);
index 832f6574e4ed7dab26d949154d0aefe04303e98b..21fc9702f81c355a772803f507aa8496801adb0e 100644 (file)
@@ -900,7 +900,8 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
                          bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, u64 *cookie)
+                         const u8 *buf, size_t len, bool no_cck,
+                         u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        const struct ieee80211_mgmt *mgmt;
@@ -991,7 +992,7 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
        /* Transmit the Action frame as requested by user space */
        return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
                                  channel_type, channel_type_valid,
-                                 wait, buf, len, cookie);
+                                 wait, buf, len, no_cck, cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
@@ -1095,3 +1096,14 @@ void cfg80211_gtk_rekey_notify(struct net_device *dev, const u8 *bssid,
        nl80211_gtk_rekey_notify(rdev, dev, bssid, replay_ctr, gfp);
 }
 EXPORT_SYMBOL(cfg80211_gtk_rekey_notify);
+
+void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
+                                    const u8 *bssid, bool preauth, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
+
+       nl80211_pmksa_candidate_notify(rdev, dev, index, bssid, preauth, gfp);
+}
+EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
index 11089541bb031b8735c9b5d7ec2e1550a959a839..b85075761e2422eaa2f8f2170501359b3e400bab 100644 (file)
@@ -191,6 +191,7 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
                                         .len = IEEE80211_MAX_DATA_LEN },
        [NL80211_ATTR_ROAM_SUPPORT] = { .type = NLA_FLAG },
        [NL80211_ATTR_SCHED_SCAN_MATCH] = { .type = NLA_NESTED },
+       [NL80211_ATTR_TX_NO_CCK_RATE] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -1235,6 +1236,11 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        goto bad_res;
                }
 
+               if (!netdev) {
+                       result = -EINVAL;
+                       goto bad_res;
+               }
+
                nla_for_each_nested(nl_txq_params,
                                    info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS],
                                    rem_txq_params) {
@@ -1247,6 +1253,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                                goto bad_res;
 
                        result = rdev->ops->set_txq_params(&rdev->wiphy,
+                                                          netdev,
                                                           &txq_params);
                        if (result)
                                goto bad_res;
@@ -2613,7 +2620,7 @@ static int nl80211_new_station(struct sk_buff *skb, struct genl_info *info)
 
        /* parse WME attributes if sta is WME capable */
        if ((rdev->wiphy.flags & WIPHY_FLAG_AP_UAPSD) &&
-           (params.sta_flags_set & NL80211_STA_FLAG_WME) &&
+           (params.sta_flags_set & BIT(NL80211_STA_FLAG_WME)) &&
            info->attrs[NL80211_ATTR_STA_WME]) {
                struct nlattr *tb[NL80211_STA_WME_MAX + 1];
                struct nlattr *nla;
@@ -3620,6 +3627,9 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       request->no_cck =
+               nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
        request->dev = dev;
        request->wiphy = &rdev->wiphy;
 
@@ -4126,22 +4136,6 @@ static bool nl80211_valid_wpa_versions(u32 wpa_versions)
                                  NL80211_WPA_VERSION_2));
 }
 
-static bool nl80211_valid_akm_suite(u32 akm)
-{
-       return akm == WLAN_AKM_SUITE_8021X ||
-               akm == WLAN_AKM_SUITE_PSK;
-}
-
-static bool nl80211_valid_cipher_suite(u32 cipher)
-{
-       return cipher == WLAN_CIPHER_SUITE_WEP40 ||
-               cipher == WLAN_CIPHER_SUITE_WEP104 ||
-               cipher == WLAN_CIPHER_SUITE_TKIP ||
-               cipher == WLAN_CIPHER_SUITE_CCMP ||
-               cipher == WLAN_CIPHER_SUITE_AES_CMAC;
-}
-
-
 static int nl80211_authenticate(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4274,7 +4268,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                memcpy(settings->ciphers_pairwise, data, len);
 
                for (i = 0; i < settings->n_ciphers_pairwise; i++)
-                       if (!nl80211_valid_cipher_suite(
+                       if (!cfg80211_supported_cipher_suite(
+                                       &rdev->wiphy,
                                        settings->ciphers_pairwise[i]))
                                return -EINVAL;
        }
@@ -4282,7 +4277,8 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
        if (info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]) {
                settings->cipher_group =
                        nla_get_u32(info->attrs[NL80211_ATTR_CIPHER_SUITE_GROUP]);
-               if (!nl80211_valid_cipher_suite(settings->cipher_group))
+               if (!cfg80211_supported_cipher_suite(&rdev->wiphy,
+                                                    settings->cipher_group))
                        return -EINVAL;
        }
 
@@ -4295,7 +4291,7 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
 
        if (info->attrs[NL80211_ATTR_AKM_SUITES]) {
                void *data;
-               int len, i;
+               int len;
 
                data = nla_data(info->attrs[NL80211_ATTR_AKM_SUITES]);
                len = nla_len(info->attrs[NL80211_ATTR_AKM_SUITES]);
@@ -4304,11 +4300,10 @@ static int nl80211_crypto_settings(struct cfg80211_registered_device *rdev,
                if (len % sizeof(u32))
                        return -EINVAL;
 
-               memcpy(settings->akm_suites, data, len);
+               if (settings->n_akm_suites > NL80211_MAX_NR_AKM_SUITES)
+                       return -EINVAL;
 
-               for (i = 0; i < settings->n_ciphers_pairwise; i++)
-                       if (!nl80211_valid_akm_suite(settings->akm_suites[i]))
-                               return -EINVAL;
+               memcpy(settings->akm_suites, data, len);
        }
 
        return 0;
@@ -4527,8 +4522,12 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
 
        wiphy = &rdev->wiphy;
 
-       if (info->attrs[NL80211_ATTR_MAC])
+       if (info->attrs[NL80211_ATTR_MAC]) {
                ibss.bssid = nla_data(info->attrs[NL80211_ATTR_MAC]);
+
+               if (!is_valid_ether_addr(ibss.bssid))
+                       return -EINVAL;
+       }
        ibss.ssid = nla_data(info->attrs[NL80211_ATTR_SSID]);
        ibss.ssid_len = nla_len(info->attrs[NL80211_ATTR_SSID]);
 
@@ -5185,6 +5184,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        struct sk_buff *msg;
        unsigned int wait = 0;
        bool offchan;
+       bool no_cck;
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -5221,6 +5221,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 
+       no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
+
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
        if (chan == NULL)
@@ -5241,7 +5243,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                                    channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
-                                   &cookie);
+                                   no_cck, &cookie);
        if (err)
                goto free_msg;
 
@@ -7266,6 +7268,52 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
        nlmsg_free(msg);
 }
 
+void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+                                   struct net_device *netdev, int index,
+                                   const u8 *bssid, bool preauth, gfp_t gfp)
+{
+       struct sk_buff *msg;
+       struct nlattr *attr;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, gfp);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_PMKSA_CANDIDATE);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
+
+       attr = nla_nest_start(msg, NL80211_ATTR_PMKSA_CANDIDATE);
+       if (!attr)
+               goto nla_put_failure;
+
+       NLA_PUT_U32(msg, NL80211_PMKSA_CANDIDATE_INDEX, index);
+       NLA_PUT(msg, NL80211_PMKSA_CANDIDATE_BSSID, ETH_ALEN, bssid);
+       if (preauth)
+               NLA_PUT_FLAG(msg, NL80211_PMKSA_CANDIDATE_PREAUTH);
+
+       nla_nest_end(msg, attr);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
+       return;
+
+ nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
 void
 nl80211_send_cqm_pktloss_notify(struct cfg80211_registered_device *rdev,
                                struct net_device *netdev, const u8 *peer,
index 5d69c56400aedf2bf7e26e0c5294e1c120d3a070..f24a1fbeaf19a8bf3cee73a3ec8b3b33d6e0f0ad 100644 (file)
@@ -113,4 +113,8 @@ void nl80211_gtk_rekey_notify(struct cfg80211_registered_device *rdev,
                              struct net_device *netdev, const u8 *bssid,
                              const u8 *replay_ctr, gfp_t gfp);
 
+void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
+                                   struct net_device *netdev, int index,
+                                   const u8 *bssid, bool preauth, gfp_t gfp);
+
 #endif /* __NET_WIRELESS_NL80211_H */
index b0f0039669536164f0f9d67147030f3f43c8a0a0..0fb1424104047ced0d99949be89388509e05fc5c 100644 (file)
@@ -228,6 +228,33 @@ const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len)
 }
 EXPORT_SYMBOL(cfg80211_find_ie);
 
+const u8 *cfg80211_find_vendor_ie(unsigned int oui, u8 oui_type,
+                                 const u8 *ies, int len)
+{
+       struct ieee80211_vendor_ie *ie;
+       const u8 *pos = ies, *end = ies + len;
+       int ie_oui;
+
+       while (pos < end) {
+               pos = cfg80211_find_ie(WLAN_EID_VENDOR_SPECIFIC, pos,
+                                      end - pos);
+               if (!pos)
+                       return NULL;
+
+               if (end - pos < sizeof(*ie))
+                       return NULL;
+
+               ie = (struct ieee80211_vendor_ie *)pos;
+               ie_oui = ie->oui[0] << 16 | ie->oui[1] << 8 | ie->oui[2];
+               if (ie_oui == oui && ie->oui_type == oui_type)
+                       return pos;
+
+               pos += 2 + ie->len;
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(cfg80211_find_vendor_ie);
+
 static int cmp_ies(u8 num, u8 *ies1, size_t len1, u8 *ies2, size_t len2)
 {
        const u8 *ie1 = cfg80211_find_ie(num, ies1, len1);
index dec0fa28372e5f5363d79d0ba912cf1e37704dd9..6e86d5acf145bef1d7ba2e842fd61f1b50610c69 100644 (file)
@@ -110,17 +110,22 @@ static int cfg80211_conn_scan(struct wireless_dev *wdev)
        else {
                int i = 0, j;
                enum ieee80211_band band;
+               struct ieee80211_supported_band *bands;
+               struct ieee80211_channel *channel;
 
                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-                       if (!wdev->wiphy->bands[band])
+                       bands = wdev->wiphy->bands[band];
+                       if (!bands)
                                continue;
-                       for (j = 0; j < wdev->wiphy->bands[band]->n_channels;
-                            i++, j++)
-                               request->channels[i] =
-                                       &wdev->wiphy->bands[band]->channels[j];
-                       request->rates[band] =
-                               (1 << wdev->wiphy->bands[band]->n_bitrates) - 1;
+                       for (j = 0; j < bands->n_channels; j++) {
+                               channel = &bands->channels[j];
+                               if (channel->flags & IEEE80211_CHAN_DISABLED)
+                                       continue;
+                               request->channels[i++] = channel;
+                       }
+                       request->rates[band] = (1 << bands->n_bitrates) - 1;
                }
+               n_channels = i;
        }
        request->n_channels = n_channels;
        request->ssids = (void *)&request->channels[n_channels];
index 39dbf4ad7ca17cdca7581355b5a5b0aaa6221b48..6304ed63588a6e1909ca39676a44266f1eb62d1e 100644 (file)
@@ -151,12 +151,19 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
                        set_mandatory_flags_band(wiphy->bands[band], band);
 }
 
+bool cfg80211_supported_cipher_suite(struct wiphy *wiphy, u32 cipher)
+{
+       int i;
+       for (i = 0; i < wiphy->n_cipher_suites; i++)
+               if (cipher == wiphy->cipher_suites[i])
+                       return true;
+       return false;
+}
+
 int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                                   struct key_params *params, int key_idx,
                                   bool pairwise, const u8 *mac_addr)
 {
-       int i;
-
        if (key_idx > 5)
                return -EINVAL;
 
@@ -226,10 +233,7 @@ int cfg80211_validate_key_settings(struct cfg80211_registered_device *rdev,
                }
        }
 
-       for (i = 0; i < rdev->wiphy.n_cipher_suites; i++)
-               if (params->cipher == rdev->wiphy.cipher_suites[i])
-                       break;
-       if (i == rdev->wiphy.n_cipher_suites)
+       if (!cfg80211_supported_cipher_suite(&rdev->wiphy, params->cipher))
                return -EINVAL;
 
        return 0;